diff options
4 files changed, 189 insertions, 37 deletions
diff --git a/java/sca/modules/databinding-jaxb-axiom/src/main/java/org/apache/tuscany/sca/databinding/jaxb/axiom/JAXBDataSource.java b/java/sca/modules/databinding-jaxb-axiom/src/main/java/org/apache/tuscany/sca/databinding/jaxb/axiom/JAXBDataSource.java index dd9fbfbfd0..b6fa362ed9 100644 --- a/java/sca/modules/databinding-jaxb-axiom/src/main/java/org/apache/tuscany/sca/databinding/jaxb/axiom/JAXBDataSource.java +++ b/java/sca/modules/databinding-jaxb-axiom/src/main/java/org/apache/tuscany/sca/databinding/jaxb/axiom/JAXBDataSource.java @@ -16,7 +16,6 @@ * specific language governing permissions and limitations * under the License. */ - package org.apache.tuscany.sca.databinding.jaxb.axiom; import java.io.OutputStream; @@ -37,6 +36,7 @@ import javax.xml.stream.XMLStreamWriter; import org.apache.axiom.om.OMDataSource; import org.apache.axiom.om.OMOutputFormat; import org.apache.axiom.om.util.StAXUtils; +import org.apache.tuscany.sca.databinding.jaxb.JAXBContextHelper; /** * @@ -55,11 +55,14 @@ public class JAXBDataSource implements OMDataSource { private Marshaller getMarshaller() throws JAXBException { if (marshaller == null) { // For thread safety, not sure we can cache the marshaller - // marshaller = JAXBContextHelper.getMarshaller(context); - marshaller = context.createMarshaller(); + marshaller = JAXBContextHelper.getMarshaller(context); } return marshaller; } + + private void releaseMarshaller(Marshaller marshaller) { + JAXBContextHelper.releaseJAXBMarshaller(context, marshaller); + } public XMLStreamReader getReader() throws XMLStreamException { // FIXME: [rfeng] This is a quick and dirty implementation @@ -75,11 +78,12 @@ public class JAXBDataSource implements OMDataSource { // marshaller.setProperty(Marshaller.JAXB_ENCODING, format.getCharSetEncoding()); AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() { public Object run() throws Exception { - Marshaller marshaller = getMarshaller(); - // Set the FRAGEMENT property to avoid duplicate XML declaration - marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE); - marshaller.marshal(element, xmlWriter); - marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.FALSE); + try { + Marshaller marshaller = getMarshaller(); + marshaller.marshal(element, xmlWriter); + } finally { + releaseMarshaller(marshaller); + } return null; } }); @@ -93,8 +97,12 @@ public class JAXBDataSource implements OMDataSource { // marshaller.setProperty(Marshaller.JAXB_ENCODING, format.getCharSetEncoding()); AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() { public Object run() throws Exception { - Marshaller marshaller = getMarshaller(); - marshaller.marshal(element, output); + try { + Marshaller marshaller = getMarshaller(); + marshaller.marshal(element, output); + } finally { + releaseMarshaller(marshaller); + } return null; } }); @@ -107,8 +115,12 @@ public class JAXBDataSource implements OMDataSource { try { AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() { public Object run() throws Exception { - Marshaller marshaller = getMarshaller(); - marshaller.marshal(element, writer); + try { + Marshaller marshaller = getMarshaller(); + marshaller.marshal(element, writer); + } finally { + releaseMarshaller(marshaller); + } return null; } }); diff --git a/java/sca/modules/databinding-jaxb-axiom/src/main/java/org/apache/tuscany/sca/databinding/jaxb/axiom/OMElement2JAXB.java b/java/sca/modules/databinding-jaxb-axiom/src/main/java/org/apache/tuscany/sca/databinding/jaxb/axiom/OMElement2JAXB.java index 00e99aaacd..827a1684bc 100644 --- a/java/sca/modules/databinding-jaxb-axiom/src/main/java/org/apache/tuscany/sca/databinding/jaxb/axiom/OMElement2JAXB.java +++ b/java/sca/modules/databinding-jaxb-axiom/src/main/java/org/apache/tuscany/sca/databinding/jaxb/axiom/OMElement2JAXB.java @@ -16,7 +16,6 @@ * specific language governing permissions and limitations * under the License. */ - package org.apache.tuscany.sca.databinding.jaxb.axiom; import java.security.AccessController; @@ -51,15 +50,21 @@ public class OMElement2JAXB extends BaseTransformer<OMElement, Object> implement try { return AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() { public Object run() throws JAXBException, XMLStreamException { + Unmarshaller unmarshaller = null; + XMLStreamReader reader = null; + Object result = null; // Marshalling directly to the output stream is faster than marshalling through the // XMLStreamWriter. // Take advantage of this optimization if there is an output stream. JAXBContext jaxbContext = JAXBContextHelper.createJAXBContext(context, false); - Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); - XMLStreamReader reader = source.getXMLStreamReaderWithoutCaching(); - Object result = - unmarshaller.unmarshal(reader, JAXBContextHelper.getJavaType(context.getTargetDataType())); - reader.close(); + try { + unmarshaller = JAXBContextHelper.getUnmarshaller(jaxbContext); + reader = source.getXMLStreamReaderWithoutCaching(); + result = unmarshaller.unmarshal(reader, JAXBContextHelper.getJavaType(context.getTargetDataType())); + } finally { + reader.close(); + JAXBContextHelper.releaseJAXBUnmarshaller(jaxbContext, unmarshaller); + } return JAXBContextHelper.createReturnValue(jaxbContext, context.getTargetDataType(), result); } }); diff --git a/java/sca/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBContextCache.java b/java/sca/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBContextCache.java index 296c39c50f..c64ce81fdf 100644 --- a/java/sca/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBContextCache.java +++ b/java/sca/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBContextCache.java @@ -16,21 +16,26 @@ * specific language governing permissions and limitations * under the License. */ - package org.apache.tuscany.sca.databinding.jaxb; import java.awt.Image; +import java.lang.ref.SoftReference; import java.net.URI; import java.security.AccessController; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; +import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; import java.util.Set; import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; import javax.activation.DataHandler; import javax.xml.bind.JAXBContext; @@ -86,8 +91,8 @@ public class JAXBContextCache { */ protected LRUCache<Object, JAXBContext> cache; - protected LRUCache<JAXBContext, Unmarshaller> upool; - protected LRUCache<JAXBContext, Marshaller> mpool; + protected Pool<JAXBContext, Marshaller> mpool; + protected Pool<JAXBContext, Unmarshaller> upool; // protected JAXBContext commonContext; protected JAXBContext defaultContext; @@ -98,8 +103,8 @@ public class JAXBContextCache { public JAXBContextCache(int contextSize, int marshallerSize, int unmarshallerSize) { cache = new LRUCache<Object, JAXBContext>(contextSize); - upool = new LRUCache<JAXBContext, Unmarshaller>(unmarshallerSize); - mpool = new LRUCache<JAXBContext, Marshaller>(marshallerSize); + mpool = new Pool<JAXBContext, Marshaller>(); + upool = new Pool<JAXBContext, Unmarshaller>(); defaultContext = getDefaultJAXBContext(); } @@ -180,27 +185,38 @@ public class JAXBContextCache { } public Marshaller getMarshaller(JAXBContext context) throws JAXBException { - synchronized (mpool) { - Marshaller marshaller = mpool.get(context); - if (marshaller == null) { - marshaller = context.createMarshaller(); - mpool.put(context, marshaller); - } - return marshaller; + Marshaller marshaller = mpool.get(context); + if (marshaller == null) { + marshaller = context.createMarshaller(); } + marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE); + return marshaller; } + public void releaseJAXBMarshaller(JAXBContext context, Marshaller marshaller) { + if (marshaller != null) { + marshaller.setAttachmentMarshaller(null); + mpool.put(context, marshaller); + // No point unsetting marshaller's JAXB_FRAGMENT property, since we'll just reset it when + // doing the next get. + } + } + public Unmarshaller getUnmarshaller(JAXBContext context) throws JAXBException { - synchronized (upool) { - Unmarshaller unmarshaller = upool.get(context); - if (unmarshaller == null) { - unmarshaller = context.createUnmarshaller(); - upool.put(context, unmarshaller); - } - return unmarshaller; + Unmarshaller unmarshaller = upool.get(context); + if (unmarshaller == null) { + unmarshaller = context.createUnmarshaller(); } + return unmarshaller; } + public void releaseJAXBUnmarshaller(JAXBContext context, Unmarshaller unmarshaller) { + if (unmarshaller != null) { + unmarshaller.setAttachmentUnmarshaller(null); + upool.put(context, unmarshaller); + } + } + public LRUCache<Object, JAXBContext> getCache() { return cache; } @@ -282,12 +298,123 @@ public class JAXBContextCache { synchronized (cache) { cache.clear(); } + /* synchronized (upool) { upool.clear(); } synchronized (upool) { upool.clear(); } + */ } + // + // This inner class is copied in its entirety from the Axis2 utility class, + // org.apache.axis2.jaxws.message.databinding.JAXBUtils. We could look into extending but it's such a basic data structure + // without other dependencies so we might be better off copying it and avoiding a new + // Axis2 dependency here. + // + + /** + * Pool a list of items for a specific key + * + * @param <K> Key + * @param <V> Pooled object + */ + private static class Pool<K,V> { + private SoftReference<Map<K,List<V>>> softMap = + new SoftReference<Map<K,List<V>>>( + new ConcurrentHashMap<K, List<V>>()); + + // The maps are freed up when a LOAD FACTOR is hit + private static int MAX_LIST_FACTOR = 50; + private static int MAX_LOAD_FACTOR = 32; // Maximum number of JAXBContext to store + + /** + * @param key + * @return removed item from pool or null. + */ + public V get(K key) { + List<V> values = getValues(key); + synchronized (values) { + if (values.size()>0) { + V v = values.remove(values.size()-1); + return v; + + } + } + return null; + } + + /** + * Add item back to pool + * @param key + * @param value + */ + public void put(K key, V value) { + adjustSize(); + List<V> values = getValues(key); + synchronized (values) { + if (values.size() < MAX_LIST_FACTOR) { + values.add(value); + } + } + } + + /** + * Get or create a list of the values for the key + * @param key + * @return list of values. + */ + private List<V> getValues(K key) { + Map<K,List<V>> map = softMap.get(); + List<V> values = null; + if (map != null) { + values = map.get(key); + if(values !=null) { + return values; + } + } + synchronized (this) { + if (map != null) { + values = map.get(key); + } + if (values == null) { + if (map == null) { + map = new ConcurrentHashMap<K, List<V>>(); + softMap = + new SoftReference<Map<K,List<V>>>(map); + } + values = new ArrayList<V>(); + map.put(key, values); + + } + return values; + } + } + + /** + * AdjustSize + * When the number of keys exceeds the maximum load, half + * of the entries are deleted. + * + * The assumption is that the JAXBContexts, UnMarshallers, Marshallers, etc. require + * a large footprint. + */ + private void adjustSize() { + Map<K,List<V>> map = softMap.get(); + if (map != null && map.size() > MAX_LOAD_FACTOR) { + // Remove every other Entry in the map. + Iterator it = map.entrySet().iterator(); + boolean removeIt = false; + while (it.hasNext()) { + it.next(); + if (removeIt) { + it.remove(); + } + removeIt = !removeIt; + } + } + } + } } diff --git a/java/sca/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBContextHelper.java b/java/sca/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBContextHelper.java index ef832bfb68..7297399f5e 100644 --- a/java/sca/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBContextHelper.java +++ b/java/sca/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBContextHelper.java @@ -112,10 +112,18 @@ public class JAXBContextHelper { return cache.getUnmarshaller(context); } + public static void releaseJAXBUnmarshaller(JAXBContext context, Unmarshaller unmarshaller) { + cache.releaseJAXBUnmarshaller(context, unmarshaller); + } + public static Marshaller getMarshaller(JAXBContext context) throws JAXBException { return cache.getMarshaller(context); } + public static void releaseJAXBMarshaller(JAXBContext context, Marshaller marshaller) { + cache.releaseJAXBMarshaller(context, marshaller); + } + @SuppressWarnings("unchecked") public static Object createJAXBElement(JAXBContext context, DataType dataType, Object value) { Class<?> type = dataType == null ? value.getClass() : dataType.getPhysical(); |