package com.fasterxml.aalto.out;

import java.util.*;
import java.lang.ref.SoftReference;

import javax.xml.stream.XMLOutputFactory; // to get constants

import org.codehaus.stax2.XMLOutputFactory2;
import org.codehaus.stax2.XMLStreamProperties;


import com.fasterxml.aalto.impl.CommonConfig;
import com.fasterxml.aalto.util.BufferRecycler;

This is the shared configuration object passed by the factory to writer.
/** * This is the shared configuration object passed by the factory to writer. */
public final class WriterConfig extends CommonConfig { // // // Constants for defaults protected final static String DEFAULT_AUTOMATIC_NS_PREFIX = "ans"; // Standard Stax flags: final static int F_NS_REPAIRING = 0x0001; // Standard Stax2 flags: final static int F_AUTO_CLOSE_OUTPUT = 0x0010; final static int F_NS_AWARE = 0x0020; final static int F_AUTO_EMPTY_ELEMS = 0x0040; // Non-flag (object) properties final static int PROP_AUTO_NS_PREFIX = -2; // No flags are set by default, yet... final static int DEFAULT_FLAGS = F_NS_AWARE ; private final static HashMap<String, Integer> sProperties; static { sProperties = new HashMap<String, Integer>(); sProperties.put(XMLOutputFactory.IS_REPAIRING_NAMESPACES, Integer.valueOf(F_NS_REPAIRING)); // Stax2: // not configurable, but are recognized sProperties.put(XMLStreamProperties.XSP_NAMESPACE_AWARE, Integer.valueOf(F_NS_AWARE)); sProperties.put(XMLStreamProperties.XSP_PROBLEM_REPORTER, null); // and then writer-side properties, mostly unsupported but recognized sProperties.put(XMLOutputFactory2.P_AUTO_CLOSE_OUTPUT, Integer.valueOf(F_AUTO_CLOSE_OUTPUT)); sProperties.put(XMLOutputFactory2.P_AUTOMATIC_EMPTY_ELEMENTS, Integer.valueOf(F_AUTO_EMPTY_ELEMS)); sProperties.put(XMLOutputFactory2.P_AUTOMATIC_NS_PREFIX, Integer.valueOf(PROP_AUTO_NS_PREFIX)); sProperties.put(XMLOutputFactory2.P_TEXT_ESCAPER, null); sProperties.put(XMLOutputFactory2.P_ATTR_VALUE_ESCAPER, null); } /* /********************************************************************** /* Configurable object properties: /********************************************************************** */ private String _propAutoNsPrefix; /* /********************************************************************** /* Output/stream state: /********************************************************************** */
A single encoding context instance is shared between all WriterConfig instances created for readers by an output factory. It is used for sharing symbol tables.
/** * A single encoding context instance is shared between all WriterConfig * instances created for readers by an output factory. It is used * for sharing symbol tables. */
private final EncodingContext _encodingContext;
Encoding passed in either during construction, or via xml declaration write.
/** * Encoding passed in either during construction, or via xml * declaration write. */
private String _encoding; /* /********************************************************************** /* Buffer recycling: /********************************************************************** */
This ThreadLocal contains a SoftRerefence to a BufferRecycler used to provide a low-cost buffer recycling between Reader instances.
/** * This <code>ThreadLocal</code> contains a {@link SoftRerefence} * to a {@link BufferRecycler} used to provide a low-cost * buffer recycling between Reader instances. */
final static ThreadLocal<SoftReference<BufferRecycler>> mRecyclerRef = new ThreadLocal<SoftReference<BufferRecycler>>();
This is the actually container of the recyclable buffers. It is obtained via ThreadLocal/SoftReference combination, if one exists, when Config instance is created. If one does not exist, it will created first time a buffer is returned.
/** * This is the actually container of the recyclable buffers. It * is obtained via ThreadLocal/SoftReference combination, if one * exists, when Config instance is created. If one does not * exist, it will created first time a buffer is returned. */
BufferRecycler _currRecycler = null; /* /********************************************************************** /* Life-cycle /********************************************************************** */ private WriterConfig(String encoding, int flags, int flagMods, EncodingContext encCtxt, String autoNsPrefix) { super(flags, flagMods); _encoding = encoding; _encodingContext = encCtxt; /* Ok, let's then see if we can find a buffer recycler. Since they * are lazily constructed, and since GC may just flush them out * on its whims, it's possible we might not find one. That's ok; * we can reconstruct one if and when we are to return one or more * buffers. */ SoftReference<BufferRecycler> ref = mRecyclerRef.get(); if (ref != null) { _currRecycler = ref.get(); } _flags = flags; _flagMods = flagMods; _propAutoNsPrefix = autoNsPrefix; } public WriterConfig() { this(null, DEFAULT_FLAGS, 0, new EncodingContext(), DEFAULT_AUTOMATIC_NS_PREFIX); } public void setActualEncodingIfNotSet(String enc) { if (_encoding == null || _encoding.length() == 0) { _encoding = enc; } } public void doAutoCloseOutput(boolean state) { setFlag(F_AUTO_CLOSE_OUTPUT, state); } public void enableXml11() { // !!! TBI } /* /********************************************************************** /* Common accessors from CommonConfig /********************************************************************** */ public WriterConfig createNonShared() { return new WriterConfig(_encoding, _flags, _flagMods, _encodingContext, _propAutoNsPrefix); } @Override public boolean isXml11() { return false; } @Override public String getExternalEncoding() { /* !!! 01-Jan-2007, tatus: Can we distinguish this from the * actual encoding? Should we be able to? */ return getActualEncoding(); } @Override public String getActualEncoding() { return _encoding; } public String getPreferredEncoding() { /* If we did have 2 separate encoding decls, we'd prefer actual * over external. For now, doesn't matter */ return _encoding; } /* /********************************************************************** /* Accessors, configurable properties /********************************************************************** */ @Override public Object getProperty(String name, boolean isMandatory) { Integer I = sProperties.get(name); if (I == null) { // Might still have it though if (sProperties.containsKey(name)) { return null; } return super.getProperty(name, isMandatory); } int f = I.intValue(); if (f >= 0) { return hasFlag(f); } switch (f) { case PROP_AUTO_NS_PREFIX: return _propAutoNsPrefix; } // Need to handle non numerics separately? return null; } @Override public boolean setProperty(String name, Object value) { Integer I = sProperties.get(name); if (I == null) { // Might still have it though if (sProperties.containsKey(name)) { return false; } return super.setProperty(name, value); } int f = I.intValue(); if (f >= 0) { // boolean values boolean state = ((Boolean) value).booleanValue(); // Some properties not supported: if (f == F_NS_AWARE) { if (!state) { //throw new IllegalArgumentException("Can not disable namespace-support for stream writers"); return false; // not supported } } setFlag(f, state); return true; } // object values ones switch (f) { case PROP_AUTO_NS_PREFIX: _propAutoNsPrefix = value.toString(); return true; } return false; } @Override public boolean isPropertySupported(String propName) { return sProperties.containsKey(propName) || super.isPropertySupported(propName); } /* /********************************************************************** /* Accessors /********************************************************************** */ // // // Configuration, Stax std props: public boolean willRepairNamespaces() { return hasFlag(F_NS_REPAIRING); } public boolean isNamespaceAware() { // !!! TBI return hasFlag(F_NS_AWARE); } // // // Stax2 standard properties public boolean willAutoCloseOutput() { return hasFlag(F_AUTO_CLOSE_OUTPUT); }
Returns:Prefix to use as the base for automatically generated namespace prefixes ("namespace prefix prefix", so to speak). Defaults to "axns".
/** * @return Prefix to use as the base for automatically generated * namespace prefixes ("namespace prefix prefix", so to speak). * Defaults to "axns". */
public String getAutomaticNsPrefix() { return _propAutoNsPrefix; } /* /********************************************************************** /* Stax2 additions /********************************************************************** */ public void configureForXmlConformance() { // !!! TBI /* doValidateAttributes(true); doValidateContent(true); doValidateStructure(true); doValidateNames(true); */ } public void configureForRobustness() { // !!! TBI /* doValidateAttributes(true); doValidateStructure(true); doValidateNames(true); doValidateContent(true); doFixContent(true); */ }
For Woodstox, setting this profile disables most checks for validity; specifically anything that can have measurable performance impact.
/** * For Woodstox, setting this profile disables most checks for validity; * specifically anything that can have measurable performance impact. * */
public void configureForSpeed() { // !!! TBI /* doValidateAttributes(false); doValidateContent(false); doValidateNames(false); // Structural validation is cheap: can be left enabled (if already so) //doValidateStructure(false); */ } /* /********************************************************************** /* Impl specific additions, validation /********************************************************************** */ public boolean willCheckStructure() { // !!! TBI return true; } public boolean willCheckContent() { // !!! TBI return true; } public boolean willCheckNames() { // !!! TBI return false; } public boolean willCheckAttributes() { // !!! TBI return false; } public boolean willFixContent() { // !!! TBI return true; } public boolean willEscapeCR() { // !!! TBI return true; } /* /********************************************************************** /* Buffer recycling: /********************************************************************** */ public char[] allocMediumCBuffer(int minSize) { if (_currRecycler != null) { char[] result = _currRecycler.getMediumCBuffer(minSize); if (result != null) { return result; } } return new char[minSize]; } public void freeMediumCBuffer(char[] buffer) { if (_currRecycler == null) { _currRecycler = createRecycler(); } _currRecycler.returnMediumCBuffer(buffer); } public char[] allocFullCBuffer(int minSize) { if (_currRecycler != null) { char[] result = _currRecycler.getFullCBuffer(minSize); if (result != null) { return result; } } return new char[minSize]; } public void freeFullCBuffer(char[] buffer) { // Need to create (and assign) the buffer? if (_currRecycler == null) { _currRecycler = createRecycler(); } _currRecycler.returnFullCBuffer(buffer); } public byte[] allocFullBBuffer(int minSize) { if (_currRecycler != null) { byte[] result = _currRecycler.getFullBBuffer(minSize); if (result != null) { return result; } } return new byte[minSize]; } public void freeFullBBuffer(byte[] buffer) { // Need to create (and assign) the buffer? if (_currRecycler == null) { _currRecycler = createRecycler(); } _currRecycler.returnFullBBuffer(buffer); } private BufferRecycler createRecycler() { BufferRecycler recycler = new BufferRecycler(); // No way to reuse/reset SoftReference, have to create new always: mRecyclerRef.set(new SoftReference<BufferRecycler>(recycler)); return recycler; } /* /********************************************************************** /* Symbol table reusing, character types /********************************************************************** */ public WNameTable getUtf8Symbols(WNameFactory f) { return _encodingContext.getUtf8Symbols(f); } public WNameTable getLatin1Symbols(WNameFactory f) { return _encodingContext.getLatin1Symbols(f); } public WNameTable getAsciiSymbols(WNameFactory f) { return _encodingContext.getAsciiSymbols(f); } public WNameTable getCharSymbols(WNameFactory f) { return _encodingContext.getCharSymbols(f); } /* /********************************************************************** /* Helper classes /********************************************************************** */
This is a simple container class that is used to encapsulate per-factory encoding-dependant information like symbol tables.
/** * This is a simple container class that is used to encapsulate * per-factory encoding-dependant information like symbol tables. */
final static class EncodingContext { WNameTable mUtf8Table; WNameTable mLatin1Table; WNameTable mAsciiTable; WNameTable mCharTable; EncodingContext() { } public synchronized WNameTable getUtf8Symbols(WNameFactory f) { if (mUtf8Table == null) { mUtf8Table = new WNameTable(64); } return mUtf8Table.createChild(f); } public synchronized WNameTable getLatin1Symbols(WNameFactory f) { if (mLatin1Table == null) { mLatin1Table = new WNameTable(64); } return mLatin1Table.createChild(f); } public synchronized WNameTable getAsciiSymbols(WNameFactory f) { if (mAsciiTable == null) { mAsciiTable = new WNameTable(64); } return mAsciiTable.createChild(f); } public synchronized WNameTable getCharSymbols(WNameFactory f) { if (mCharTable == null) { mCharTable = new WNameTable(64); } return mCharTable.createChild(f); } } }