You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tuscany.apache.org by an...@apache.org on 2007/10/26 15:52:37 UTC

svn commit: r588644 - in /incubator/tuscany/java/sca/modules: ./ contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/impl/ contribution-impl/src/test/java/org/apache/tuscany/sca/contribution/impl/ contribution-java/src/main/java/org/apa...

Author: antelder
Date: Fri Oct 26 06:52:36 2007
New Revision: 588644

URL: http://svn.apache.org/viewvc?rev=588644&view=rev
Log:
TUSCANY-1871, apply patch from Rajini Sivaram for Application contribution classloaders

Added:
    incubator/tuscany/java/sca/modules/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/impl/ContributionClassLoader.java   (with props)
    incubator/tuscany/java/sca/modules/contribution-impl/src/test/java/org/apache/tuscany/sca/contribution/impl/
    incubator/tuscany/java/sca/modules/contribution-impl/src/test/java/org/apache/tuscany/sca/contribution/impl/ContributionClassLoaderTestCase.java   (with props)
Modified:
    incubator/tuscany/java/sca/modules/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/impl/ContributionImpl.java
    incubator/tuscany/java/sca/modules/contribution-java/src/main/java/org/apache/tuscany/sca/contribution/java/impl/ClassReferenceModelResolver.java
    incubator/tuscany/java/sca/modules/contribution-java/src/main/java/org/apache/tuscany/sca/contribution/java/impl/JavaExportImpl.java
    incubator/tuscany/java/sca/modules/contribution-java/src/main/java/org/apache/tuscany/sca/contribution/java/impl/JavaImportExportListener.java
    incubator/tuscany/java/sca/modules/contribution-java/src/main/java/org/apache/tuscany/sca/contribution/java/impl/JavaImportImpl.java
    incubator/tuscany/java/sca/modules/contribution-namespace/src/main/java/org/apache/tuscany/sca/contribution/namespace/impl/NamespaceExportImpl.java
    incubator/tuscany/java/sca/modules/contribution-namespace/src/main/java/org/apache/tuscany/sca/contribution/namespace/impl/NamespaceImportExportListener.java
    incubator/tuscany/java/sca/modules/contribution-namespace/src/main/java/org/apache/tuscany/sca/contribution/namespace/impl/NamespaceImportImpl.java
    incubator/tuscany/java/sca/modules/contribution/src/main/java/org/apache/tuscany/sca/contribution/Contribution.java
    incubator/tuscany/java/sca/modules/contribution/src/main/java/org/apache/tuscany/sca/contribution/Export.java
    incubator/tuscany/java/sca/modules/contribution/src/main/java/org/apache/tuscany/sca/contribution/Import.java
    incubator/tuscany/java/sca/modules/pom.xml

