/* * 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.domain.impl; import java.net.URI; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import javax.xml.namespace.QName; import org.apache.tuscany.sca.assembly.AssemblyFactory; import org.apache.tuscany.sca.assembly.Component; import org.apache.tuscany.sca.assembly.ComponentService; import org.apache.tuscany.sca.assembly.Composite; import org.apache.tuscany.sca.assembly.CompositeService; import org.apache.tuscany.sca.assembly.SCABinding; import org.apache.tuscany.sca.assembly.SCABindingFactory; import org.apache.tuscany.sca.assembly.xml.Constants; import org.apache.tuscany.sca.contribution.Contribution; import org.apache.tuscany.sca.contribution.DeployedArtifact; import org.apache.tuscany.sca.contribution.ModelFactoryExtensionPoint; import org.apache.tuscany.sca.contribution.service.ContributionService; import org.apache.tuscany.sca.core.assembly.ActivationException; import org.apache.tuscany.sca.core.context.ServiceReferenceImpl; import org.apache.tuscany.sca.domain.DomainException; import org.apache.tuscany.sca.domain.DomainManagerInitService; import org.apache.tuscany.sca.domain.SCADomainSPI; import org.apache.tuscany.sca.domain.model.Domain; import org.apache.tuscany.sca.domain.model.DomainModelFactory; import org.apache.tuscany.sca.domain.model.Node; import org.apache.tuscany.sca.domain.model.Service; import org.apache.tuscany.sca.domain.model.impl.DomainModelFactoryImpl; import org.apache.tuscany.sca.host.embedded.impl.ReallySmallRuntime; import org.apache.tuscany.sca.interfacedef.InterfaceContract; import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceFactory; import org.apache.tuscany.sca.node.NodeManagerService; import org.apache.tuscany.sca.node.NodeFactoryImpl; import org.apache.tuscany.sca.runtime.RuntimeComponent; import org.apache.tuscany.sca.runtime.RuntimeComponentContext; import org.apache.tuscany.sca.runtime.RuntimeComponentReference; import org.osoa.sca.CallableReference; import org.osoa.sca.ServiceReference; import org.osoa.sca.ServiceRuntimeException; /** * The SCA domain implementation. In Tuscany we currently have a model of the * SCA Domain that relies on a central domain manager this class provides that * central manager. * * @version $Rev: 552343 $ $Date: 2007-09-09 23:54:46 +0100 (Sun, 09 Sep 2007) $ */ public class SCADomainImpl implements SCADomainSPI { private final static Logger logger = Logger.getLogger(SCADomainImpl.class.getName()); // class loader used to get the runtime going private ClassLoader domainClassLoader; // management runtime private ReallySmallRuntime domainManagementRuntime; private ContributionService domainManagementContributionService; private Composite domainManagementComposite; private DomainManagerNodeImpl domainManagerNode; // management services private DomainManagerInitService domainManagerInitService; // The domain model private DomainModelFactory domainModelFactory = new DomainModelFactoryImpl(); private Domain domainModel; private HashMap contributions = new HashMap(); /** * Create a domain giving the URI for the domain. * * @param domainUri - identifies what host and port the domain service is running on, e.g. http://localhost:8081 * @throws ActivationException */ public SCADomainImpl(String domainURI) throws DomainException { this.domainModel = domainModelFactory.createDomain(); this.domainModel.setDomainURI(domainURI); this.domainClassLoader = SCADomainImpl.class.getClassLoader(); init(); } /** * Create the domain management runtime etc */ private void init() throws DomainException { try { // check whether domain uri is a url URI tmpURI; try { tmpURI = new URI(domainModel.getDomainURI()); if (tmpURI.isAbsolute()){ domainModel.setDomainURL(tmpURI.toURL().toExternalForm()); } } catch(Exception ex) { throw new ActivationException("domain uri " + domainModel.getDomainURI() + "must be a valid url"); } // create a runtime for the domain management services to run on domainManagementRuntime = new ReallySmallRuntime(domainClassLoader); domainManagementRuntime.start(); // Create an in-memory domain level management composite AssemblyFactory assemblyFactory = domainManagementRuntime.getAssemblyFactory(); domainManagementComposite = assemblyFactory.createComposite(); domainManagementComposite.setName(new QName(Constants.SCA10_NS, "domainManagement")); domainManagementComposite.setURI(domainModel.getDomainURI() + "/Management"); // Set up the domain so that we can push in the node endpoint before we // call a node domainManagerNode = new DomainManagerNodeImpl(this); ModelFactoryExtensionPoint factories = domainManagementRuntime.getExtensionPointRegistry().getExtensionPoint(ModelFactoryExtensionPoint.class); NodeFactoryImpl domainFactory = new NodeFactoryImpl(domainManagerNode); factories.addFactory(domainFactory); // Find the composite that will configure the domain String domainCompositeName = "domain.composite"; URL contributionURL = SCADomainUtil.findContributionFromComposite(domainClassLoader, domainCompositeName); if ( contributionURL != null ){ logger.log(Level.INFO, "Domain management configured from " + contributionURL); // add node composite to the management domain domainManagementContributionService = domainManagementRuntime.getContributionService(); Contribution contribution = null; contribution = domainManagementContributionService.contribute(domainModel.getDomainURI(), contributionURL, false); Composite composite = null; for (DeployedArtifact artifact: contribution.getArtifacts()) { if (domainCompositeName.equals(artifact.getURI())) { composite = (Composite)artifact.getModel(); } } if (composite != null) { domainManagementComposite.getIncludes().add(composite); domainManagementRuntime.getCompositeBuilder().build(composite); // TODO fix up the domain manager URI to match the provided // domain uri domainManagementRuntime.getCompositeActivator().activate(composite); domainManagementRuntime.getCompositeActivator().start(composite); // get the management components out of the domain so that they // can be configured/used. domainManagerInitService = getService(DomainManagerInitService.class, "DomainManagerComponent/DomainManagerInitService", domainManagementRuntime, domainManagementComposite); domainManagerInitService.setDomain((SCADomainSPI)this); } else { throw new ActivationException("Domain management contribution " + contributionURL + " found but could not be loaded"); } } else { throw new ActivationException("Domain management contribution " + domainCompositeName + " not found on the classpath"); } } catch(Exception ex) { throw new DomainException(ex); } } public Component getComponent(String componentName) { for (Composite composite: domainManagementComposite.getIncludes()) { for (Component component: composite.getComponents()) { if (component.getName().equals(componentName)) { return component; } } } return null; } // SCADomain SPI methods public Domain getDomainModel(){ return domainModel; } public String addNode(String nodeURI, String nodeURL){ // try and remove it first just in case it's already registered removeNode(nodeURI); Node node = domainModelFactory.createNode(); node.setNodeURI(nodeURI); node.setNodeURL(nodeURL); domainModel.getNodes().put(nodeURI, node); logger.log(Level.INFO, "Registered node: " + nodeURI + " at endpoint " + nodeURL); return "DummyReturn"; } public String removeNode(String nodeURI){ domainModel.getNodes().remove(nodeURI); logger.log(Level.INFO, "Removed node: " + nodeURI); return "DummyReturn"; } public void registerContribution(String nodeURI, String contributionURI, String contributionURL){ try { if ( domainModel.getContributions().containsKey(contributionURI) == false ){ // add the contribution information to the domain model org.apache.tuscany.sca.domain.model.Contribution contributionModel = parseContribution(contributionURI, contributionURL); } // assign the contribution to the referenced node } catch (Exception ex) { logger.log(Level.SEVERE, "Exception when registering contribution " + contributionURI + ex.toString() ); } } public void unregisterContribution(String contributionURI){ // TODO } public String registerServiceEndpoint(String domainURI, String nodeURI, String serviceName, String bindingName, String URL){ // if the service name ends in a "/" remove it String modifiedServiceName = null; if ( serviceName.endsWith("/") ) { modifiedServiceName = serviceName.substring(0, serviceName.length() - 1); } else { modifiedServiceName = serviceName; } // collect the service info Service service = domainModelFactory.createService(); service.setServiceURI(modifiedServiceName); service.setServiceURL(URL); service.setServiceBinding(bindingName); // find the node Node node = domainModel.getNodes().get(nodeURI); if (node != null){ //store the service node.getServices().put(serviceName+bindingName, service); logger.log(Level.INFO, "Registered service: " + modifiedServiceName); } else { logger.log(Level.WARNING, "Trying to register service: " + modifiedServiceName + " for a node " + nodeURI + "that isn't registered"); } return ""; } public String removeServiceEndpoint(String domainUri, String nodeURI, String serviceName, String bindingName){ Node node = domainModel.getNodes().get(nodeURI); node.getServices().remove(serviceName + bindingName); logger.log(Level.INFO, "Removed service: " + serviceName ); return ""; } public String findServiceEndpoint(String domainUri, String serviceName, String bindingName){ logger.log(Level.INFO, "Finding service: [" + domainUri + " " + serviceName + " " + bindingName + "]"); String url = ""; String serviceKey = serviceName + bindingName; for (Node node : domainModel.getNodes().values()){ Service service = node.getServices().get(serviceKey); if (service != null){ url = service.getServiceURL(); //url = replacePort(url, "8085", "8086"); logger.log(Level.INFO, "Found service url: " + url); break; } } return url; } /** * Converts a port number to something else to allow for debugging using a * HTTP sniffer * @param url * @param fromPort the port to look for * @param toPort the port to replace it with * @return the new url */ private String replacePort(String url, String fromPort, String toPort) { return url.replace(fromPort, toPort); } // SCADomain API methods public void start() throws DomainException { // TODO } public void stop() throws DomainException { try { // Stop the node domainManagementRuntime.stop(); } catch(ActivationException ex) { throw new DomainException(ex); } } public String getURI(){ return domainModel.getDomainURI(); } private org.apache.tuscany.sca.domain.model.Contribution parseContribution(String contributionURI, String contributionURL) throws DomainException { // add the contribution information to the domain model org.apache.tuscany.sca.domain.model.Contribution contributionModel = domainModelFactory.createContribution(); contributionModel.setContributionURI(contributionURI); contributionModel.setContributionURL(contributionURL); domainModel.getContributions().put(contributionURI, contributionModel); // read the assembly model objects. try { // Create a local model from the contribution. Using the contribution // processor from the domain management runtime just because we already have it Contribution contribution = domainManagementContributionService.contribute(contributionURI, new URL(contributionURL), false); // store the contribution contributions.put(contributionURI, contribution); // add the composite info to the domain model for (DeployedArtifact artifact : contribution.getArtifacts()) { if (artifact.getModel() instanceof Composite) { Composite composite = (Composite)artifact.getModel(); org.apache.tuscany.sca.domain.model.Composite compositeModel = domainModelFactory.createComposite(); compositeModel.setCompositeQName(composite.getName()); contributionModel.getComposites().put(compositeModel.getCompositeQName(), compositeModel); } } // add all composites into the domain model for (Composite composite : contribution.getDeployables()) { org.apache.tuscany.sca.domain.model.Composite compositeModel = domainModelFactory.createComposite(); compositeModel.setCompositeQName(composite.getName()); contributionModel.getComposites().put(compositeModel.getCompositeQName(), compositeModel); } // add the deployable composite info to the domain model for (Composite composite : contribution.getDeployables()) { org.apache.tuscany.sca.domain.model.Composite compositeModel = contributionModel.getComposites().get(composite.getName()); contributionModel.getDeployableComposites().put(compositeModel.getCompositeQName(), compositeModel); domainModel.getDeployedComposites().put(compositeModel.getCompositeQName(), compositeModel); } } catch(Exception ex) { throw new DomainException(ex); } return contributionModel; } private void assignContributionToNode(org.apache.tuscany.sca.domain.model.Contribution contributionModel) throws DomainException { // Find a node to run the contribution. // TODO - add some more sophisticated algorithm here // find a node without a contribution and add it to it. There is no deployment // step here we just assume the contribution is available. boolean foundFreeNode = false; for(Node node : domainModel.getNodes().values()) { if ( node.getContributions().isEmpty()){ foundFreeNode = true; node.getContributions().put(contributionModel.getContributionURI(), contributionModel); break; } } if (foundFreeNode == false){ throw new DomainException("No free node available for contribution " + contributionModel.getContributionURI()); } } public void addContribution(String contributionURI, URL contributionURL) throws DomainException { // add the contribution information to the domain model org.apache.tuscany.sca.domain.model.Contribution contributionModel = parseContribution(contributionURI, contributionURL.toExternalForm()); assignContributionToNode(contributionModel); } public void removeContribution(String uri) throws DomainException { // TODO } public void addDeploymentComposite(String contributionURI, String compositeXML) throws DomainException { // TODO } public void addToDomainLevelComposite(QName compositeName) throws DomainException { // find the nodes with this composite and add the composite as a deployable composite for ( Node node : domainModel.getNodes().values()) { for (org.apache.tuscany.sca.domain.model.Contribution contribution : node.getContributions().values()){ org.apache.tuscany.sca.domain.model.Composite composite = contribution.getComposites().get(compositeName); if (composite != null) { contribution.getDeployableComposites().put(compositeName, composite); domainModel.getDeployedComposites().put(compositeName, composite); } } } } public void removeFromDomainLevelComposite(QName qname) throws DomainException { // TODO } public void startComposite(QName compositeName) throws DomainException { for (Node node : domainModel.getNodes().values()){ boolean startNode = false; for (org.apache.tuscany.sca.domain.model.Contribution contribution : node.getContributions().values()){ org.apache.tuscany.sca.domain.model.Composite composite = contribution.getDeployableComposites().get(compositeName); if (composite != null) { startNode = true; break; } } if (startNode == true){ // get the endpoint of the node in question and set it into the // domain manager node in order to flip the node reference to // the correct endpoint String nodeURL = node.getNodeURL(); domainManagerNode.setNodeEndpoint(nodeURL); // get a node manager service reference. This will have to have its // physical endpoint set by the domain node manage we have just // configured NodeManagerService nodeManagerService = getService(NodeManagerService.class, "NodeManagerComponent/NodeManagerService", domainManagementRuntime, domainManagementComposite); // add contributions for (org.apache.tuscany.sca.domain.model.Contribution contribution : node.getContributions().values()){ nodeManagerService.addContribution(contribution.getContributionURI(), contribution.getContributionURL().toString()); } // deploy composite nodeManagerService.deployComposite(compositeName.toString()); // start node nodeManagerService.start(); // TODO // somewhere we need to add the deployed composites into the node model // reset the endpoint setting function domainManagerNode.setNodeEndpoint(null); } } } public void stopComposite(QName qname) throws DomainException { // TODO } public > R cast(B target) throws IllegalArgumentException { return (R)cast(target, domainManagementRuntime); } private > R cast(B target, ReallySmallRuntime runtime) throws IllegalArgumentException { return (R)runtime.getProxyFactory().cast(target); } public B getService(Class businessInterface, String serviceName) { return getService( businessInterface, serviceName, domainManagementRuntime, null); } private B getService(Class businessInterface, String serviceName, ReallySmallRuntime runtime, Composite domainComposite) { ServiceReference serviceReference = getServiceReference(businessInterface, serviceName, runtime, domainComposite); if (serviceReference == null) { throw new ServiceRuntimeException("Service not found: " + serviceName); } return serviceReference.getService(); } private ServiceReference createServiceReference(Class businessInterface, String targetURI) { return createServiceReference(businessInterface, targetURI, domainManagementRuntime, null); } private ServiceReference createServiceReference(Class businessInterface, String targetURI, ReallySmallRuntime runtime, Composite domainComposite) { try { AssemblyFactory assemblyFactory = runtime.getAssemblyFactory(); Composite composite = assemblyFactory.createComposite(); composite.setName(new QName(Constants.SCA10_TUSCANY_NS, "default")); RuntimeComponent component = (RuntimeComponent)assemblyFactory.createComponent(); component.setName("default"); component.setURI("default"); runtime.getCompositeActivator().configureComponentContext(component); composite.getComponents().add(component); RuntimeComponentReference reference = (RuntimeComponentReference)assemblyFactory.createComponentReference(); reference.setName("default"); ModelFactoryExtensionPoint factories = runtime.getExtensionPointRegistry().getExtensionPoint(ModelFactoryExtensionPoint.class); JavaInterfaceFactory javaInterfaceFactory = factories.getFactory(JavaInterfaceFactory.class); InterfaceContract interfaceContract = javaInterfaceFactory.createJavaInterfaceContract(); interfaceContract.setInterface(javaInterfaceFactory.createJavaInterface(businessInterface)); reference.setInterfaceContract(interfaceContract); component.getReferences().add(reference); reference.setComponent(component); SCABindingFactory scaBindingFactory = factories.getFactory(SCABindingFactory.class); SCABinding binding = scaBindingFactory.createSCABinding(); binding.setURI(targetURI); reference.getBindings().add(binding); return new ServiceReferenceImpl(businessInterface, component, reference, binding, runtime .getProxyFactory(), runtime.getCompositeActivator()); } catch (Exception e) { throw new ServiceRuntimeException(e); } } public ServiceReference getServiceReference(Class businessInterface, String name) { return getServiceReference(businessInterface, name, domainManagementRuntime, null); } private ServiceReference getServiceReference(Class businessInterface, String name, ReallySmallRuntime runtime, Composite domainComposite) { // Extract the component name String componentName; String serviceName; int i = name.indexOf('/'); if (i != -1) { componentName = name.substring(0, i); serviceName = name.substring(i + 1); } else { componentName = name; serviceName = null; } // Lookup the component Component component = null; if ( domainComposite != null ) { for (Composite composite: domainComposite.getIncludes()) { for (Component compositeComponent: composite.getComponents()) { if (compositeComponent.getName().equals(componentName)) { component = compositeComponent; } } } } if (component == null) { // The component is not local in the partition, try to create a remote service ref return createServiceReference(businessInterface, name, runtime, domainComposite); } RuntimeComponentContext componentContext = null; // If the component is a composite, then we need to find the // non-composite component that provides the requested service if (component.getImplementation() instanceof Composite) { for (ComponentService componentService : component.getServices()) { if (serviceName == null || serviceName.equals(componentService.getName())) { CompositeService compositeService = (CompositeService)componentService.getService(); if (compositeService != null) { if (serviceName != null) { serviceName = "$promoted$." + serviceName; } componentContext = ((RuntimeComponent)compositeService.getPromotedComponent()).getComponentContext(); return componentContext.createSelfReference(businessInterface, compositeService .getPromotedService()); } break; } } // No matching service is found throw new ServiceRuntimeException("Composite service not found: " + name); } else { componentContext = ((RuntimeComponent)component).getComponentContext(); if (serviceName != null) { return componentContext.createSelfReference(businessInterface, serviceName); } else { return componentContext.createSelfReference(businessInterface); } } } }