All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.tuscany.sca.TuscanyRuntime Maven / Gradle / Ivy

/*
 * 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;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;

import javax.xml.stream.XMLStreamException;

import org.apache.tuscany.sca.assembly.AssemblyFactory;
import org.apache.tuscany.sca.common.java.io.IOHelper;
import org.apache.tuscany.sca.contribution.processor.ContributionReadException;
import org.apache.tuscany.sca.contribution.processor.ProcessorContext;
import org.apache.tuscany.sca.core.DefaultExtensionPointRegistry;
import org.apache.tuscany.sca.core.ExtensionPointRegistry;
import org.apache.tuscany.sca.core.FactoryExtensionPoint;
import org.apache.tuscany.sca.core.ModuleActivatorExtensionPoint;
import org.apache.tuscany.sca.core.UtilityExtensionPoint;
import org.apache.tuscany.sca.core.assembly.RuntimeAssemblyFactory;
import org.apache.tuscany.sca.deployment.Deployer;
import org.apache.tuscany.sca.impl.NodeImpl;
import org.apache.tuscany.sca.monitor.ValidationException;
import org.apache.tuscany.sca.node.configuration.ContributionConfiguration;
import org.apache.tuscany.sca.node.configuration.NodeConfiguration;
import org.apache.tuscany.sca.runtime.ActivationException;
import org.apache.tuscany.sca.runtime.CompositeActivator;
import org.apache.tuscany.sca.runtime.DomainRegistry;
import org.apache.tuscany.sca.runtime.ExtensibleDomainRegistryFactory;
import org.apache.tuscany.sca.runtime.RuntimeProperties;
import org.apache.tuscany.sca.work.WorkScheduler;
import org.oasisopen.sca.ServiceRuntimeException;

/**
 * The TuscanyRuntime is the main class for using Tuscany. It can create Nodes,
 * run composites, and provides access to various utility APIs
 */
public class TuscanyRuntime {

    public static final String DEFAUL_DOMAIN_NAME = "default";
    private Deployer deployer;
    private ExtensionPointRegistry extensionPointRegistry;
    private CompositeActivator compositeActivator;
    private ExtensibleDomainRegistryFactory domainRegistryFactory;
    private RuntimeAssemblyFactory assemblyFactory;

    /**
     * Creates a new TuscanyRuntime 
     * @return a TuscanyRuntime
     */
    public static TuscanyRuntime newInstance() {
        return new TuscanyRuntime(null);
    }
    
    /**
     * Creates a new TuscanyRuntime 
     * @param config  Properties to configure the TuscanyRuntime
     * @return a TuscanyRuntime
     */
    public static TuscanyRuntime newInstance(Properties config) {
        return new TuscanyRuntime(config);
    }

    /**
     * A helper method to run a standalone SCA composite in the default standalone SCA domain.
     * @param compositeURI  URI within the contribution of a composite to run 
     *         if compositeURI is null then all deployable composites in the contribution will be run 
     * @param contributionURL  URL of the contribution
     * @param dependentContributionURLs  optional URLs of dependent contributions
     * @return a Node with installed contributions
     */
    public static Node runComposite(String compositeURI, String contributionURL, String... dependentContributionURLs) {
        return runComposite(null, compositeURI, contributionURL, dependentContributionURLs);
    }