Added: incubator/tuscany/java/sca/modules/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/impl/ContributionClassLoader.java
URL: http://svn.apache.org/viewvc/incubator/tuscany/java/sca/modules/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/impl/ContributionClassLoader.java?rev=588644&view=auto
==============================================================================
--- incubator/tuscany/java/sca/modules/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/impl/ContributionClassLoader.java (added)
+++ incubator/tuscany/java/sca/modules/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/impl/ContributionClassLoader.java Fri Oct 26 06:52:36 2007
@@ -0,0 +1,353 @@
+package org.apache.tuscany.sca.contribution.impl;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+
+import org.apache.tuscany.sca.contribution.Contribution;
+import org.apache.tuscany.sca.contribution.Export;
+import org.apache.tuscany.sca.contribution.Import;
+import org.apache.tuscany.sca.contribution.java.JavaImport;
+import org.apache.tuscany.sca.contribution.namespace.NamespaceImport;
+
+public class ContributionClassLoader extends URLClassLoader {
+    
+    private Contribution contribution;
+
+    /**
+     * Constructor for contribution classloader
+     * 
+     * @param contribution
+     * @throws MalformedURLException
+     */
+    public ContributionClassLoader(Contribution contribution) {
+        
+        // To enable contributions to access code outside of SCA contributions
+        // (typically by providing them on CLASSPATH), use the thread context
+        // classloader as the parent of all contribution classloaders.
+        
+        super(new URL[0], Thread.currentThread().getContextClassLoader());
+        this.contribution = contribution;
+    }
+
+    
+    /**
+     * Add the URL of the contribution to the classloader search path.
+     * 
+     * @param location Contribution URL
+     */
+    public void setContributionLocation(String location) {
+        
+        try {
+            this.addURL(new URL(contribution.getLocation()));
+        } catch (MalformedURLException e) {
+            throw new RuntimeException(e);
+        }
+    }
+    
+
+    /* (non-Javadoc)
+     * @see java.net.URLClassLoader#findClass(java.lang.String)
+     * 
+     * Search path for class:
+     *     This contribution
+     *     Imported contributions
+     */
+    @Override   
+    protected Class<?> findClass(String className) throws ClassNotFoundException {
+        
+        Class<?> clazz = null;
+        try {
+            clazz = findClassFromContribution(className);
+        } catch (ClassNotFoundException e) {
+                
+            for (Import import_ : this.contribution.getImports()) {
+                if (matchesImport(className, import_, true)) {
+                    // Delegate the resolution to the imported contribution
+                    for (Contribution exportingContribution : import_.getExportContributions()) {
+                                    
+                        if (exportingContribution.getClassLoader() instanceof ContributionClassLoader) {
+
+                            for (Export export : exportingContribution.getExports()) {
+                                try {
+                                    if (import_.match(export)) {
+                                        clazz = ((ContributionClassLoader)exportingContribution.getClassLoader()).findClassFromContribution(className);
+                                        break;
+                                    }
+                                } catch (ClassNotFoundException e1) { 
+                                    continue;
+                                }
+                                    
+                            }
+                            if (clazz != null)  break;
+                        }
+                    }
+                    if (clazz != null) break;
+                }
+            }
+
+            if (clazz == null) throw e;
+        }
+        return clazz;
+    }
+
+    
+    /* (non-Javadoc)
+     * @see java.lang.ClassLoader#loadClass(java.lang.String, boolean)
+     * 
+     * Search path for class:
+     *     Parent classloader
+     *     This contribution
+     *     Imported contributions
+     *     
+     */
+    @Override
+    protected synchronized Class<?> loadClass(String className, boolean resolveClass) 
+        throws ClassNotFoundException {
+       
+        Class<?> clazz = null;
+        try {
+            
+            if (this.getParent() != null)
+                clazz = this.getParent().loadClass(className);
+            
+        } catch (ClassNotFoundException e) {
+        }
+
+        if (clazz == null)
+            clazz = findClass(className);
+
+
+        if (resolveClass)
+            this.resolveClass(clazz);
+        return clazz;
+        
+    }
+
+
+   
+    /*
+     * (non-Javadoc)
+     * 
+     * @see java.net.URLClassLoader#findResource(java.lang.String)
+     */
+    @Override
+    public URL findResource(String name) {
+        
+        URL url = findResourceFromContribution(name);
+        
+        if (url == null) {
+            for (Import import_ : this.contribution.getImports()) {
+                if (matchesImport(name, import_, false)) {
+                    // Delegate the resolution to the imported contribution
+                    for (Contribution exportingContribution : import_.getExportContributions()) {
+                                
+                        if (exportingContribution.getClassLoader() instanceof ContributionClassLoader) {
+
+                            for (Export export : exportingContribution.getExports()) {
+                                if (import_.match(export)) {
+                                    url = ((ContributionClassLoader)exportingContribution.getClassLoader()).findResourceFromContribution(name);
+                                    if (url != null) break;
+                                }
+                            }
+                            if (url != null)  break;
+                        }
+                    }
+                    if (url != null) break;
+                }
+            }
+
+        }
+        return url;
+    }
+
+
+    /* (non-Javadoc)
+     * @see java.net.URLClassLoader#findResources(java.lang.String)
+     */
+    @Override
+    public Enumeration<URL> findResources(String name) throws IOException {
+              
+        return collectionToEnumeration(findResourceSet(name));
+    }
+    
+    
+
+    
+    /* (non-Javadoc)
+     * @see java.lang.ClassLoader#getResource(java.lang.String)
+     * 
+     * Find a resource. 
+     * Search path for resource:
+     *     Parent classloader
+     *     This contribution
+     *     Imported contributions
+     */
+    @Override
+    public URL getResource(String resName) {
+ 
+        URL resource  = null;
+        
+        if (this.getParent() != null) {
+            resource  = this.getParent().getResource(resName);
+        }        
+        if (resource == null)
+            resource  = findResource(resName);
+        
+        return resource;
+    }
+
+
+    
+    /* (non-Javadoc)
+     * @see java.lang.ClassLoader#getResources(java.lang.String)
+     * 
+     * Return list of resources from this contribution, resources
+     * imported through imported contributions and resources from parent 
+     * classloader.
+     */
+    @Override
+    public Enumeration<URL> getResources(String resName) throws IOException {
+       
+        HashSet<URL> resourceSet = findResourceSet(resName);
+        addEnumerationToCollection(resourceSet, super.getResources(resName));
+        
+        return collectionToEnumeration(resourceSet);
+    }
+    
+
+    /*
+     * Find set of resources
+     */
+    private HashSet<URL> findResourceSet(String name) throws IOException {
+        
+        HashSet<URL> resources = new HashSet<URL>();
+
+        addEnumerationToCollection(resources, super.findResources(name));
+        
+        for (Import import_ : this.contribution.getImports()) {
+            if (matchesImport(name, import_, false)) {
+                // Delegate the resolution to the imported contribution
+                for (Contribution exportingContribution : import_.getExportContributions()) {
+                                
+                    if (exportingContribution.getClassLoader() instanceof ContributionClassLoader) {
+
+                        for (Export export : exportingContribution.getExports()) {
+                            if (import_.match(export)) {
+                                addEnumerationToCollection(resources,
+                                        ((ContributionClassLoader)exportingContribution.getClassLoader()).findResources(name));
+                            }
+                        }
+                    }
+                }
+            }
+         }
+
+        return resources;
+    }
+
+
+    /*
+     * Find class from contribution. If class has already been loaded, return loaded class.
+     */
+    private Class<?> findClassFromContribution(String className) throws ClassNotFoundException {
+        
+        Class<?> clazz = findLoadedClass(className);
+        if (clazz == null)
+            clazz =  super.findClass(className);
+        return clazz;
+       
+    }
+    
+    /*
+     * Find resource from contribution.
+     */
+    private URL findResourceFromContribution(String name) {
+        
+        return super.findResource(name);
+    }
+    
+    /**
+     * Check if a class or resource matches an import statement.
+     * Class matches if the package name used in <import.java/> matches
+     * Resource matches if package/namespace match the directory of resource.
+     * 
+     * @param name    Name of class or resource
+     * @param import_ SCA contribution import
+     * @param matchJavaClass
+     * @return true if this is a matching import
+     */
+    private boolean matchesImport(String name, Import import_, boolean matchJavaClass) {
+       
+        if (matchJavaClass) {
+            if (import_ instanceof JavaImport && name != null && name.lastIndexOf('.') > 0) {
+                JavaImport javaImport = (JavaImport) import_;
+                String packageName = name.substring(0, name.lastIndexOf('.'));
+                if (javaImport.getPackage() == null)
+                    return false;
+                else
+                    return packageName.equals(javaImport.getPackage());
+            }
+            
+        } else {
+            if (name == null || name.lastIndexOf('/') <= 0)
+                return false;
+            else if (import_ instanceof JavaImport) {
+                JavaImport javaImport = (JavaImport) import_;
+                String packageName = name.substring(0, name.lastIndexOf('/'));
+                if (javaImport.getPackage() == null)
+                    return false;
+                else
+                    return packageName.equals(javaImport.getPackage().replaceAll("\\.", "/"));
+            } else if (import_ instanceof NamespaceImport) {
+                NamespaceImport namespaceImport = (NamespaceImport) import_;
+                String namespace = name.substring(0, name.lastIndexOf('/'));
+                if (namespaceImport.getNamespace() == null)
+                    return false;
+                else
+                    return namespaceImport.getNamespace().equals(namespace);
+            }
+        }
+        return false;
+    }
+    
+    /*
+     * Add an enumeration to a Collection
+     */
+    private <T extends Object> void addEnumerationToCollection(Collection<T> collection, Enumeration<T> enumeration) {
+        
+        while (enumeration.hasMoreElements())
+            collection.add(enumeration.nextElement());
+    }
+    
+    /*
+     * Return an enumeration corresponding to a collection
+     */
+    private <T extends Object> Enumeration<T>  collectionToEnumeration(Collection<T> collection) {
+        
+        final Iterator<T> iterator = collection.iterator();
+        
+        return new Enumeration<T>() {
+            public boolean hasMoreElements() {
+                return iterator.hasNext();
+            }
+
+            public T nextElement() {
+                return iterator.next();
+            }
+        };
+    }
+
+
+    @Override
+    public String toString() {
+        return "SCA contribution classloader for : " + contribution.getLocation();
+    }
+    
+    
+}

