001: package org.compass.core.converter.xsem;
002:
003: import java.io.Reader;
004:
005: import org.compass.core.CompassException;
006: import org.compass.core.config.CompassConfigurable;
007: import org.compass.core.config.CompassEnvironment;
008: import org.compass.core.config.CompassSettings;
009: import org.compass.core.converter.ConversionException;
010: import org.compass.core.xml.AliasedXmlObject;
011: import org.compass.core.xml.XmlObject;
012:
013: /**
014: * An {@link XmlContentConverter} implementation that wraps the actual {@link XmlContentConverter}
015: * configured (based on the settings) and creates and configures a pool of {@link XmlContentConverter}s
016: * for both {@link #toXml(org.compass.core.xml.XmlObject)} and {@link #fromXml(String, java.io.Reader)}.
017: * <p/>
018: * The pool has a maximum capacity, to limit overhead. If all instances in the
019: * pool are in use and another is required, it shall block until one becomes
020: * available.
021: *
022: * @author kimchy
023: */
024: public class PoolXmlContentConverterWrapper implements
025: XmlContentConverter, CompassConfigurable {
026:
027: private CompassSettings settings;
028:
029: private int initialPoolSize;
030:
031: private int maxPoolSize;
032:
033: private transient XmlContentConverter[] pool;
034:
035: private int nextAvailable = 0;
036:
037: private final Object mutex = new Object();
038:
039: /**
040: * Configures the pool used from {@link CompassEnvironment.Converter.XmlContent#MIN_POOL_SIZE} and
041: * {@link CompassEnvironment.Converter.XmlContent#MAX_POOL_SIZE}.
042: */
043: public void configure(CompassSettings settings)
044: throws CompassException {
045: this .settings = settings;
046: this .initialPoolSize = settings.getSettingAsInt(
047: CompassEnvironment.Converter.XmlContent.MIN_POOL_SIZE,
048: 10);
049: this .maxPoolSize = settings.getSettingAsInt(
050: CompassEnvironment.Converter.XmlContent.MAX_POOL_SIZE,
051: 30);
052: // warm up the pool
053: XmlContentConverter converter = fetchFromPool();
054: putInPool(converter);
055: }
056:
057: /**
058: * Converts the {@link XmlObject} into raw xml by using the pool of
059: * {@link XmlContentConverter}s implementation.
060: *
061: * @see XmlContentConverter#toXml(org.compass.core.xml.XmlObject)
062: */
063: public String toXml(XmlObject xmlObject) throws ConversionException {
064: XmlContentConverter converter = fetchFromPool();
065: try {
066: return converter.toXml(xmlObject);
067: } finally {
068: putInPool(converter);
069: }
070: }
071:
072: /**
073: * Converts a raw xml and an alias into an {@link AliasedXmlObject} by using the pool of
074: * {@link XmlContentConverter}s implementation.
075: *
076: * @see XmlContentConverter#fromXml(String, java.io.Reader)
077: */
078: public AliasedXmlObject fromXml(String alias, Reader xml)
079: throws ConversionException {
080: XmlContentConverter converter = fetchFromPool();
081: try {
082: return converter.fromXml(alias, xml);
083: } finally {
084: putInPool(converter);
085: }
086: }
087:
088: private XmlContentConverter fetchFromPool() {
089: XmlContentConverter result;
090: synchronized (mutex) {
091: if (pool == null) {
092: nextAvailable = -1;
093: pool = new XmlContentConverter[maxPoolSize];
094: for (int i = 0; i < initialPoolSize; i++) {
095: putInPool(XmlContentConverterUtils
096: .createXmlContentConverter(settings));
097: }
098: }
099: while (nextAvailable < 0) {
100: try {
101: mutex.wait();
102: } catch (InterruptedException e) {
103: throw new ConversionException(
104: "Interrupted whilst waiting for a free item in the pool",
105: e);
106: }
107: }
108: result = pool[nextAvailable];
109: nextAvailable--;
110: }
111: if (result == null) {
112: result = XmlContentConverterUtils
113: .createXmlContentConverter(settings);
114: putInPool(result);
115: }
116: return result;
117: }
118:
119: private void putInPool(XmlContentConverter converter) {
120: synchronized (mutex) {
121: nextAvailable++;
122: pool[nextAvailable] = converter;
123: mutex.notify();
124: }
125: }
126: }
|