summaryrefslogtreecommitdiffstats
path: root/sca-java-2.x/tags/2.0.1-RC1/modules/node-api/src/main/java/org/apache/tuscany/sca/node/NodeFactory.java
diff options
context:
space:
mode:
Diffstat (limited to 'sca-java-2.x/tags/2.0.1-RC1/modules/node-api/src/main/java/org/apache/tuscany/sca/node/NodeFactory.java')
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/node-api/src/main/java/org/apache/tuscany/sca/node/NodeFactory.java661
1 files changed, 661 insertions, 0 deletions
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/node-api/src/main/java/org/apache/tuscany/sca/node/NodeFactory.java b/sca-java-2.x/tags/2.0.1-RC1/modules/node-api/src/main/java/org/apache/tuscany/sca/node/NodeFactory.java
new file mode 100644
index 0000000000..0aa01a477d
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/node-api/src/main/java/org/apache/tuscany/sca/node/NodeFactory.java
@@ -0,0 +1,661 @@
+/*
+ * 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.node;
+
+import static org.apache.tuscany.sca.node.ContributionLocationHelper.getContributionLocations;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.lang.reflect.InvocationTargetException;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.node.configuration.DefaultNodeConfigurationFactory;
+import org.apache.tuscany.sca.node.configuration.NodeConfiguration;
+import org.apache.tuscany.sca.node.configuration.NodeConfigurationFactory;
+import org.apache.tuscany.sca.node.extensibility.NodeExtension;
+import org.oasisopen.sca.ServiceReference;
+import org.oasisopen.sca.ServiceRuntimeException;
+
+/**
+ * A factory for SCA processing nodes. An SCA processing node can be loaded
+ * with an SCA composite and the SCA contributions required by the composite.
+ *
+ * @version $Rev$ $Date$
+ * @tuscany.spi.extension.asclient
+ */
+public abstract class NodeFactory extends DefaultNodeConfigurationFactory {
+ /**
+ * Default location of contribution metadata in an SCA contribution.
+ */
+ private static final String SCA_CONTRIBUTION_META = "META-INF/sca-contribution.xml";
+
+ /**
+ * Default location of a generated contribution metadata in an SCA contribution.
+ */
+ private static final String SCA_CONTRIBUTION_GENERATED_META = "META-INF/sca-contribution-generated.xml";
+
+ protected static NodeFactory instance;
+ protected static Class<?> factoryImplClass;
+
+ protected static List<NodeFactory> factories = new ArrayList<NodeFactory>();
+
+ protected static void setNodeFactory(NodeFactory factory) {
+ instance = factory;
+ }
+
+ public static class NodeProxy implements Node {
+ private Object node;
+
+ private NodeProxy(Object node) {
+ super();
+ this.node = node;
+ }
+
+ public static <T> T createProxy(Class<T> type, Object node) {
+ try {
+ return type.getDeclaredConstructor(Object.class).newInstance(node);
+ } catch (Exception e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ public <B, R extends ServiceReference<B>> R cast(B target) throws IllegalArgumentException {
+ try {
+ return (R)node.getClass().getMethod("cast", Object.class).invoke(node, target);
+ } catch (Throwable e) {
+ handleException(e);
+ return null;
+ }
+ }
+
+ public <B> B getService(Class<B> businessInterface, String serviceName) {
+ try {
+ return (B)node.getClass().getMethod("getService", Class.class, String.class).invoke(node, businessInterface, serviceName);
+ } catch (Throwable e) {
+ handleException(e);
+ return null;
+ }
+ }
+
+ public <B> ServiceReference<B> getServiceReference(Class<B> businessInterface, String serviceName) {
+ try {
+ return (ServiceReference<B>)node.getClass().getMethod("getServiceReference", Class.class, String.class).invoke(node, businessInterface, serviceName);
+ } catch (Throwable e) {
+ handleException(e);
+ return null;
+ }
+ }
+
+ public Node start() {
+ try {
+ return new NodeProxy(node.getClass().getMethod("start").invoke(node));
+ } catch (Throwable e) {
+ handleException(e);
+ return null;
+ }
+ }
+
+ public void stop() {
+ try {
+ node.getClass().getMethod("stop").invoke(node);
+ } catch (Throwable e) {
+ handleException(e);
+ }
+ }
+
+ public void destroy() {
+ try {
+ node.getClass().getMethod("destroy").invoke(node);
+ } catch (Throwable e) {
+ handleException(e);
+ }
+ }
+
+ private static void handleException(Throwable ex) {
+ if (ex instanceof InvocationTargetException) {
+ ex = ((InvocationTargetException)ex).getTargetException();
+ }
+ if (ex instanceof RuntimeException) {
+ throw (RuntimeException)ex;
+ }
+ if (ex instanceof Error) {
+ throw (Error)ex;
+ } else {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ @Override
+ public String getEndpointAddress(String serviceBindingName) {
+ try {
+ return (String)node.getClass().getMethod("getEndpointAddress", String.class)
+ .invoke(node, serviceBindingName);
+ } catch (Throwable e) {
+ handleException(e);
+ return null;
+ }
+ }
+
+ }
+
+ /**
+ * Returns the SCA node factory instance.
+ *
+ * @return the SCA node factory
+ */
+ public synchronized static NodeFactory getInstance() {
+ if (instance == null) {
+ instance = newInstance();
+ }
+ return instance;
+ }
+
+ /**
+ * Returns a new SCA node factory instance.
+ *
+ * @return a new SCA node factory
+ */
+ public static NodeFactory newInstance() {
+ NodeFactory nodeFactory = null;
+ try {
+ Class<?> factoryClass = getFactoryImplClass();
+ nodeFactory = (NodeFactory)factoryClass.newInstance();
+
+ } catch (Exception e) {
+ throw new ServiceRuntimeException(e);
+ }
+ factories.add(nodeFactory);
+ return nodeFactory;
+ }
+
+ public static NodeFactory newInstance(Map<String, Map<String, String>> attributes) {
+ NodeFactory nodeFactory = null;
+ try {
+ Class<?> factoryClass = getFactoryImplClass();
+ nodeFactory = (NodeFactory)factoryClass.newInstance();
+ nodeFactory.configure(attributes);
+ } catch (Exception e) {
+ throw new ServiceRuntimeException(e);
+ }
+ factories.add(nodeFactory);
+ return nodeFactory;
+ }
+
+ protected Properties properties;
+
+ protected NodeFactory() {
+ this.properties = new Properties();
+ }
+
+ public static NodeFactory newInstance(Properties configProperties) {
+ NodeFactory nodeFactory = null;
+ try {
+ Class<?> factoryClass = getFactoryImplClass();
+ nodeFactory = (NodeFactory)factoryClass.newInstance();
+ nodeFactory.properties = configProperties;
+ nodeFactory.configure(new HashMap<String, Map<String,String>>());
+ } catch (Exception e) {
+ throw new ServiceRuntimeException(e);
+ }
+ factories.add(nodeFactory);
+ return nodeFactory;
+ }
+
+ public static NodeFactory newInstance(String configURI) {
+ Properties properties;
+ if (configURI == null || configURI.length() < 1) {
+ return newInstance();
+ } else if (configURI.startsWith("properties:")) {
+ try {
+ properties = loadProperties(configURI.substring("properties:".length()));
+ } catch (IOException e) {
+ throw new ServiceRuntimeException(e);
+ }
+ } else if (configURI.startsWith("uri:")) {
+ properties = parseConfigURI(configURI.substring("uri:".length()));
+ } else {
+ properties = new Properties();
+ properties.setProperty("defaultDomainName", configURI);
+ }
+ return newInstance(properties);
+ }
+
+ /**
+ * Parse the config string into a Properties object.
+ * The config URI has the following format:
+ * uri:<domainName>?name=value&...
+ */
+ private static Properties parseConfigURI(String configURI) {
+ Properties properties = new Properties();
+ int qm = configURI.indexOf('?');
+ if (qm < 0) {
+ properties.setProperty("defaultDomainName", configURI);
+ } else {
+ if (qm == 0) {
+ properties.setProperty("defaultDomainName", "default");
+ } else {
+ properties.setProperty("defaultDomainName", configURI.substring(0, qm));
+ }
+ if (configURI.length() > qm+1) {
+ Map<String, String> params = new HashMap<String, String>();
+ for (String param : configURI.substring(qm+1).split("&")) {
+ String[] px = param.split("=");
+ if (px.length == 2) {
+ params.put(px[0], px[1]);
+ } else {
+ params.put(px[0], "");
+ }
+ }
+ for (String name : params.keySet()) {
+ properties.setProperty(name, params.get(name));
+ }
+ }
+ }
+ return properties;
+ }
+
+ /**
+ * load the properties from external URL or a relative file
+ * properties:<url to properties file>
+ */
+ private static Properties loadProperties(String propsURL) throws IOException {
+
+ Properties properties = new Properties();
+ File file = new File(propsURL);
+
+ InputStream inputStream = null;
+ if (file.exists()) {
+ inputStream = new FileInputStream(file);
+ } else {
+ URL url = null;
+ try {
+ url = new URL(propsURL);
+ } catch (MalformedURLException e) {
+ inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(propsURL);
+ if (inputStream == null) {
+ throw new IOException("File does not exist: " + propsURL + ", could not be found on the classpath and is not a valid URL: " + e);
+ }
+ }
+ if (inputStream == null && url != null) {
+ inputStream = url.openStream();
+ }
+ }
+ if (inputStream != null) {
+ properties.load(inputStream);
+ inputStream.close();
+ }
+
+ return properties;
+ }
+
+ /**
+ * Configure the NodeFactory instance
+ * @param attributes
+ */
+ public void configure(Map<String, Map<String, String>> attributes) {
+ }
+
+ private synchronized static Class<?> getFactoryImplClass() throws Exception {
+ if (factoryImplClass == null) {
+ // Use reflection APIs to call ServiceDiscovery to avoid hard dependency to tuscany-extensibility
+ try {
+ Class<?> discoveryClass = Class.forName("org.apache.tuscany.sca.extensibility.ServiceDiscovery");
+ Object instance = discoveryClass.getMethod("getInstance").invoke(null);
+ Object factoryDeclaration =
+ discoveryClass.getMethod("getServiceDeclaration", Class.class).invoke(instance, NodeFactory.class);
+ if (factoryDeclaration != null) {
+ factoryImplClass =
+ (Class<?>)factoryDeclaration.getClass().getMethod("loadClass").invoke(factoryDeclaration);
+ }
+ } catch (ClassNotFoundException e) {
+ // Ignore
+ }
+
+ if (factoryImplClass == null) {
+ // Fail back to default impl
+ String className = "org.apache.tuscany.sca.node.impl.NodeFactoryImpl";
+
+ factoryImplClass = Class.forName(className);
+ }
+ }
+ return factoryImplClass;
+ }
+
+ /**
+ * Open a URL connection without cache
+ * @param url
+ * @return
+ * @throws IOException
+ */
+ private static InputStream openStream(URL url) throws IOException {
+ InputStream is = null;
+ URLConnection connection = url.openConnection();
+ connection.setUseCaches(false);
+ is = connection.getInputStream();
+ return is;
+ }
+
+ /**
+ * Escape the space in URL string
+ * @param uri
+ * @return
+ */
+ private static URI createURI(String uri) {
+ int index = uri.indexOf(':');
+ String scheme = null;
+ String ssp = uri;
+ if (index != -1) {
+ scheme = uri.substring(0, index);
+ ssp = uri.substring(index + 1);
+ }
+ try {
+ return new URI(scheme, ssp, null);
+ } catch (URISyntaxException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ /**
+ * Creates a new SCA node from the configuration URL
+ *
+ * @param configurationURL the URL of the node configuration which is the XML document
+ * that contains the URI of the composite and a collection of URLs for the contributions
+ *
+ * @return a new SCA node.
+ */
+ public Node createNode(URL configurationURL) {
+ try {
+ InputStream is = openStream(configurationURL);
+ NodeConfiguration configuration = loadConfiguration(is, configurationURL);
+ return createNode(configuration);
+ } catch (IOException e) {
+ throw new ServiceRuntimeException(e);
+ }
+ }
+
+ /**
+ * Creates a new SCA node from the XML configuration of the node
+ * @param is The input stream that the XML configuration can be read. The stream will be closed
+ * after this call.
+ * @return a new SCA node
+ */
+ public Node createNode(InputStream is) {
+ NodeConfiguration configuration = loadConfiguration(is, null);
+ return createNode(configuration);
+ }
+
+ /**
+ * Creates a new SCA node.
+ *
+ * @param deploymentCompositeURI the URI of the deployment composite. If the URI is relative, it should
+ * be resolved against the first contribution. Otherwise, the absolute URI is used to load the XML
+ * description of the composite. The deployment composite will be attached to the first contribution.
+ *
+ * @param contributions the URI of the contributions that provides the composites and related
+ * artifacts. If the list is empty, then we will use the thread context classloader to discover
+ * the contribution on the classpath
+ *
+ * @return a new SCA node.
+ */
+ public Node createNode(String deploymentCompositeURI, Contribution... contributions) {
+ if (contributions == null || contributions.length == 0) {
+ if (deploymentCompositeURI == null || deploymentCompositeURI.indexOf(':') != -1) {
+ throw new ServiceRuntimeException("No SCA contribution is provided or discovered");
+ }
+ // Try to find contributions on the classpath by the composite URI
+ List<String> locations = getContributionLocations(null, deploymentCompositeURI);
+ if (locations.isEmpty()) {
+ throw new ServiceRuntimeException("No SCA contributions are found on the classpath");
+ }
+ contributions = getContributions(locations);
+ }
+ NodeConfiguration configuration = createConfiguration(contributions);
+ if (deploymentCompositeURI != null && configuration.getContributions().size() > 0) {
+ configuration.getContributions().get(0).addDeploymentComposite(createURI(deploymentCompositeURI));
+ }
+ return createNode(configuration);
+ }
+
+ public final Node createNode(URI domainRegistryURI, String... locations) {
+ return createNode(domainRegistryURI, null, locations);
+ }
+
+ public final Node createNode(URI domainRegistryURI, String deploymentCompositeURI, String[] locations) {
+ Contribution[] contributions = getContributions(Arrays.asList(locations));
+ NodeConfiguration configuration = createConfiguration(contributions);
+ if (deploymentCompositeURI != null && configuration.getContributions().size() > 0) {
+ configuration.getContributions().get(0).addDeploymentComposite(createURI(deploymentCompositeURI));
+ }
+ configuration.setDomainRegistryURI(domainRegistryURI.toString());
+ configuration.setDomainURI(getDomainURI(domainRegistryURI));
+ return createNode(configuration);
+ }
+
+ /**
+ * TODO: cleanup node use of registry uri, domain uri, and domain name
+ * so that its consistent across the code base
+ */
+ public static String getDomainURI(URI configURI) {
+ String s = configURI.getHost();
+ if (s == null) {
+ s = configURI.getSchemeSpecificPart();
+ if (s != null) {
+ if (s.indexOf('?') > -1) {
+ s = s.substring(0, s.indexOf('?'));
+ }
+ }
+ }
+ return s;
+ }
+
+ /**
+ * The following methods are used by the node launcher
+ */
+ public final Node createNode(String deploymentCompositeURI, String[] uris, String locations[]) {
+ return createNode(deploymentCompositeURI, getContributions(Arrays.asList(uris), Arrays.asList(locations)));
+ }
+
+ public final Node createNode(String deploymentCompositeURI, String locations[]) {
+ return createNode(deploymentCompositeURI, getContributions(Arrays.asList(locations)));
+ }
+
+ public final Node createNode(Reader deploymentCompositeContent, String[] uris, String locations[]) {
+ return createNode(deploymentCompositeContent, getContributions(Arrays.asList(uris), Arrays.asList(locations)));
+ }
+
+ public final Node createNode(String compositeURI, ClassLoader classLoader) {
+ List<String> locations = ContributionLocationHelper.getContributionLocations(classLoader, compositeURI);
+ return createNode(compositeURI, locations.toArray(new String[locations.size()]));
+ }
+ /**
+ * ------------------- end of methods -----------------
+ */
+
+ /**
+ * Create a new SCA node using the list of SCA contributions
+ * @param contributions
+ * @return
+ */
+ public Node createNode(Contribution... contributions) {
+ NodeConfiguration configuration = createConfiguration(contributions);
+ return createNode(configuration);
+ }
+
+
+ /**
+ * Creates a new SCA node.
+ *
+ * @param compositeContent the XML content of the deployment composite
+ * @param contributions the URI of the contributions that provides the composites and related artifacts
+ * @return a new SCA node.
+ */
+ public Node createNode(InputStream compositeContent, Contribution... contributions) {
+ NodeConfiguration configuration = createConfiguration(contributions);
+ if (compositeContent != null && configuration.getContributions().size() > 0) {
+ configuration.getContributions().get(0).addDeploymentComposite(compositeContent);
+ }
+ return createNode(configuration);
+ }
+
+ /**
+ * Creates a new SCA node.
+ *
+ * @param compositeContent the XML content of the deployment composite
+ * @param contributions the URI of the contributions that provides the composites and related artifacts
+ * @return a new SCA node.
+ */
+ public Node createNode(Reader compositeContent, Contribution... contributions) {
+ NodeConfiguration configuration = createConfiguration(contributions);
+ if (compositeContent != null && configuration.getContributions().size() > 0) {
+ configuration.getContributions().get(0).addDeploymentComposite(compositeContent);
+ }
+ return createNode(configuration);
+ }
+
+ /**
+ * Creates a new SCA node using defaults for the contribution location and deployable composites.
+ * By default, it uses the Thread context classloader to find META-INF/sca-contribution.xml or
+ * META-INF/sca-contribution-generated.xml on the classpath. The locations that contain such resources
+ * are taken as the SCA contributions.
+ *
+ * @return a new SCA node.
+ */
+ public Node createNode() {
+ List<String> locations = new ArrayList<String>();
+ locations.addAll(getContributionLocations(null, SCA_CONTRIBUTION_META));
+ locations.addAll(getContributionLocations(null, SCA_CONTRIBUTION_GENERATED_META));
+ if (locations.isEmpty()) {
+ throw new ServiceRuntimeException("No SCA contributions are found on the classpath");
+ }
+ Contribution[] contributions = getContributions(locations);
+ return createNode(contributions);
+ }
+
+ private NodeConfiguration createConfiguration(Contribution... contributions) {
+ NodeConfigurationFactory factory = this;
+ NodeConfiguration configuration = factory.createNodeConfiguration();
+ if (properties.getProperty("defaultDomainName") != null) {
+ configuration.setDomainURI(properties.getProperty("defaultDomainName"));
+ }
+ // Make sure a unique node URI is created for the same node factory
+ configuration.setURI(generateNodeURI());
+ if (contributions != null) {
+ for (Contribution c : contributions) {
+ configuration.addContribution(c.getURI(), c.getLocation());
+ }
+ }
+ return configuration;
+ }
+
+ private static int count = 0;
+
+ protected synchronized String generateNodeURI() {
+ return Node.DEFAULT_NODE_URI + (count++);
+ }
+
+ private Contribution[] getContributions(List<String> locations) {
+ Contribution[] contributions = new Contribution[locations.size()];
+ int index = 0;
+ for (String location : locations) {
+ contributions[index++] = new Contribution(location, location);
+ }
+ return contributions;
+ }
+
+ private Contribution[] getContributions(List<String> uris, List<String> locations) {
+ if (uris.size() != locations.size()) {
+ throw new IllegalArgumentException("The number of URIs does not match the number of locations");
+ }
+ Contribution[] contributions = new Contribution[locations.size()];
+ for (int i = 0, n = locations.size(); i < n; i++) {
+ contributions[i] = new Contribution(uris.get(i), locations.get(i));
+ }
+ return contributions;
+ }
+
+ public void destroy() {
+ count = 0;
+ instance = null;
+ factories.remove(this);
+ }
+
+ public static List<NodeFactory> getNodeFactories() {
+ return factories;
+ }
+
+ /**
+ * Create a new SCA node based on the configuration
+ * @param configuration The configuration of a node
+ * @return The SCA node
+ */
+ public abstract Node createNode(NodeConfiguration configuration);
+
+ /**
+ * Create an SCA node from a list of pre-built o.a.t.sca.contribution.Contribution objects.
+ * Pass java.lang.Objects for now as this class doesn't have direct dependencies on
+ * o.a.t.sca.contribution.Contribution.
+ */
+ public abstract Node createNode(List<?> contributions);
+
+ /**
+ * Create the node configuration from the XML document
+ * @param configuration The input stream of the XML document
+ * @return The node configuration
+ */
+ public abstract NodeConfiguration loadConfiguration(InputStream xml, URL base);
+
+ /**
+ * Get the ExtensionPointRegistry
+ * @return
+ */
+ public abstract ExtensionPointRegistry getExtensionPointRegistry();
+
+ /**
+ * Initialize the factory
+ */
+ public abstract void init();
+
+ /**
+ * Set auto destroy flag when all nodes are stopped
+ * @param b
+ */
+ public abstract void setAutoDestroy(boolean b);
+
+ /**
+ * Create and load the node for the purpose of metadata introspection
+ * @param configuration
+ * @return The extended Node
+ */
+ public abstract NodeExtension loadNode(NodeConfiguration configuration);
+}