Propchange: incubator/tuscany/java/sca/modules/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/impl/ContributionClassLoader.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/tuscany/java/sca/modules/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/impl/ContributionClassLoader.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Modified: incubator/tuscany/java/sca/modules/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/impl/ContributionImpl.java
URL: http://svn.apache.org/viewvc/incubator/tuscany/java/sca/modules/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/impl/ContributionImpl.java?rev=588644&r1=588643&r2=588644&view=diff
==============================================================================
--- incubator/tuscany/java/sca/modules/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/impl/ContributionImpl.java (original)
+++ incubator/tuscany/java/sca/modules/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/impl/ContributionImpl.java Fri Oct 26 06:52:36 2007
@@ -39,6 +39,7 @@
     private List<Import> imports = new ArrayList<Import>();
     private List<Composite> deployables = new ArrayList<Composite>();
     private ModelResolver modelResolver;
+    private ContributionClassLoader classLoader;
     
     /**
      * A list of artifacts in the contribution
@@ -46,6 +47,7 @@
     private List<DeployedArtifact> artifacts = new ArrayList<DeployedArtifact>();
 
     protected ContributionImpl() {
+        classLoader = new ContributionClassLoader(this);
     }
     
     public List<Export> getExports() {
@@ -71,4 +73,21 @@
     public void setModelResolver(ModelResolver modelResolver) {
         this.modelResolver = modelResolver;
     }
+    
+    
+
+    @Override
+    public void setLocation(String location) {
+        String origLocation = this.getLocation();
+        super.setLocation(location);
+        
+        if (origLocation != null)
+            classLoader = new ContributionClassLoader(this);
+        classLoader.setContributionLocation(location);
+    }
+
+    public ClassLoader getClassLoader() {
+        return classLoader;
+    }
+
 }

Added: incubator/tuscany/java/sca/modules/contribution-impl/src/test/java/org/apache/tuscany/sca/contribution/impl/ContributionClassLoaderTestCase.java
URL: http://svn.apache.org/viewvc/incubator/tuscany/java/sca/modules/contribution-impl/src/test/java/org/apache/tuscany/sca/contribution/impl/ContributionClassLoaderTestCase.java?rev=588644&view=auto
==============================================================================
--- incubator/tuscany/java/sca/modules/contribution-impl/src/test/java/org/apache/tuscany/sca/contribution/impl/ContributionClassLoaderTestCase.java (added)
+++ incubator/tuscany/java/sca/modules/contribution-impl/src/test/java/org/apache/tuscany/sca/contribution/impl/ContributionClassLoaderTestCase.java Fri Oct 26 06:52:36 2007
@@ -0,0 +1,258 @@
+/*
+ * 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.contribution.impl;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+
+import org.apache.tuscany.sca.contribution.Contribution;
+import org.apache.tuscany.sca.contribution.ContributionFactory;
+import org.apache.tuscany.sca.contribution.impl.ContributionFactoryImpl;
+import org.apache.tuscany.sca.contribution.java.JavaExport;
+import org.apache.tuscany.sca.contribution.java.JavaImport;
+import org.apache.tuscany.sca.contribution.java.JavaImportExportFactory;
+import org.apache.tuscany.sca.contribution.java.impl.JavaImportExportFactoryImpl;
+import org.apache.tuscany.sca.contribution.namespace.NamespaceExport;
+import org.apache.tuscany.sca.contribution.namespace.NamespaceImport;
+import org.apache.tuscany.sca.contribution.namespace.NamespaceImportExportFactory;
+import org.apache.tuscany.sca.contribution.namespace.impl.NamespaceImportExportFactoryImpl;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+
+/**
+ * Test ContributionClassLoader.
+ *
+ */
+public class ContributionClassLoaderTestCase  {
+    
+    private ContributionFactory contribFactory;
+    private JavaImportExportFactory javaImportExportFactory;
+    private NamespaceImportExportFactory namespaceImportExportFactory;
+    
+    @Before
+    public void setUp() throws Exception {
+        contribFactory = new ContributionFactoryImpl();
+        javaImportExportFactory = new JavaImportExportFactoryImpl();
+        namespaceImportExportFactory = new NamespaceImportExportFactoryImpl();
+    }
+    
+    @After
+    public void tearDown() throws Exception {
+    }
+    
+    private Contribution createContribution(String fileName) throws MalformedURLException {
+
+        Contribution contrib = contribFactory.createContribution();
+        File contribDir = new File(fileName);        
+        contrib.setLocation(contribDir.toURL().toString());
+        
+        return contrib;
+    }
+    
+   
+    @Test
+    public void testClassLoadingFromContribution() throws ClassNotFoundException, MalformedURLException {
+        
+        Contribution contribA = createContribution("target/test-classes");
+        Contribution contribB = createContribution("target");
+        Contribution contribC = createContribution("target/test-classes/deployables/sample-calculator.jar");
+        
+        // Class present in contribution, also in parent. Class is loaded from parent
+        Class<?> testClassA = contribA.getClassLoader().loadClass(this.getClass().getName());        
+        Assert.assertNotNull(testClassA);
+        Assert.assertSame(this.getClass(), testClassA);
+        
+        // Class not present in contribution, but present in parent classloader
+        Class<?> testClassB = contribB.getClassLoader().loadClass(this.getClass().getName());
+        Assert.assertNotNull(testClassB);
+        Assert.assertSame(this.getClass(), testClassB);
+        
+        // Class present in contribution, but not in parent
+        Class<?> testClassC = contribC.getClassLoader().loadClass("calculator.AddService");        
+        Assert.assertNotNull(testClassC);
+        
+        // Class not present in contribution or in parent
+        try {
+            contribA.getClassLoader().loadClass("NonExistent");
+            
+            Assert.assertTrue("ClassNotFoundException not thrown as expected", false);
+            
+        } catch (ClassNotFoundException e) {
+        }
+        
+        
+        
+    }
+    
+    @Test
+    public void testResourceLoadingFromContribution() throws ClassNotFoundException, MalformedURLException {
+        
+        Contribution contribA = createContribution("target/test-classes");
+        Contribution contribB = createContribution("target");
+        Contribution contribC = createContribution("target/test-classes/deployables/sample-calculator.jar");
+        
+        // Resource present in contribution, and in parent
+        URL resA = contribA.getClassLoader().getResource("deployables/sample-calculator.jar");
+        Assert.assertNotNull(resA);
+        
+        // Resource not present in contribution, but present in parent classloader
+        URL resB = contribB.getClassLoader().getResource("deployables/sample-calculator.jar");
+        Assert.assertNotNull(resB);
+        
+        // Resource present in contribution, but not in parent
+        URL resC = contribC.getClassLoader().getResource("calculator/AddService.class");
+        Assert.assertNotNull(resC);        
+        
+        // Load Java class as resource from parent
+        String classResName = this.getClass().getName().replaceAll("\\.", "/") + ".class";
+        URL classResA = contribA.getClassLoader().getResource(classResName);
+        Assert.assertNotNull(classResA);
+               
+        // Non-existent resource
+        URL res = contribA.getClassLoader().getResource("deployables/NonExistent");
+        Assert.assertNull(res);
+        
+    }
+    
+
+    @Test
+    public void testClassLoadingFromImportedContribution() throws ClassNotFoundException, MalformedURLException {
+        
+        Contribution contribA = createContribution("target/test-classes");
+        Contribution contribB = createContribution("target");
+        Contribution contribC = createContribution("target/test-classes/deployables/sample-calculator.jar");
+        ArrayList<Contribution> exportContribList = new ArrayList<Contribution>();
+        exportContribList.add(contribA);
+        exportContribList.add(contribC);
+        
+        JavaImport import_ = javaImportExportFactory.createJavaImport();
+        import_.setPackage(this.getClass().getPackage().getName());
+        import_.setExportContributions(exportContribList);
+        contribB.getImports().add(import_);
+        import_ = javaImportExportFactory.createJavaImport();
+        import_.setPackage("calculator");
+        import_.setExportContributions(exportContribList);
+        contribB.getImports().add(import_);
+        
+        JavaExport export = javaImportExportFactory.createJavaExport();
+        export.setPackage(this.getClass().getPackage().getName());
+        contribA.getExports().add(export);
+        export = javaImportExportFactory.createJavaExport();
+        export.setPackage("calculator");
+        contribC.getExports().add(export);
+        
+        // Load class from parent, class is also present in imported contribution. Class should
+        // be loaded from parent
+        Class<?> testClassB = contribB.getClassLoader().loadClass(this.getClass().getName());        
+        Assert.assertNotNull(testClassB);
+        Assert.assertSame(this.getClass(), testClassB);
+        
+        // Load class from parent, class is also present in parent. Class should be loaded
+        // from parent.
+        Class<?> testClassA = contribA.getClassLoader().loadClass(this.getClass().getName());        
+        Assert.assertNotNull(testClassA);
+        Assert.assertSame(this.getClass(), testClassA);
+        
+        // Imported class should be the same as the one loaded by the exporting contribution
+        Assert.assertSame(testClassA, testClassB);
+        
+        // Load class from imported contribution, class is not present in parent
+        Class<?> testClassB1 = contribB.getClassLoader().loadClass("calculator.AddService");
+        Assert.assertNotNull(testClassB1);
+        
+        // Imported class should be the same as the one loaded by the exporting contribution
+        Class<?> testClassC = contribC.getClassLoader().loadClass("calculator.AddService");
+        Assert.assertNotNull(testClassC);        
+        Assert.assertSame(testClassC, testClassB1);
+        
+
+        // Try to load class from package which is not explicitly imported - should throw ClassNotFoundException
+        try {
+            contribA.getClassLoader().loadClass("calculator.AddService");
+            
+            Assert.assertTrue("ClassNotFoundException not thrown as expected", false);
+            
+        } catch (ClassNotFoundException e) {
+        }
+        
+        // Try to load non-existent class from imported package - should throw ClassNotFoundException
+        try {
+            contribB.getClassLoader().loadClass(this.getClass().getPackage().getName() + ".NonExistentClass");
+            
+            Assert.assertTrue("ClassNotFoundException not thrown as expected", false);
+            
+        } catch (ClassNotFoundException e) {
+        }
+        
+    }
+
+    @Test
+    public void testResourceLoadingFromImportedContribution() throws ClassNotFoundException, MalformedURLException {
+        
+        Contribution contribA = createContribution("target/test-classes");
+        Contribution contribB = createContribution("target");
+        Contribution contribC = createContribution("target/test-classes/deployables/sample-calculator.jar");
+        
+        ArrayList<Contribution> exportContribList = new ArrayList<Contribution>();
+        exportContribList.add(contribA);
+        exportContribList.add(contribC);
+        
+        JavaImport import_ = javaImportExportFactory.createJavaImport();
+        import_.setPackage(this.getClass().getPackage().getName());
+        import_.setExportContributions(exportContribList);
+        contribB.getImports().add(import_);
+        NamespaceImport import1_ = namespaceImportExportFactory.createNamespaceImport();
+        import1_.setNamespace("calculator");
+        import1_.setExportContributions(exportContribList);
+        contribB.getImports().add(import1_);
+        
+        JavaExport export = javaImportExportFactory.createJavaExport();
+        export.setPackage(this.getClass().getPackage().getName());
+        contribA.getExports().add(export);
+        NamespaceExport export1 = namespaceImportExportFactory.createNamespaceExport();
+        export1.setNamespace("calculator");
+        contribC.getExports().add(export1);
+
+        // Load resource from parent
+        URL resB = contribB.getClassLoader().getResource("deployables/sample-calculator.jar"); 
+        Assert.assertNotNull(resB);
+        
+        // Load Java class as resource from imported contribution with JavaImport
+        String classResName = this.getClass().getName().replaceAll("\\.", "/") + ".class";               
+        URL classResB = contribB.getClassLoader().getResource(classResName);
+        Assert.assertNotNull(classResB);
+        
+        // Load Java class as resource from imported contribution with NamespaceImport
+        URL classResB1 = contribB.getClassLoader().getResource("calculator/AddService.class");
+        Assert.assertNotNull(classResB1);
+        
+        // Try to load resource not explicitly imported by contribution
+        URL classResA1 = contribA.getClassLoader().getResource("calculator/AddService.class");
+        Assert.assertNull(classResA1);
+        
+        
+    }
+
+}

