From 725006d4c47e63986ac042ade23a4d193298b1fe Mon Sep 17 00:00:00 2001 From: lresende Date: Wed, 11 Nov 2009 23:08:29 +0000 Subject: Moving 1.x branches git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@835131 13f79535-47bb-0310-9956-ffa450edef68 --- .../sca-java-1.4/modules/extensibility/LICENSE | 205 +++++++++++++++++ .../sca-java-1.4/modules/extensibility/NOTICE | 5 + .../sca-java-1.4/modules/extensibility/pom.xml | 50 +++++ .../sca/core/DefaultExtensionPointRegistry.java | 184 +++++++++++++++ .../core/DefaultModuleActivatorExtensionPoint.java | 92 ++++++++ .../sca/core/DefaultUtilityExtensionPoint.java | 184 +++++++++++++++ .../tuscany/sca/core/ExtensionPointRegistry.java | 56 +++++ .../apache/tuscany/sca/core/ModuleActivator.java | 60 +++++ .../sca/core/ModuleActivatorExtensionPoint.java | 53 +++++ .../tuscany/sca/core/UtilityExtensionPoint.java | 54 +++++ .../ContextClassLoaderServiceDiscoverer.java | 248 +++++++++++++++++++++ .../sca/extensibility/ServiceDeclaration.java | 68 ++++++ .../sca/extensibility/ServiceDiscoverer.java | 37 +++ .../sca/extensibility/ServiceDiscovery.java | 170 ++++++++++++++ ....tuscany.sca.core.ModuleActivatorExtensionPoint | 18 ++ ...g.apache.tuscany.sca.core.UtilityExtensionPoint | 18 ++ ...ontextClassLoaderServiceDiscovererTestCase.java | 72 ++++++ 17 files changed, 1574 insertions(+) create mode 100644 sca-java-1.x/branches/sca-java-1.4/modules/extensibility/LICENSE create mode 100644 sca-java-1.x/branches/sca-java-1.4/modules/extensibility/NOTICE create mode 100644 sca-java-1.x/branches/sca-java-1.4/modules/extensibility/pom.xml create mode 100644 sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/java/org/apache/tuscany/sca/core/DefaultExtensionPointRegistry.java create mode 100644 sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/java/org/apache/tuscany/sca/core/DefaultModuleActivatorExtensionPoint.java create mode 100644 sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/java/org/apache/tuscany/sca/core/DefaultUtilityExtensionPoint.java create mode 100644 sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/java/org/apache/tuscany/sca/core/ExtensionPointRegistry.java create mode 100644 sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/java/org/apache/tuscany/sca/core/ModuleActivator.java create mode 100644 sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/java/org/apache/tuscany/sca/core/ModuleActivatorExtensionPoint.java create mode 100644 sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/java/org/apache/tuscany/sca/core/UtilityExtensionPoint.java create mode 100644 sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/java/org/apache/tuscany/sca/extensibility/ContextClassLoaderServiceDiscoverer.java create mode 100644 sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/java/org/apache/tuscany/sca/extensibility/ServiceDeclaration.java create mode 100644 sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/java/org/apache/tuscany/sca/extensibility/ServiceDiscoverer.java create mode 100644 sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/java/org/apache/tuscany/sca/extensibility/ServiceDiscovery.java create mode 100644 sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/resources/META-INF/services/org.apache.tuscany.sca.core.ModuleActivatorExtensionPoint create mode 100644 sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/resources/META-INF/services/org.apache.tuscany.sca.core.UtilityExtensionPoint create mode 100644 sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/test/java/org/apache/tuscany/sca/extensibility/ContextClassLoaderServiceDiscovererTestCase.java (limited to 'sca-java-1.x/branches/sca-java-1.4/modules/extensibility') diff --git a/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/LICENSE b/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/LICENSE new file mode 100644 index 0000000000..8aa906c321 --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/LICENSE @@ -0,0 +1,205 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. + + + diff --git a/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/NOTICE b/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/NOTICE new file mode 100644 index 0000000000..b3e4797aaa --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/NOTICE @@ -0,0 +1,5 @@ +Copyright (c) 2005 - 2008 The Apache Software Foundation + +This product includes software developed by +The Apache Software Foundation (http://www.apache.org/). + diff --git a/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/pom.xml b/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/pom.xml new file mode 100644 index 0000000000..be3ed67921 --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/pom.xml @@ -0,0 +1,50 @@ + + + + 4.0.0 + + org.apache.tuscany.sca + tuscany-modules + 1.4.1-SNAPSHOT + ../pom.xml + + tuscany-extensibility + Apache Tuscany SCA Extensibility + + + + + + org.apache.felix + maven-bundle-plugin + + + + ${tuscany.version} + org.apache.tuscany.sca.extensibility + ${pom.name} + org.apache.tuscany.sca.* + + + + + + + diff --git a/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/java/org/apache/tuscany/sca/core/DefaultExtensionPointRegistry.java b/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/java/org/apache/tuscany/sca/core/DefaultExtensionPointRegistry.java new file mode 100644 index 0000000000..48f240559c --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/java/org/apache/tuscany/sca/core/DefaultExtensionPointRegistry.java @@ -0,0 +1,184 @@ +/* + * 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.core; + +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.apache.tuscany.sca.extensibility.ServiceDiscovery; + +/** + * Default implementation of a registry to hold all the Tuscany core extension + * points. As the point of contact for all extension artifacts this registry + * allows loaded extensions to find all other parts of the system and register + * themselves appropriately. + * + * @version $Rev$ $Date$ + */ +public class DefaultExtensionPointRegistry implements ExtensionPointRegistry { + private Map, Object> extensionPoints = new HashMap, Object>(); + + /** + * Constructs a new registry. + */ + public DefaultExtensionPointRegistry() { + } + + /** + * Add an extension point to the registry. This default implementation + * stores extensions against the interfaces that they implement. + * + * @param extensionPoint The instance of the extension point + * + * @throws IllegalArgumentException if extensionPoint is null + */ + public void addExtensionPoint(Object extensionPoint) { + if (extensionPoint == null) { + throw new IllegalArgumentException("Cannot register null as an ExtensionPoint"); + } + + Set> interfaces = getAllInterfaces(extensionPoint.getClass()); + for (Class i : interfaces) { + extensionPoints.put(i, extensionPoint); + } + } + + private Constructor getConstructor(Constructor[] constructors, Class[] paramTypes) { + for (Constructor c : constructors) { + Class[] types = c.getParameterTypes(); + if (c.getParameterTypes().length == paramTypes.length) { + boolean found = true; + for (int i = 0; i < types.length; i++) { + if (types[i] != paramTypes[i]) { + found = false; + break; + } + } + if (found) { + return c; + } + } + } + return null; + } + + /** + * Get the extension point by the interface that it implements + * + * @param extensionPointType The lookup key (extension point interface) + * @return The instance of the extension point + * + * @throws IllegalArgumentException if extensionPointType is null + */ + public T getExtensionPoint(Class extensionPointType) { + if (extensionPointType == null) { + throw new IllegalArgumentException("Cannot lookup ExtensionPoint of type null"); + } + + Object extensionPoint = extensionPoints.get(extensionPointType); + if (extensionPoint == null) { + + // Dynamically load an extension point class declared under META-INF/services + try { + Class extensionPointClass = + ServiceDiscovery.getInstance().loadFirstServiceClass(extensionPointType); + if (extensionPointClass != null) { + // Construct the extension point + Constructor[] constructors = extensionPointClass.getConstructors(); + Constructor constructor = getConstructor(constructors, new Class[] {ExtensionPointRegistry.class}); + if (constructor != null) { + extensionPoint = constructor.newInstance(this); + } else { + constructor = getConstructor(constructors, new Class[] {}); + if (constructor != null) { + extensionPoint = constructor.newInstance(); + } else { + throw new IllegalArgumentException( + "No valid constructor is found for " + extensionPointClass); + } + } + + // Cache the loaded extension point + addExtensionPoint(extensionPoint); + } + } catch (InvocationTargetException e) { + throw new IllegalArgumentException(e); + } catch (IOException e) { + throw new IllegalArgumentException(e); + } catch (ClassNotFoundException e) { + throw new IllegalArgumentException(e); + } catch (InstantiationException e) { + throw new IllegalArgumentException(e); + } catch (IllegalAccessException e) { + throw new IllegalArgumentException(e); + } + } + return extensionPointType.cast(extensionPoint); + } + + /** + * Remove an extension point based on the interface that it implements + * + * @param extensionPoint The extension point to remove + * + * @throws IllegalArgumentException if extensionPoint is null + */ + public void removeExtensionPoint(Object extensionPoint) { + if (extensionPoint == null) { + throw new IllegalArgumentException("Cannot remove null as an ExtensionPoint"); + } + + Set> interfaces = getAllInterfaces(extensionPoint.getClass()); + for (Class i : interfaces) { + extensionPoints.remove(i); + } + } + + /** + * Returns the set of interfaces implemented by the given class and its + * ancestors or a blank set if none + */ + private static Set> getAllInterfaces(Class clazz) { + Set> implemented = new HashSet>(); + getAllInterfaces(clazz, implemented); + return implemented; + } + + private static void getAllInterfaces(Class clazz, Set> implemented) { + Class[] interfaces = clazz.getInterfaces(); + for (Class interfaze : interfaces) { + if (Modifier.isPublic(interfaze.getModifiers())) { + implemented.add(interfaze); + } + } + Class superClass = clazz.getSuperclass(); + // Object has no superclass so check for null + if (superClass != null && !superClass.equals(Object.class)) { + getAllInterfaces(superClass, implemented); + } + } + +} diff --git a/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/java/org/apache/tuscany/sca/core/DefaultModuleActivatorExtensionPoint.java b/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/java/org/apache/tuscany/sca/core/DefaultModuleActivatorExtensionPoint.java new file mode 100644 index 0000000000..8ca030c0dd --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/java/org/apache/tuscany/sca/core/DefaultModuleActivatorExtensionPoint.java @@ -0,0 +1,92 @@ +/* + * 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.core; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import org.apache.tuscany.sca.extensibility.ServiceDeclaration; +import org.apache.tuscany.sca.extensibility.ServiceDiscovery; + +/** + * Default implementation of an extension point to hold Tuscany module activators. + * + * @version $Rev$ $Date$ + */ +public class DefaultModuleActivatorExtensionPoint implements ModuleActivatorExtensionPoint { + private List activators = new ArrayList(); + private boolean loadedActivators; + + /** + * Constructs a new extension point. + */ + public DefaultModuleActivatorExtensionPoint() { + } + + public void addModuleActivator(ModuleActivator activator) { + activators.add(activator); + } + + public List getModuleActivators() { + loadModuleActivators(); + return activators; + } + + public void removeModuleActivator(Object activator) { + activators.remove(activator); + } + + /** + * Dynamically load module activators declared under META-INF/services + */ + private void loadModuleActivators() { + if (loadedActivators) + return; + + // Get the activator service declarations + Set activatorDeclarations; + try { + activatorDeclarations = ServiceDiscovery.getInstance().getServiceDeclarations(ModuleActivator.class); + } catch (IOException e) { + throw new IllegalStateException(e); + } + + // Load and instantiate module activators + for (ServiceDeclaration activatorDeclaration: activatorDeclarations) { + ModuleActivator activator; + try { + Class activatorClass = (Class)activatorDeclaration.loadClass(); + activator = activatorClass.newInstance(); + } catch (ClassNotFoundException e) { + throw new IllegalArgumentException(e); + } catch (InstantiationException e) { + throw new IllegalArgumentException(e); + } catch (IllegalAccessException e) { + throw new IllegalArgumentException(e); + } + addModuleActivator(activator); + } + + loadedActivators = true; + } + +} diff --git a/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/java/org/apache/tuscany/sca/core/DefaultUtilityExtensionPoint.java b/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/java/org/apache/tuscany/sca/core/DefaultUtilityExtensionPoint.java new file mode 100644 index 0000000000..6f7c83c8d9 --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/java/org/apache/tuscany/sca/core/DefaultUtilityExtensionPoint.java @@ -0,0 +1,184 @@ +/* + * 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.core; + +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.apache.tuscany.sca.extensibility.ServiceDiscovery; + +/** + * Default implementation of an extension point to hold Tuscany utility utilities. + * + * @version $Rev$ $Date$ + */ +public class DefaultUtilityExtensionPoint implements UtilityExtensionPoint { + private Map, Object> utilities = new HashMap, Object>(); + + private ExtensionPointRegistry extensionPoints; + + /** + * Constructs a new extension point. + */ + public DefaultUtilityExtensionPoint(ExtensionPointRegistry extensionPoints) { + this.extensionPoints = extensionPoints; + } + + /** + * Add a utility to the extension point. This default implementation + * stores utilities against the interfaces that they implement. + * + * @param utility The instance of the utility + * + * @throws IllegalArgumentException if utility is null + */ + public void addUtility(Object utility) { + if (utility == null) { + throw new IllegalArgumentException("Cannot register null as a Service"); + } + + Set> interfaces = getAllInterfaces(utility.getClass()); + for (Class i : interfaces) { + utilities.put(i, utility); + } + } + + private Constructor getConstructor(Constructor[] constructors, Class[] paramTypes) { + for (Constructor c : constructors) { + Class[] types = c.getParameterTypes(); + if (c.getParameterTypes().length == paramTypes.length) { + boolean found = true; + for (int i = 0; i < types.length; i++) { + if (types[i] != paramTypes[i]) { + found = false; + break; + } + } + if (found) { + return c; + } + } + } + return null; + } + + /** + * Get the utility by the interface that it implements + * + * @param utilityType The lookup key (utility interface) + * @return The instance of the utility + * + * @throws IllegalArgumentException if utilityType is null + */ + public T getUtility(Class utilityType) { + if (utilityType == null) { + throw new IllegalArgumentException("Cannot lookup Service of type null"); + } + + Object utility = utilities.get(utilityType); + if (utility == null) { + + // Dynamically load a utility class declared under META-INF/utilities + try { + Class utilityClass = + ServiceDiscovery.getInstance().loadFirstServiceClass(utilityType); + if (utilityClass != null) { + // Construct the utility + Constructor[] constructors = utilityClass.getConstructors(); + Constructor constructor = getConstructor(constructors, new Class[] {ExtensionPointRegistry.class}); + if (constructor != null) { + utility = constructor.newInstance(extensionPoints); + } else { + constructor = getConstructor(constructors, new Class[] {}); + if (constructor != null) { + utility = constructor.newInstance(); + } else { + throw new IllegalArgumentException( + "No valid constructor is found for " + utilityClass); + } + } + + // Cache the loaded utility + addUtility(utility); + } + } catch (InvocationTargetException e) { + throw new IllegalArgumentException(e); + } catch (IOException e) { + throw new IllegalArgumentException(e); + } catch (ClassNotFoundException e) { + throw new IllegalArgumentException(e); + } catch (InstantiationException e) { + throw new IllegalArgumentException(e); + } catch (IllegalAccessException e) { + throw new IllegalArgumentException(e); + } + } + return utilityType.cast(utility); + } + + /** + * Remove a utility based on the interface that it implements + * + * @param utility The utility to remove + * + * @throws IllegalArgumentException if utility is null + */ + public void removeUtility(Object utility) { + if (utility == null) { + throw new IllegalArgumentException("Cannot remove null as a Service"); + } + + Set> interfaces = getAllInterfaces(utility.getClass()); + for (Class i : interfaces) { + utilities.remove(i); + } + } + + /** + * Returns the set of interfaces implemented by the given class and its + * ancestors or a blank set if none + */ + private static Set> getAllInterfaces(Class clazz) { + Set> implemented = new HashSet>(); + getAllInterfaces(clazz, implemented); + return implemented; + } + + private static void getAllInterfaces(Class clazz, Set> implemented) { + Class[] interfaces = clazz.getInterfaces(); + for (Class interfaze : interfaces) { + if (Modifier.isPublic(interfaze.getModifiers())) { + implemented.add(interfaze); + } + } + Class superClass = clazz.getSuperclass(); + // Object has no superclass so check for null + if (superClass != null && !superClass.equals(Object.class)) { + getAllInterfaces(superClass, implemented); + } + } + +} diff --git a/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/java/org/apache/tuscany/sca/core/ExtensionPointRegistry.java b/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/java/org/apache/tuscany/sca/core/ExtensionPointRegistry.java new file mode 100644 index 0000000000..f2f67b2d52 --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/java/org/apache/tuscany/sca/core/ExtensionPointRegistry.java @@ -0,0 +1,56 @@ +/* + * 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.core; + + +/** + * The registry for the Tuscany core extension points. As the point of contact + * for all extension artifacts this registry allows loaded extensions to find + * all other parts of the system and register themselves appropriately. + * + * @version $Rev$ $Date$ + */ +public interface ExtensionPointRegistry { + + /** + * Add an extension point to the registry + * @param extensionPoint The instance of the extension point + * + * @throws IllegalArgumentException if extensionPoint is null + */ + void addExtensionPoint(Object extensionPoint); + + /** + * Get the extension point by the interface + * @param extensionPointType The lookup key (extension point interface) + * @return The instance of the extension point + * + * @throws IllegalArgumentException if extensionPointType is null + */ + T getExtensionPoint(Class extensionPointType); + + /** + * Remove an extension point + * @param extensionPoint The extension point to remove + * + * @throws IllegalArgumentException if extensionPoint is null + */ + void removeExtensionPoint(Object extensionPoint); +} diff --git a/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/java/org/apache/tuscany/sca/core/ModuleActivator.java b/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/java/org/apache/tuscany/sca/core/ModuleActivator.java new file mode 100644 index 0000000000..dbfd0dcd90 --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/java/org/apache/tuscany/sca/core/ModuleActivator.java @@ -0,0 +1,60 @@ +/* + * 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.core; + + +/** + * ModuleActivator represents a module that plugs into the Tuscany system. Each + * module should provide an implementation of this interface and register the + * ModuleActivator implementation class by defining a file named + * + * "META-INF/services/org.apache.tuscany.core.ModuleActivator" + * + * The content of the file is the class name of the ModuleActivator implementation. + * The implementation class must have a no-arg constructor. The same instance + * will be used to invoke all the methods during different phases of the module + * activation. Note that the start and stop methods defined by this interface + * take a reference to the Tuscany SCA runtime ExtensionPointRegistry. This + * gives the ModuleActivator the opportunity to add extension points to the + * registry as it is requested to start up and remove them when it is requested + * to shut down. + * + * @version $Rev$ $Date$ + */ +public interface ModuleActivator { + + /** + * This method is invoked when the module is started by the Tuscany system. + * It can be used by this module to register extensions against extension + * points. + * + * @param registry The extension point registry + */ + void start(ExtensionPointRegistry registry); + + /** + * This method is invoked when the module is stopped by the Tuscany system. + * It can be used by this module to unregister extensions against the + * extension points. + * + * @param registry The extension point registry + */ + void stop(ExtensionPointRegistry registry); +} diff --git a/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/java/org/apache/tuscany/sca/core/ModuleActivatorExtensionPoint.java b/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/java/org/apache/tuscany/sca/core/ModuleActivatorExtensionPoint.java new file mode 100644 index 0000000000..ec0f12b8ba --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/java/org/apache/tuscany/sca/core/ModuleActivatorExtensionPoint.java @@ -0,0 +1,53 @@ +/* + * 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.core; + +import java.util.List; + + +/** + * The extension point for the Tuscany module activator extensions. + * + * @version $Rev$ $Date$ + */ +public interface ModuleActivatorExtensionPoint { + + /** + * Add a module activator extension to the extension point + * @param activator The instance of the module activator + * + * @throws IllegalArgumentException if activator is null + */ + void addModuleActivator(ModuleActivator activator); + + /** + * Returns the module activator extensions. + * @return The module activator extensions + */ + List getModuleActivators(); + + /** + * Remove a module activator + * @param activator The module activator to remove + * + * @throws IllegalArgumentException if activator is null + */ + void removeModuleActivator(Object activator); +} diff --git a/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/java/org/apache/tuscany/sca/core/UtilityExtensionPoint.java b/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/java/org/apache/tuscany/sca/core/UtilityExtensionPoint.java new file mode 100644 index 0000000000..6b14b95666 --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/java/org/apache/tuscany/sca/core/UtilityExtensionPoint.java @@ -0,0 +1,54 @@ +/* + * 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.core; + + +/** + * The extension point for the Tuscany core utility extensions. + * + * @version $Rev$ $Date$ + */ +public interface UtilityExtensionPoint { + + /** + * Add a utility to the extension point + * @param utility The instance of the utility + * + * @throws IllegalArgumentException if utility is null + */ + void addUtility(Object utility); + + /** + * Get the utility by the interface + * @param utilityType The lookup key (utility interface) + * @return The instance of the utility + * + * @throws IllegalArgumentException if utilityType is null + */ + T getUtility(Class utilityType); + + /** + * Remove a utility + * @param utility The utility to remove + * + * @throws IllegalArgumentException if utility is null + */ + void removeUtility(Object utility); +} diff --git a/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/java/org/apache/tuscany/sca/extensibility/ContextClassLoaderServiceDiscoverer.java b/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/java/org/apache/tuscany/sca/extensibility/ContextClassLoaderServiceDiscoverer.java new file mode 100644 index 0000000000..da3a12732d --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/java/org/apache/tuscany/sca/extensibility/ContextClassLoaderServiceDiscoverer.java @@ -0,0 +1,248 @@ +/* + * 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.extensibility; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.lang.ref.WeakReference; +import java.net.URL; +import java.net.URLConnection; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * A ServiceDiscoverer that find META-INF/services/... using the Context ClassLoader. + * + * @version $Rev$ $Date$ + */ +public class ContextClassLoaderServiceDiscoverer implements ServiceDiscoverer { + private static final Logger logger = Logger.getLogger(ContextClassLoaderServiceDiscoverer.class.getName()); + + public class ServiceDeclarationImpl implements ServiceDeclaration { + private URL url; + private String className; + private Class javaClass; + private Map attributes; + + public ServiceDeclarationImpl(URL url, String className, Map attributes) { + super(); + this.url = url; + this.className = className; + this.attributes = attributes; + } + + public Map getAttributes() { + return attributes; + } + + public String getClassName() { + return className; + } + + public URL getLocation() { + return url; + } + + public Class loadClass() throws ClassNotFoundException { + if (className == null) { + return null; + } + if (javaClass == null) { + javaClass = loadClass(className); + } + return javaClass; + } + + public Class loadClass(String className) throws ClassNotFoundException { + return classLoaderReference.get().loadClass(className); + } + + public String toString() { + StringBuffer sb = new StringBuffer(); + sb.append("ClassLoader: ").append(classLoaderReference.get()); + sb.append(" Attributes: ").append(attributes); + return sb.toString(); + } + + public URL getResource(final String name) { + return AccessController.doPrivileged(new PrivilegedAction() { + public URL run() { + return classLoaderReference.get().getResource(name); + } + }); + } + + } + + private WeakReference classLoaderReference; + + public ContextClassLoaderServiceDiscoverer() { + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + this.classLoaderReference = new WeakReference(classLoader); + } + + private List getResources(final String name, final boolean firstOnly) throws IOException { + try { + return AccessController.doPrivileged(new PrivilegedExceptionAction>() { + public List run() throws IOException { + if (firstOnly) { + URL url = classLoaderReference.get().getResource(name); + if (url != null) { + return Arrays.asList(url); + } else { + return Collections.emptyList(); + } + } else { + List urls = Collections.list(classLoaderReference.get().getResources(name)); + return urls; + } + } + }); + } catch (PrivilegedActionException e) { + throw (IOException)e.getException(); + } + } + + /** + * Parse a service declaration in the form class;attr=value,attr=value and + * return a map of attributes + * + * @param declaration + * @return a map of attributes + */ + private static Map parseServiceDeclaration(String declaration) { + Map attributes = new HashMap(); + int index = declaration.indexOf(';'); + if (index != -1) { + attributes.put("class", declaration.substring(0, index).trim()); + declaration = declaration.substring(index); + } else { + int j = declaration.indexOf('='); + if (j == -1) { + attributes.put("class", declaration.trim()); + return attributes; + } else { + declaration = ";" + declaration; + } + } + StringTokenizer tokens = new StringTokenizer(declaration); + for (; tokens.hasMoreTokens();) { + String key = tokens.nextToken("=").substring(1).trim(); + if (key == null) + break; + String value = tokens.nextToken(",").substring(1).trim(); + if (value == null) + break; + attributes.put(key, value); + } + return attributes; + } + + public Set discover(String serviceName, boolean firstOnly) { + Set descriptors = new HashSet(); + + String name = "META-INF/services/" + serviceName; + boolean debug = logger.isLoggable(Level.FINE); + try { + for (final URL url : getResources(name, firstOnly)) { + if (debug) { + logger.fine("Reading service provider file: " + url.toExternalForm()); + } + + // Allow privileged access to open URL stream. Add FilePermission to added to security + // policy file. + InputStream is; + try { + is = AccessController.doPrivileged(new PrivilegedExceptionAction() { + public InputStream run() throws IOException { + URLConnection connection = url.openConnection(); + // TUSCANY-2539 + // Don't cache connections by default to stop Tuscany locking contribution jar files + // done here as this is one of the first places we open a stream and the only way to + // set the default is to set it on an instance of URLConnection + connection.setDefaultUseCaches(false); + connection.setUseCaches(false); + return url.openStream(); + } + }); + } catch (PrivilegedActionException e) { + throw (IOException)e.getException(); + } + BufferedReader reader = null; + try { + reader = new BufferedReader(new InputStreamReader(is)); + int count = 0; + while (true) { + String line = reader.readLine(); + if (line == null) + break; + line = line.trim(); + if (!line.startsWith("#") && !"".equals(line)) { + String reg = line.trim(); + if (debug) { + logger.fine("Registering service provider: " + reg); + } + + Map attributes = parseServiceDeclaration(reg); + String className = attributes.get("class"); + if (className == null) { + // Add a unique class name to prevent equals() from returning true + className = "_class_" + count; + count++; + } + ServiceDeclarationImpl descriptor = new ServiceDeclarationImpl(url, className, attributes); + descriptors.add(descriptor); + if (firstOnly) { + return descriptors; + } + } + } + } finally { + if (reader != null) { + try { + reader.close(); + } catch (IOException e) { + // Ignore + } + } + } + } + } catch (IOException e) { + logger.log(Level.SEVERE, e.getMessage(), e); + } + return descriptors; + + } + +} diff --git a/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/java/org/apache/tuscany/sca/extensibility/ServiceDeclaration.java b/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/java/org/apache/tuscany/sca/extensibility/ServiceDeclaration.java new file mode 100644 index 0000000000..403b6aa7a7 --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/java/org/apache/tuscany/sca/extensibility/ServiceDeclaration.java @@ -0,0 +1,68 @@ +/* + * 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.extensibility; + +import java.net.URL; +import java.util.Map; + +/** + * Service declaration using J2SE Jar service provider spec Classes specified + * inside this declaration are loaded using the ClassLoader used to read the + * configuration file corresponding to this declaration. + * + * @version $Rev$ $Date$ + */ +public interface ServiceDeclaration { + /** + * Load a java class in the same context as the service definition + * @param className The class name + * @return The loaded class + * @throws ClassNotFoundException + */ + Class loadClass(String className) throws ClassNotFoundException; + /** + * Get the java class for the service impl + * @return The java class + */ + Class loadClass() throws ClassNotFoundException; + /** + * Get all attributes (name=value pairs) defined for the given entry + * @return All attributes keyed by name + */ + Map getAttributes(); + + URL getLocation(); + + String getClassName(); + + URL getResource(String name); + + /** + * The service descriptor might be hashed + * @param obj Another object + * @return + */ + boolean equals(Object obj); + /** + * The service descriptor might be hashed + * @return + */ + int hashCode(); +} diff --git a/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/java/org/apache/tuscany/sca/extensibility/ServiceDiscoverer.java b/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/java/org/apache/tuscany/sca/extensibility/ServiceDiscoverer.java new file mode 100644 index 0000000000..1722cd5f49 --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/java/org/apache/tuscany/sca/extensibility/ServiceDiscoverer.java @@ -0,0 +1,37 @@ +/* + * 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.extensibility; + +import java.util.Set; + +/** + * A SPI that allows different implementations of discovering service declarations + */ +public interface ServiceDiscoverer { + /** + * Discover the service descriptors by name + * @param serviceName The name of the service + * @param firstOnly A flag to indicate if only the first instance is to be discovered + * + * @return A set of service descriptors + */ + Set discover(String serviceName, boolean firstOnly); + +} diff --git a/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/java/org/apache/tuscany/sca/extensibility/ServiceDiscovery.java b/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/java/org/apache/tuscany/sca/extensibility/ServiceDiscovery.java new file mode 100644 index 0000000000..ce41a44068 --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/java/org/apache/tuscany/sca/extensibility/ServiceDiscovery.java @@ -0,0 +1,170 @@ +/* + * 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.extensibility; + +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.HashSet; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Service discovery for Tuscany based on J2SE Jar service provider spec. + * Services are described using configuration files in META-INF/services. + * Service description specifies a class name followed by optional properties. + * + * + * @version $Rev$ $Date$ + */ +public class ServiceDiscovery { + private static final Logger logger = Logger.getLogger(ServiceDiscovery.class.getName()); + + private final static ServiceDiscovery INSTANCE = new ServiceDiscovery(); + + private ServiceDiscoverer discoverer; + private Set registeredClassLoaders = new HashSet(); + + /** + * Get an instance of Service discovery, one instance is created per + * ClassLoader that this class is loaded from + * + * @return + */ + public static ServiceDiscovery getInstance() { + return INSTANCE; + } + + public ServiceDiscoverer getServiceDiscoverer() { + if (discoverer == null) { + discoverer = new ContextClassLoaderServiceDiscoverer(); + } + return discoverer; + } + + public void setServiceDiscoverer(ServiceDiscoverer sd) { + if (discoverer != null) { + throw new IllegalStateException("The ServiceDiscoverer cannot be reset"); + } + discoverer = sd; + } + + /** + * @deprecated + * Register a ClassLoader with this discovery mechanism. Tuscany extension + * ClassLoaders are registered here. + * + * @param classLoader + */ + @Deprecated + public synchronized void registerClassLoader(ClassLoader classLoader) { + registeredClassLoaders.add(classLoader); + } + + /** + * @deprecated + * Unregister a ClassLoader with this discovery mechanism. + * + * @param classLoader + */ + @Deprecated + public synchronized void unregisterClassLoader(ClassLoader classLoader) { + registeredClassLoaders.remove(classLoader); + } + + /** + * Get all service declarations for this name + * + * @param name + * @return set of service declarations + * @throws IOException + */ + public Set getServiceDeclarations(String name) throws IOException { + Set services = getServiceDiscoverer().discover(name, false); + return services; + } + + /** + * Get all service declarations for this interface + * + * @param serviceInterface + * @return set of service declarations + * @throws IOException + */ + public Set getServiceDeclarations(Class serviceInterface) throws IOException { + + return getServiceDeclarations(serviceInterface.getName()); + } + + /** + * Load one service implementation class for this interface + * + * @param serviceInterface + * @return service implementation class + * @throws IOException + * @throws ClassNotFoundException + */ + public Class loadFirstServiceClass(final Class serviceInterface) throws IOException, ClassNotFoundException { + // Try System property first + String className = AccessController.doPrivileged(new PrivilegedAction() { + public String run() { + return System.getProperty(serviceInterface.getName()); + } + }); + if (className != null) { + try { + // Try the classloader for the service interface first + return Class.forName(className, false, serviceInterface.getClassLoader()); + } catch (ClassNotFoundException e) { + try { + // Try the thread context classloader + return Class.forName(className, false, Thread.currentThread().getContextClassLoader()); + } catch (ClassNotFoundException ex) { + logger.log(Level.WARNING, ex.getMessage(), ex); + } + } + } + Set services = getServiceDiscoverer().discover(serviceInterface.getName(), true); + if (services.isEmpty()) { + return null; + } + return services.iterator().next().loadClass(); + } + + /** + * Create a new instance of a factory service class. + * + * @param serviceInterface + * @return service implementation class + * @throws SecurityException + * @throws NoSuchMethodException + * @throws InvocationTargetException + * @throws IllegalAccessException + */ + public Object newFactoryClassInstance(final Class serviceInterface) throws SecurityException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Method newInstanceMethod = serviceInterface.getMethod("newInstance"); + Object factory = newInstanceMethod.invoke(null); + return factory; + } + +} diff --git a/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/resources/META-INF/services/org.apache.tuscany.sca.core.ModuleActivatorExtensionPoint b/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/resources/META-INF/services/org.apache.tuscany.sca.core.ModuleActivatorExtensionPoint new file mode 100644 index 0000000000..42bad63132 --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/resources/META-INF/services/org.apache.tuscany.sca.core.ModuleActivatorExtensionPoint @@ -0,0 +1,18 @@ +# 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. + +org.apache.tuscany.sca.core.DefaultModuleActivatorExtensionPoint diff --git a/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/resources/META-INF/services/org.apache.tuscany.sca.core.UtilityExtensionPoint b/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/resources/META-INF/services/org.apache.tuscany.sca.core.UtilityExtensionPoint new file mode 100644 index 0000000000..d769bad283 --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/main/resources/META-INF/services/org.apache.tuscany.sca.core.UtilityExtensionPoint @@ -0,0 +1,18 @@ +# 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. + +org.apache.tuscany.sca.core.DefaultUtilityExtensionPoint diff --git a/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/test/java/org/apache/tuscany/sca/extensibility/ContextClassLoaderServiceDiscovererTestCase.java b/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/test/java/org/apache/tuscany/sca/extensibility/ContextClassLoaderServiceDiscovererTestCase.java new file mode 100644 index 0000000000..fd508402fc --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.4/modules/extensibility/src/test/java/org/apache/tuscany/sca/extensibility/ContextClassLoaderServiceDiscovererTestCase.java @@ -0,0 +1,72 @@ +/* + * 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.extensibility; + +import java.util.Set; + +import junit.framework.Assert; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * Test Case for ClasspathServiceDiscover + */ +public class ContextClassLoaderServiceDiscovererTestCase { + private static ContextClassLoaderServiceDiscoverer discover; + + /** + * @throws java.lang.Exception + */ + @BeforeClass + public static void setUpBeforeClass() throws Exception { + discover = new ContextClassLoaderServiceDiscoverer(); + } + + @Test + public void testDiscovery() { + Set discriptors = + discover.discover("org.apache.tuscany.sca.core.ModuleActivatorExtensionPoint", false); + Assert.assertEquals(1, discriptors.size()); + discriptors = + discover.discover("notthere", false); + Assert.assertEquals(0, discriptors.size()); + } + + @Test + public void testDiscoveryFirst() { + Set discriptors = + discover.discover("org.apache.tuscany.sca.core.ModuleActivatorExtensionPoint", true); + Assert.assertEquals(1, discriptors.size()); + discriptors = + discover.discover("notthere", true); + Assert.assertEquals(0, discriptors.size()); + } + + + /** + * @throws java.lang.Exception + */ + @AfterClass + public static void tearDownAfterClass() throws Exception { + } + +} -- cgit v1.2.3