diff options
9 files changed, 200 insertions, 37 deletions
diff --git a/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/interfacedef/impl/DataTypeImpl.java b/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/interfacedef/impl/DataTypeImpl.java index 5d084d9289..8d84e0352e 100644 --- a/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/interfacedef/impl/DataTypeImpl.java +++ b/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/interfacedef/impl/DataTypeImpl.java @@ -18,6 +18,7 @@ */ package org.apache.tuscany.sca.interfacedef.impl; +import java.lang.ref.WeakReference; import java.lang.reflect.Type; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -44,8 +45,8 @@ import org.apache.tuscany.sca.interfacedef.DataType; */ public class DataTypeImpl<L> implements DataType<L> { private String dataBinding; - private Class<?> physical; - private Type genericType; + private WeakReference<Class<?>> physical; + private WeakReference<Type> genericType; private L logical; private Map<Class<?>, Object> metaDataMap; @@ -78,8 +79,8 @@ public class DataTypeImpl<L> implements DataType<L> { public DataTypeImpl(String dataBinding, Class<?> physical, Type genericType, L logical) { super(); this.dataBinding = dataBinding; - this.physical = physical; - this.genericType = genericType; + this.physical = new WeakReference<Class<?>>(physical); + this.genericType = new WeakReference<Type>(genericType); this.logical = logical; } @@ -89,14 +90,14 @@ public class DataTypeImpl<L> implements DataType<L> { * @return the physical type used by the runtime */ public Class<?> getPhysical() { - return physical; + return physical.get(); } /** * @param physical the physical to set */ public void setPhysical(Class<?> physical) { - this.physical = physical; + this.physical = new WeakReference<Class<?>>(physical); } /** @@ -104,7 +105,7 @@ public class DataTypeImpl<L> implements DataType<L> { * @return The java generic type */ public Type getGenericType() { - return genericType; + return genericType.get(); } /** @@ -112,7 +113,7 @@ public class DataTypeImpl<L> implements DataType<L> { * @param genericType */ public void setGenericType(Type genericType) { - this.genericType = genericType; + this.genericType = new WeakReference<Type>(genericType); } /** @@ -156,8 +157,8 @@ public class DataTypeImpl<L> implements DataType<L> { StringBuilder b = new StringBuilder( 256 ); b.append( "DataType[" ); b.append( "dataBinding=" + ((dataBinding==null) ? "null" : dataBinding) ); - b.append( ", genericType=" + ((genericType==null) ? "null" : genericType) ); - b.append( ", physical=" + ((physical==null) ? "null" : physical) ); + b.append( ", genericType=" + ((genericType==null || genericType.get() == null) ? "null" : genericType) ); + b.append( ", physical=" + ((physical==null || physical.get() == null) ? "null" : physical) ); b.append( ", logical=" + ((logical==null) ? "null" : logical) ); b.append( ", metaData size=" + ((metaDataMap==null) ? "0" : metaDataMap.size()) ); b.append( "]" ); @@ -190,9 +191,9 @@ public class DataTypeImpl<L> implements DataType<L> { final int prime = 31; int result = 1; result = prime * result + ((dataBinding == null) ? 0 : dataBinding.hashCode()); - result = prime * result + ((genericType == null) ? 0 : genericType.hashCode()); + result = prime * result + ((genericType == null || genericType.get() == null) ? 0 : genericType.hashCode()); result = prime * result + ((logical == null) ? 0 : logical.hashCode()); - result = prime * result + ((physical == null) ? 0 : physical.hashCode()); + result = prime * result + ((physical == null || physical.get() == null) ? 0 : physical.hashCode()); return result; } @@ -210,20 +211,20 @@ public class DataTypeImpl<L> implements DataType<L> { return false; } else if (!dataBinding.equals(other.dataBinding)) return false; - if (genericType == null) { - if (other.genericType != null) + if (genericType == null || genericType.get() == null) { + if (other.genericType != null && other.genericType.get() != null) return false; - } else if (!genericType.equals(other.genericType)) + } else if (!genericType.get().equals(other.genericType.get())) return false; if (logical == null) { if (other.logical != null) return false; } else if (!logical.equals(other.logical)) return false; - if (physical == null) { - if (other.physical != null) + if (physical == null || physical.get() == null) { + if (other.physical != null && other.physical.get() != null) return false; - } else if (!physical.equals(other.physical)) + } else if (!physical.get().equals(other.physical.get())) return false; return true; } diff --git a/sca-java-2.x/trunk/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBContextCache.java b/sca-java-2.x/trunk/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBContextCache.java index 77b6b619ad..5ddf7d3604 100644 --- a/sca-java-2.x/trunk/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBContextCache.java +++ b/sca-java-2.x/trunk/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBContextCache.java @@ -59,6 +59,7 @@ 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; +import org.oasisopen.sca.ServiceRuntimeException; /** * @version $Rev$ $Date$ @@ -403,6 +404,12 @@ public class JAXBContextCache { } } } + public void removeCtx(K key){ + Map<K,List<V>> map = softMap.get(); + if (map !=null && key !=null){ + map.remove(key); + } + } } /** @@ -566,5 +573,61 @@ public class JAXBContextCache { } } -} + public void removeJAXBContextFromPools(JAXBContext ctx){ + if (mpool != null && ctx != null){ + mpool.removeCtx(ctx); + } + if (upool != null && ctx !=null){ + upool.removeCtx(ctx); + } + } + + /** + * Removes all the cached information relating to a contribution. The + * contribution is identified by the contribution classloader passed in + * as a parameter. This is used when a contribution is removed from + * the runtime. + * + * @param contributionClassloader + */ + public void removeJAXBContextForContribution(ClassLoader contributionClassloader){ + if (cache != null){ + try { + synchronized(cache) { + Set<Object> objSet = cache.keySet(); + List<Object> toRemove = new ArrayList<Object>(); + Iterator<Object> i = objSet.iterator(); + while(i.hasNext()) { + Object obj = i.next(); + if (obj instanceof Set){ + Set<Class> innerSet = (Set<Class>)obj; + Iterator<Class> j = innerSet.iterator(); + loop: + while(j.hasNext()) { + Class cls = j.next(); + ClassLoader cl = cls.getClassLoader(); + while (cl != null){ + if (cl == contributionClassloader){ + toRemove.add(obj); + break loop; + } + // take account of generated classes + cl = cl.getParent(); + } + } + } + } + for (Object obj : toRemove){ + JAXBContext ctx = cache.get(obj); + removeJAXBContextFromPools(ctx); + cache.remove(obj); + } + } + } catch(Exception e) { + throw new ServiceRuntimeException(e); + } + } + } + +} diff --git a/sca-java-2.x/trunk/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBContextHelper.java b/sca-java-2.x/trunk/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBContextHelper.java index 1837e43c36..44c172a07a 100644 --- a/sca-java-2.x/trunk/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBContextHelper.java +++ b/sca-java-2.x/trunk/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBContextHelper.java @@ -66,7 +66,7 @@ import org.apache.tuscany.sca.interfacedef.util.XMLType; * * @version $Rev$ $Date$ */ -// FIXME: [rfeng] We probably should turn this into a pluggable system service + public final class JAXBContextHelper { private final JAXBContextCache cache; private final static SimpleTypeMapper SIMPLE_TYPE_MAPPER = new SimpleTypeMapperImpl(); @@ -587,4 +587,14 @@ public final class JAXBContextHelper { return name.substring(0, decap).toLowerCase() + name.substring(decap); } + public void removeJAXBContextForContribution(ClassLoader contributionClassloader){ + cache.removeJAXBContextForContribution(contributionClassloader); + } + + /** + * Just for testing that the cache is being removed on stop + */ + public JAXBContextCache getJAXBContextCache(){ + return cache; + } } diff --git a/sca-java-2.x/trunk/modules/deployment/src/main/java/org/apache/tuscany/sca/deployment/impl/DeployerImpl.java b/sca-java-2.x/trunk/modules/deployment/src/main/java/org/apache/tuscany/sca/deployment/impl/DeployerImpl.java index 0725237936..ae9a869417 100644 --- a/sca-java-2.x/trunk/modules/deployment/src/main/java/org/apache/tuscany/sca/deployment/impl/DeployerImpl.java +++ b/sca-java-2.x/trunk/modules/deployment/src/main/java/org/apache/tuscany/sca/deployment/impl/DeployerImpl.java @@ -226,7 +226,7 @@ public class DeployerImpl implements Deployer { // Add the (empty) matchingExports List and report a warning import_.setModelResolver(new DefaultImportModelResolver(matchingExports)); - // push context here as the "stack" in this case is a list of nexted contributions + // push context here as the "stack" in this case is a list of nested contributions // through which imports have been chased which may not make much sense to the // user so just report the contribution in error monitor.pushContext("Contribution: " + contribution.getURI()); diff --git a/sca-java-2.x/trunk/modules/domain-node/pom.xml b/sca-java-2.x/trunk/modules/domain-node/pom.xml index 7f012c48a3..56092a1f9d 100644 --- a/sca-java-2.x/trunk/modules/domain-node/pom.xml +++ b/sca-java-2.x/trunk/modules/domain-node/pom.xml @@ -37,12 +37,19 @@ <artifactId>tuscany-node-impl</artifactId> <version>2.0-SNAPSHOT</version> </dependency> + <dependency> <groupId>org.apache.tuscany.sca</groupId> <artifactId>tuscany-assembly-xml</artifactId> <version>2.0-SNAPSHOT</version> </dependency> + <dependency> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-databinding-jaxb</artifactId> + <version>2.0-SNAPSHOT</version> + </dependency> + <dependency> <groupId>org.apache.tuscany.sca</groupId> <artifactId>tuscany-implementation-java-runtime</artifactId> @@ -55,7 +62,7 @@ <artifactId>tuscany-data-api</artifactId> <version>2.0-SNAPSHOT</version> <scope>test</scope> - </dependency> + </dependency> <dependency> <groupId>org.apache.tuscany.sca</groupId> diff --git a/sca-java-2.x/trunk/modules/domain-node/src/main/java/org/apache/tuscany/sca/impl/NodeImpl.java b/sca-java-2.x/trunk/modules/domain-node/src/main/java/org/apache/tuscany/sca/impl/NodeImpl.java index e95dd9f699..9ee36c1e38 100644 --- a/sca-java-2.x/trunk/modules/domain-node/src/main/java/org/apache/tuscany/sca/impl/NodeImpl.java +++ b/sca-java-2.x/trunk/modules/domain-node/src/main/java/org/apache/tuscany/sca/impl/NodeImpl.java @@ -38,6 +38,7 @@ import javax.xml.stream.XMLStreamException; import org.apache.tuscany.sca.Node; import org.apache.tuscany.sca.TuscanyRuntime; +import org.apache.tuscany.sca.assembly.AssemblyFactory; import org.apache.tuscany.sca.assembly.Composite; import org.apache.tuscany.sca.assembly.xml.Utils; import org.apache.tuscany.sca.common.java.io.IOHelper; @@ -51,8 +52,11 @@ import org.apache.tuscany.sca.contribution.resolver.ClassReference; import org.apache.tuscany.sca.contribution.resolver.ExtensibleModelResolver; import org.apache.tuscany.sca.contribution.resolver.ModelResolver; import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.FactoryExtensionPoint; import org.apache.tuscany.sca.core.UtilityExtensionPoint; +import org.apache.tuscany.sca.databinding.jaxb.JAXBContextHelper; import org.apache.tuscany.sca.deployment.Deployer; +import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceFactory; import org.apache.tuscany.sca.monitor.Monitor; import org.apache.tuscany.sca.monitor.ValidationException; import org.apache.tuscany.sca.runtime.ActivationException; @@ -73,6 +77,8 @@ public class NodeImpl implements Node { private CompositeActivator compositeActivator; private DomainRegistry domainRegistry; private ExtensionPointRegistry extensionPointRegistry; + private UtilityExtensionPoint utilityExtensionPoint; + private FactoryExtensionPoint factoryExtensionPoint; private TuscanyRuntime tuscanyRuntime; private Map<String, Contribution> loadedContributions = new ConcurrentHashMap<String, Contribution>(); @@ -95,8 +101,11 @@ public class NodeImpl implements Node { this.domainRegistry = domainRegistry; this.extensionPointRegistry = extensionPointRegistry; this.tuscanyRuntime = tuscanyRuntime; - - extensionPointRegistry.getExtensionPoint(UtilityExtensionPoint.class).getUtility(ActiveNodes.class).getActiveNodes().add(this); + + utilityExtensionPoint = extensionPointRegistry.getExtensionPoint(UtilityExtensionPoint.class); + factoryExtensionPoint = extensionPointRegistry.getExtensionPoint(FactoryExtensionPoint.class); + + utilityExtensionPoint.getUtility(ActiveNodes.class).getActiveNodes().add(this); domainRegistry.addContributionListener(new ContributionListener() { public void contributionInstalled(String uri) { @@ -226,6 +235,21 @@ public class NodeImpl implements Node { } public void uninstallContribution(String contributionURI) { + // give the runtime the chance to release only artifacts + // held by this contribution (and its classloader) + Contribution contribution = loadedContributions.get(contributionURI); + if (contribution != null) { + ClassLoader contributionClassloader = contribution.getClassLoader(); + + // These are very specific at the moment as there is no + // common lifecycle interface at this level + JAXBContextHelper jaxbContextHelper = utilityExtensionPoint.getUtility(JAXBContextHelper.class); + jaxbContextHelper.removeJAXBContextForContribution(contributionClassloader); + + JavaInterfaceFactory javaInterfaceFactory = factoryExtensionPoint.getFactory(JavaInterfaceFactory.class); + javaInterfaceFactory.removeInterfacesForContribution(contributionClassloader); + } + domainRegistry.uninstallContribution(contributionURI); // remove any stopped composite that used the contribution @@ -236,6 +260,7 @@ public class NodeImpl implements Node { i.remove(); } } + if (logger.isLoggable(quietLogging? Level.FINE : Level.INFO)) logger.log(quietLogging? Level.FINE : Level.INFO, "uninstallContribution: " + contributionURI); } diff --git a/sca-java-2.x/trunk/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/JavaElementImpl.java b/sca-java-2.x/trunk/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/JavaElementImpl.java index e748a5f6fa..44dec0376a 100644 --- a/sca-java-2.x/trunk/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/JavaElementImpl.java +++ b/sca-java-2.x/trunk/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/JavaElementImpl.java @@ -21,6 +21,7 @@ package org.apache.tuscany.sca.implementation.java; import java.lang.annotation.Annotation; import java.lang.annotation.ElementType; +import java.lang.ref.WeakReference; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Constructor; import java.lang.reflect.Field; @@ -36,8 +37,8 @@ import java.lang.reflect.Type; public class JavaElementImpl { private AnnotatedElement anchor; private ElementType elementType; - private Class<?> type; - private Type genericType; + private WeakReference<Class<?>> type; + private WeakReference<Type> genericType; private int index = -1; private String name; private Class<? extends Annotation> classifer; @@ -45,24 +46,24 @@ public class JavaElementImpl { public JavaElementImpl(Class<?> cls) { this.anchor = cls; this.elementType = ElementType.TYPE; - this.type = cls; - this.genericType = cls; + this.type = new WeakReference<Class<?>>(cls); + this.genericType = new WeakReference<Type>(cls); this.name = cls.getName(); } public JavaElementImpl(Field field) { this.anchor = field; this.elementType = ElementType.FIELD; - this.type = field.getType(); - this.genericType = field.getGenericType(); + this.type = new WeakReference<Class<?>>(field.getType()); + this.genericType = new WeakReference<Type>(field.getGenericType()); this.name = field.getName(); } public JavaElementImpl(Constructor<?> constructor, int index) { this.anchor = constructor; this.elementType = ElementType.PARAMETER; - this.type = constructor.getParameterTypes()[index]; - this.genericType = constructor.getGenericParameterTypes()[index]; + this.type = new WeakReference<Class<?>>(constructor.getParameterTypes()[index]); + this.genericType = new WeakReference<Type>(constructor.getGenericParameterTypes()[index]); this.index = index; this.name = ""; } @@ -70,8 +71,8 @@ public class JavaElementImpl { public JavaElementImpl(Method method, int index) { this.anchor = method; this.elementType = ElementType.PARAMETER; - this.type = method.getParameterTypes()[index]; - this.genericType = method.getGenericParameterTypes()[index]; + this.type = new WeakReference<Class<?>>(method.getParameterTypes()[index]); + this.genericType = new WeakReference<Type>(method.getGenericParameterTypes()[index]); this.index = index; this.name = ""; } @@ -86,7 +87,7 @@ public class JavaElementImpl { */ public JavaElementImpl(String name, Class<?> type, Class<? extends Annotation> classifer) { super(); - this.type = type; + this.type = new WeakReference<Class<?>>(type); this.name = name; this.classifer = classifer; } @@ -109,7 +110,7 @@ public class JavaElementImpl { * @return the genericType */ public Type getGenericType() { - return genericType; + return genericType.get(); } /** @@ -123,7 +124,7 @@ public class JavaElementImpl { * @return the type */ public Class<?> getType() { - return type; + return type.get(); } /** diff --git a/sca-java-2.x/trunk/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/JavaInterfaceFactory.java b/sca-java-2.x/trunk/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/JavaInterfaceFactory.java index 55d694d7f8..c1357af9d6 100644 --- a/sca-java-2.x/trunk/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/JavaInterfaceFactory.java +++ b/sca-java-2.x/trunk/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/JavaInterfaceFactory.java @@ -96,4 +96,13 @@ public interface JavaInterfaceFactory { * @return */ List<JavaInterfaceVisitor> getInterfaceVisitors(); + + /** + * Remove the interfaces that have been registered for + * the contribution identified by the contribution class + * loader provided + * + * @param contributionClassloader + */ + void removeInterfacesForContribution(ClassLoader contributionClassloader); } diff --git a/sca-java-2.x/trunk/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceFactoryImpl.java b/sca-java-2.x/trunk/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceFactoryImpl.java index 8229c7812d..21c21e075d 100644 --- a/sca-java-2.x/trunk/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceFactoryImpl.java +++ b/sca-java-2.x/trunk/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceFactoryImpl.java @@ -21,8 +21,10 @@ package org.apache.tuscany.sca.interfacedef.java.impl; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; +import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.WeakHashMap; import org.apache.tuscany.sca.interfacedef.InvalidInterfaceException; @@ -31,6 +33,7 @@ import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceContract; import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceFactory; import org.apache.tuscany.sca.interfacedef.java.JavaOperation; import org.apache.tuscany.sca.interfacedef.java.introspect.JavaInterfaceVisitor; +import org.oasisopen.sca.ServiceRuntimeException; /** * A factory for the Java model. @@ -112,4 +115,48 @@ public abstract class JavaInterfaceFactoryImpl implements JavaInterfaceFactory { op.setName(method.getName()); return op; } + + /** + * Removes all the cached information relating to a contribution. The + * contribution is identified by the contribution classloader passed in + * as a parameter. This is used when a contribution is removed from + * the runtime. + * + * @param contributionClassloader + */ + public void removeInterfacesForContribution(ClassLoader contributionClassloader){ + removeInterfacesFromCache(contributionClassloader, normalCache); + removeInterfacesFromCache(contributionClassloader, forceRemotableCache); + } + + private void removeInterfacesFromCache(ClassLoader contributionClassloader, Map<Class<?>, JavaInterface> cache){ + try { + synchronized(cache) { + Set<Class<?>> clsSet = cache.keySet(); + Iterator<Class<?>> i = clsSet.iterator(); + while (i.hasNext()) { + Class<?> cls = i.next(); + if (cls.getClassLoader() == contributionClassloader) { + i.remove(); + } + } + } + } catch(Exception e) { + throw new ServiceRuntimeException(e); + } + } + + /** + * For testing so we can check that the cache is being cleared + */ + public Map<Class<?>, JavaInterface> getNormalCache(){ + return normalCache; + } + + /** + * For testing so we can check that the cache is being cleared + */ + public Map<Class<?>, JavaInterface> getForceRemotableCache(){ + return forceRemotableCache; + } } |