Propchange: incubator/tuscany/java/sca/modules/contribution-impl/src/test/java/org/apache/tuscany/sca/contribution/impl/ContributionClassLoaderTestCase.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/tuscany/java/sca/modules/contribution-impl/src/test/java/org/apache/tuscany/sca/contribution/impl/ContributionClassLoaderTestCase.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Modified: incubator/tuscany/java/sca/modules/contribution-java/src/main/java/org/apache/tuscany/sca/contribution/java/impl/ClassReferenceModelResolver.java
URL: http://svn.apache.org/viewvc/incubator/tuscany/java/sca/modules/contribution-java/src/main/java/org/apache/tuscany/sca/contribution/java/impl/ClassReferenceModelResolver.java?rev=588644&r1=588643&r2=588644&view=diff
==============================================================================
--- incubator/tuscany/java/sca/modules/contribution-java/src/main/java/org/apache/tuscany/sca/contribution/java/impl/ClassReferenceModelResolver.java (original)
+++ incubator/tuscany/java/sca/modules/contribution-java/src/main/java/org/apache/tuscany/sca/contribution/java/impl/ClassReferenceModelResolver.java Fri Oct 26 06:52:36 2007
@@ -25,9 +25,7 @@
 import java.util.Map;
 
 import org.apache.tuscany.sca.contribution.Contribution;