    /**
     * A helper method to run a standalone SCA composite in a SCA domain
     * @param domainURI the URI of the SCA domain
     * @param compositeURI  URI within the contribution of a composite to run 
     *         if compositeURI is null then all deployable composites in the contribution will be run 
     * @param contributionURL  URL of the contribution
     * @param dependentContributionURLs  optional URLs of dependent contributions
     * @return a Node with installed contributions
     */
    public static Node runComposite(URI domainURI, String compositeURI, String contributionURL, String... dependentContributionURLs) {
        try {
            TuscanyRuntime runtime = newInstance();
            String domain = domainURI == null ? DEFAUL_DOMAIN_NAME : domainURI.toString();
            DomainRegistry domainRegistry = runtime.domainRegistryFactory.getEndpointRegistry(domain, null);
            NodeImpl node = new NodeImpl(runtime.deployer, runtime.compositeActivator, domainRegistry, runtime.extensionPointRegistry, runtime);

            if (dependentContributionURLs != null) {
                for (int i=dependentContributionURLs.length-1; i>-1; i--) {
                    node.installContribution(null, dependentContributionURLs[i], null, null);
                }
            }

            String curi = node.installContribution(null, contributionURL, null, null);
            if (compositeURI != null) {
                node.startComposite(curi, compositeURI);
            } else {
                for (String compURI : node.getDeployableCompositeURIs(curi)) {
                    node.startComposite(curi, compURI);
                }
            }
            return node;
            
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    protected TuscanyRuntime(Properties config) {
        init(config);
    }
    
    /**
     * Creates a Node
     * @return a Node
     */
    public Node createNode() {
        return createNode((String)null);
    }

    /**
     * Creates a Node in an SCA domain 
     * @param domainURI  the URI of the SCA domain
     * @return a Node
     */
    public Node createNode(String domainURI) {
        if (domainURI == null){
            domainURI = DEFAUL_DOMAIN_NAME;
        }
        DomainRegistry domainRegistry = domainRegistryFactory.getEndpointRegistry(domainURI, null);
        return new NodeImpl(deployer, compositeActivator, domainRegistry, extensionPointRegistry, null);
    }
    
    /*
     * Create a node from a file system directory. 
     * If the directory is actually a file use createNodeFromXML
     * if the directory contains a file named node.xml then use createNodeFromXML
     * Otherwise, the directory can contain:
     *  domain.properties 
     *  contributions - jar, zip, or exploded directories
     *  sca-contribution.xml metaData files to override whats in a contribution
     *  .composite files to add to contributions as additional deployables
     * 
     * TODO: Review if this is useful?
     */
    public Node createNode(File directory) throws ContributionReadException, ValidationException, ActivationException, XMLStreamException, IOException {
        
        if (!directory.isDirectory()) {
            return createNodeFromXML(directory.toURI().toURL().toString());
        }
        
        File nodeXML = new File(directory, "node.xml");
        if (nodeXML.exists()) {
            return createNodeFromXML(nodeXML.toURI().toURL().toString());
        }
        
        Properties domainProps = new Properties();
        File propsFile = new File(directory, "domain.properties");
        if (propsFile.exists()) {
            domainProps.load(new FileInputStream(propsFile));
        }
        String domainName = domainProps.getProperty("domainName", directory.getName());
        String domainURI = domainProps.getProperty("domainURI", domainName);

        DomainRegistry domainRegistry = domainRegistryFactory.getEndpointRegistry(domainURI, domainName);
        Node node = new NodeImpl(deployer, compositeActivator, domainRegistry, extensionPointRegistry, null);

        List installed = new ArrayList();
        for (File f : directory.listFiles()) {
            if (f.getName().endsWith(".jar") || f.getName().endsWith(".zip") || (f.isDirectory() && !f.getName().startsWith("."))) {
                String fn = f.getName().lastIndexOf('.') == -1 ? f.getName() : f.getName().substring(0, f.getName().lastIndexOf('.'));
                // ignore the contribution if it has an associated exploded folder version
                if (!f.isDirectory() && new File(f.getParent(), fn).isDirectory()) {
                    continue;
                }
                String metaData = null;
                for (File f2 : directory.listFiles()) {
                    if (f2.getName().startsWith(fn) && f2.getName().endsWith(".xml")) {
                        metaData = f2.getPath();
                        break;
                    }
                }
                
                List dependencyURIs = new ArrayList();
                File dependencyFile = new File(directory, fn + ".dependencies");
                if (dependencyFile.exists()) {
                    BufferedReader br = new BufferedReader(new FileReader(dependencyFile));
                    String s;
                    while ((s = br.readLine()) != null)   {
                        if (!s.startsWith("#") && s.trim().length() > 0) {
                            dependencyURIs.addAll(Arrays.asList(s.trim().split("[ ,]+")));
                        }
                    }
                    br.close();
                }

                String curi = node.installContribution(null, f.getPath(), metaData, dependencyURIs);
                installed.add(curi);

                for (File f2 : directory.listFiles()) {
                    if (f2.getName().startsWith(fn) && f2.getName().endsWith(".composite")) {
                        node.addDeploymentComposite(curi, new FileReader(f2));
                    }
                }
            }
        }

        for (String curi : installed) {
            node.startDeployables(curi);
        }

        return node;
    }

    /* Node.xml hot update
     * - domain URi changed 
     *       - restart entire node
     * - List of contributions (matched on uri)
     *    - uninstall removed
     *    - install added
     *    - for each existing
     *        - if url or metadata or duris changed - update
     *        - if startdeployables changed
     *           - if now false then stop all started
     *           - if now true then start deployables
     *        
     *        
     *        
     */       
    
    /**
     * Creates a Node from an XML configuration file
     * @param configURL  the URL to the XML configuration file
     * @return Node  the configured Node
     */
    public Node createNodeFromXML(String configURL) throws ContributionReadException, ActivationException, ValidationException {
        NodeConfiguration configuration = loadConfiguration(configURL);
        NodeImpl node = (NodeImpl)createNode(configuration.getDomainURI());
        for ( ContributionConfiguration c : configuration.getContributions()) {
            String curi = node.installContribution(c.getURI(), c.getLocation(), c.getMetaDataURL(), c.getDependentContributionURIs());
            if (c.isStartDeployables()) {
                for (String compURI : node.getDeployableCompositeURIs(curi)) {
                    node.startComposite(curi, compURI);
                }
            }
        }
        return node;
    }

    /**
     * Stop the TuscanyRuntime
     */
    public void stop() {
        extensionPointRegistry.stop();
    }

    protected void init(Properties config) {
        if (config == null) {
            config = new Properties();
        }
        this.extensionPointRegistry = new DefaultExtensionPointRegistry();
        extensionPointRegistry.start();

        FactoryExtensionPoint modelFactories = extensionPointRegistry.getExtensionPoint(FactoryExtensionPoint.class);
        this.assemblyFactory = new RuntimeAssemblyFactory(extensionPointRegistry);
        modelFactories.addFactory(assemblyFactory);

        UtilityExtensionPoint utilities = extensionPointRegistry.getExtensionPoint(UtilityExtensionPoint.class);
        this.compositeActivator = utilities.getUtility(CompositeActivator.class);
        this.deployer = utilities.getUtility(Deployer.class);
        utilities.getUtility(RuntimeProperties.class).setProperties(config);
        utilities.getUtility(WorkScheduler.class);

        // Initialize the Tuscany module activators
        // The module activators will be started
        extensionPointRegistry.getExtensionPoint(ModuleActivatorExtensionPoint.class);

        this.domainRegistryFactory = ExtensibleDomainRegistryFactory.getInstance(extensionPointRegistry);

    }
    
    /**
     * Get the ExtensionPointRegistry used by this runtime
     * @return extensionPointRegistry
     */
    public ExtensionPointRegistry getExtensionPointRegistry() {
        return extensionPointRegistry;
    }
    
    /**
     * Get the Deployer. The Deployer can be used to create contribution artifacts 
     * when configuring a Node programatically.
     * @return the Deployer
     */
    public Deployer getDeployer() {
        return deployer;
    }
    
    /**
     * Get the AssemblyFactory. The AssemblyFactory can be used to create contribution
     * artifact contents when configuring a Node programatically.
     * @return the AssemblyFactory
     */
    public AssemblyFactory getAssemblyFactory() {
        return assemblyFactory;
    }

    protected NodeConfiguration loadConfiguration(String configURL) {
        InputStream xml =null;
        try {
            URL base = IOHelper.getLocationAsURL(configURL);
            xml = IOHelper.openStream(base);
            InputStreamReader reader = new InputStreamReader(xml, "UTF-8");
            ProcessorContext context = deployer.createProcessorContext();
            NodeConfiguration config = deployer.loadXMLDocument(reader, context.getMonitor());
            if (base != null && config != null) {
                // Resolve the contribution location against the node.xml
                // TODO: absolute locations?
                for (ContributionConfiguration c : config.getContributions()) {
                    String location = c.getLocation();
                    if (location != null) {
                        URL url = new URL(base, location);
                        url = IOHelper.normalize(url);
                        c.setLocation(url.toString());
                    }
                }
            }
            return config;
        } catch (Throwable e) {
            throw new ServiceRuntimeException(e);
        } finally {
            try {
                if (xml != null) xml.close();
            } catch (IOException e) {
                throw new ServiceRuntimeException(e);
            }
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy