diff options
Diffstat (limited to 'sca-java-2.x/tags/2.0-Beta2-RC3/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBContextCache.java')
-rw-r--r-- | sca-java-2.x/tags/2.0-Beta2-RC3/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBContextCache.java | 561 |
1 files changed, 0 insertions, 561 deletions
diff --git a/sca-java-2.x/tags/2.0-Beta2-RC3/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBContextCache.java b/sca-java-2.x/tags/2.0-Beta2-RC3/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBContextCache.java deleted file mode 100644 index 025b4f7c73..0000000000 --- a/sca-java-2.x/tags/2.0-Beta2-RC3/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBContextCache.java +++ /dev/null @@ -1,561 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.tuscany.sca.databinding.jaxb; - -import java.awt.Image; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -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.Collection; -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; -import javax.xml.bind.JAXBException; -import javax.xml.bind.Marshaller; -import javax.xml.bind.Unmarshaller; -import javax.xml.bind.annotation.XmlEnum; -import javax.xml.bind.annotation.XmlRootElement; -import javax.xml.bind.annotation.XmlSeeAlso; -import javax.xml.bind.annotation.XmlTransient; -import javax.xml.bind.annotation.XmlType; -import javax.xml.datatype.DatatypeFactory; -import javax.xml.transform.Source; - -import org.apache.tuscany.sca.common.java.collection.LRUCache; -import org.apache.tuscany.sca.core.ExtensionPointRegistry; -import org.apache.tuscany.sca.extensibility.ClassLoaderContext; - -/** - * @version $Rev$ $Date$ - */ -public class JAXBContextCache { - private static final int CACHE_SIZE = 128; - - private static HashMap<String, Class<?>> loadClassMap = new HashMap<String, Class<?>>(); - - static { - loadClassMap.put("byte", byte.class); - loadClassMap.put("int", int.class); - loadClassMap.put("short", short.class); - loadClassMap.put("long", long.class); - loadClassMap.put("float", float.class); - loadClassMap.put("double", double.class); - loadClassMap.put("boolean", boolean.class); - loadClassMap.put("char", char.class); - loadClassMap.put("void", void.class); - } - - protected static Class<?>[] JAXB_BUILTIN_CLASSES = - {byte[].class, boolean.class, byte.class, char.class, double.class, float.class, int.class, long.class, - short.class, void.class, java.awt.Image.class, java.io.File.class, java.lang.Boolean.class, - java.lang.Byte.class, java.lang.Character.class, java.lang.Class.class, java.lang.Double.class, - java.lang.Float.class, java.lang.Integer.class, java.lang.Long.class, java.lang.Object.class, - java.lang.Short.class, java.lang.String.class, java.lang.Void.class, java.math.BigDecimal.class, - java.math.BigInteger.class, java.net.URI.class, java.net.URL.class, java.util.Calendar.class, - java.util.Date.class, java.util.GregorianCalendar.class, java.util.UUID.class, - javax.activation.DataHandler.class, javax.xml.bind.JAXBElement.class, javax.xml.datatype.Duration.class, - javax.xml.datatype.XMLGregorianCalendar.class, javax.xml.namespace.QName.class, - javax.xml.transform.Source.class}; - - protected static final Set<Class<?>> BUILTIN_CLASSES_SET = new HashSet<Class<?>>(Arrays.asList(JAXB_BUILTIN_CLASSES)); - - /* - protected static Class<?>[] COMMON_ARRAY_CLASSES = - new Class[] {char[].class, short[].class, int[].class, long[].class, float[].class, double[].class, - String[].class - }; - - protected static final Set<Class<?>> COMMON_CLASSES_SET = new HashSet<Class<?>>(Arrays.asList(COMMON_ARRAY_CLASSES)); - */ - - protected LRUCache<Object, JAXBContext> cache; - protected Pool<JAXBContext, Marshaller> mpool; - protected Pool<JAXBContext, Unmarshaller> upool; - - // protected JAXBContext commonContext; - protected JAXBContext defaultContext; - private ExtensionPointRegistry registry; - - public JAXBContextCache(ExtensionPointRegistry registry) { - this(CACHE_SIZE, CACHE_SIZE, CACHE_SIZE, registry); - } - - public JAXBContextCache(int contextSize, int marshallerSize, int unmarshallerSize, ExtensionPointRegistry registry) { - this.registry = registry; - cache = new LRUCache<Object, JAXBContext>(contextSize); - mpool = new Pool<JAXBContext, Marshaller>(); - upool = new Pool<JAXBContext, Unmarshaller>(); - defaultContext = getDefaultJAXBContext(); - } - - private JAXBContext newJAXBContext(final Class<?>... classesToBeBound) throws JAXBException { - try { - return AccessController.doPrivileged(new PrivilegedExceptionAction<JAXBContext>() { - public JAXBContext run() throws JAXBException { - // Try to set up TCCL so that JAXBContext service discovery works in OSGi - ClassLoader tccl = - ClassLoaderContext.setContextClassLoader(JAXBContextCache.class.getClassLoader(), - registry.getServiceDiscovery(), - // The service provider of JAXBContext doesn't extend JAXBContext - // We should use the service name instead of the class - JAXBContext.class.getName(), - DatatypeFactory.class.getName()); - try { - JAXBContext context = JAXBContext.newInstance(classesToBeBound); - return context; - } finally { - if (tccl != null) { - Thread.currentThread().setContextClassLoader(tccl); - } - } - } - }); - } catch (PrivilegedActionException e) { - throw (JAXBException)e.getException(); - } - } - - - public JAXBContext getDefaultJAXBContext() { - try { - return newJAXBContext(); - } catch (JAXBException e) { - throw new IllegalArgumentException(e); - } - } - - /** - * @param name of primitive type - * @return primitive Class or null - */ - public static Class<?> getPrimitiveClass(String text) { - return loadClassMap.get(text); - } - - /** - * Return the class for this name - * - * @return Class - */ - private static Class<?> forName(final String className, final boolean initialize, final ClassLoader classloader) - throws ClassNotFoundException { - // NOTE: This method must remain private because it uses AccessController - Class<?> cl = null; - try { - cl = AccessController.doPrivileged(new PrivilegedExceptionAction<Class<?>>() { - public Class<?> run() throws ClassNotFoundException { - // Class.forName does not support primitives - Class<?> cls = getPrimitiveClass(className); - if (cls == null) { - cls = Class.forName(className, initialize, classloader); - } - return cls; - } - }); - } catch (PrivilegedActionException e) { - throw (ClassNotFoundException)e.getException(); - } - - return cl; - } - - public Marshaller getMarshaller(JAXBContext context) throws JAXBException { - 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 { - 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; - } - - public JAXBContext getJAXBContext(Class<?> cls) throws JAXBException { - if (BUILTIN_CLASSES_SET.contains(cls)) { - return defaultContext; - } - return getJAXBContext(new Class<?>[] {cls}); - } - - public JAXBContext getJAXBContext(Class<?>[] classes) throws JAXBException { - Set<Class<?>> classSet = new HashSet<Class<?>>(Arrays.asList(classes)); - return getJAXBContext(classSet); - } - - public JAXBContext getJAXBContext(Set<Class<?>> classes) throws JAXBException { - // Remove the JAXB built-in types to maximize the cache hit - Set<Class<?>> classSet = new HashSet<Class<?>>(classes); - classSet.removeAll(BUILTIN_CLASSES_SET); - - // FIXME: [rfeng] Remove java classes that are mapped to the same XSD type to avoid - // conflicts - if (classSet.contains(Date[].class)) { - classSet.remove(Calendar[].class); - } - - if (classSet.contains(URI[].class)) { - classSet.remove(UUID[].class); - } - - if (classSet.contains(Source[].class)) { - classSet.remove(Image[].class); - classSet.remove(DataHandler[].class); - } - - classSet = getJAXBClasses(classSet); - - if(classSet.isEmpty()) { - return defaultContext; - } - - synchronized (cache) { - JAXBContext context = cache.get(classSet); - if (context != null) { - return context; - } - context = newJAXBContext(classSet.toArray(new Class<?>[classSet.size()])); - cache.put(classSet, context); - return context; - } - } - - public void clear() { - 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 final int MAX_LIST_FACTOR = 50; - private static final 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; - } - } - } - } - - /** - * Find the JAXB classes (looking into packages) to be bound - * @param classes A collection of classes - * @return A set of classes that include the ObjectFactory and indexed JAXB classes - * @throws JAXBException - */ - private static Set<Class<?>> getJAXBClasses(Collection<Class<?>> classes) throws JAXBException { - Set<Class<?>> classSet = new HashSet<Class<?>>(); - // Index the packages - Map<Package, ClassLoader> pkgs = getPackages(classes); - Set<Package> nonJAXBPackages = new HashSet<Package>(); - for (Map.Entry<Package, ClassLoader> p : pkgs.entrySet()) { - Package pkg = p.getKey(); - if (pkg == null) { - continue; - } - Set<Class<?>> set = getJAXBClasses(pkg.getName(), p.getValue()); - if (set.isEmpty()) { - // No JAXB package - nonJAXBPackages.add(pkg); - } else { - // Add JAXB ObjectFactory and indexed classes - classSet.addAll(set); - } - } - // Adding classes that are not part of JAXB packages - for (Class<?> cls : classes) { - - Package pkg = getPackage(cls); - if (pkg == null || nonJAXBPackages.contains(pkg)) { - classSet.add(cls); - } else { - // TUSCANY-3162: Test if a class is generated by JAXB - // There might be the case that non-JAXB classes are in the same package as the JAXB classes - if (!cls.isAnnotationPresent(XmlType.class) - && !cls.isAnnotationPresent(XmlEnum.class) - && !cls.isAnnotationPresent(XmlSeeAlso.class) - && !cls.isAnnotationPresent(XmlRootElement.class) - && !cls.isAnnotationPresent(XmlTransient.class)) { - classSet.add(cls); - } - } - } - return classSet; - } - - /** - * Get the package for a class, taking array into account - * @param cls - * @return - */ - private static Package getPackage(Class<?> cls) { - Class<?> type = cls; - while (type.isArray()) { - type = type.getComponentType(); - } - return type.getPackage(); - } - - /** - * Get a map of packages - * @param classes - * @return - */ - private static Map<Package, ClassLoader> getPackages(Collection<Class<?>> classes) { - Map<Package, ClassLoader> pkgs = new HashMap<Package, ClassLoader>(); - for (Class<?> cls : classes) { - Package pkg = getPackage(cls); - if (pkg != null) { - pkgs.put(pkg, cls.getClassLoader()); - } - } - return pkgs; - } - - /** - * Find ObjectFactory and indexed JAXB classes for the package - * @param pkg - * @param classLoader - * @return - * @throws JAXBException - */ - private static Set<Class<?>> getJAXBClasses(String pkg, ClassLoader classLoader) throws JAXBException { - Set<Class<?>> classes = new HashSet<Class<?>>(); - List<Class<?>> indexedClasses; - - // look for ObjectFactory and load it - final Class<?> o; - try { - o = forName(pkg + ".ObjectFactory", false, classLoader); - classes.add(o); - } catch (ClassNotFoundException e) { - // not necessarily an error - } - - // look for jaxb.index and load the list of classes - try { - indexedClasses = loadIndexedClasses(pkg, classLoader); - } catch (IOException e) { - throw new JAXBException(e); - } - if (indexedClasses != null) { - classes.addAll(indexedClasses); - } - - return classes; - } - - /** - * Look for jaxb.index file in the specified package and load it's contents - * - * @param pkg package name to search in - * @param classLoader ClassLoader to search in - * @return a List of Class objects to load, null if there weren't any - * @throws IOException if there is an error reading the index file - * @throws JAXBException if there are any errors in the index file - */ - private static List<Class<?>> loadIndexedClasses(String pkg, ClassLoader classLoader) throws IOException, - JAXBException { - if (classLoader == null) { - return null; - } - final String resource = pkg.replace('.', '/') + "/jaxb.index"; - final InputStream resourceAsStream = classLoader.getResourceAsStream(resource); - - if (resourceAsStream == null) { - return null; - } - - BufferedReader in = new BufferedReader(new InputStreamReader(resourceAsStream, "UTF-8")); - try { - List<Class<?>> classes = new ArrayList<Class<?>>(); - String className = in.readLine(); - while (className != null) { - className = className.trim(); - if (className.startsWith("#") || (className.length() == 0)) { - className = in.readLine(); - continue; - } - - try { - classes.add(forName(pkg + '.' + className, false, classLoader)); - } catch (ClassNotFoundException e) { - throw new JAXBException(e); - } - - className = in.readLine(); - } - return classes; - } finally { - in.close(); - } - } - -} - |