-import org.apache.tuscany.sca.contribution.Import;
 import org.apache.tuscany.sca.contribution.ModelFactoryExtensionPoint;
-import org.apache.tuscany.sca.contribution.java.JavaImport;
 import org.apache.tuscany.sca.contribution.resolver.ClassReference;
 import org.apache.tuscany.sca.contribution.resolver.ModelResolver;
 
@@ -45,8 +43,12 @@
 
     public ClassReferenceModelResolver(Contribution contribution, ModelFactoryExtensionPoint modelFactories) {
         this.contribution = contribution;
-        //FIXME The classloader should be passed in
-        this.classLoader = new WeakReference<ClassLoader>(Thread.currentThread().getContextClassLoader());
+        if (this.contribution != null) {
+            this.classLoader = new WeakReference<ClassLoader>(this.contribution.getClassLoader());
+        } else {
+            // This path should be used only for unit testing.
+            this.classLoader = new WeakReference<ClassLoader>(this.getClass().getClassLoader());
+        }
 
         try {
             Class osgiResolverClass =
@@ -69,29 +71,7 @@
         return map.remove(((ClassReference)resolved).getClassName());
     }
 
-    /**
-     * Handle artifact resolution when the specific class reference is imported from another contribution
-     * @param unresolved
-     * @return
-     */
-    private ClassReference resolveImportedModel(ClassReference unresolved) {
-        ClassReference resolved = unresolved;
-
-        if (this.contribution != null) {
-            for (Import import_ : this.contribution.getImports()) {
-                if (import_ instanceof JavaImport) {
-                    JavaImport javaImport = (JavaImport)import_;
-                    String packageName = javaImport.getPackage();
-                    if (javaImport.getPackage().equals(packageName)) {
-                        // Delegate the resolution to the import resolver
-                        resolved = import_.getModelResolver().resolveModel(ClassReference.class, unresolved);
-                    }
-                }
-            }
-
-        }
-        return resolved;
-    }
+  
 
     public <T> T resolveModel(Class<T> modelClass, T unresolved) {
         Object resolved = map.get(unresolved);
@@ -122,9 +102,7 @@
             // Return the resolved ClassReference
             return modelClass.cast(classReference);
         } else {
-            //delegate resolution of the class
-            resolved = this.resolveImportedModel((ClassReference)unresolved);
-            return modelClass.cast(resolved);
+            return unresolved;
         }
 
     }

