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);
}
}
}