diff options
Diffstat (limited to 'sca-java-1.x/branches/sca-java-1.2/itest/contribution-classloader/contribution-test')
4 files changed, 1036 insertions, 0 deletions
diff --git a/sca-java-1.x/branches/sca-java-1.2/itest/contribution-classloader/contribution-test/pom.xml b/sca-java-1.x/branches/sca-java-1.2/itest/contribution-classloader/contribution-test/pom.xml new file mode 100644 index 0000000000..3725b973e1 --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.2/itest/contribution-classloader/contribution-test/pom.xml @@ -0,0 +1,53 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * 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. +--> +<project> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-itest</artifactId> + <version>1.2-incubating-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> + </parent> + <artifactId>itest-contribution-classloader-test</artifactId> + <name>Apache Tuscany Contribution Classloader tests</name> + +<dependencies> + <dependency> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-host-embedded</artifactId> + <version>1.2-incubating-SNAPSHOT</version> + </dependency> + + <dependency> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-implementation-java-runtime</artifactId> + <version>1.2-incubating-SNAPSHOT</version> + <scope>runtime</scope> + </dependency> + + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.2</version> + <scope>test</scope> + </dependency> + + </dependencies> +</project> diff --git a/sca-java-1.x/branches/sca-java-1.2/itest/contribution-classloader/contribution-test/src/test/java/org/apache/tuscany/sca/test/contribution/ContributionTestCase.java b/sca-java-1.x/branches/sca-java-1.2/itest/contribution-classloader/contribution-test/src/test/java/org/apache/tuscany/sca/test/contribution/ContributionTestCase.java new file mode 100644 index 0000000000..5f92342b8c --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.2/itest/contribution-classloader/contribution-test/src/test/java/org/apache/tuscany/sca/test/contribution/ContributionTestCase.java @@ -0,0 +1,371 @@ +/* + * 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.test.contribution; + + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URLClassLoader; + +import org.apache.tuscany.sca.contribution.Contribution; +import org.apache.tuscany.sca.contribution.resolver.ClassReference; +import org.apache.tuscany.sca.contribution.service.ContributionResolveException; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +/* + * + * Contribution classloading integration tests + */ + +public class ContributionTestCase { + + private SupplyChain supplyChain; + + + @Before + public void setUp() throws Exception { + supplyChain = new SupplyChain(); + } + + + @After + public void tearDown() throws Exception { + + supplyChain.tearDown(); + + } + + + /** + * Test static classloading for classes that are visible from contribution + * + * @throws Exception + */ + public void staticClassLoadingTestForVisibleClasses() throws Exception { + + Contribution customerContribution = supplyChain.getContribution("Customer"); + ClassReference customerClassRef = new ClassReference("supplychain.customer.Customer"); + customerClassRef = customerContribution.getModelResolver().resolveModel(ClassReference.class, customerClassRef); + Class<?> customerClass = customerClassRef.getJavaClass(); + + Class customerClassFromContribution = customerContribution.getClassLoader().loadClass("supplychain.customer.Customer"); + Assert.assertEquals(customerClass, customerClassFromContribution); + + Object customer = supplyChain.getCustomer(customerClass); + + Method m = customerClass.getMethod("purchaseGoods"); + m.invoke(customer); + + + m = customerClass.getMethod("outstandingOrderCount"); + + int retries = 10; + int outstandingCount = 1; + while (retries-- > 0) { + + outstandingCount = (int)(Integer)m.invoke(customer); + if (outstandingCount == 0) + break; + else + Thread.sleep(100); + } + Assert.assertEquals(0, outstandingCount); + + + } + + + /** + * Test dynamic classloading for classes that are visible from contribution + * + * @throws Exception + */ + public void dynamicClassLoadingTestForVisibleClasses() throws Exception { + + Contribution customerContribution = supplyChain.getContribution("Customer"); + Contribution retailerContribution = supplyChain.getContribution("Retailer"); + Contribution warehouseContribution = supplyChain.getContribution("Warehouse"); + Contribution shipperContribution = supplyChain.getContribution("Shipper"); + Contribution supplyChainContribution = supplyChain.getContribution("SupplyChain"); + + ClassReference customerClassRef = new ClassReference("supplychain.customer.Customer"); + customerClassRef = customerContribution.getModelResolver().resolveModel(ClassReference.class, customerClassRef); + Class customerClass = customerClassRef.getJavaClass(); + + Class customerClassFromContribution = customerContribution.getClassLoader().loadClass("supplychain.customer.Customer"); + Assert.assertEquals(customerClass, customerClassFromContribution); + + Object customer = supplyChain.getCustomer(customerClass); + Assert.assertTrue(customerClass.isInstance(customer)); + + ClassReference retailerClassRef = new ClassReference("supplychain.retailer.Retailer"); + retailerClassRef = retailerContribution.getModelResolver().resolveModel(ClassReference.class, retailerClassRef); + Class retailerClass = retailerClassRef.getJavaClass(); + + Class retailerClassFromContribution = retailerContribution.getClassLoader().loadClass("supplychain.retailer.Retailer"); + Assert.assertEquals(retailerClass, retailerClassFromContribution); + + Class retailerClassFromCustomer = customerContribution.getClassLoader().loadClass("supplychain.retailer.Retailer"); + Assert.assertEquals(retailerClass, retailerClassFromCustomer); + + ClassReference warehouseClassRef = new ClassReference("supplychain.warehouse.Warehouse"); + warehouseClassRef = warehouseContribution.getModelResolver().resolveModel(ClassReference.class, warehouseClassRef); + Class warehouseClass = warehouseClassRef.getJavaClass(); + + Class warehouseClassFromContribution = warehouseContribution.getClassLoader().loadClass("supplychain.warehouse.Warehouse"); + Assert.assertEquals(warehouseClass, warehouseClassFromContribution); + + Class warehouseClassFromRetailer = retailerContribution.getClassLoader().loadClass("supplychain.warehouse.Warehouse"); + Assert.assertEquals(warehouseClass, warehouseClassFromRetailer); + + ClassReference shipperClassRef = new ClassReference("supplychain.shipper.Shipper"); + shipperClassRef = shipperContribution.getModelResolver().resolveModel(ClassReference.class, shipperClassRef); + Class shipperClass = shipperClassRef.getJavaClass(); + + Class shipperClassFromContribution = shipperContribution.getClassLoader().loadClass("supplychain.shipper.Shipper"); + Assert.assertEquals(shipperClass, shipperClassFromContribution); + + Class shipperClassFromWarehouse = shipperContribution.getClassLoader().loadClass("supplychain.shipper.Shipper"); + Assert.assertEquals(shipperClass, shipperClassFromWarehouse); + + Class customerClassFromShipper = shipperContribution.getClassLoader().loadClass("supplychain.customer.Customer"); + Assert.assertEquals(customerClass, customerClassFromShipper); + + Class customerClassFromSupplyChain = supplyChainContribution.getClassLoader().loadClass("supplychain.customer.Customer"); + Assert.assertEquals(customerClass, customerClassFromSupplyChain); + Class retailerClassFromSupplyChain = supplyChainContribution.getClassLoader().loadClass("supplychain.retailer.Retailer"); + Assert.assertEquals(retailerClass, retailerClassFromSupplyChain); + Class warehouseClassFromSupplyChain = supplyChainContribution.getClassLoader().loadClass("supplychain.warehouse.Warehouse"); + Assert.assertEquals(warehouseClass, warehouseClassFromSupplyChain); + Class shipperClassFromSupplyChain = supplyChainContribution.getClassLoader().loadClass("supplychain.shipper.Shipper"); + Assert.assertEquals(shipperClass, shipperClassFromSupplyChain); + + } + + /** + * Test dynamic classloading for classes that are visible from contribution + * + * @throws Exception + */ + public void dynamicClassLoadingTestForNonImportedClasses() throws Exception { + + Contribution customerContribution = supplyChain.getContribution("Customer"); + Contribution shipperContribution = supplyChain.getContribution("Shipper"); + + Class customerClass = customerContribution.getClassLoader().loadClass("supplychain.customer.Customer"); + Class shipperClass = shipperContribution.getClassLoader().loadClass("supplychain.shipper.Shipper"); + + try { + customerClass.getClassLoader().loadClass("supplychain.warehouse.Warehouse"); + Assert.fail("Non-imported class loaded incorrectly"); + } catch (ClassNotFoundException e) { + } + try { + customerClass.getClassLoader().loadClass("supplychain.shipper.JavaShipperComponentImpl"); + Assert.fail("Non-imported class loaded incorrectly"); + } catch (ClassNotFoundException e) { + } + + try { + Class.forName("supplychain.warehouse.Warehouse", true, customerClass.getClassLoader()); + Assert.fail("Non-imported class loaded incorrectly"); + } catch (ClassNotFoundException e) { + } + try { + Class.forName("supplychain.shipper.JavaShipperComponentImpl", true, customerClass.getClassLoader()); + Assert.fail("Non-imported class loaded incorrectly"); + } catch (ClassNotFoundException e) { + } + + try { + shipperClass.getClassLoader().loadClass("supplychain.warehouse.JavaWarehouseComponentImpl"); + Assert.fail("Non-imported class loaded incorrectly"); + } catch (ClassNotFoundException e) { + } + try { + shipperClass.getClassLoader().loadClass("supplychain.retailer.Retailer"); + Assert.fail("Non-imported class loaded incorrectly"); + } catch (ClassNotFoundException e) { + } + + try { + Class.forName("supplychain.warehouse.JavaWarehouseComponentImpl", true, shipperClass.getClassLoader()); + Assert.fail("Non-imported class loaded incorrectly"); + } catch (ClassNotFoundException e) { + } + try { + Class.forName("supplychain.retailer.Retailer", true, shipperClass.getClassLoader()); + Assert.fail("Non-imported class loaded incorrectly"); + } catch (ClassNotFoundException e) { + } + + + } + + + /** + * This test ensures that classes from imported packages can be statically loaded + * from other contributions even though the classes are not on CLASSPATH or on the + * parent classloader, or the thread context classloader. + * + * @throws Exception + */ + @Test + public void testValidStaticClassLoading() throws Exception { + + supplyChain.setUp(this.getClass().getClassLoader()); + + staticClassLoadingTestForVisibleClasses(); + } + + /** + * This test ensures that all imported classes are loaded from the exporting contributions + * rather than the parent classLoader. If any of the interface classes were incorrectly loaded + * through the parent classloader, LinkageError should result. + * + * @throws Exception + */ + @Test + public void testValidStaticClassLoadingWithContributionsInParentClassLoader() throws Exception { + + + URLClassLoader parentClassLoader = new URLClassLoader( + supplyChain.getContributionURLs(), + this.getClass().getClassLoader()); + + supplyChain.setUp(parentClassLoader); + + staticClassLoadingTestForVisibleClasses(); + } + + + /** + * This test ensures that classes from imported packages can be dynamically loaded from + * other contributions even though the classes are not on CLASSPATH or on the + * parent classloader, or the thread context classloader. + * + * @throws Exception + */ + @Test + public void testValidDynamicClassLoading() throws Exception { + + supplyChain.setUp(this.getClass().getClassLoader()); + + dynamicClassLoadingTestForVisibleClasses(); + } + + /** + * This test ensures that all imported classes are dynamically loaded from the exporting + * contributions rather than the parent classLoader. If any of the interface classes were + * incorrectly loaded through the parent, NoClassDefFoundError or LinkageError should result. + * + * @throws Exception + */ + @Test + public void testValidDynamicClassLoadingWithContributionsInParentClassLoader() throws Exception { + + + URLClassLoader parentClassLoader = new URLClassLoader( + supplyChain.getContributionURLs(), + this.getClass().getClassLoader()); + + supplyChain.setUp(parentClassLoader); + + dynamicClassLoadingTestForVisibleClasses(); + } + + @Test + public void testIllegalStaticClassLoading1() throws Exception { + + try { + supplyChain.setUp(this.getClass().getClassLoader(), SupplyChain.SUPPLYCHAIN_ILLEGAL_1); + + Assert.fail("Composite containing unresolved references resolved incorrectly"); + } catch (ContributionResolveException e) { + } + } + + @Test + public void testIllegalStaticClassLoading2() throws Exception { + + supplyChain.setUp(this.getClass().getClassLoader(), SupplyChain.SUPPLYCHAIN_ILLEGAL_2); + + Contribution customerContribution = supplyChain.getContribution("Customer"); + ClassReference customerClassRef = new ClassReference("supplychain.customer.Customer"); + customerClassRef = customerContribution.getModelResolver().resolveModel(ClassReference.class, customerClassRef); + Class<?> customerClass = customerClassRef.getJavaClass(); + + Object customer = supplyChain.getCustomer(customerClass); + + try { + Method m = customerClass.getMethod("purchaseGoods"); + m.invoke(customer); + + Assert.fail("Classloading exception not thrown as expected"); + } catch (InvocationTargetException e) { + + Throwable cause = e.getCause(); + Assert.assertTrue(cause instanceof NoClassDefFoundError); + Assert.assertTrue(cause.getMessage().indexOf("JavaWarehouseComponentImpl") > -1); } + + } + + /** + * This test ensures that classes from imported packages can be dynamically loaded from + * other contributions even though the classes are not on CLASSPATH or on the + * parent classloader, or the thread context classloader. + * + * @throws Exception + */ + @Test + public void testIllegalDynamicClassLoading() throws Exception { + + supplyChain.setUp(this.getClass().getClassLoader()); + + dynamicClassLoadingTestForNonImportedClasses(); + } + + + /** + * Self-contained contribution containing composites, componentType files and implementations + * should not require import/export statements for these files to find each other or for Tuscany + * to load these files. + * @throws Exception + */ + @Test + public void testSelfContainedContribution() throws Exception { + + supplyChain.setUp(this.getClass().getClassLoader(), SupplyChain.SUPPLYCHAIN_SELFCONTAINED); + + staticClassLoadingTestForVisibleClasses(); + } + + @Test + public void testContributionsWithSplitPackage() throws Exception { + + supplyChain.setUp(this.getClass().getClassLoader(), SupplyChain.SUPPLYCHAIN_SPLITPACKAGE); + + staticClassLoadingTestForVisibleClasses(); + + dynamicClassLoadingTestForNonImportedClasses(); + } +} diff --git a/sca-java-1.x/branches/sca-java-1.2/itest/contribution-classloader/contribution-test/src/test/java/org/apache/tuscany/sca/test/contribution/SupplyChain.java b/sca-java-1.x/branches/sca-java-1.2/itest/contribution-classloader/contribution-test/src/test/java/org/apache/tuscany/sca/test/contribution/SupplyChain.java new file mode 100644 index 0000000000..05da52edc6 --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.2/itest/contribution-classloader/contribution-test/src/test/java/org/apache/tuscany/sca/test/contribution/SupplyChain.java @@ -0,0 +1,231 @@ +/* + * 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.test.contribution; + + +import java.io.File; +import java.net.URL; +import java.util.Hashtable; + +import org.apache.tuscany.sca.assembly.Composite; +import org.apache.tuscany.sca.contribution.Contribution; +import org.apache.tuscany.sca.contribution.service.ContributionService; +import org.apache.tuscany.sca.host.embedded.impl.EmbeddedSCADomain; +import org.junit.Assert; + +/* + * + * Contribution classloading integration tests + */ + +public class SupplyChain { + + public static final int SUPPLYCHAIN = 0; + public static final int SUPPLYCHAIN_ILLEGAL_1 = 1; + public static final int SUPPLYCHAIN_ILLEGAL_2 = 2; + public static final int SUPPLYCHAIN_SELFCONTAINED = 3; + public static final int SUPPLYCHAIN_SPLITPACKAGE = 4; + + private String folderName = "../contribution-classes/target/classes"; + + private String customerJarName = "Customer"; + private String retailerJarName = "Retailer"; + private String warehouseJarName = "Warehouse"; + private String shipperJarName = "Shipper"; + private String supplychainJarName = "SupplyChain"; + private String illegalSupplyChain1JarName = "IllegalSupplyChain1"; + private String illegalSupplyChain2JarName = "IllegalSupplyChain2"; + private String illegalCustomerJarName = "IllegalCustomer"; + private String completeSupplychainJarName = "CompleteSupplyChain"; + private String customerInterfaceJarName = "CustomerInterface"; + private String customerImplJarName = "CustomerImpl"; + + + private EmbeddedSCADomain domain; + private ContributionService contributionService; + private int supplyChainVersion; + + private Hashtable<String, Contribution> contributions = new Hashtable<String, Contribution>(); + + private URL customerContribURL; + private URL retailerContribURL; + private URL warehouseContribURL; + private URL shipperContribURL; + private URL supplyChainContribURL; + private URL illegalSupplyChain1ContribURL; + private URL illegalSupplyChain2ContribURL; + private URL illegalCustomerContribURL; + private URL completeSupplyChainContribURL; + private URL customerInterfaceContribURL; + private URL customerImplContribURL; + + public SupplyChain() throws Exception { + + customerContribURL = new File(folderName + "/" + customerJarName + ".jar").toURI().toURL(); + retailerContribURL = new File(folderName + "/" + retailerJarName + ".jar").toURI().toURL(); + warehouseContribURL = new File(folderName + "/" + warehouseJarName + ".jar").toURI().toURL(); + shipperContribURL = new File(folderName + "/" + shipperJarName + ".jar").toURI().toURL(); + supplyChainContribURL = new File(folderName + "/" + supplychainJarName + ".jar").toURI().toURL(); + illegalSupplyChain1ContribURL = new File(folderName + "/" + illegalSupplyChain1JarName + ".jar").toURI().toURL(); + illegalSupplyChain2ContribURL = new File(folderName + "/" + illegalSupplyChain2JarName + ".jar").toURI().toURL(); + illegalCustomerContribURL = new File(folderName + "/" + illegalCustomerJarName + ".jar").toURI().toURL(); + completeSupplyChainContribURL = new File(folderName + "/" + completeSupplychainJarName + ".jar").toURI().toURL(); + customerInterfaceContribURL = new File(folderName + "/" + customerInterfaceJarName + ".jar").toURI().toURL(); + customerImplContribURL = new File(folderName + "/" + customerImplJarName + ".jar").toURI().toURL(); + } + + public void setUp(ClassLoader parentClassLoader) throws Exception { + this.setUp(parentClassLoader, SUPPLYCHAIN); + } + + public void setUp(ClassLoader parentClassLoader, int supplyChainVersion) throws Exception { + + this.supplyChainVersion = supplyChainVersion; + + Thread.currentThread().setContextClassLoader(parentClassLoader); + + //Create an embedded SCA domain + domain = new EmbeddedSCADomain(parentClassLoader, "http://localhost"); + + //Start the domain + domain.start(); + + this.contributionService = domain.getContributionService(); + + addContributions(supplyChainVersion); + } + + protected void addContributions(int supplyChainVersion) throws Exception { + + Contribution contribution; + + if (supplyChainVersion != SUPPLYCHAIN_SELFCONTAINED) { + contribution = contributionService.contribute("Shipper", shipperContribURL, true); + contributions.put("Shipper", contribution); + contribution = contributionService.contribute("Warehouse", warehouseContribURL, true); + contributions.put("Warehouse", contribution); + contribution = contributionService.contribute("Retailer", retailerContribURL, true); + contributions.put("Retailer", contribution); + } + + switch (supplyChainVersion) { + case SUPPLYCHAIN: + contribution = contributionService.contribute("Customer", customerContribURL, true); + contributions.put("Customer", contribution); + + contribution = contributionService.contribute("SupplyChain", supplyChainContribURL, true); + contributions.put("SupplyChain", contribution); + break; + case SUPPLYCHAIN_ILLEGAL_1: + contribution = contributionService.contribute("Customer", customerContribURL, true); + contributions.put("Customer", contribution); + + contribution = contributionService.contribute("SupplyChain", illegalSupplyChain1ContribURL, true); + contributions.put("SupplyChain", contribution); + break; + case SUPPLYCHAIN_ILLEGAL_2: + contribution = contributionService.contribute("Customer", illegalCustomerContribURL, true); + contributions.put("Customer", contribution); + + contribution = contributionService.contribute("SupplyChain", illegalSupplyChain2ContribURL, true); + contributions.put("SupplyChain", contribution); + break; + case SUPPLYCHAIN_SELFCONTAINED: + contribution = contributionService.contribute("SupplyChain", completeSupplyChainContribURL, true); + contributions.put("SupplyChain", contribution); + break; + case SUPPLYCHAIN_SPLITPACKAGE: + contribution = contributionService.contribute("Customer", customerInterfaceContribURL, true); + contributions.put("Customer", contribution); + + contribution = contributionService.contribute("CustomerImpl", customerImplContribURL, true); + contributions.put("CustomerImpl", contribution); + + contribution = contributionService.contribute("SupplyChain", supplyChainContribURL, true); + contributions.put("SupplyChain", contribution); + break; + } + + // SUPPLYCHAIN_ILLEGAL_1 should throw an exception when the composite is resolved, and hence + // should not get this far. + Assert.assertTrue(supplyChainVersion != SUPPLYCHAIN_ILLEGAL_1); + + + for (Contribution c : contributions.values()) { + + for (Composite deployable : c.getDeployables()) { + domain.getDomainComposite().getIncludes().add(deployable); + domain.buildComposite(deployable); + } + + } + + // Start Components from my composite + for (Composite deployable : contributions.get("SupplyChain").getDeployables() ) { + domain.getCompositeActivator().activate(deployable); + domain.getCompositeActivator().start(deployable); + } + } + + public void tearDown() throws Exception { + + if (domain == null) + return; + + for (String contributionURI : contributions.keySet()) { + contributionService.remove(contributionURI); + } + + + if (contributions.get("SupplyChain") != null) { + // Stop Components from my composite + for (Composite deployable : contributions.get("SupplyChain").getDeployables() ) { + domain.getCompositeActivator().stop(deployable); + domain.getCompositeActivator().deactivate(deployable); + } + } + + domain.stop(); + + domain.close(); + } + + public Contribution getContribution(String uri) { + if (supplyChainVersion == SUPPLYCHAIN_SELFCONTAINED) + return contributions.get("SupplyChain"); + else + return contributions.get(uri); + } + + public Object getCustomer(Class<?> customerClass) { + return domain.getService(customerClass, "CustomerComponent"); + } + + public URL[] getContributionURLs() { + return new URL[] { + customerContribURL, + retailerContribURL, + warehouseContribURL, + shipperContribURL, + supplyChainContribURL + }; + } + + +} diff --git a/sca-java-1.x/branches/sca-java-1.2/itest/contribution-classloader/contribution-test/src/test/java/org/apache/tuscany/sca/test/contribution/TuscanyClassloadingTestCaseFIXME.java b/sca-java-1.x/branches/sca-java-1.2/itest/contribution-classloader/contribution-test/src/test/java/org/apache/tuscany/sca/test/contribution/TuscanyClassloadingTestCaseFIXME.java new file mode 100644 index 0000000000..e0c11cdbee --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.2/itest/contribution-classloader/contribution-test/src/test/java/org/apache/tuscany/sca/test/contribution/TuscanyClassloadingTestCaseFIXME.java @@ -0,0 +1,381 @@ +/* + * 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.test.contribution; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; + +import org.apache.tuscany.sca.assembly.Composite; +import org.apache.tuscany.sca.extensibility.ServiceDiscovery; +import org.apache.tuscany.sca.host.embedded.impl.EmbeddedSCADomain; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.osoa.sca.ServiceReference; + +/* + * + * Contribution classloading integration tests + */ + +//FIXME This test case needs some serious rework! +// First it is very dependent on the names of the Tuscany runtime JARs +// and this is going to be difficult to maintain +// Second its usage of reflection requires the Tuscany implementation classes +// to be made public and this breaks isolation between modules. +public class TuscanyClassloadingTestCaseFIXME { + + // private static final int SCA_API = 1; + // private static final int TUSCANY_CORE_SPI = 2; + // private static final int TUSCANY_RUNTIME = 3; + // private static final int TUSCANY_EXTENSIONS = 4; + // private static final int TUSCANY_DEPENDENCIES = 0; + + private static final String[] scaApiJars = {"sca-api"}; + private static final String[] tuscanyCoreSpiJars = + {"core-spi", "interface", "interface-java", "interface-wsdl", "assembly", "policy", "databinding", + "contribution", "definitions"}; + private static final String[] tuscanyRuntimeJars = + { + + "binding-sca-xml", "binding-sca", "assembly-java-dsl", "assembly-xml", "assembly-xsd", "contribution-impl", + "contribution-java", "contribution-namespace", "core-databinding", "core-spring", "core", "definitions-xml", + "domain-api", "domain-impl", "domain", "extension-helper", "host-embedded", "interface-java-xml", + "interface-wsdl-xml", "java2wsdl", "node-api", "node-impl", "node", "osgi-runtime", "policy-logging", + "policy-security", "policy-transaction", "policy-xml", "wsdl2java"}; + private static final String[] tuscanyExtensionJars = + {"binding-dwr", "binding-ejb", "binding-feed", "binding-http", "binding-jms", "binding-jsonrpc", + "binding-notification", "binding-rmi", "binding-sca-axis2", "binding-ws-axis2", "binding-ws-xml", + "binding-ws", "databinding-axiom", "databinding-fastinfoset", "databinding-jaxb", "databinding-json", + "databinding-saxon", "databinding-sdo-axiom", "databinding-sdo", "databinding-xmlbeans", "host-http", + "host-jetty", "host-rmi", "host-tomcat", "host-webapp", "implementation-das.jar", "implementation-data.jar", + "implementation-java-runtime", "implementation-java-xml", "implementation-java", + "implementation-node-runtime", "implementation-node-xml", "implementation-node", + "implementation-notification", "implementation-osgi", "implementation-resource", "implementation-script", + "implementation-spring", "implementation-xquery", "contribution-osgi"}; + + private Class<?> embeddedDomainClass; + Object domain; + + @Before + public void setUp() throws Exception { + + embeddedDomainClass = getEmbeddedDomainClass(); + + Constructor c = embeddedDomainClass.getConstructor(ClassLoader.class, String.class); + // Create an embedded domain + domain = c.newInstance(embeddedDomainClass.getClassLoader(), "http://localhost"); + + // Start the domain + invokeNoArgsMethod(domain, "start"); + + } + + @After + public void tearDown() throws Exception { + + // Stop the domain + invokeNoArgsMethod(domain, "stop"); + + } + + /** + * Create a classloader hierarchy for Tuscany runtime + * Dependencies <- SCA-API <- Core-SPI+ Runtime <- Extensions + * Load the embedded SCA domain class using the runtime classloader + * + * @return embedded SCA domain class + * @throws Exception + */ + private Class<?> getEmbeddedDomainClass() throws Exception { + + URL[] scaApiUrls; + URL[] runtimeUrls; + URL[] extensionUrls; + URL[] dependencyUrls; + + // When the test is run under Eclipse, the classloader for the test is + // sun.misc.Launcher$AppClassLoader. The first code path is taken. + // When the test is run under maven, the classloader for the test is + // org.apache.maven.surefire.booter.IsolatedClassLoader, which is a subclass + // of URLClassLoader. The second code path is taken. + if (!(this.getClass().getClassLoader() instanceof URLClassLoader)) { + String classPath = System.getProperty("java.class.path"); + String[] classPathEntries = classPath.split(System.getProperty("path.separator")); + HashSet<String> dependentJars = new HashSet<String>(); + for (int i = 0; i < classPathEntries.length; i++) { + dependentJars.add(classPathEntries[i]); + } + + scaApiUrls = getTuscanyClassLoaderURLs(classPathEntries, dependentJars, scaApiJars); + runtimeUrls = + getTuscanyClassLoaderURLs(classPathEntries, dependentJars, tuscanyCoreSpiJars, tuscanyRuntimeJars); + extensionUrls = getTuscanyClassLoaderURLs(classPathEntries, dependentJars, tuscanyExtensionJars); + dependencyUrls = getTuscanyClassLoaderURLs(classPathEntries, dependentJars); + } else { + HashSet<URL> dependentJars = new HashSet<URL>(); + URL[] classPathEntries = ((URLClassLoader)this.getClass().getClassLoader()).getURLs(); + for (int i = 0; i < classPathEntries.length; i++) { + dependentJars.add(classPathEntries[i]); + } + scaApiUrls = getTuscanyClassLoaderURLs(classPathEntries, dependentJars, scaApiJars); + runtimeUrls = + getTuscanyClassLoaderURLs(classPathEntries, dependentJars, tuscanyCoreSpiJars, tuscanyRuntimeJars); + extensionUrls = getTuscanyClassLoaderURLs(classPathEntries, dependentJars, tuscanyExtensionJars); + dependencyUrls = getTuscanyClassLoaderURLs(classPathEntries, dependentJars); + + } + + boolean useSingleClassLoader = + (scaApiUrls == null || scaApiUrls.length == 0) || (runtimeUrls == null || runtimeUrls.length == 0) + || (extensionUrls == null || extensionUrls.length == 0) + || (dependencyUrls == null || dependencyUrls.length == 0); + + if (useSingleClassLoader) { + return EmbeddedSCADomain.class; + } else { + + ClassLoader dependencyLoader = new URLClassLoader(dependencyUrls, null); + ClassLoader scaApiLoader = new URLClassLoader(scaApiUrls, dependencyLoader); + ClassLoader runtimeClassLoader = new URLClassLoader(runtimeUrls, scaApiLoader); + ClassLoader extensionClassLoader = new URLClassLoader(extensionUrls, runtimeClassLoader); + + Class<?> serviceDiscoveryClass = runtimeClassLoader.loadClass(ServiceDiscovery.class.getName()); + Method getInstanceMethod = serviceDiscoveryClass.getMethod("getInstance"); + Object serviceDiscoveryObj = getInstanceMethod.invoke(null); + Method registerClassLoaderMethod = + serviceDiscoveryClass.getMethod("registerClassLoader", ClassLoader.class); + registerClassLoaderMethod.invoke(serviceDiscoveryObj, extensionClassLoader); + + Thread.currentThread().setContextClassLoader(extensionClassLoader); + + return runtimeClassLoader.loadClass(EmbeddedSCADomain.class.getName()); + + } + + } + + /** + * From the list of entries in the test classloader, match + * Tuscany jars corresponding to a classloader, and return the list + * of matching entries as URLs. + * This method is used when the test is run under eclipse, using CLASSPATH + * based application classloader. + * + * @param classPathEntries List of entries on CLASSPATH + * @param dependentJars Complete set of jars, remove jars corresponding to this + * classloader from the set. + * @param jars List of Tuscany jars corresponding to this classloader + * @return Matching URLs for the classloader + * @throws IOException + */ + private URL[] getTuscanyClassLoaderURLs(String[] classPathEntries, HashSet<String> dependentJars, String[]... jars) + throws IOException { + + String pathSeparator = System.getProperty("file.separator"); + HashSet<String> classPathEntrySet; + + if (jars.length == 0) + classPathEntrySet = dependentJars; + else { + classPathEntrySet = new HashSet<String>(); + + for (int i = 0; i < classPathEntries.length; i++) { + + String classPathEntry = classPathEntries[i]; + for (int j = 0; j < jars.length; j++) { + String[] jarList = jars[j]; + if (jarList != null) { + for (int k = 0; k < jarList.length; k++) { + String jarName = "tuscany-" + jarList[k]; + String alternateJarName = "modules" + pathSeparator + jarList[k]; + if (classPathEntry.indexOf(jarName) >= 0 || classPathEntry.indexOf(alternateJarName) >= 0) { + classPathEntrySet.add(classPathEntry); + dependentJars.remove(classPathEntry); + } + } + } + } + } + + } + ArrayList<URL> urls = new ArrayList<URL>(); + + for (String fileName : classPathEntrySet) { + File file = new File((String)fileName); + if (!file.exists()) { + throw new FileNotFoundException(fileName); + + } else { + urls.add(file.toURL()); + + } + } + + return (URL[])urls.toArray(new URL[urls.size()]); + } + + /** + * From the list of URLs of the test classloader, match + * Tuscany jars corresponding to a classloader, and return the matching URLs + * This method is used when the test is run under maven. The test classloader is + * org.apache.maven.surefire.booter.IsolatedClassLoader, which is a subclass + * of URLClassLoader + * + * @param classPathEntries List of URLs from the test classloader + * @param dependentJars Complete set of jars, remove jars corresponding to this + * classloader from the set. + * @param jars List of Tuscany jars corresponding to this classloader + * @return Matching URLs for the classloader + * @throws IOException + */ + private URL[] getTuscanyClassLoaderURLs(URL[] classPathEntries, HashSet<URL> dependentJars, String[]... jars) + throws IOException { + + String pathSeparator = System.getProperty("file.separator"); + HashSet<URL> classPathEntrySet; + + if (jars.length == 0) + classPathEntrySet = dependentJars; + else { + classPathEntrySet = new HashSet<URL>(); + + for (int i = 0; i < classPathEntries.length; i++) { + + URL classPathEntry = classPathEntries[i]; + String classPathEntryStr = classPathEntry.getPath(); + for (int j = 0; j < jars.length; j++) { + String[] jarList = jars[j]; + if (jarList != null) { + for (int k = 0; k < jarList.length; k++) { + String jarName = "tuscany-" + jarList[k]; + String alternateJarName = "modules" + pathSeparator + jarList[k]; + if (classPathEntryStr.indexOf(jarName) >= 0 || classPathEntryStr.indexOf(alternateJarName) >= 0) { + classPathEntrySet.add(classPathEntry); + dependentJars.remove(classPathEntry); + } + } + } + } + } + + } + return (URL[])classPathEntrySet.toArray(new URL[classPathEntrySet.size()]); + } + + private Object invokeNoArgsMethod(Object obj, String methodName) throws Exception { + + return obj.getClass().getMethod(methodName).invoke(obj); + } + + private Object invokeOneArgMethod(Object obj, String methodName, Class argType, Object arg) throws Exception { + + return obj.getClass().getMethod(methodName, argType).invoke(obj, arg); + } + + /** + * + * Load Tuscany runtime using multiple classloaders, and run supplychain + * test. + * + * @throws Exception + */ + @SuppressWarnings("unchecked") + @Test + public void test() throws Exception { + + ClassLoader runtimeClassloader = embeddedDomainClass.getClassLoader(); + + if (runtimeClassloader == this.getClass().getClassLoader()) { + System.out.println("Runtime and test loaded using the same classloader " + runtimeClassloader); + } else { + System.out + .println("Running test using separate Tuscany classloaders, runtime classloader=" + runtimeClassloader); + ClassLoader apiClassLoader = + runtimeClassloader.loadClass(ServiceReference.class.getName()).getClassLoader(); + Assert.assertTrue(apiClassLoader != runtimeClassloader); + + try { + runtimeClassloader.loadClass("org.apache.tuscany.sca.implementation.java.JavaImplementation"); + Assert.fail("Loaded extension class incorrectly from runtimeClassLoader"); + } catch (ClassNotFoundException e) { + } + + } + + // Contribute supplychain (as single contribution) + Object contributionService = invokeNoArgsMethod(domain, "getContributionService"); + Method contributeMethod = + contributionService.getClass().getMethod("contribute", String.class, URL.class, boolean.class); + + String folderName = "../contribution-classes/target/classes"; + String supplychainJarName = "CompleteSupplyChain"; + URL supplyChainContribURL = new File(folderName + "/" + supplychainJarName + ".jar").toURL(); + Object contribution = contributeMethod.invoke(contributionService, "SupplyChain", supplyChainContribURL, true); + + Object composite = ((List)invokeNoArgsMethod(contribution, "getDeployables")).get(0); + Object domainComposite = invokeNoArgsMethod(domain, "getDomainComposite"); + List includes = (List)invokeNoArgsMethod(domainComposite, "getIncludes"); + includes.add(composite); + //Object compositeBuilder = invokeNoArgsMethod(domain, "getCompositeBuilder"); + Object compositeActivator = invokeNoArgsMethod(domain, "getCompositeActivator"); + + Class compositeClass = embeddedDomainClass.getClassLoader().loadClass(Composite.class.getName()); + invokeOneArgMethod(domain, "buildComposite", compositeClass, composite); + invokeOneArgMethod(compositeActivator, "activate", compositeClass, composite); + invokeOneArgMethod(compositeActivator, "start", compositeClass, composite); + + // Get customer service + Method getClassLoaderMethod = contribution.getClass().getMethod("getClassLoader"); + ClassLoader classLoader = (ClassLoader)getClassLoaderMethod.invoke(contribution); + + Class customerClass = classLoader.loadClass("supplychain.customer.Customer"); + Method getServiceMethod = embeddedDomainClass.getMethod("getService", Class.class, String.class); + Object customer = getServiceMethod.invoke(domain, customerClass, "CustomerComponent"); + + // Invoke purchaseGoods + Method m = customerClass.getMethod("purchaseGoods"); + m.invoke(customer); + + m = customerClass.getMethod("outstandingOrderCount"); + + int retries = 10; + int outstandingCount = 1; + while (retries-- > 0) { + + outstandingCount = (int)(Integer)m.invoke(customer); + if (outstandingCount == 0) + break; + else + Thread.sleep(100); + } + Assert.assertEquals(0, outstandingCount); + + } + +} |