Modified: incubator/tuscany/java/sca/modules/contribution-java/src/main/java/org/apache/tuscany/sca/contribution/java/impl/JavaExportImpl.java
URL: http://svn.apache.org/viewvc/incubator/tuscany/java/sca/modules/contribution-java/src/main/java/org/apache/tuscany/sca/contribution/java/impl/JavaExportImpl.java?rev=588644&r1=588643&r2=588644&view=diff
==============================================================================
--- incubator/tuscany/java/sca/modules/contribution-java/src/main/java/org/apache/tuscany/sca/contribution/java/impl/JavaExportImpl.java (original)
+++ incubator/tuscany/java/sca/modules/contribution-java/src/main/java/org/apache/tuscany/sca/contribution/java/impl/JavaExportImpl.java Fri Oct 26 06:52:36 2007
@@ -19,6 +19,7 @@
 
 package org.apache.tuscany.sca.contribution.java.impl;
 
+import org.apache.tuscany.sca.contribution.Contribution;
 import org.apache.tuscany.sca.contribution.java.JavaExport;
 import org.apache.tuscany.sca.contribution.resolver.ModelResolver;
 
@@ -29,6 +30,7 @@
  */
 public class JavaExportImpl implements JavaExport {
     private ModelResolver modelResolver;
+    private Contribution contribution;
     /**
      * Java package being exported
      */
@@ -54,4 +56,11 @@
         this.modelResolver = modelResolver;
     }
 
+    public Contribution getContribution() {
+        return contribution;
+    }
+
+    public void setContribution(Contribution contribution) {
+        this.contribution = contribution;
+    }
 }

Modified: incubator/tuscany/java/sca/modules/contribution-java/src/main/java/org/apache/tuscany/sca/contribution/java/impl/JavaImportExportListener.java
URL: http://svn.apache.org/viewvc/incubator/tuscany/java/sca/modules/contribution-java/src/main/java/org/apache/tuscany/sca/contribution/java/impl/JavaImportExportListener.java?rev=588644&r1=588643&r2=588644&view=diff
==============================================================================
--- incubator/tuscany/java/sca/modules/contribution-java/src/main/java/org/apache/tuscany/sca/contribution/java/impl/JavaImportExportListener.java (original)
+++ incubator/tuscany/java/sca/modules/contribution-java/src/main/java/org/apache/tuscany/sca/contribution/java/impl/JavaImportExportListener.java Fri Oct 26 06:52:36 2007
@@ -19,6 +19,9 @@
 
 package org.apache.tuscany.sca.contribution.java.impl;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import org.apache.tuscany.sca.contribution.Contribution;
 import org.apache.tuscany.sca.contribution.Export;
 import org.apache.tuscany.sca.contribution.Import;
@@ -42,16 +45,20 @@
      * Export model resolvers are same as Contribution model resolver
      * Import model resolvers are matched to a specific contribution if a location uri is specified, 
      *    otherwise it try to resolve agains all the other contributions
