package org.compass.core.converter.xsem; import java.io.Reader; import org.compass.core.CompassException; import org.compass.core.config.CompassConfigurable; import org.compass.core.config.CompassEnvironment; import org.compass.core.config.CompassSettings; import org.compass.core.converter.ConversionException; import org.compass.core.xml.AliasedXmlObject; import org.compass.core.xml.XmlObject; /** * An {@link XmlContentConverter} implementation that wraps the actual {@link XmlContentConverter} * configured (based on the settings) and creates and configures a pool of {@link XmlContentConverter}s * for both {@link #toXml(org.compass.core.xml.XmlObject)} and {@link #fromXml(String, java.io.Reader)}. * <p/> * The pool has a maximum capacity, to limit overhead. If all instances in the * pool are in use and another is required, it shall block until one becomes * available. * * @author kimchy */ public class PoolXmlContentConverterWrapper implements XmlContentConverterWrapper, CompassConfigurable { private CompassSettings settings; private int initialPoolSize; private int maxPoolSize; private transient XmlContentConverter[] pool; private int nextAvailable = 0; private final Object mutex = new Object(); /** * Configures the pool used from {@link CompassEnvironment.Xsem.XmlContent#MIN_POOL_SIZE} and * {@link CompassEnvironment.Xsem.XmlContent#MAX_POOL_SIZE}. */ public void configure(CompassSettings settings) throws CompassException { this.settings = settings; this.initialPoolSize = settings.getGloablSettings().getSettingAsInt(CompassEnvironment.Xsem.XmlContent.MIN_POOL_SIZE, 10); this.maxPoolSize = settings.getGloablSettings().getSettingAsInt(CompassEnvironment.Xsem.XmlContent.MAX_POOL_SIZE, 30); // warm up the pool XmlContentConverter converter = fetchFromPool(); putInPool(converter); } /** * Converts the {@link XmlObject} into raw xml by using the pool of * {@link XmlContentConverter}s implementation. * * @see XmlContentConverter#toXml(org.compass.core.xml.XmlObject) */ public String toXml(XmlObject xmlObject) throws ConversionException { XmlContentConverter converter = fetchFromPool(); try { return converter.toXml(xmlObject); } finally { putInPool(converter); } } /** * Converts a raw xml and an alias into an {@link AliasedXmlObject} by using the pool of * {@link XmlContentConverter}s implementation. * * @see XmlContentConverter#fromXml(String, java.io.Reader) */ public AliasedXmlObject fromXml(String alias, Reader xml) throws ConversionException { XmlContentConverter converter = fetchFromPool(); try { return converter.fromXml(alias, xml); } finally { putInPool(converter); } } public XmlContentConverter createContentConverter() { return XmlContentConverterUtils.createXmlContentConverter(settings); } private XmlContentConverter fetchFromPool() { XmlContentConverter result; synchronized (mutex) { if (pool == null) { nextAvailable = -1; pool = new XmlContentConverter[maxPoolSize]; for (int i = 0; i < initialPoolSize; i++) { putInPool(createContentConverter()); } } while (nextAvailable < 0) { try { mutex.wait(); } catch (InterruptedException e) { throw new ConversionException("Interrupted whilst waiting for a free item in the pool", e); } } result = pool[nextAvailable]; nextAvailable--; } if (result == null) { result = createContentConverter(); putInPool(result); } return result; } private void putInPool(XmlContentConverter converter) { synchronized (mutex) { nextAvailable++; pool[nextAvailable] = converter; mutex.notify(); } } }