diff options
author | jsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68> | 2008-09-15 00:26:00 +0000 |
---|---|---|
committer | jsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68> | 2008-09-15 00:26:00 +0000 |
commit | d5f1d093fe6fa491cdec392dca7137639e98d149 (patch) | |
tree | b98c79d8231a2617ee1dce43b1782d30d93686bc /branches/sca-android/itest/contribution-classloader/contribution-test/src/test/java | |
parent | f4e3e383071b6947d56794d9af5e9e6438aa3235 (diff) |
Pulled a recent revision of trunk into the sca-android branch, to apply the android patches from JIRA TUSCANY-2440 to it.
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@695318 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'branches/sca-android/itest/contribution-classloader/contribution-test/src/test/java')
3 files changed, 985 insertions, 0 deletions
diff --git a/branches/sca-android/itest/contribution-classloader/contribution-test/src/test/java/org/apache/tuscany/sca/test/contribution/ContributionTestCase.java b/branches/sca-android/itest/contribution-classloader/contribution-test/src/test/java/org/apache/tuscany/sca/test/contribution/ContributionTestCase.java new file mode 100644 index 0000000000..692f16f6f6 --- /dev/null +++ b/branches/sca-android/itest/contribution-classloader/contribution-test/src/test/java/org/apache/tuscany/sca/test/contribution/ContributionTestCase.java @@ -0,0 +1,373 @@ +/* + * 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 { + // FIXME we have commented this code as we are not throwing exceptions anymore + // need to deal with monitor logs to catch the errors. + + /*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/branches/sca-android/itest/contribution-classloader/contribution-test/src/test/java/org/apache/tuscany/sca/test/contribution/SupplyChain.java b/branches/sca-android/itest/contribution-classloader/contribution-test/src/test/java/org/apache/tuscany/sca/test/contribution/SupplyChain.java new file mode 100644 index 0000000000..1ec7aaaa3a --- /dev/null +++ b/branches/sca-android/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/branches/sca-android/itest/contribution-classloader/contribution-test/src/test/java/org/apache/tuscany/sca/test/contribution/TuscanyClassloadingTestCaseFIXME.java b/branches/sca-android/itest/contribution-classloader/contribution-test/src/test/java/org/apache/tuscany/sca/test/contribution/TuscanyClassloadingTestCaseFIXME.java new file mode 100644 index 0000000000..b123951ef6 --- /dev/null +++ b/branches/sca-android/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);
+
+ }
+
+}
|