+     * Also set the exporting contributions used by contribution classloaders to 
+     * match import/export for class loading.
      */
     public void contributionAdded(ContributionRepository repository, Contribution contribution) {
         // Initialize the contribution exports
         for (Export export: contribution.getExports()) {
             export.setModelResolver(contribution.getModelResolver());
+            export.setContribution(contribution);
         }
         
         // Initialize the contribution imports
         for (Import import_: contribution.getImports()) {
             boolean initialized = false;
+            
             if(import_ instanceof JavaImport) {
                 JavaImport javaImport = (JavaImport) import_;
                 
@@ -66,6 +73,11 @@
                                 JavaExport javaExport = (JavaExport)export;
                                 if (javaImport.getPackage().equals(javaExport.getPackage())) {
                                     javaImport.setModelResolver(javaExport.getModelResolver());
+                                    
+                                    List<Contribution> exportingContributions = new ArrayList<Contribution>();
+                                    exportingContributions.add(export.getContribution());
+                                    import_.setExportContributions(exportingContributions);
+                                    
                                     initialized = true;
                                     break;
                                 }
@@ -78,6 +90,7 @@
                 if (!initialized) {
                     //Use a resolver that will consider all contributions
                     import_.setModelResolver(new DefaultImportAllModelResolver(import_, repository.getContributions()));
+                    import_.setExportContributions(repository.getContributions());
                 }
             }
         }

Modified: incubator/tuscany/java/sca/modules/contribution-java/src/main/java/org/apache/tuscany/sca/contribution/java/impl/JavaImportImpl.java
URL: http://svn.apache.org/viewvc/incubator/tuscany/java/sca/modules/contribution-java/src/main/java/org/apache/tuscany/sca/contribution/java/impl/JavaImportImpl.java?rev=588644&r1=588643&r2=588644&view=diff
==============================================================================
--- incubator/tuscany/java/sca/modules/contribution-java/src/main/java/org/apache/tuscany/sca/contribution/java/impl/JavaImportImpl.java (original)
+++ incubator/tuscany/java/sca/modules/contribution-java/src/main/java/org/apache/tuscany/sca/contribution/java/impl/JavaImportImpl.java Fri Oct 26 06:52:36 2007
@@ -19,6 +19,9 @@
 
 package org.apache.tuscany.sca.contribution.java.impl;
 
+import java.util.List;
+
+import org.apache.tuscany.sca.contribution.Contribution;
 import org.apache.tuscany.sca.contribution.Export;
 import org.apache.tuscany.sca.contribution.java.JavaExport;
 import org.apache.tuscany.sca.contribution.java.JavaImport;
@@ -31,6 +34,7 @@
  */
 public class JavaImportImpl implements JavaImport {
     private ModelResolver modelResolver;
+    private List<Contribution> contributions;
     /**
      * Java package name being imported
      */
@@ -66,6 +70,13 @@
 
     public void setModelResolver(ModelResolver modelResolver) {
         this.modelResolver = modelResolver;
+    }
+    public List<Contribution> getExportContributions() {
+        return contributions;
+    }
+
+    public void setExportContributions(List<Contribution> contributions) {
+        this.contributions = contributions;
     }
 
     /**

Modified: incubator/tuscany/java/sca/modules/contribution-namespace/src/main/java/org/apache/tuscany/sca/contribution/namespace/impl/NamespaceExportImpl.java
URL: http://svn.apache.org/viewvc/incubator/tuscany/java/sca/modules/contribution-namespace/src/main/java/org/apache/tuscany/sca/contribution/namespace/impl/NamespaceExportImpl.java?rev=588644&r1=588643&r2=588644&view=diff
==============================================================================
--- incubator/tuscany/java/sca/modules/contribution-namespace/src/main/java/org/apache/tuscany/sca/contribution/namespace/impl/NamespaceExportImpl.java (original)
+++ incubator/tuscany/java/sca/modules/contribution-namespace/src/main/java/org/apache/tuscany/sca/contribution/namespace/impl/NamespaceExportImpl.java Fri Oct 26 06:52:36 2007
@@ -19,6 +19,7 @@
 
 package org.apache.tuscany.sca.contribution.namespace.impl;
 
+import org.apache.tuscany.sca.contribution.Contribution;
 import org.apache.tuscany.sca.contribution.namespace.NamespaceExport;
 import org.apache.tuscany.sca.contribution.resolver.ModelResolver;
 
@@ -33,6 +34,7 @@
      */
     private String namespace; 
     private ModelResolver modelResolver;
+    private Contribution contribution;
     
     protected NamespaceExportImpl() {
         super();
@@ -52,5 +54,13 @@
     
     public void setModelResolver(ModelResolver modelResolver) {
         this.modelResolver = modelResolver;
+    }
+    
+    public Contribution getContribution() {
+        return contribution;
+    }
+
+    public void setContribution(Contribution contribution) {
+        this.contribution = contribution;
     }
 }

Modified: incubator/tuscany/java/sca/modules/contribution-namespace/src/main/java/org/apache/tuscany/sca/contribution/namespace/impl/NamespaceImportExportListener.java
URL: http://svn.apache.org/viewvc/incubator/tuscany/java/sca/modules/contribution-namespace/src/main/java/org/apache/tuscany/sca/contribution/namespace/impl/NamespaceImportExportListener.java?rev=588644&r1=588643&r2=588644&view=diff
==============================================================================
--- incubator/tuscany/java/sca/modules/contribution-namespace/src/main/java/org/apache/tuscany/sca/contribution/namespace/impl/NamespaceImportExportListener.java (original)
+++ incubator/tuscany/java/sca/modules/contribution-namespace/src/main/java/org/apache/tuscany/sca/contribution/namespace/impl/NamespaceImportExportListener.java Fri Oct 26 06:52:36 2007
@@ -19,6 +19,9 @@
 
 package org.apache.tuscany.sca.contribution.namespace.impl;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import org.apache.tuscany.sca.contribution.Contribution;
 import org.apache.tuscany.sca.contribution.Export;
 import org.apache.tuscany.sca.contribution.Import;
@@ -42,16 +45,20 @@
      * Export model resolvers are same as Contribution model resolver
      * Import model resolvers are matched to a specific contribution if a location uri is specified, 
      *    otherwise it try to resolve agains all the other contributions
+     * Also set the exporting contributions used by contribution classloaders to 
+     * match import/export for class loading.
      */    
     public void contributionAdded(ContributionRepository repository, Contribution contribution) {
         // Initialize the contribution exports
         for (Export export: contribution.getExports()) {
             export.setModelResolver(contribution.getModelResolver());
+            export.setContribution(contribution);
         }
         
         // Initialize the contribution imports
         for (Import import_: contribution.getImports()) {
             boolean initialized = false;
+
             
             if (import_ instanceof NamespaceImport) {
                 NamespaceImport namespaceImport = (NamespaceImport)import_;
@@ -67,6 +74,11 @@
                                 NamespaceExport namespaceExport = (NamespaceExport)export;
                                 if (namespaceImport.getNamespace().equals(namespaceExport.getNamespace())) {
                                     namespaceImport.setModelResolver(namespaceExport.getModelResolver());
+                                    
+                                    List<Contribution> exportingContributions = new ArrayList<Contribution>();
+                                    exportingContributions.add(namespaceExport.getContribution());
+                                    import_.setExportContributions(exportingContributions);
+                                    
                                     initialized = true;
                                     break;
                                 }
@@ -80,8 +92,8 @@
             if( !initialized ) {
                 // Use a resolver that will consider all contributions
                 import_.setModelResolver(new DefaultImportAllModelResolver(import_, repository.getContributions()));
+                import_.setExportContributions(repository.getContributions());
             }
-            
         }
 
     }

Modified: incubator/tuscany/java/sca/modules/contribution-namespace/src/main/java/org/apache/tuscany/sca/contribution/namespace/impl/NamespaceImportImpl.java
URL: http://svn.apache.org/viewvc/incubator/tuscany/java/sca/modules/contribution-namespace/src/main/java/org/apache/tuscany/sca/contribution/namespace/impl/NamespaceImportImpl.java?rev=588644&r1=588643&r2=588644&view=diff
==============================================================================
--- incubator/tuscany/java/sca/modules/contribution-namespace/src/main/java/org/apache/tuscany/sca/contribution/namespace/impl/NamespaceImportImpl.java (original)
+++ incubator/tuscany/java/sca/modules/contribution-namespace/src/main/java/org/apache/tuscany/sca/contribution/namespace/impl/NamespaceImportImpl.java Fri Oct 26 06:52:36 2007
@@ -19,6 +19,9 @@
 
 package org.apache.tuscany.sca.contribution.namespace.impl;
 
+import java.util.List;
+
+import org.apache.tuscany.sca.contribution.Contribution;
 import org.apache.tuscany.sca.contribution.Export;
 import org.apache.tuscany.sca.contribution.namespace.NamespaceExport;
 import org.apache.tuscany.sca.contribution.namespace.NamespaceImport;
@@ -31,6 +34,7 @@
  */
 public class NamespaceImportImpl implements NamespaceImport {
     private ModelResolver modelResolver;
+    private List<Contribution> exportContributions;
     /**
      * The namespace to be imported
      */
@@ -67,6 +71,15 @@
     
     public void setModelResolver(ModelResolver modelResolver) {
         this.modelResolver = modelResolver;
+    }
+
+    
+    public List<Contribution> getExportContributions() {
+        return exportContributions;
+    }
+
+    public void setExportContributions(List<Contribution> contributions) {
+        this.exportContributions = contributions;
     }
 
     /**

Modified: incubator/tuscany/java/sca/modules/contribution/src/main/java/org/apache/tuscany/sca/contribution/Contribution.java
URL: http://svn.apache.org/viewvc/incubator/tuscany/java/sca/modules/contribution/src/main/java/org/apache/tuscany/sca/contribution/Contribution.java?rev=588644&r1=588643&r2=588644&view=diff
==============================================================================
--- incubator/tuscany/java/sca/modules/contribution/src/main/java/org/apache/tuscany/sca/contribution/Contribution.java (original)
+++ incubator/tuscany/java/sca/modules/contribution/src/main/java/org/apache/tuscany/sca/contribution/Contribution.java Fri Oct 26 06:52:36 2007
@@ -88,4 +88,13 @@
      */
     void setModelResolver(ModelResolver modelResolver);
     
+    /**
+     * Returns the classloader used to load classes and resources from
+     * this contribution
+     * 
+     * @return The contribution classloader
+     */
+    ClassLoader getClassLoader();
+    
+    
 }

Modified: incubator/tuscany/java/sca/modules/contribution/src/main/java/org/apache/tuscany/sca/contribution/Export.java
URL: http://svn.apache.org/viewvc/incubator/tuscany/java/sca/modules/contribution/src/main/java/org/apache/tuscany/sca/contribution/Export.java?rev=588644&r1=588643&r2=588644&view=diff
==============================================================================
--- incubator/tuscany/java/sca/modules/contribution/src/main/java/org/apache/tuscany/sca/contribution/Export.java (original)
+++ incubator/tuscany/java/sca/modules/contribution/src/main/java/org/apache/tuscany/sca/contribution/Export.java Fri Oct 26 06:52:36 2007
@@ -44,4 +44,19 @@
      */
     void setModelResolver(ModelResolver modelResolver);
     
+
+    /**
+     * Returns the exporting contribution 
+     * 
+     * @return The exporting contribution
+     */
+    Contribution getContribution();
+    
+    /**
+     * Sets the exporting contribution
+     * 
+     * @param contribution
+     */
+    void setContribution(Contribution contribution);
+    
 }

Modified: incubator/tuscany/java/sca/modules/contribution/src/main/java/org/apache/tuscany/sca/contribution/Import.java
URL: http://svn.apache.org/viewvc/incubator/tuscany/java/sca/modules/contribution/src/main/java/org/apache/tuscany/sca/contribution/Import.java?rev=588644&r1=588643&r2=588644&view=diff
==============================================================================
--- incubator/tuscany/java/sca/modules/contribution/src/main/java/org/apache/tuscany/sca/contribution/Import.java (original)
+++ incubator/tuscany/java/sca/modules/contribution/src/main/java/org/apache/tuscany/sca/contribution/Import.java Fri Oct 26 06:52:36 2007
@@ -19,6 +19,8 @@
 
 package org.apache.tuscany.sca.contribution;
 
+import java.util.List;
+
 import org.apache.tuscany.sca.contribution.resolver.ModelResolver;
 
 
@@ -44,6 +46,22 @@
      * @param modelResolver The model resolver
      */
     void setModelResolver(ModelResolver modelResolver);
+    
+    /**
+     * Returns the list of exporting contributions that can be used to match 
+     * this import.
+     * 
+     * @return List of exporting contributions
+     */
+    List<Contribution> getExportContributions();
+    
+    /**
+     * Sets the list of exporting contributions that can be used to match 
+     * this import.
+     * 
+     * @param contributions List of exporting contributions
+     */
+    void setExportContributions(List<Contribution> contributions);
     
     /**
      * Verify is a specific export is provider of what is being imported

Modified: incubator/tuscany/java/sca/modules/pom.xml
URL: http://svn.apache.org/viewvc/incubator/tuscany/java/sca/modules/pom.xml?rev=588644&r1=588643&r2=588644&view=diff
==============================================================================
--- incubator/tuscany/java/sca/modules/pom.xml (original)
+++ incubator/tuscany/java/sca/modules/pom.xml Fri Oct 26 06:52:36 2007
@@ -58,9 +58,9 @@
                 <module>binding-ws-axis2</module>
                 <module>binding-ws-xml</module>
                 <module>contribution</module>
-                <module>contribution-impl</module>
                 <module>contribution-namespace</module>
                 <module>contribution-java</module>
+                <module>contribution-impl</module>
                 <module>contribution-osgi</module>
                 <module>core</module>
                 <module>core-databinding</module>



---------------------------------------------------------------------
To unsubscribe, e-mail: tuscany-commits-unsubscribe@ws.apache.org
For additional commands, e-mail: tuscany-commits-help@ws.apache.org