summaryrefslogtreecommitdiffstats
path: root/sca-java-1.x/trunk/modules/domain-manager/src/main/java
diff options
context:
space:
mode:
Diffstat (limited to 'sca-java-1.x/trunk/modules/domain-manager/src/main/java')
-rw-r--r--sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/CompositeConfigurationCollectionImpl.java127
-rw-r--r--sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/CompositeConfigurationServiceImpl.java657
-rw-r--r--sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/CompositeGeneratorServiceImpl.java255
-rw-r--r--sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/ContributionCollectionImpl.java705
-rw-r--r--sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/ContributionServiceImpl.java77
-rw-r--r--sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/ContributionsReader.java9
-rw-r--r--sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/DeployableCompositeCollectionImpl.java481
-rw-r--r--sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/DeployableCompositeServiceImpl.java128
-rw-r--r--sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/DeployedCompositeCollectionImpl.java417
-rw-r--r--sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/DomainManagerConfiguration.java53
-rw-r--r--sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/DomainManagerConfigurationImpl.java85
-rw-r--r--sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/DomainManagerUtil.java295
-rw-r--r--sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/FileCollectionImpl.java136
-rw-r--r--sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/FileServiceImpl.java210
-rw-r--r--sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/NodeConfigurationServiceImpl.java96
-rw-r--r--sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/NodeProcessCollectionFacadeImpl.java251
-rw-r--r--sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/QuickStartServiceImpl.java242
-rw-r--r--sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/Searcher.java461
-rw-r--r--sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/launcher/DomainManagerLauncherBootstrap.java95
19 files changed, 4780 insertions, 0 deletions
diff --git a/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/CompositeConfigurationCollectionImpl.java b/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/CompositeConfigurationCollectionImpl.java
new file mode 100644
index 0000000000..0e25068f5f
--- /dev/null
+++ b/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/CompositeConfigurationCollectionImpl.java
@@ -0,0 +1,127 @@
+/*
+ * 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.manager.impl;
+
+import static org.apache.tuscany.sca.domain.manager.impl.DomainManagerUtil.compositeQName;
+import static org.apache.tuscany.sca.domain.manager.impl.DomainManagerUtil.compositeTitle;
+import static org.apache.tuscany.sca.domain.manager.impl.DomainManagerUtil.contributionURI;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Logger;
+
+import javax.xml.namespace.QName;
+
+import org.apache.tuscany.sca.data.collection.Entry;
+import org.apache.tuscany.sca.data.collection.Item;
+import org.apache.tuscany.sca.data.collection.ItemCollection;
+import org.apache.tuscany.sca.data.collection.LocalItemCollection;
+import org.apache.tuscany.sca.data.collection.NotFoundException;
+import org.osoa.sca.annotations.Init;
+import org.osoa.sca.annotations.Reference;
+import org.osoa.sca.annotations.Scope;
+import org.osoa.sca.annotations.Service;
+
+/**
+ * Implementation of a component that returns composite configuration collections.
+ *
+ * @version $Rev$ $Date$
+ */
+@Scope("COMPOSITE")
+@Service(interfaces={ItemCollection.class, LocalItemCollection.class})
+public class CompositeConfigurationCollectionImpl implements ItemCollection, LocalItemCollection {
+
+ private static final Logger logger = Logger.getLogger(CompositeConfigurationCollectionImpl.class.getName());
+
+ @Reference
+ public LocalItemCollection contributionCollection;
+
+ @Reference
+ public LocalItemCollection cloudCollection;
+
+ /**
+ * Initialize the component.
+ */
+ @Init
+ public void initialize() {
+ }
+
+ public Entry<String, Item>[] getAll() {
+ throw new UnsupportedOperationException();
+ }
+
+ public Item get(String key) throws NotFoundException {
+ throw new UnsupportedOperationException();
+ }
+
+ public String post(String key, Item item) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void put(String key, Item item) throws NotFoundException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void delete(String key) throws NotFoundException {
+ throw new UnsupportedOperationException();
+ }
+
+ public Entry<String, Item>[] query(String queryString) {
+ logger.fine("query " + queryString);
+
+ if (queryString.startsWith("composite=")) {
+
+ // Expecting a key in the form:
+ // composite:contributionURI;namespace;localName
+ int e = queryString.indexOf('=');
+ String key = queryString.substring(e + 1);
+ String contributionURI = contributionURI(key);
+ QName qname = compositeQName(key);
+
+ // Return a collection containing the following entries:
+ // the resolved version of the specified composite
+ // the required contributions
+ List<Entry<String, Item>> entries = new ArrayList<Entry<String, Item>>();
+
+ // Add the resolved composite entry
+ Entry<String, Item> compositeEntry = new Entry<String, Item>();
+ Item compositeItem = new Item();
+ compositeItem.setTitle(compositeTitle(contributionURI, qname));
+ compositeItem.setLink("/composite-resolved/" + key);
+ compositeEntry.setKey(key);
+ compositeEntry.setData(compositeItem);
+ entries.add(compositeEntry);
+
+ // Get the collection of required contributions
+ Entry<String, Item>[] contributionEntries = contributionCollection.query("alldependencies=" + contributionURI);
+ for (Entry<String, Item> entry: contributionEntries) {
+ Item item = entry.getData();
+ item.setContents(null);
+ entries.add(entry);
+ }
+
+ return entries.toArray(new Entry[entries.size()]);
+
+ } else {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+}
diff --git a/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/CompositeConfigurationServiceImpl.java b/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/CompositeConfigurationServiceImpl.java
new file mode 100644
index 0000000000..4178a2e8a0
--- /dev/null
+++ b/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/CompositeConfigurationServiceImpl.java
@@ -0,0 +1,657 @@
+/*
+ * 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.manager.impl;
+
+import static org.apache.tuscany.sca.domain.manager.impl.DomainManagerUtil.compositeQName;
+import static org.apache.tuscany.sca.domain.manager.impl.DomainManagerUtil.contributionURI;
+import static org.apache.tuscany.sca.domain.manager.impl.DomainManagerUtil.locationURL;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Logger;
+
+import javax.servlet.Servlet;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.xml.namespace.QName;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamWriter;
+import javax.xml.transform.TransformerFactory;
+
+import org.apache.tuscany.sca.assembly.AssemblyFactory;
+import org.apache.tuscany.sca.assembly.Binding;
+import org.apache.tuscany.sca.assembly.Component;
+import org.apache.tuscany.sca.assembly.Composite;
+import org.apache.tuscany.sca.assembly.SCABindingFactory;
+import org.apache.tuscany.sca.assembly.builder.CompositeBuilder;
+import org.apache.tuscany.sca.assembly.builder.CompositeBuilderException;
+import org.apache.tuscany.sca.assembly.builder.impl.CompositeBuilderImpl;
+import org.apache.tuscany.sca.assembly.builder.impl.CompositeIncludeBuilderImpl;
+import org.apache.tuscany.sca.assembly.xml.CompositeDocumentProcessor;
+import org.apache.tuscany.sca.assembly.xml.Constants;
+import org.apache.tuscany.sca.contribution.Artifact;
+import org.apache.tuscany.sca.contribution.Contribution;
+import org.apache.tuscany.sca.contribution.ModelFactoryExtensionPoint;
+import org.apache.tuscany.sca.contribution.processor.ExtensibleStAXArtifactProcessor;
+import org.apache.tuscany.sca.contribution.processor.ExtensibleURLArtifactProcessor;
+import org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor;
+import org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessorExtensionPoint;
+import org.apache.tuscany.sca.contribution.processor.URLArtifactProcessor;
+import org.apache.tuscany.sca.contribution.processor.URLArtifactProcessorExtensionPoint;
+import org.apache.tuscany.sca.contribution.processor.ValidatingXMLInputFactory;
+import org.apache.tuscany.sca.contribution.resolver.DefaultModelResolver;
+import org.apache.tuscany.sca.contribution.resolver.ExtensibleModelResolver;
+import org.apache.tuscany.sca.contribution.resolver.ModelResolver;
+import org.apache.tuscany.sca.contribution.resolver.ModelResolverExtensionPoint;
+import org.apache.tuscany.sca.contribution.service.ContributionReadException;
+import org.apache.tuscany.sca.contribution.service.ContributionResolveException;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.core.UtilityExtensionPoint;
+import org.apache.tuscany.sca.data.collection.Entry;
+import org.apache.tuscany.sca.data.collection.Item;
+import org.apache.tuscany.sca.data.collection.LocalItemCollection;
+import org.apache.tuscany.sca.data.collection.NotFoundException;
+import org.apache.tuscany.sca.definitions.SCADefinitions;
+import org.apache.tuscany.sca.definitions.impl.SCADefinitionsImpl;
+import org.apache.tuscany.sca.definitions.util.SCADefinitionsUtil;
+import org.apache.tuscany.sca.implementation.node.NodeImplementation;
+import org.apache.tuscany.sca.implementation.node.builder.impl.NodeCompositeBuilderImpl;
+import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper;
+import org.apache.tuscany.sca.monitor.Monitor;
+import org.apache.tuscany.sca.monitor.MonitorFactory;
+import org.apache.tuscany.sca.monitor.MonitorRuntimeException;
+import org.apache.tuscany.sca.monitor.Problem;
+import org.apache.tuscany.sca.monitor.Problem.Severity;
+import org.apache.tuscany.sca.policy.Intent;
+import org.apache.tuscany.sca.policy.IntentAttachPointType;
+import org.apache.tuscany.sca.policy.IntentAttachPointTypeFactory;
+import org.apache.tuscany.sca.policy.PolicySet;
+import org.apache.tuscany.sca.provider.SCADefinitionsProvider;
+import org.apache.tuscany.sca.provider.SCADefinitionsProviderExtensionPoint;
+import org.apache.tuscany.sca.workspace.Workspace;
+import org.apache.tuscany.sca.workspace.WorkspaceFactory;
+import org.apache.tuscany.sca.workspace.builder.ContributionDependencyBuilder;
+import org.apache.tuscany.sca.workspace.builder.impl.ContributionDependencyBuilderImpl;
+import org.apache.tuscany.sca.workspace.processor.impl.ContributionContentProcessor;
+import org.osoa.sca.ServiceRuntimeException;
+import org.osoa.sca.annotations.Init;
+import org.osoa.sca.annotations.Reference;
+import org.osoa.sca.annotations.Scope;
+import org.osoa.sca.annotations.Service;
+
+/**
+ * Implementation of a service that returns a fully configured composite.
+ *
+ * @version $Rev$ $Date$
+ */
+@Scope("COMPOSITE")
+@Service(Servlet.class)
+public class CompositeConfigurationServiceImpl extends HttpServlet implements Servlet {
+ private static final long serialVersionUID = -8809641932774129152L;
+
+ private static final Logger logger = Logger.getLogger(CompositeConfigurationServiceImpl.class.getName());
+
+ @Reference
+ public LocalItemCollection contributionCollection;
+
+ @Reference
+ public LocalItemCollection domainCompositeCollection;
+
+ @Reference
+ public DomainManagerConfiguration domainManagerConfiguration;
+
+ @Reference
+ public LocalItemCollection cloudCollection;
+
+ private ExtensionPointRegistry extensionPoints;
+ private ModelFactoryExtensionPoint modelFactories;
+ private ModelResolverExtensionPoint modelResolvers;
+ private AssemblyFactory assemblyFactory;
+ private WorkspaceFactory workspaceFactory;
+ private URLArtifactProcessor<Contribution> contributionProcessor;
+ private StAXArtifactProcessorExtensionPoint staxProcessors;
+ private StAXArtifactProcessor<Composite> compositeProcessor;
+ private XMLOutputFactory outputFactory;
+ private ContributionDependencyBuilder contributionDependencyBuilder;
+ private CompositeBuilder compositeIncludeBuilder;
+ private CompositeBuilder nodeConfigurationBuilder;
+ private Monitor monitor;
+ private List<SCADefinitions> policyDefinitions;
+ private ModelResolver policyDefinitionsResolver;
+ private SCABindingFactory scaBindingFactory;
+ private IntentAttachPointTypeFactory intentAttachPointTypeFactory;
+ private DocumentBuilderFactory documentBuilderFactory;
+ private TransformerFactory transformerFactory;
+ private InterfaceContractMapper contractMapper;
+ private Map<Binding, Binding> bindingMap;
+
+ /**
+ * Initialize the component.
+ */
+ @Init
+ public void initialize() throws ParserConfigurationException {
+
+ extensionPoints = domainManagerConfiguration.getExtensionPoints();
+
+ // Create a monitor
+ UtilityExtensionPoint utilities = extensionPoints.getExtensionPoint(UtilityExtensionPoint.class);
+ MonitorFactory monitorFactory = utilities.getUtility(MonitorFactory.class);
+ monitor = monitorFactory.createMonitor();
+
+ // Get model factories
+ modelFactories = extensionPoints.getExtensionPoint(ModelFactoryExtensionPoint.class);
+ assemblyFactory = modelFactories.getFactory(AssemblyFactory.class);
+ XMLInputFactory inputFactory = modelFactories.getFactory(XMLInputFactory.class);
+ outputFactory = modelFactories.getFactory(XMLOutputFactory.class);
+ outputFactory.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true);
+ workspaceFactory = modelFactories.getFactory(WorkspaceFactory.class);
+
+ // Get and initialize artifact processors
+ staxProcessors = extensionPoints.getExtensionPoint(StAXArtifactProcessorExtensionPoint.class);
+ compositeProcessor = (StAXArtifactProcessor<Composite>)staxProcessors.getProcessor(Composite.class);
+ StAXArtifactProcessor<Object> staxProcessor = new ExtensibleStAXArtifactProcessor(staxProcessors, inputFactory, outputFactory, monitor);
+
+ URLArtifactProcessorExtensionPoint urlProcessors = extensionPoints.getExtensionPoint(URLArtifactProcessorExtensionPoint.class);
+ URLArtifactProcessor<Object> urlProcessor = new ExtensibleURLArtifactProcessor(urlProcessors, monitor);
+ policyDefinitionsResolver = new DefaultModelResolver();
+ policyDefinitions = new ArrayList<SCADefinitions>();
+
+ // The following was copied from RuntimeBuilder to fix TUSCANY-3171
+ XMLInputFactory validatingInputFactory = modelFactories.getFactory(ValidatingXMLInputFactory.class);
+ documentBuilderFactory = modelFactories.getFactory(DocumentBuilderFactory.class);
+ //documentBuilderFactory.setNamespaceAware(true);
+ urlProcessors.getProcessor(Composite.class);
+ urlProcessors.addArtifactProcessor(new CompositeDocumentProcessor(staxProcessor, validatingInputFactory,
+ documentBuilderFactory, policyDefinitions, monitor));
+
+ // Create contribution processor
+ modelResolvers = extensionPoints.getExtensionPoint(ModelResolverExtensionPoint.class);
+ contributionProcessor = new ContributionContentProcessor(extensionPoints, monitor, policyDefinitionsResolver, policyDefinitions);
+
+ // Create contribution and composite builders
+ transformerFactory = modelFactories.getFactory(TransformerFactory.class);
+ contributionDependencyBuilder = new ContributionDependencyBuilderImpl(monitor);
+ scaBindingFactory = modelFactories.getFactory(SCABindingFactory.class);
+ intentAttachPointTypeFactory = modelFactories.getFactory(IntentAttachPointTypeFactory.class);
+ contractMapper = utilities.getUtility(InterfaceContractMapper.class);
+ compositeIncludeBuilder = new CompositeIncludeBuilderImpl(monitor);
+ bindingMap = new HashMap<Binding, Binding>();
+ nodeConfigurationBuilder = new NodeCompositeBuilderImpl(assemblyFactory, scaBindingFactory, documentBuilderFactory,
+ transformerFactory, contractMapper, null, monitor, bindingMap);
+
+ // Load the definitions.xml
+ loadSCADefinitions(extensionPoints);
+ }
+
+ @Override
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+
+ // Get the request path
+ String path = URLDecoder.decode(request.getRequestURI().substring(request.getServletPath().length()), "UTF-8");
+ String key;
+ if (path.startsWith("/")) {
+ if (path.length() > 1) {
+ key = path.substring(1);
+ } else {
+ key ="";
+ }
+ } else {
+ key =path;
+ }
+ logger.fine("get " + key);
+
+ // Expect a key in the form composite:contributionURI;namespace;localName or
+ // a path in the form componentName/componentName/...
+ // and return the corresponding resolved composite
+ String requestedContributionURI = null;
+ QName requestedCompositeName = null;
+ String[] requestedComponentPath = null;
+ if (key.startsWith("composite:")) {
+
+ // Extract the composite qname from the key
+ requestedContributionURI = contributionURI(key);
+ requestedCompositeName = compositeQName(key);
+
+ } else if (key.length() != 0) {
+
+ // Extract the path to the requested component from the key
+ requestedComponentPath = key.split("/");
+ }
+
+ // Somewhere to store the composite we expect to write out at the end
+ Composite requestedComposite = null;
+
+ // Create a domain composite model
+ Composite domainComposite = assemblyFactory.createComposite();
+ domainComposite.setName(new QName(Constants.SCA10_TUSCANY_NS, "domain"));
+
+ // Get the domain composite items
+ Entry<String, Item>[] domainEntries = domainCompositeCollection.getAll();
+
+ // Populate the domain composite
+ Workspace workspace = workspaceFactory.createWorkspace();
+ workspace.setModelResolver(new ExtensibleModelResolver(workspace, extensionPoints));
+
+ Map<String, Contribution> contributionMap = new HashMap<String, Contribution>();
+ for (Entry<String, Item> domainEntry: domainEntries) {
+
+ // Load the required contributions
+ String contributionURI = contributionURI(domainEntry.getKey());
+ Contribution contribution = contributionMap.get(contributionURI);
+ if (contribution == null) {
+
+ // The contribution has not been loaded yet, load it with all its dependencies
+ Entry<String, Item>[] entries = contributionCollection.query("alldependencies=" + contributionURI);
+ for (Entry<String, Item> entry: entries) {
+ Item dependencyItem = entry.getData();
+ String dependencyURI = entry.getKey();
+
+ if (!contributionMap.containsKey(dependencyURI)) {
+
+ // Read the contribution
+ Contribution dependency;
+ try {
+ String dependencyLocation = dependencyItem.getAlternate();
+ dependency = contribution(workspace, dependencyURI, dependencyLocation);
+ } catch (Exception e) {
+ if (contributionURI.equals(dependencyURI)) {
+ response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, getDescription(e));
+ return;
+ } else {
+ continue;
+ }
+ }
+ workspace.getContributions().add(dependency);
+ contributionMap.put(dependencyURI, dependency);
+
+ if (contributionURI.equals(entry.getKey())) {
+ contribution = dependency;
+ }
+ }
+ }
+ }
+
+ if (contribution == null) {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND, contributionURI);
+ return;
+ }
+
+ // Find the specified deployable composite in the contribution
+ Composite deployable = null;
+ QName qn = compositeQName(domainEntry.getKey());
+ for (Composite d: contribution.getDeployables()) {
+ if (qn.equals(d.getName())) {
+ deployable = d;
+ break;
+ }
+ }
+ if (deployable == null) {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND, qn.toString());
+ return;
+ }
+
+ // add the deployable composite to the domain composite
+ domainComposite.getIncludes().add(deployable);
+
+ // Fuse includes into the deployable composite
+ try {
+ compositeIncludeBuilder.build(deployable);
+ analyzeProblems();
+ } catch (Exception e) {
+ response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, getDescription(e));
+ return;
+ }
+
+ // Store away the requested composite
+ if (requestedCompositeName != null) {
+ if (requestedContributionURI.equals(contributionURI) && requestedCompositeName.equals(deployable.getName())){
+ requestedComposite = deployable;
+ }
+ }
+ }
+
+ // The requested composite was not found
+ if (requestedCompositeName != null && requestedComposite == null) {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND, key);
+ return;
+ }
+
+ // Get the clouds composite
+ Composite cloudsComposite;
+ try {
+ cloudsComposite = cloud();
+ } catch (NotFoundException e) {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND, e.getMessage());
+ return;
+ }
+
+ // configure the endpoints for each composite in the domain
+ List<Composite> domainIncludes = domainComposite.getIncludes();
+ for (int i = 0, n =domainIncludes.size(); i < n; i++) {
+ Composite composite = domainIncludes.get(i);
+ QName compositeName = composite.getName();
+ String contributionURI = contributionURI(domainEntries[i].getKey());
+
+ // find the node that will run this composite and the default
+ // bindings that it configures
+ Component nodeComponent = null;
+ QName nodeCompositeName = null;
+ for (Composite cloudComposite : cloudsComposite.getIncludes()) {
+ for (Component nc : cloudComposite.getComponents()) {
+ NodeImplementation nodeImplementation = (NodeImplementation)nc.getImplementation();
+ if (nodeImplementation.getComposite().getName().equals(compositeName) &&
+ nodeImplementation.getComposite().getURI().equals(contributionURI)) {
+ nodeImplementation.setComposite(composite);
+ nodeComponent = nc;
+ nodeCompositeName = cloudComposite.getName();
+ break;
+ }
+ }
+ }
+
+ if (nodeComponent != null) {
+ try {
+ Composite nodeComposite = assemblyFactory.createComposite();
+ nodeComposite.setName(nodeCompositeName);
+ nodeComposite.getComponents().add(nodeComponent);
+ nodeConfigurationBuilder.build(nodeComposite);
+ } catch (CompositeBuilderException e) {
+ throw new ServletException(e);
+ }
+ }
+ }
+
+ // Build the domain composite
+ SCADefinitions aggregatedDefinitions = new SCADefinitionsImpl();
+ for (SCADefinitions definition : policyDefinitions) {
+ SCADefinitionsUtil.aggregateSCADefinitions(definition, aggregatedDefinitions);
+ }
+ CompositeBuilder compositeBuilder = new CompositeBuilderImpl(assemblyFactory, null, scaBindingFactory,
+ intentAttachPointTypeFactory, documentBuilderFactory, transformerFactory,
+ contractMapper, aggregatedDefinitions, monitor, bindingMap);
+ try {
+ compositeBuilder.build(domainComposite);
+ analyzeProblems();
+ } catch (Exception e) {
+ response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, getDescription(e));
+ return;
+ }
+
+ // Return the requested composite
+ if (requestedComposite != null) {
+
+ // Rebuild the requested composite from the domain composite
+ // we have to reverse the flattening that went on when the domain
+ // composite was built
+ List<Component> tempComponentList = new ArrayList<Component>();
+ tempComponentList.addAll(requestedComposite.getComponents());
+ requestedComposite.getComponents().clear();
+ for (Component inputComponent : tempComponentList){
+ for (Component deployComponent : domainComposite.getComponents()){
+ if (deployComponent.getName().equals(inputComponent.getName())){
+ requestedComposite.getComponents().add(deployComponent);
+ }
+ }
+ }
+
+ } else if (requestedComponentPath != null) {
+
+ // If a component path was specified, walk the path to get to the requested
+ // component and the composite that implements it
+ Composite nestedComposite = domainComposite;
+ for (String componentName: requestedComponentPath) {
+ Component component = null;
+ for (Component c: nestedComposite.getComponents()) {
+ if (componentName.equals(c.getName())) {
+ component = c;
+ break;
+ }
+ }
+ if (component == null) {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND, key);
+ return;
+ } else {
+ if (component.getImplementation() instanceof Composite) {
+ nestedComposite = (Composite)component.getImplementation();
+ } else {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND, key);
+ return;
+ }
+ }
+ }
+
+ // Return the nested composite
+ requestedComposite = nestedComposite;
+
+ } else {
+
+
+ // Return the whole domain composite
+ requestedComposite = domainComposite;
+ }
+
+ // Write the composite in the requested format
+ StAXArtifactProcessor<Composite> processor;
+ String queryString = request.getQueryString();
+ if (queryString != null && queryString.startsWith("format=")) {
+ String format = queryString.substring(7);
+ int s = format.indexOf(';');
+ QName formatName = new QName(format.substring(0, s), format.substring(s +1));
+ processor = (StAXArtifactProcessor<Composite>)staxProcessors.getProcessor(formatName);
+ if (processor == null) {
+ response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, new IllegalArgumentException(queryString).toString());
+ return;
+ }
+ } else {
+ processor = compositeProcessor;
+ }
+ try {
+ response.setContentType("text/xml");
+ XMLStreamWriter writer = outputFactory.createXMLStreamWriter(response.getOutputStream());
+ processor.write(requestedComposite, writer);
+ } catch (Exception e) {
+ response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.toString());
+ return;
+ }
+
+
+ }
+
+ /**
+ * Returns the cloud composite.
+ *
+ * @return the cloud composite
+ */
+ private Composite cloud() throws NotFoundException {
+
+ // Create a new composite for the clouds
+ Composite cloudComposite = assemblyFactory.createComposite();
+ cloudComposite.setName(new QName(Constants.SCA10_TUSCANY_NS, "cloud"));
+
+ // Get the collection of cloud composites
+ Entry<String, Item>[] cloudEntries = cloudCollection.getAll();
+
+ // Load the cloud contributions
+ Workspace workspace = workspaceFactory.createWorkspace();
+ Map<String, Contribution> contributionMap = new HashMap<String, Contribution>();
+ for (Entry<String, Item> cloudEntry: cloudEntries) {
+ String key = cloudEntry.getKey();
+ String contributionURI = contributionURI(key);
+
+ // Load the contribution
+ Contribution contribution = contributionMap.get(contributionURI);
+ if (contribution == null) {
+ Item contributionItem = contributionCollection.get(contributionURI);
+
+ // Read the contribution
+ try {
+ contribution = contribution(workspace, contributionURI, contributionItem.getAlternate());
+ } catch (ContributionReadException e) {
+ continue;
+ }
+ workspace.getContributions().add(contribution);
+ contributionMap.put(contributionURI, contribution);
+
+ }
+
+ // Include the cloud composite in the clouds composite
+ QName qname = compositeQName(key);
+ for (Artifact artifact : contribution.getArtifacts()) {
+ if (artifact.getModel() instanceof Composite) {
+ Composite composite = (Composite)artifact.getModel();
+ if (composite.getName().equals(qname)) {
+ cloudComposite.getIncludes().add(composite);
+ }
+ }
+ }
+ }
+
+ return cloudComposite;
+ }
+
+ /**
+ * Returns the contribution with the given URI.
+ *
+ * @param workspace
+ * @param contributionURI
+ * @param contributionLocation
+ * @return
+ * @throws NotFoundException
+ */
+ private Contribution contribution(Workspace workspace, String contributionURI, String contributionLocation) throws ContributionReadException {
+ try {
+ URI uri = URI.create(contributionURI);
+ URL location = locationURL(contributionLocation);
+
+ Contribution contribution = (Contribution)contributionProcessor.read(null, uri, location);
+ try {
+ analyzeProblems();
+ } catch (ServiceRuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new ContributionReadException(e);
+ }
+
+ // Resolve the contribution dependencies
+ contributionDependencyBuilder.buildContributionDependencies(contribution, workspace);
+
+ contributionProcessor.resolve(contribution, workspace.getModelResolver());
+ try {
+ analyzeProblems();
+ } catch (ServiceRuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new ContributionReadException(e);
+ }
+ return contribution;
+
+ } catch (ContributionReadException e) {
+ throw e;
+ } catch (ContributionResolveException e) {
+ throw new ContributionReadException(e);
+ } catch (MalformedURLException e) {
+ throw new ContributionReadException(e);
+ }
+ }
+
+ private void analyzeProblems() throws Exception {
+
+ for (Problem problem : monitor.getProblems()) {
+ if ((problem.getSeverity() == Severity.ERROR) && (!problem.getMessageId().equals("SchemaError"))) {
+ if (problem.getCause() != null) {
+ throw new ServiceRuntimeException(new MonitorRuntimeException(problem.getCause()));
+ } else {
+ throw new ServiceRuntimeException(new MonitorRuntimeException(problem.toString()));
+ }
+ }
+ }
+ }
+
+ private String getDescription(Exception e) {
+ if (e instanceof ServiceRuntimeException && e.getCause() instanceof MonitorRuntimeException) {
+ Throwable ce = e.getCause();
+ return ce.getCause() != null ? ce.getCause().toString() : ce.getMessage();
+ } else {
+ return e.toString();
+ }
+ }
+
+
+ /**
+ * The following code was copied from RuntimeBootStrapper to fix TUSCANY-3171
+ *
+ * @param registry
+ */
+ private void loadSCADefinitions(ExtensionPointRegistry registry) throws ParserConfigurationException {
+ try {
+ URLArtifactProcessorExtensionPoint documentProcessors =
+ registry.getExtensionPoint(URLArtifactProcessorExtensionPoint.class);
+ URLArtifactProcessor<SCADefinitions> definitionsProcessor =
+ documentProcessors.getProcessor(SCADefinitions.class);
+ SCADefinitionsProviderExtensionPoint scaDefnProviders =
+ registry.getExtensionPoint(SCADefinitionsProviderExtensionPoint.class);
+
+ SCADefinitions systemSCADefinitions = new SCADefinitionsImpl();
+ SCADefinitions aSCADefn = null;
+ for (SCADefinitionsProvider aProvider : scaDefnProviders.getSCADefinitionsProviders()) {
+ aSCADefn = aProvider.getSCADefinition();
+ SCADefinitionsUtil.aggregateSCADefinitions(aSCADefn, systemSCADefinitions);
+ }
+
+ policyDefinitions.add(systemSCADefinitions);
+
+ //we cannot expect that providers will add the intents and policysets into the resolver
+ //so we do this here explicitly
+ for (Intent intent : systemSCADefinitions.getPolicyIntents()) {
+ policyDefinitionsResolver.addModel(intent);
+ }
+
+ for (PolicySet policySet : systemSCADefinitions.getPolicySets()) {
+ policyDefinitionsResolver.addModel(policySet);
+ }
+
+ for (IntentAttachPointType attachPoinType : systemSCADefinitions.getBindingTypes()) {
+ policyDefinitionsResolver.addModel(attachPoinType);
+ }
+
+ for (IntentAttachPointType attachPoinType : systemSCADefinitions.getImplementationTypes()) {
+ policyDefinitionsResolver.addModel(attachPoinType);
+ }
+
+ //now that all system sca definitions have been read, lets resolve them right away
+ definitionsProcessor.resolve(systemSCADefinitions, policyDefinitionsResolver);
+ } catch (Exception e) {
+ throw new ServiceRuntimeException(e);
+ }
+ }
+
+}
diff --git a/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/CompositeGeneratorServiceImpl.java b/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/CompositeGeneratorServiceImpl.java
new file mode 100644
index 0000000000..c476d82e72
--- /dev/null
+++ b/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/CompositeGeneratorServiceImpl.java
@@ -0,0 +1,255 @@
+/*
+ * 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.manager.impl;
+
+import static org.apache.tuscany.sca.domain.manager.impl.DomainManagerUtil.compositeQName;
+import static org.apache.tuscany.sca.domain.manager.impl.DomainManagerUtil.contributionURI;
+import static org.apache.tuscany.sca.domain.manager.impl.DomainManagerUtil.lastModified;
+import static org.apache.tuscany.sca.domain.manager.impl.DomainManagerUtil.locationURL;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.logging.Logger;
+
+import javax.servlet.Servlet;
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.xml.namespace.QName;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+
+import org.apache.tuscany.sca.assembly.Composite;
+import org.apache.tuscany.sca.contribution.Contribution;
+import org.apache.tuscany.sca.contribution.ModelFactoryExtensionPoint;
+import org.apache.tuscany.sca.contribution.processor.ExtensibleStAXArtifactProcessor;
+import org.apache.tuscany.sca.contribution.processor.ExtensibleURLArtifactProcessor;
+import org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor;
+import org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessorExtensionPoint;
+import org.apache.tuscany.sca.contribution.processor.URLArtifactProcessor;
+import org.apache.tuscany.sca.contribution.processor.URLArtifactProcessorExtensionPoint;
+import org.apache.tuscany.sca.contribution.resolver.DefaultModelResolver;
+import org.apache.tuscany.sca.contribution.resolver.ModelResolverExtensionPoint;
+import org.apache.tuscany.sca.contribution.service.ContributionReadException;
+import org.apache.tuscany.sca.contribution.service.ContributionResolveException;
+import org.apache.tuscany.sca.contribution.service.ContributionWriteException;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.core.UtilityExtensionPoint;
+import org.apache.tuscany.sca.data.collection.Item;
+import org.apache.tuscany.sca.data.collection.LocalItemCollection;
+import org.apache.tuscany.sca.data.collection.NotFoundException;
+import org.apache.tuscany.sca.domain.manager.impl.CompositeGeneratorServiceImpl.Cache.ContributionCache;
+import org.apache.tuscany.sca.monitor.Monitor;
+import org.apache.tuscany.sca.monitor.MonitorFactory;
+import org.apache.tuscany.sca.workspace.processor.impl.ContributionContentProcessor;
+import org.osoa.sca.annotations.Init;
+import org.osoa.sca.annotations.Reference;
+import org.osoa.sca.annotations.Scope;
+import org.osoa.sca.annotations.Service;
+
+/**
+ * Implementation of a service that generates a composite from a composite model.
+ *
+ * @version $Rev$ $Date$
+ */
+@Scope("COMPOSITE")
+@Service(interfaces={Servlet.class})
+public class CompositeGeneratorServiceImpl extends HttpServlet implements Servlet {
+ private static final long serialVersionUID = -6531448326726908269L;
+
+ private static final Logger logger = Logger.getLogger(CompositeGeneratorServiceImpl.class.getName());
+
+ @Reference
+ public LocalItemCollection contributionCollection;
+
+ @Reference
+ public DomainManagerConfiguration domainManagerConfiguration;
+
+ private ModelFactoryExtensionPoint modelFactories;
+ private ModelResolverExtensionPoint modelResolvers;
+ private URLArtifactProcessor<Contribution> contributionProcessor;
+ private StAXArtifactProcessor<Composite> compositeProcessor;
+ private XMLOutputFactory outputFactory;
+
+ /**
+ * Cache contribution models.
+ */
+ static class Cache {
+ static class ContributionCache {
+ private Contribution contribution;
+ private long contributionLastModified;
+ }
+ private Map<URL, ContributionCache> contributions = new HashMap<URL, ContributionCache>();
+ }
+
+ private Cache cache = new Cache();
+
+ /**
+ * Initialize the component.
+ */
+ @Init
+ public void initialize() throws ParserConfigurationException {
+
+ ExtensionPointRegistry extensionPoints = domainManagerConfiguration.getExtensionPoints();
+
+ // Create a monitor
+ UtilityExtensionPoint services = extensionPoints.getExtensionPoint(UtilityExtensionPoint.class);
+ MonitorFactory monitorFactory = services.getUtility(MonitorFactory.class);
+ Monitor monitor = monitorFactory.createMonitor();
+
+ // Get model factories
+ modelFactories = extensionPoints.getExtensionPoint(ModelFactoryExtensionPoint.class);
+ XMLInputFactory inputFactory = modelFactories.getFactory(XMLInputFactory.class);
+ outputFactory = modelFactories.getFactory(XMLOutputFactory.class);
+ outputFactory.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true);
+
+ // Get and initialize artifact processors
+ StAXArtifactProcessorExtensionPoint staxProcessors = extensionPoints.getExtensionPoint(StAXArtifactProcessorExtensionPoint.class);
+ compositeProcessor = (StAXArtifactProcessor<Composite>)staxProcessors.getProcessor(Composite.class);
+ StAXArtifactProcessor<Object> staxProcessor = new ExtensibleStAXArtifactProcessor(staxProcessors, inputFactory, outputFactory, monitor);
+
+ URLArtifactProcessorExtensionPoint urlProcessors = extensionPoints.getExtensionPoint(URLArtifactProcessorExtensionPoint.class);
+ URLArtifactProcessor<Object> urlProcessor = new ExtensibleURLArtifactProcessor(urlProcessors, monitor);
+
+ // Create contribution processor
+ modelResolvers = extensionPoints.getExtensionPoint(ModelResolverExtensionPoint.class);
+ contributionProcessor = new ContributionContentProcessor(extensionPoints, monitor);
+ }
+
+ @Override
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+
+ // Expect a key in the form
+ // composite:contributionURI;namespace;localName
+ // and return the corresponding source file
+
+ // Get the request path
+ String path = URLDecoder.decode(request.getRequestURI().substring(request.getServletPath().length()), "UTF-8");
+ String key = path.startsWith("/")? path.substring(1) : path;
+ logger.fine("get " + key);
+
+ // Get the specified contribution info
+ String contributionURI = contributionURI(key);
+ Item contributionItem;
+ try {
+ contributionItem = contributionCollection.get(contributionURI);
+ } catch (NotFoundException e) {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND, key);
+ return;
+ }
+
+ // Read the contribution
+ Contribution contribution;
+ try {
+ contribution = contribution(contributionURI, contributionItem.getAlternate());
+ } catch (ContributionReadException e) {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND, key);
+ return;
+ }
+
+ // Find the specified deployable composite
+ QName qname = compositeQName(key);
+ Composite composite = null;
+ for (Composite deployable: contribution.getDeployables()) {
+ if (qname.equals(deployable.getName())) {
+ if (!deployable.isUnresolved()) {
+ composite = deployable;
+ }
+ break;
+ }
+ }
+ if (composite == null) {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND, key);
+ return;
+ }
+
+ // Write the composite
+ response.setContentType("text/xml");
+ ServletOutputStream os = response.getOutputStream();
+ try {
+ compositeProcessor.write(composite, outputFactory.createXMLStreamWriter(os));
+ } catch (ContributionWriteException e) {
+ response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.toString());
+ return;
+ } catch (XMLStreamException e) {
+ response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.toString());
+ return;
+ }
+ os.flush();
+ }
+
+ /**
+ * Returns the contribution with the given URI.
+ *
+ * @param contributionURI
+ * @param contributionLocation
+ * @return
+ * @throws NotFoundException
+ */
+ private Contribution contribution(String contributionURI, String contributionLocation) throws ContributionReadException {
+ try {
+ URI uri = URI.create(contributionURI);
+ URL location = locationURL(contributionLocation);
+
+ // Get contribution from cache
+ ContributionCache contributionCache = cache.contributions.get(location);
+ long lastModified = lastModified(location);
+ if (contributionCache != null) {
+ if (contributionCache.contributionLastModified == lastModified) {
+ return contributionCache.contribution;
+ }
+
+ // Reset contribution cache
+ cache.contributions.remove(location);
+ }
+
+ Contribution contribution = (Contribution)contributionProcessor.read(null, uri, location);
+
+ contributionProcessor.resolve(contribution, new DefaultModelResolver());
+
+ // Cache contribution
+ contributionCache = new ContributionCache();
+ contributionCache.contribution = contribution;
+ contributionCache.contributionLastModified = lastModified;
+ cache.contributions.put(location, contributionCache);
+
+ return contribution;
+
+ } catch (ContributionReadException e) {
+ throw e;
+ } catch (MalformedURLException e) {
+ throw new ContributionReadException(e);
+ } catch (IOException e) {
+ throw new ContributionReadException(e);
+ } catch (ContributionResolveException e) {
+ throw new ContributionReadException(e);
+ }
+ }
+
+}
diff --git a/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/ContributionCollectionImpl.java b/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/ContributionCollectionImpl.java
new file mode 100644
index 0000000000..3e17ae007b
--- /dev/null
+++ b/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/ContributionCollectionImpl.java
@@ -0,0 +1,705 @@
+/*
+ * 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.manager.impl;
+
+import static javax.xml.stream.XMLStreamConstants.START_ELEMENT;
+import static org.apache.tuscany.sca.domain.manager.impl.DomainManagerUtil.DEPLOYMENT_CONTRIBUTION_URI;
+import static org.apache.tuscany.sca.domain.manager.impl.DomainManagerUtil.compositeSimpleTitle;
+import static org.apache.tuscany.sca.domain.manager.impl.DomainManagerUtil.compositeSourceLink;
+import static org.apache.tuscany.sca.domain.manager.impl.DomainManagerUtil.lastModified;
+import static org.apache.tuscany.sca.domain.manager.impl.DomainManagerUtil.locationURL;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Logger;
+
+import javax.xml.namespace.QName;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.stream.XMLStreamWriter;
+
+import org.apache.tuscany.sca.assembly.Composite;
+import org.apache.tuscany.sca.contribution.Contribution;
+import org.apache.tuscany.sca.contribution.ContributionFactory;
+import org.apache.tuscany.sca.contribution.DefaultExport;
+import org.apache.tuscany.sca.contribution.DefaultImport;
+import org.apache.tuscany.sca.contribution.Export;
+import org.apache.tuscany.sca.contribution.Import;
+import org.apache.tuscany.sca.contribution.ModelFactoryExtensionPoint;
+import org.apache.tuscany.sca.contribution.processor.ExtensibleStAXArtifactProcessor;
+import org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor;
+import org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessorExtensionPoint;
+import org.apache.tuscany.sca.contribution.processor.URLArtifactProcessor;
+import org.apache.tuscany.sca.contribution.processor.URLArtifactProcessorExtensionPoint;
+import org.apache.tuscany.sca.contribution.service.ContributionReadException;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.core.UtilityExtensionPoint;
+import org.apache.tuscany.sca.data.collection.Entry;
+import org.apache.tuscany.sca.data.collection.Item;
+import org.apache.tuscany.sca.data.collection.ItemCollection;
+import org.apache.tuscany.sca.data.collection.LocalItemCollection;
+import org.apache.tuscany.sca.data.collection.NotFoundException;
+import org.apache.tuscany.sca.domain.manager.impl.ContributionCollectionImpl.Cache.ContributionCache;
+import org.apache.tuscany.sca.domain.search.DomainSearch;
+import org.apache.tuscany.sca.domain.search.IndexException;
+import org.apache.tuscany.sca.monitor.Monitor;
+import org.apache.tuscany.sca.monitor.MonitorFactory;
+import org.apache.tuscany.sca.monitor.Problem;
+import org.apache.tuscany.sca.monitor.Problem.Severity;
+import org.apache.tuscany.sca.monitor.impl.ProblemImpl;
+import org.apache.tuscany.sca.workspace.Workspace;
+import org.apache.tuscany.sca.workspace.WorkspaceFactory;
+import org.apache.tuscany.sca.workspace.builder.ContributionDependencyBuilder;
+import org.apache.tuscany.sca.workspace.builder.impl.ContributionDependencyBuilderImpl;
+import org.apache.xml.serialize.OutputFormat;
+import org.apache.xml.serialize.XMLSerializer;
+import org.osoa.sca.ServiceRuntimeException;
+import org.osoa.sca.annotations.Init;
+import org.osoa.sca.annotations.Property;
+import org.osoa.sca.annotations.Reference;
+import org.osoa.sca.annotations.Scope;
+import org.osoa.sca.annotations.Service;
+import org.w3c.dom.Document;
+
+/**
+ * Implementation of a contribution collection service component.
+ *
+ * @version $Rev$ $Date$
+ */
+@Scope("COMPOSITE")
+@Service(interfaces={ItemCollection.class, LocalItemCollection.class})
+public class ContributionCollectionImpl implements ItemCollection, LocalItemCollection {
+
+ private static final Logger logger = Logger.getLogger(ContributionCollectionImpl.class.getName());
+
+ @Property
+ public String workspaceFile;
+
+ @Property
+ public String deploymentContributionDirectory;
+
+ @Reference
+ public DomainManagerConfiguration domainManagerConfiguration;
+
+ @Reference
+ public DomainSearch domainSearch;
+
+ private Monitor monitor;
+ private ContributionFactory contributionFactory;
+ private WorkspaceFactory workspaceFactory;
+ private StAXArtifactProcessor<Object> staxProcessor;
+ private URLArtifactProcessor<Contribution> contributionProcessor;
+ private XMLInputFactory inputFactory;
+ private XMLOutputFactory outputFactory;
+ private DocumentBuilder documentBuilder;
+
+ /**
+ * Cache workspace and contribution models.
+ */
+ static class Cache {
+ private Workspace workspace;
+ private long workspaceLastModified;
+
+ static class ContributionCache {
+ private Contribution contribution;
+ private long contributionLastModified;
+ }
+ private Map<URL, ContributionCache> contributions = new HashMap<URL, ContributionCache>();
+ }
+
+ private Cache cache = new Cache();
+
+ /**
+ * Initialize the component.
+ */
+ @Init
+ public void initialize() throws ParserConfigurationException {
+
+ ExtensionPointRegistry extensionPoints = domainManagerConfiguration.getExtensionPoints();
+
+ // Create a validation monitor
+ UtilityExtensionPoint utilities = extensionPoints.getExtensionPoint(UtilityExtensionPoint.class);
+ MonitorFactory monitorFactory = utilities.getUtility(MonitorFactory.class);
+ monitor = monitorFactory.createMonitor();
+
+ // Create model factories
+ ModelFactoryExtensionPoint modelFactories = extensionPoints.getExtensionPoint(ModelFactoryExtensionPoint.class);
+ outputFactory = modelFactories.getFactory(XMLOutputFactory.class);
+ outputFactory.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true);
+ contributionFactory = modelFactories.getFactory(ContributionFactory.class);
+ workspaceFactory = modelFactories.getFactory(WorkspaceFactory.class);
+
+ // Create artifact processors
+ inputFactory = modelFactories.getFactory(XMLInputFactory.class);
+ StAXArtifactProcessorExtensionPoint staxProcessors = extensionPoints.getExtensionPoint(StAXArtifactProcessorExtensionPoint.class);
+ staxProcessor = new ExtensibleStAXArtifactProcessor(staxProcessors, inputFactory, outputFactory, monitor);
+
+ URLArtifactProcessorExtensionPoint urlProcessors = extensionPoints.getExtensionPoint(URLArtifactProcessorExtensionPoint.class);
+
+ // Create contribution info processor
+ contributionProcessor = urlProcessors.getProcessor(".contribution/info");
+
+ // Create a document builder (used to pretty print XML)
+ documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+ }
+
+ public Entry<String, Item>[] getAll() {
+ logger.fine("getAll");
+
+ // Return all the contributions
+ List<Entry<String, Item>> entries = new ArrayList<Entry<String, Item>>();
+ Workspace workspace = readContributions(readWorkspace());
+
+ for (Contribution contribution: workspace.getContributions()) {
+ if (contribution.getURI().equals(DEPLOYMENT_CONTRIBUTION_URI)) {
+ continue;
+ }
+ entries.add(entry(workspace, contribution));
+ }
+ return entries.toArray(new Entry[entries.size()]);
+ }
+
+ public Item get(String key) throws NotFoundException {
+ logger.fine("get " + key);
+
+ // Returns the contribution with the given URI key
+ Workspace workspace = readContributions(readWorkspace());
+ for (Contribution contribution: workspace.getContributions()) {
+ if (key.equals(contribution.getURI())) {
+ return item(workspace, contribution);
+ }
+ }
+ throw new NotFoundException(key);
+ }
+
+ public String post(String key, Item item) {
+ logger.fine("post " + key);
+
+ // Adds a new contribution to the workspace
+ Workspace workspace = readWorkspace();
+ Contribution contribution = contributionFactory.createContribution();
+ contribution.setURI(key);
+ try {
+ contribution.setLocation(locationURL(item.getLink()).toString());
+ } catch (MalformedURLException e) {
+ throw new ServiceRuntimeException(e);
+ }
+ workspace.getContributions().add(contribution);
+
+ // Write the workspace
+ writeWorkspace(workspace);
+
+ // add it to the search index, contributionUpdated is called to guarantee
+ // only one contribution with the same URI in the index
+ if (domainSearch != null) { // can be null in unit tests
+
+ try {
+ domainSearch.updateContribution(contribution, contribution);
+
+ } catch (IndexException e) {
+ logger.warning("Could not update contribution on index: " + contribution.getURI());
+ }
+
+ }
+
+ return key;
+
+ }
+
+ public void put(String key, Item item) throws NotFoundException {
+
+ // Update a contribution already in the workspace
+ Workspace workspace = readWorkspace();
+ Contribution newContribution = contributionFactory.createContribution();
+ newContribution.setURI(key);
+ try {
+ newContribution.setLocation(locationURL(item.getLink()).toString());
+ } catch (MalformedURLException e) {
+ throw new ServiceRuntimeException(e);
+ }
+ List<Contribution> contributions = workspace.getContributions();
+ for (int i = 0, n = contributions.size(); i < n; i++) {
+ if (contributions.get(i).getURI().equals(key)) {
+ contributions.set(i, newContribution);
+
+ // Write the workspace
+ writeWorkspace(workspace);
+ return;
+ }
+ }
+ throw new NotFoundException(key);
+ }
+
+ public void delete(String key) throws NotFoundException {
+ logger.fine("delete " + key);
+
+ // Delete a contribution from the workspace
+ Workspace workspace = readWorkspace();
+ List<Contribution> contributions = workspace.getContributions();
+ for (int i = 0, n = contributions.size(); i < n; i++) {
+
+ Contribution contribution = contributions.get(i);
+
+ if (contribution.getURI().equals(key)) {
+ contributions.remove(i);
+
+ // Write the workspace
+ writeWorkspace(workspace);
+
+ // delete it from the search index
+ if (domainSearch != null) { // can be null in unit tests
+
+ try {
+ domainSearch.removeContribution(contribution);
+ } catch (IndexException e) {
+ logger.warning("Could not remove contribution from index: " + contribution.getURI());
+ }
+
+ }
+
+ return;
+
+ }
+ }
+ throw new NotFoundException(key);
+ }
+
+ public Entry<String, Item>[] query(String queryString) {
+ logger.fine("query " + queryString);
+
+ if (queryString.startsWith("dependencies=") || queryString.startsWith("alldependencies=")) {
+
+ // Return the collection of dependencies of the specified contribution
+ List<Entry<String, Item>> entries = new ArrayList<Entry<String,Item>>();
+
+ // Extract the contribution URI
+ int eq = queryString.indexOf('=');
+ String key = queryString.substring(eq+1);
+
+ // Read the metadata for all the contributions
+ Workspace workspace = readContributions(readWorkspace());
+
+ // Look for the specified contribution
+ for (Contribution contribution: workspace.getContributions()) {
+ if (key.equals(contribution.getURI())) {
+
+ // Compute the contribution dependencies
+ ContributionDependencyBuilder analyzer = new ContributionDependencyBuilderImpl(monitor);
+ List<Contribution> dependencies = analyzer.buildContributionDependencies(contribution, workspace);
+
+ // Returns entries for the dependencies
+ // optionally skip the specified contribution
+ boolean allDependencies = queryString.startsWith("alldependencies=");
+ for (Contribution dependency: dependencies) {
+ if (!allDependencies && dependency == contribution) {
+ // Skip the specified contribution
+ continue;
+ }
+ entries.add(entry(workspace, dependency));
+ }
+ break;
+ }
+ }
+
+ return entries.toArray(new Entry[entries.size()]);
+
+ } if (queryString.startsWith("suggestions=true")) {
+
+ // Returns a list of contribution suggestions, scan the parent of the workspace
+ // directory for potential contribution directories
+
+ // For now, recognize project directories that contain .project files
+ // Directories containing .classpath files are likely to be Java projects, we parse
+ // the .classpath file to determine the Java project output location
+ Workspace suggestionWorkspace = workspaceFactory.createWorkspace();
+ List<Entry> entries = new ArrayList<Entry>();
+ String rootDirectory = domainManagerConfiguration.getRootDirectory();
+ File rootLocation = new File(new File(rootDirectory).toURI().normalize());
+ for (File project: rootLocation.getParentFile().listFiles()) {
+ File dotProject = new File(project, ".project");
+ if (!dotProject.exists()) {
+ continue;
+ }
+
+ // We have a potential contribution
+ String uri = project.getName();
+ File location = project;
+
+ // If this is a Java project, parse its .classpath file to determine it's output location
+ File dotClasspath = new File(project, ".classpath");
+ if (dotClasspath.exists()) {
+ try {
+ XMLStreamReader reader = inputFactory.createXMLStreamReader(new FileInputStream(dotClasspath));
+ reader.nextTag();
+ while (reader.hasNext()) {
+ int event = reader.getEventType();
+ if (event == START_ELEMENT) {
+ if ("classpathentry".equals(reader.getName().getLocalPart())) {
+ if ("output".equals(reader.getAttributeValue("", "kind"))) {
+ location = new File(project, reader.getAttributeValue("", "path"));
+ break;
+ }
+ }
+ }
+ if (reader.hasNext()) {
+ reader.next();
+ }
+ }
+ } catch (FileNotFoundException e) {
+ } catch (XMLStreamException e) {
+ }
+
+ }
+
+ // Create a contribution entry, skip the domain root directory and childrens of the
+ // domain root directory
+ String rootLocationPath = rootLocation.getPath();
+ if (rootLocationPath.indexOf('\\') != -1 || rootLocationPath.indexOf(' ') != -1) {
+ rootLocationPath = new File(rootLocationPath.replace('\\', '/')).toURI().toString();
+ }
+ String locationPath = location.getPath();
+ if (locationPath.indexOf('\\') != -1 || locationPath.indexOf(' ') != -1) {
+ locationPath = new File(locationPath.replace('\\', '/')).toURI().toString();
+ }
+ if (!locationPath.startsWith(rootLocationPath + "/") && !locationPath.equals(rootLocationPath)) {
+ Contribution contribution = contributionFactory.createContribution();
+ contribution.setURI(uri);
+ contribution.setLocation(locationPath);
+ entries.add(entry(suggestionWorkspace, contribution));
+ }
+ }
+
+ return entries.toArray(new Entry[entries.size()]);
+
+ } else {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ /**
+ * Returns an entry representing a contribution
+ * @param contribution
+ * @return
+ */
+ private static Entry<String, Item> entry(Workspace workspace, Contribution contribution) {
+ Entry<String, Item> entry = new Entry<String, Item>();
+ entry.setKey(contribution.getURI());
+ entry.setData(item(workspace, contribution));
+ return entry;
+ }
+
+ /**
+ * Returns an item representing a contribution.
+ *
+ * @param contribution
+ * @return
+ */
+ private static Item item(Workspace workspace, Contribution contribution) {
+ String contributionURI = contribution.getURI();
+ Item item = new Item();
+ item.setTitle(title(contributionURI));
+ item.setLink(link(contributionURI));
+ item.setAlternate(contribution.getLocation());
+
+ // List the contribution dependencies in the item contents
+ final List<String> problems = new ArrayList<String>();
+ Monitor monitor = new Monitor() {
+ public void problem(Problem problem) {
+ problems.add(problem.getMessageId() + " " + problem.getProblemObject().toString());
+ }
+
+ public List<Problem> getProblems() {
+ return null;
+ }
+ public Problem createProblem(String sourceClassName, String bundleName,
+ Severity severity, Object problemObject, String messageId,
+ Exception cause) {
+ return new ProblemImpl(sourceClassName, bundleName, severity,
+ problemObject, messageId, cause);
+ }
+
+ public Problem createProblem(String sourceClassName, String bundleName,
+ Severity severity, Object problemObject, String messageId,
+ Object... messageParams) {
+ return new ProblemImpl(sourceClassName, bundleName, severity,
+ problemObject, messageId, messageParams);
+ }
+ };
+
+ StringBuffer sb = new StringBuffer();
+ ContributionDependencyBuilderImpl analyzer = new ContributionDependencyBuilderImpl(monitor);
+ List<Contribution> dependencies = analyzer.buildContributionDependencies(contribution, workspace);
+ if (dependencies.size() > 1) {
+ sb.append("Dependencies: <span id=\"dependencies\">");
+ for (int i = 0, n = dependencies.size(); i < n ; i++) {
+ if (i > 0) {
+ sb.append(" ");
+ }
+ Contribution dependency = dependencies.get(i);
+ if (dependency != contribution) {
+ String dependencyURI = dependency.getURI();
+ sb.append("<a href=\""+ link(dependencyURI) +"\">" + title(dependencyURI) + "</a>");
+ }
+ }
+ sb.append("</span><br>");
+ }
+
+ // List the deployables
+ List<Composite> deployables = contribution.getDeployables();
+ if (!deployables.isEmpty()) {
+ sb.append("Deployables: <span id=\"deployables\">");
+ for (int i = 0, n = deployables.size(); i < n ; i++) {
+ if (i > 0) {
+ sb.append(" ");
+ }
+ Composite deployable = deployables.get(i);
+ QName qname = deployable.getName();
+ sb.append("<a href=\""+ compositeSourceLink(contributionURI, qname) +"\">" + compositeSimpleTitle(contributionURI, qname) + "</a>");
+ }
+ sb.append("</span><br>");
+ }
+
+ // List the dependency problems
+ if (contribution.isUnresolved()) {
+ problems.add("Contribution not found");
+ }
+ if (problems.size() > 0) {
+ sb.append("<span id=\"problems\" style=\"color: red\">");
+ for (int i = 0, n = problems.size(); i < n ; i++) {
+ sb.append("Problem: "+ problems.get(i) + "<br>");
+ }
+ sb.append("</span>");
+ }
+
+ // Store in the item contents
+ item.setContents(sb.toString());
+
+ return item;
+ }
+
+ /**
+ * Returns a link to a contribution.
+ * @param contributionURI
+ * @return
+ */
+ private static String link(String contributionURI) {
+ return "/contribution/" + contributionURI;
+ }
+
+ /**
+ * Returns a title for the given contribution
+ *
+ * @param contributionURI
+ * @return
+ */
+ private static String title(String contributionURI) {
+ return contributionURI;
+ }
+
+ /**
+ * Read the workspace.
+ *
+ * @return
+ */
+ Workspace readWorkspace() {
+ String rootDirectory = domainManagerConfiguration.getRootDirectory();
+
+ Workspace workspace;
+ File file = new File(rootDirectory + "/" + workspaceFile);
+ if (file.exists()) {
+
+ // Get workspace from cache
+ if (cache.workspace != null && file.lastModified() == cache.workspaceLastModified) {
+ workspace = cache.workspace;
+
+ } else {
+
+ try {
+ FileInputStream is = new FileInputStream(file);
+ XMLStreamReader reader = inputFactory.createXMLStreamReader(is);
+ reader.nextTag();
+ workspace = (Workspace)staxProcessor.read(reader);
+ } catch (Exception e) {
+ throw new ServiceRuntimeException(e);
+ }
+
+ // Cache workspace
+ cache.workspaceLastModified = file.lastModified();
+ cache.workspace = workspace;
+ }
+
+ } else {
+
+ // Create new workspace
+ workspace = workspaceFactory.createWorkspace();
+
+ // Cache workspace
+ cache.workspaceLastModified = 0;
+ cache.workspace = workspace;
+ }
+
+ // Make sure that the workspace contains the cloud contribution
+ // The cloud contribution contains the composites describing the
+ // SCA nodes declared in the cloud
+ Contribution cloudContribution = null;
+ for (Contribution contribution: workspace.getContributions()) {
+ if (contribution.getURI().equals(DEPLOYMENT_CONTRIBUTION_URI)) {
+ cloudContribution = contribution;
+ }
+ }
+ if (cloudContribution == null) {
+ Contribution contribution = contributionFactory.createContribution();
+ contribution.setURI(DEPLOYMENT_CONTRIBUTION_URI);
+ File cloudDirectory = new File(rootDirectory + "/" + deploymentContributionDirectory);
+ contribution.setLocation(cloudDirectory.toURI().toString());
+ workspace.getContributions().add(contribution);
+ }
+
+ return workspace;
+ }
+
+ /**
+ * Write the workspace back to disk
+ *
+ * @param workspace
+ */
+ private void writeWorkspace(Workspace workspace) {
+ try {
+ String rootDirectory = domainManagerConfiguration.getRootDirectory();
+
+ // First write to a byte stream
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ XMLStreamWriter writer = outputFactory.createXMLStreamWriter(bos);
+ staxProcessor.write(workspace, writer);
+
+ // Parse again to pretty format the document
+ Document document = documentBuilder.parse(new ByteArrayInputStream(bos.toByteArray()));
+ OutputFormat format = new OutputFormat();
+ format.setIndenting(true);
+ format.setIndent(2);
+
+ // Write to workspace.xml
+ File file = new File(rootDirectory + "/" + workspaceFile);
+ FileOutputStream os = new FileOutputStream(file);
+ XMLSerializer serializer = new XMLSerializer(os, format);
+ serializer.serialize(document);
+ os.close();
+
+ // Cache workspace
+ cache.workspace = workspace;
+ cache.workspaceLastModified = file.lastModified();
+
+ } catch (Exception e) {
+ throw new ServiceRuntimeException(e);
+ }
+ }
+
+ /**
+ * Returns a workspace populated with the contribution info read from
+ * the contributions.
+ *
+ * @param workspace
+ * @return
+ */
+ private Workspace readContributions(Workspace workspace) {
+
+ Workspace contributions = workspaceFactory.createWorkspace();
+ try {
+ for (Contribution c: workspace.getContributions()) {
+ URI uri = URI.create(c.getURI());
+ URL location = locationURL(c.getLocation());
+
+ // Get contribution from cache
+ ContributionCache contributionCache = cache.contributions.get(location);
+ long lastModified = lastModified(location);
+ if (contributionCache != null) {
+ if (contributionCache.contributionLastModified == lastModified) {
+ Contribution contribution = contributionCache.contribution;
+ contribution.setUnresolved(false);
+ contributions.getContributions().add(contribution);
+ continue;
+ }
+
+ // Reset contribution cache
+ cache.contributions.remove(location);
+ }
+
+ try {
+ Contribution contribution = (Contribution)contributionProcessor.read(null, uri, location);
+ contribution.setUnresolved(false);
+ contributions.getContributions().add(contribution);
+
+ // Cache contribution
+ contributionCache = new ContributionCache();
+ contributionCache.contribution = contribution;
+ contributionCache.contributionLastModified = lastModified;
+ cache.contributions.put(location, contributionCache);
+
+
+ // Make sure that the cloud contribution does not contain
+ // default imports/exports as we want to isolate it from application
+ // provided contributions
+ if (contribution.getURI().equals(DEPLOYMENT_CONTRIBUTION_URI)) {
+ for (Iterator<Import> i = contribution.getImports().iterator(); i.hasNext(); ) {
+ Import import_ = i.next();
+ if (import_ instanceof DefaultImport) {
+ i.remove();
+ }
+ }
+ for (Iterator<Export> i = contribution.getExports().iterator(); i.hasNext(); ) {
+ Export export = i.next();
+ if (export instanceof DefaultExport) {
+ i.remove();
+ }
+ }
+ }
+
+ } catch (ContributionReadException e) {
+ Contribution contribution = contributionFactory.createContribution();
+ contribution.setURI(c.getURI());
+ contribution.setLocation(c.getLocation());
+ contribution.setUnresolved(true);
+ contributions.getContributions().add(contribution);
+ }
+ }
+ } catch (Exception e) {
+ throw new ServiceRuntimeException(e);
+ }
+ return contributions;
+ }
+
+}
diff --git a/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/ContributionServiceImpl.java b/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/ContributionServiceImpl.java
new file mode 100644
index 0000000000..a4d7680cb0
--- /dev/null
+++ b/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/ContributionServiceImpl.java
@@ -0,0 +1,77 @@
+/*
+ * 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.manager.impl;
+
+import java.io.IOException;
+import java.net.URLDecoder;
+import java.util.logging.Logger;
+
+import javax.servlet.Servlet;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.tuscany.sca.data.collection.Item;
+import org.apache.tuscany.sca.data.collection.LocalItemCollection;
+import org.apache.tuscany.sca.data.collection.NotFoundException;
+import org.osoa.sca.annotations.Reference;
+import org.osoa.sca.annotations.Scope;
+import org.osoa.sca.annotations.Service;
+
+/**
+ * Implementation of a contribution collection service component.
+ *
+ * @version $Rev$ $Date$
+ */
+@Scope("COMPOSITE")
+@Service(interfaces={Servlet.class})
+public class ContributionServiceImpl extends HttpServlet implements Servlet {
+ private static final long serialVersionUID = -4759297945439322773L;
+
+ private static final Logger logger = Logger.getLogger(ContributionServiceImpl.class.getName());
+
+ @Reference
+ public LocalItemCollection contributionCollection;
+
+ @Override
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+
+ // Get the request path
+ String path = URLDecoder.decode(request.getRequestURI().substring(request.getServletPath().length()), "UTF-8");
+
+ // The key is the contribution URI
+ String key = path.startsWith("/")? path.substring(1) : path;
+ logger.fine("get " + key);
+
+ // Get the item describing the composite
+ Item item;
+ try {
+ item = contributionCollection.get(key);
+ } catch (NotFoundException e) {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND, key);
+ return;
+ }
+
+ // Redirect to the actual contribution location
+ response.sendRedirect("/files/" + item.getAlternate());
+ }
+
+}
diff --git a/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/ContributionsReader.java b/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/ContributionsReader.java
new file mode 100644
index 0000000000..b679f594e6
--- /dev/null
+++ b/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/ContributionsReader.java
@@ -0,0 +1,9 @@
+package org.apache.tuscany.sca.domain.manager.impl;
+
+import org.apache.tuscany.sca.contribution.Contribution;
+
+public interface ContributionsReader {
+
+ Contribution[] readContributions();
+
+}
diff --git a/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/DeployableCompositeCollectionImpl.java b/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/DeployableCompositeCollectionImpl.java
new file mode 100644
index 0000000000..63af213fbb
--- /dev/null
+++ b/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/DeployableCompositeCollectionImpl.java
@@ -0,0 +1,481 @@
+/*
+ * 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.manager.impl;
+
+import static org.apache.tuscany.sca.domain.manager.impl.DomainManagerUtil.compositeAlternateLink;
+import static org.apache.tuscany.sca.domain.manager.impl.DomainManagerUtil.compositeKey;
+import static org.apache.tuscany.sca.domain.manager.impl.DomainManagerUtil.compositeQName;
+import static org.apache.tuscany.sca.domain.manager.impl.DomainManagerUtil.compositeSourceLink;
+import static org.apache.tuscany.sca.domain.manager.impl.DomainManagerUtil.compositeTitle;
+import static org.apache.tuscany.sca.domain.manager.impl.DomainManagerUtil.contributionURI;
+import static org.apache.tuscany.sca.domain.manager.impl.DomainManagerUtil.lastModified;
+import static org.apache.tuscany.sca.domain.manager.impl.DomainManagerUtil.locationURL;
+
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Logger;
+
+import javax.xml.namespace.QName;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLOutputFactory;
+
+import org.apache.tuscany.sca.assembly.Binding;
+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.contribution.Contribution;
+import org.apache.tuscany.sca.contribution.ModelFactoryExtensionPoint;
+import org.apache.tuscany.sca.contribution.processor.ExtensibleStAXArtifactProcessor;
+import org.apache.tuscany.sca.contribution.processor.ExtensibleURLArtifactProcessor;
+import org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor;
+import org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessorExtensionPoint;
+import org.apache.tuscany.sca.contribution.processor.URLArtifactProcessor;
+import org.apache.tuscany.sca.contribution.processor.URLArtifactProcessorExtensionPoint;
+import org.apache.tuscany.sca.contribution.resolver.ModelResolverExtensionPoint;
+import org.apache.tuscany.sca.contribution.service.ContributionReadException;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.core.UtilityExtensionPoint;
+import org.apache.tuscany.sca.data.collection.Entry;
+import org.apache.tuscany.sca.data.collection.Item;
+import org.apache.tuscany.sca.data.collection.ItemCollection;
+import org.apache.tuscany.sca.data.collection.LocalItemCollection;
+import org.apache.tuscany.sca.data.collection.NotFoundException;
+import org.apache.tuscany.sca.domain.manager.impl.DeployableCompositeCollectionImpl.Cache.ContributionCache;
+import org.apache.tuscany.sca.implementation.node.NodeImplementation;
+import org.apache.tuscany.sca.monitor.Monitor;
+import org.apache.tuscany.sca.monitor.MonitorFactory;
+import org.apache.tuscany.sca.workspace.builder.ContributionDependencyBuilder;
+import org.apache.tuscany.sca.workspace.builder.impl.ContributionDependencyBuilderImpl;
+import org.apache.tuscany.sca.workspace.processor.impl.ContributionContentProcessor;
+import org.osoa.sca.annotations.Init;
+import org.osoa.sca.annotations.Reference;
+import org.osoa.sca.annotations.Scope;
+import org.osoa.sca.annotations.Service;
+
+/**
+ * Implementation of a deployable composite collection service.
+ *
+ * @version $Rev$ $Date$
+ */
+@Scope("COMPOSITE")
+@Service(interfaces = { ItemCollection.class, LocalItemCollection.class, ContributionsReader.class })
+public class DeployableCompositeCollectionImpl implements ItemCollection,
+ LocalItemCollection, ContributionsReader {
+
+ private static final Logger logger = Logger
+ .getLogger(DeployableCompositeCollectionImpl.class.getName());
+
+ @Reference
+ public LocalItemCollection contributionCollection;
+
+ @Reference
+ public DomainManagerConfiguration domainManagerConfiguration;
+
+ private ModelFactoryExtensionPoint modelFactories;
+ private ModelResolverExtensionPoint modelResolvers;
+ private URLArtifactProcessor<Contribution> contributionProcessor;
+ private XMLOutputFactory outputFactory;
+ private ContributionDependencyBuilder contributionDependencyBuilder;
+ private Monitor monitor;
+
+ /**
+ * Cache contribution models.
+ */
+ static class Cache {
+ static class ContributionCache {
+ private Contribution contribution;
+ private long contributionLastModified;
+ }
+
+ private Map<URL, ContributionCache> contributions = new HashMap<URL, ContributionCache>();
+ }
+
+ private Cache cache = new Cache();
+
+ /**
+ * Initialize the component.
+ */
+ @Init
+ public void initialize() throws ParserConfigurationException {
+
+ ExtensionPointRegistry extensionPoints = domainManagerConfiguration
+ .getExtensionPoints();
+
+ // Create a monitor
+ UtilityExtensionPoint utilities = extensionPoints
+ .getExtensionPoint(UtilityExtensionPoint.class);
+ MonitorFactory monitorFactory = utilities
+ .getUtility(MonitorFactory.class);
+ monitor = monitorFactory.createMonitor();
+
+ // Get model factories
+ modelFactories = extensionPoints
+ .getExtensionPoint(ModelFactoryExtensionPoint.class);
+ XMLInputFactory inputFactory = modelFactories
+ .getFactory(XMLInputFactory.class);
+ outputFactory = modelFactories.getFactory(XMLOutputFactory.class);
+ outputFactory.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES,
+ true);
+
+ // Get and initialize artifact processors
+ StAXArtifactProcessorExtensionPoint staxProcessors = extensionPoints
+ .getExtensionPoint(StAXArtifactProcessorExtensionPoint.class);
+ StAXArtifactProcessor<Object> staxProcessor = new ExtensibleStAXArtifactProcessor(
+ staxProcessors, inputFactory, outputFactory, monitor);
+
+ URLArtifactProcessorExtensionPoint urlProcessors = extensionPoints
+ .getExtensionPoint(URLArtifactProcessorExtensionPoint.class);
+ URLArtifactProcessor<Object> urlProcessor = new ExtensibleURLArtifactProcessor(
+ urlProcessors, monitor);
+
+ // Create contribution processor
+ modelResolvers = extensionPoints
+ .getExtensionPoint(ModelResolverExtensionPoint.class);
+ contributionProcessor = new ContributionContentProcessor(
+ extensionPoints, monitor);
+
+ // Create contribution and composite builders
+ contributionDependencyBuilder = new ContributionDependencyBuilderImpl(
+ monitor);
+ }
+
+ public Entry<String, Item>[] getAll() {
+ logger.fine("getAll");
+
+ // Return all the deployable composites in the contributions
+ List<Entry<String, Item>> entries = new ArrayList<Entry<String, Item>>();
+
+ // Get the list of contributions in the workspace
+ Entry<String, Item>[] contributionEntries = contributionCollection
+ .getAll();
+
+ // Read contribution metadata
+ for (Entry<String, Item> contributionEntry : contributionEntries) {
+ Item contributionItem = contributionEntry.getData();
+ Contribution contribution;
+ try {
+ contribution = contribution(contributionEntry.getKey(),
+ contributionItem.getAlternate());
+ } catch (ContributionReadException e) {
+ continue;
+ }
+
+ // Create entries for the deployable composites
+ for (Composite deployable : contribution.getDeployables()) {
+ entries.add(entry(contribution, deployable));
+ }
+
+ }
+ return entries.toArray(new Entry[entries.size()]);
+ }
+
+ public Contribution[] readContributions() {
+
+ // Get the list of contributions in the workspace
+ Entry<String, Item>[] contributionEntries = contributionCollection
+ .getAll();
+
+ LinkedList<Contribution> contributions = new LinkedList<Contribution>();
+
+ // Read contribution metadata
+ for (Entry<String, Item> contributionEntry : contributionEntries) {
+ Item contributionItem = contributionEntry.getData();
+ Contribution contribution;
+ try {
+ contribution = contribution(contributionEntry.getKey(),
+ contributionItem.getAlternate());
+
+ } catch (ContributionReadException e) {
+ continue;
+ }
+
+ LinkedList<Composite> resolvedComposites = new LinkedList<Composite>();
+
+ for (Composite composite : contribution.getDeployables()) {
+
+ // find the deployable composite
+ composite = contribution.getModelResolver().resolveModel(
+ Composite.class, composite);
+
+ resolvedComposites.add(composite);
+
+ }
+
+ contribution.getDeployables().clear();
+ contribution.getDeployables().addAll(resolvedComposites);
+
+ contributions.add(contribution);
+
+ }
+
+ return contributions.toArray(new Contribution[0]);
+
+ }
+
+ public Item get(String key) throws NotFoundException {
+ logger.fine("get " + key);
+
+ // Get the specified contribution info
+ String contributionURI = contributionURI(key);
+ Item contributionItem = contributionCollection.get(contributionURI);
+
+ // Read the contribution
+ Contribution contribution;
+ try {
+ contribution = contribution(contributionURI, contributionItem
+ .getAlternate());
+ } catch (ContributionReadException e) {
+ throw new NotFoundException(key);
+ }
+
+ // Find the specified deployable composite
+ QName qname = compositeQName(key);
+ for (Composite deployable : contribution.getDeployables()) {
+ if (qname.equals(deployable.getName())) {
+ // find the deployable composite
+ deployable = contribution.getModelResolver().resolveModel(
+ Composite.class, deployable);
+
+ if (deployable.isUnresolved()) {
+ throw new NotFoundException(key);
+ }
+
+ // Return an item describing the deployable composite
+ return item(contribution, deployable);
+ }
+ }
+
+ throw new NotFoundException(key);
+ }
+
+ public String post(String key, Item item) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void put(String key, Item item) throws NotFoundException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void delete(String key) throws NotFoundException {
+ throw new UnsupportedOperationException();
+ }
+
+ public Entry<String, Item>[] query(String queryString) {
+ logger.fine("query " + queryString);
+
+ if (queryString.startsWith("contribution=")) {
+
+ // Return all the deployable composites in the specified
+ // contribution
+ List<Entry<String, Item>> entries = new ArrayList<Entry<String, Item>>();
+
+ // Get the specified contribution info
+ String contributionURI = queryString.substring(queryString
+ .indexOf('=') + 1);
+ Item contributionItem;
+ try {
+ contributionItem = contributionCollection.get(contributionURI);
+ } catch (NotFoundException e) {
+ return entries.toArray(new Entry[entries.size()]);
+ }
+
+ // Read the contribution
+ Contribution contribution;
+ try {
+ contribution = contribution(contributionURI, contributionItem
+ .getAlternate());
+ } catch (ContributionReadException e) {
+ return entries.toArray(new Entry[entries.size()]);
+ }
+
+ // Create entries for the deployable composites
+ for (Composite deployable : contribution.getDeployables()) {
+ entries.add(entry(contribution, deployable));
+ }
+
+ return entries.toArray(new Entry[entries.size()]);
+
+ } else {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ /**
+ * Returns the contribution with the given URI.
+ *
+ * @param contributionURI
+ * @param contributionLocation
+ * @return
+ * @throws NotFoundException
+ */
+ private Contribution contribution(String contributionURI,
+ String contributionLocation) throws ContributionReadException {
+ try {
+ URI uri = URI.create(contributionURI);
+ URL location = locationURL(contributionLocation);
+
+ // Get contribution from cache
+ ContributionCache contributionCache = cache.contributions
+ .get(location);
+ long lastModified = lastModified(location);
+ if (contributionCache != null) {
+ if (contributionCache.contributionLastModified == lastModified) {
+ return contributionCache.contribution;
+ }
+
+ // Reset contribution cache
+ cache.contributions.remove(location);
+ }
+
+ Contribution contribution = (Contribution) contributionProcessor
+ .read(null, uri, location);
+
+ // TODO - analyse dependencies here?
+
+ // contributionProcessor.resolve(contribution, new
+ // DefaultModelResolver());
+
+ // Cache contribution
+ contributionCache = new ContributionCache();
+ contributionCache.contribution = contribution;
+ contributionCache.contributionLastModified = lastModified;
+ cache.contributions.put(location, contributionCache);
+
+ return contribution;
+
+ } catch (ContributionReadException e) {
+ throw e;
+ } catch (MalformedURLException e) {
+ throw new ContributionReadException(e);
+ // } catch (ContributionResolveException e) {
+ // throw new ContributionReadException(e);
+ } catch (Throwable e) {
+ throw new ContributionReadException(e);
+ }
+ }
+
+ /**
+ * Returns the entry contents describing a composite.
+ *
+ * @param composite
+ * @return
+ */
+ private static String content(Composite composite) {
+ StringBuffer sb = new StringBuffer();
+ List<Component> components = composite.getComponents();
+ for (int i = 0, n = components.size(); i < n; i++) {
+ Component component = components.get(i);
+ if (component.getImplementation() instanceof NodeImplementation) {
+ List<ComponentService> services = component.getServices();
+ if (!services.isEmpty()) {
+ List<Binding> bindings = services.get(0).getBindings();
+ if (!bindings.isEmpty()) {
+
+ // List node URIs
+ sb.append("Node URI: <span id=\"nodeURI\">");
+ sb.append(component.getServices().get(0).getBindings()
+ .get(0).getURI());
+ break;
+ }
+ }
+ } else {
+
+ // List component names
+ if (sb.length() == 0) {
+ sb.append("Components: <span id=\"components\">");
+ } else {
+ sb.append(" ");
+ }
+ sb.append(component.getName());
+ }
+ }
+ if (sb.length() != 0) {
+ sb.append("</span>");
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Returns the link to the resource related to a composite.
+ *
+ * @param composite
+ * @return
+ */
+ private static String relatedLink(Composite composite) {
+ for (Component component : composite.getComponents()) {
+ if (component.getImplementation() instanceof NodeImplementation) {
+ NodeImplementation nodeImplementation = (NodeImplementation) component
+ .getImplementation();
+ Composite deployable = nodeImplementation.getComposite();
+ String contributionURI = deployable.getURI();
+ QName qname = deployable.getName();
+ String key = compositeKey(contributionURI, qname);
+ return "/composite-source/" + key;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns an entry describing the given deployable.
+ *
+ * @param contribution
+ * @param deployable
+ * @return
+ */
+ private static Entry<String, Item> entry(Contribution contribution,
+ Composite deployable) {
+ Entry<String, Item> entry = new Entry<String, Item>();
+ entry.setKey(DomainManagerUtil.compositeKey(contribution.getURI(),
+ deployable.getName()));
+ entry.setData(item(contribution, deployable));
+ return entry;
+ }
+
+ /**
+ * Returns an item describing the given deployable.
+ *
+ * @param contribution
+ * @param deployable
+ * @return
+ */
+ private static Item item(Contribution contribution, Composite deployable) {
+ String contributionURI = contribution.getURI();
+ String contributionLocation = contribution.getLocation();
+ QName qname = deployable.getName();
+ String deployableURI = deployable.getURI();
+ Item item = new Item();
+ item.setTitle(compositeTitle(contributionURI, qname));
+ item.setContents(content(deployable));
+ item.setLink(compositeSourceLink(contributionURI, qname));
+ item.setAlternate(compositeAlternateLink(contributionLocation,
+ deployableURI));
+ item.setRelated(relatedLink(deployable));
+ return item;
+ }
+
+}
diff --git a/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/DeployableCompositeServiceImpl.java b/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/DeployableCompositeServiceImpl.java
new file mode 100644
index 0000000000..14ab9579f4
--- /dev/null
+++ b/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/DeployableCompositeServiceImpl.java
@@ -0,0 +1,128 @@
+/*
+ * 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.manager.impl;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLDecoder;
+import java.util.logging.Logger;
+
+import javax.servlet.Servlet;
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.data.collection.Item;
+import org.apache.tuscany.sca.data.collection.LocalItemCollection;
+import org.apache.tuscany.sca.data.collection.NotFoundException;
+import org.osoa.sca.annotations.Init;
+import org.osoa.sca.annotations.Reference;
+import org.osoa.sca.annotations.Scope;
+import org.osoa.sca.annotations.Service;
+
+/**
+ * Implementation of a service that returns the source of a deployable composite.
+ *
+ * @version $Rev$ $Date$
+ */
+@Scope("COMPOSITE")
+@Service(Servlet.class)
+public class DeployableCompositeServiceImpl extends HttpServlet implements Servlet {
+ private static final long serialVersionUID = -3477992129462720902L;
+
+ private static final Logger logger = Logger.getLogger(DeployableCompositeServiceImpl.class.getName());
+
+ @Reference
+ public DomainManagerConfiguration domainManagerConfiguration;
+
+ @Reference
+ public LocalItemCollection deployableCollection;
+
+ /**
+ * Initialize the component.
+ */
+ @Init
+ public void initialize() throws ParserConfigurationException {
+
+ ExtensionPointRegistry extensionPoints = domainManagerConfiguration.getExtensionPoints();
+ }
+
+ @Override
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+
+ // Expect a key in the form
+ // composite:contributionURI;namespace;localName
+ // and return the corresponding source file
+
+ // Get the request path
+ String path = URLDecoder.decode(request.getRequestURI().substring(request.getServletPath().length()), "UTF-8");
+ String key = path.startsWith("/")? path.substring(1) : path;
+ logger.fine("get " + key);
+
+ // Get the item describing the composite
+ Item item;
+ try {
+ item = deployableCollection.get(key);
+ } catch (NotFoundException e) {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND, key);
+ return;
+ }
+
+ // Redirect if there is no composite file
+ String uri = item.getAlternate();
+ if (uri == null) {
+ response.sendRedirect("/composite-generated/" + key);
+ return;
+ }
+
+ // Read the composite file and write to response
+ InputStream is;
+ try {
+ URLConnection connection = new URL(uri).openConnection();
+ connection.setUseCaches(false);
+ connection.connect();
+ is = connection.getInputStream();
+ } catch (FileNotFoundException ex) {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND, key);
+ return;
+ }
+
+ response.setContentType("text/xml");
+ ServletOutputStream os = response.getOutputStream();
+ byte[] buffer = new byte[4096];
+ for (;;) {
+ int n = is.read(buffer);
+ if (n < 0) {
+ break;
+ }
+ os.write(buffer, 0, n);
+ }
+ is.close();
+ os.flush();
+ }
+
+}
diff --git a/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/DeployedCompositeCollectionImpl.java b/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/DeployedCompositeCollectionImpl.java
new file mode 100644
index 0000000000..6501f2c4b9
--- /dev/null
+++ b/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/DeployedCompositeCollectionImpl.java
@@ -0,0 +1,417 @@
+/*
+ * 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.manager.impl;
+
+import static org.apache.tuscany.sca.domain.manager.impl.DomainManagerUtil.DEPLOYMENT_CONTRIBUTION_URI;
+import static org.apache.tuscany.sca.domain.manager.impl.DomainManagerUtil.compositeKey;
+import static org.apache.tuscany.sca.domain.manager.impl.DomainManagerUtil.compositeQName;
+import static org.apache.tuscany.sca.domain.manager.impl.DomainManagerUtil.compositeSourceLink;
+import static org.apache.tuscany.sca.domain.manager.impl.DomainManagerUtil.compositeTitle;
+import static org.apache.tuscany.sca.domain.manager.impl.DomainManagerUtil.contributionURI;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.xml.namespace.QName;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.stream.XMLStreamWriter;
+
+import org.apache.tuscany.sca.assembly.AssemblyFactory;
+import org.apache.tuscany.sca.assembly.Composite;
+import org.apache.tuscany.sca.assembly.xml.Constants;
+import org.apache.tuscany.sca.contribution.Contribution;
+import org.apache.tuscany.sca.contribution.ModelFactoryExtensionPoint;
+import org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor;
+import org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessorExtensionPoint;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.data.collection.Entry;
+import org.apache.tuscany.sca.data.collection.Item;
+import org.apache.tuscany.sca.data.collection.ItemCollection;
+import org.apache.tuscany.sca.data.collection.LocalItemCollection;
+import org.apache.tuscany.sca.data.collection.NotFoundException;
+import org.apache.tuscany.sca.domain.search.DomainSearch;
+import org.apache.tuscany.sca.domain.search.IndexException;
+import org.apache.xml.serialize.OutputFormat;
+import org.apache.xml.serialize.XMLSerializer;
+import org.osoa.sca.ServiceRuntimeException;
+import org.osoa.sca.annotations.Init;
+import org.osoa.sca.annotations.Property;
+import org.osoa.sca.annotations.Reference;
+import org.osoa.sca.annotations.Scope;
+import org.osoa.sca.annotations.Service;
+import org.w3c.dom.Document;
+
+/**
+ * Implementation of a composite collection service.
+ *
+ * @version $Rev$ $Date$
+ */
+@Scope("COMPOSITE")
+@Service(interfaces={ItemCollection.class,LocalItemCollection.class})
+public class DeployedCompositeCollectionImpl implements ItemCollection, LocalItemCollection {
+ private static final Logger logger = Logger.getLogger(DeployedCompositeCollectionImpl.class.getName());
+
+ @Property
+ public String compositeFile;
+
+ @Property
+ public String deploymentContributionDirectory;
+
+ @Reference
+ public LocalItemCollection deployableCollection;
+
+ @Reference
+ public DomainSearch domainSearch;
+
+ @Reference(required=false)
+ public LocalItemCollection processCollection;
+
+ @Reference
+ public DomainManagerConfiguration domainManagerConfiguration;
+
+ @Reference
+ public ContributionsReader contributionReader;
+
+ private ModelFactoryExtensionPoint modelFactories;
+ private AssemblyFactory assemblyFactory;
+ private StAXArtifactProcessor<Composite> compositeProcessor;
+ private XMLOutputFactory outputFactory;
+ private DocumentBuilder documentBuilder;
+
+ /**
+ * Cache domain composite model.
+ */
+ static class Cache {
+ private Composite compositeCollection;
+ private long compositeCollectionLastModified;
+ }
+
+ private Cache cache = new Cache();
+
+ /**
+ * Initialize the component.
+ */
+ @Init
+ public void initialize() throws ParserConfigurationException {
+
+ // Create factories
+ ExtensionPointRegistry extensionPoints = domainManagerConfiguration.getExtensionPoints();
+ modelFactories = extensionPoints.getExtensionPoint(ModelFactoryExtensionPoint.class);
+ assemblyFactory = modelFactories.getFactory(AssemblyFactory.class);
+ outputFactory = modelFactories.getFactory(XMLOutputFactory.class);
+ outputFactory.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true);
+
+ // Create composite processor
+ StAXArtifactProcessorExtensionPoint staxProcessors = extensionPoints.getExtensionPoint(StAXArtifactProcessorExtensionPoint.class);
+ compositeProcessor = staxProcessors.getProcessor(Composite.class);
+
+ // Create a document builder (used to pretty print XML)
+ documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+ }
+
+ public Entry<String, Item>[] getAll() {
+ logger.fine("getAll");
+
+ // Return all the composites in the domain composite
+ List<Entry<String, Item>> entries = new ArrayList<Entry<String, Item>>();
+ Composite compositeCollection = readCompositeCollection();
+ for (Composite composite: compositeCollection.getIncludes()) {
+ String contributionURI = composite.getURI();
+ QName qname = composite.getName();
+ String key = compositeKey(contributionURI, qname);
+ Item item;
+ try {
+ item = deployableCollection.get(key);
+ } catch (NotFoundException e) {
+ item = new Item();
+ item.setTitle(compositeTitle(contributionURI, qname));
+ item.setLink(compositeSourceLink(contributionURI, qname));
+ item.setContents("<span id=\"problem\" style=\"color: red\">Problem: Composite not found</span>");
+ }
+ Entry<String, Item> entry = new Entry<String, Item>();
+ entry.setKey(key);
+ entry.setData(item);
+ entries.add(entry);
+ }
+ return entries.toArray(new Entry[entries.size()]);
+ }
+
+ public Item get(String key) throws NotFoundException {
+ logger.fine("get " + key);
+
+ String contributionURI = contributionURI(key);
+ QName qname = compositeQName(key);
+
+ // Look for the specified composite in the domain composite
+ List<Entry<String, Item>> entries = new ArrayList<Entry<String, Item>>();
+ Composite compositeCollection = readCompositeCollection();
+ for (Composite composite: compositeCollection.getIncludes()) {
+ if (contributionURI.equals(composite.getURI()) && qname.equals(composite.getName())) {
+ return deployableCollection.get(key);
+ }
+ }
+ throw new NotFoundException(key);
+ }
+
+ public String post(String key, Item item) {
+ logger.fine("post " + key);
+
+ String contributionURI = contributionURI(key);
+ QName qname = compositeQName(key);
+
+ // Adds a new composite to the domain composite
+ Composite compositeCollection = readCompositeCollection();
+ Composite composite = assemblyFactory.createComposite();
+ composite.setName(qname);
+ composite.setURI(contributionURI);
+ composite.setUnresolved(true);
+ compositeCollection.getIncludes().add(composite);
+
+ // Optionally, write the composite contents in a new composite file
+ // under the deployment composites directory, if that directory is
+ // configured on this component
+ if (deploymentContributionDirectory != null && item.getContents() != null) {
+ String rootDirectory = domainManagerConfiguration.getRootDirectory();
+
+ File directory = new File(rootDirectory + "/" + deploymentContributionDirectory);
+ if (!directory.exists()) {
+ directory.mkdirs();
+ }
+ File file = new File(directory, qname.getLocalPart() + ".composite");
+ try {
+ Writer w = new OutputStreamWriter(new FileOutputStream(file));
+ w.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+ w.write(item.getContents());
+ w.close();
+ } catch (IOException e) {
+ throw new ServiceRuntimeException(e);
+ }
+ }
+
+ // Write the composite collection
+ writeCompositeCollection(compositeCollection);
+
+ updateDomainSearch(contributionURI);
+
+ return key;
+ }
+
+ public void put(String key, Item item) throws NotFoundException {
+ logger.fine("put " + key);
+
+ String contributionURI = contributionURI(key);
+ QName qname = compositeQName(key);
+
+ // Update a composite already in the domain composite
+ Composite compositeCollection = readCompositeCollection();
+ Composite newComposite = assemblyFactory.createComposite();
+ newComposite.setName(qname);
+ newComposite.setURI(contributionURI);
+ newComposite.setUnresolved(true);
+ List<Composite> composites = compositeCollection.getIncludes();
+ for (int i = 0, n = composites.size(); i < n; i++) {
+ Composite composite = composites.get(i);
+ if (contributionURI.equals(composite.getURI()) && qname.equals(composite.getName())) {
+ composites.set(i, newComposite);
+
+ // Write the domain composite
+ writeCompositeCollection(compositeCollection);
+
+ updateDomainSearch(contributionURI);
+
+ return;
+ }
+ }
+ throw new NotFoundException(key);
+ }
+
+ public void delete(String key) throws NotFoundException {
+ logger.fine("delete " + key);
+
+ String contributionURI = contributionURI(key);
+ QName qname = compositeQName(key);
+
+ // Delete/stop the corresponding process, if any
+ try {
+ processCollection.delete(qname.getLocalPart());
+ } catch (Exception e) {}
+
+ // Delete a composite from the composite collection
+ Composite compositeCollection = readCompositeCollection();
+ List<Composite> composites = compositeCollection.getIncludes();
+ Composite deleted = null;
+ for (int i = 0, n = composites.size(); i < n; i++) {
+ Composite composite = composites.get(i);
+ if (contributionURI.equals(composite.getURI()) && qname.equals(composite.getName())) {
+ composites.remove(i);
+ deleted = composite;
+
+ // Write the domain composite
+ writeCompositeCollection(compositeCollection);
+ updateDomainSearch(contributionURI);
+
+ break;
+
+ }
+ }
+
+ // Delete the file too if it is in the deployment contribution directory
+ if (deploymentContributionDirectory != null && contributionURI.equals(DEPLOYMENT_CONTRIBUTION_URI)) {
+ String rootDirectory = domainManagerConfiguration.getRootDirectory();
+
+ File file = new File(rootDirectory + "/" + deploymentContributionDirectory, qname.getLocalPart() + ".composite");
+ if (file.exists()) {
+ file.delete();
+ }
+ }
+
+ if (deleted == null) {
+ throw new NotFoundException(key);
+ }
+ }
+
+ private void updateDomainSearch(String contributionURI) {
+ Contribution[] contributions = this.contributionReader.readContributions();
+
+ for (Contribution contribution : contributions) {
+
+ if (contributionURI.equals(contribution.getURI())) {
+
+ try {
+ this.domainSearch.updateContribution(contribution, contribution);
+
+ } catch (IndexException e) {
+ logger.log(Level.WARNING, "Could not update contribution " + contribution.getURI() + " on the index, reason: " + e.getMessage());
+ }
+
+ break;
+
+ }
+
+ }
+
+ }
+
+ public Entry<String, Item>[] query(String queryString) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Reads the domain composite.
+ *
+ * @return the domain composite
+ * @throws ServiceRuntimeException
+ */
+ private Composite readCompositeCollection() throws ServiceRuntimeException {
+ String rootDirectory = domainManagerConfiguration.getRootDirectory();
+
+ Composite compositeCollection;
+ File file = new File(rootDirectory + "/" + compositeFile);
+ if (file.exists()) {
+
+ // Get composite collection from cache
+ if (cache.compositeCollection != null && file.lastModified() == cache.compositeCollectionLastModified) {
+ compositeCollection = cache.compositeCollection;
+
+ } else {
+
+ XMLInputFactory inputFactory = modelFactories.getFactory(XMLInputFactory.class);
+ try {
+ FileInputStream is = new FileInputStream(file);
+ XMLStreamReader reader = inputFactory.createXMLStreamReader(is);
+ compositeCollection = compositeProcessor.read(reader);
+ } catch (Exception e) {
+ throw new ServiceRuntimeException(e);
+ }
+
+ // Cache composite collection
+ cache.compositeCollectionLastModified = file.lastModified();
+ cache.compositeCollection = compositeCollection;
+ }
+
+ } else {
+ compositeCollection = assemblyFactory.createComposite();
+ String name;
+ int d = compositeFile.lastIndexOf('.');
+ if (d != -1) {
+ name = compositeFile.substring(0, d);
+ } else {
+ name = compositeFile;
+ }
+ compositeCollection.setName(new QName(Constants.SCA10_TUSCANY_NS, name));
+
+ // Cache composite collection
+ cache.compositeCollectionLastModified = 0;
+ cache.compositeCollection = compositeCollection;
+ }
+ return compositeCollection;
+ }
+
+ /**
+ * Write the domain composite back to disk.
+ *
+ * @param compositeCollection
+ */
+ private void writeCompositeCollection(Composite compositeCollection) {
+ try {
+ String rootDirectory = domainManagerConfiguration.getRootDirectory();
+
+ // First write to a byte stream
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ XMLStreamWriter writer = outputFactory.createXMLStreamWriter(bos);
+ compositeProcessor.write(compositeCollection, writer);
+
+ // Parse again to pretty format the document
+ Document document = documentBuilder.parse(new ByteArrayInputStream(bos.toByteArray()));
+ OutputFormat format = new OutputFormat();
+ format.setIndenting(true);
+ format.setIndent(2);
+
+ // Write to domain.composite
+ File file = new File(rootDirectory + "/" + compositeFile);
+ FileOutputStream os = new FileOutputStream(file);
+ XMLSerializer serializer = new XMLSerializer(os, format);
+ serializer.serialize(document);
+
+ // Cache composite collection
+ cache.compositeCollection = compositeCollection;
+ cache.compositeCollectionLastModified = file.lastModified();
+
+ } catch (Exception e) {
+ throw new ServiceRuntimeException(e);
+ }
+ }
+
+}
diff --git a/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/DomainManagerConfiguration.java b/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/DomainManagerConfiguration.java
new file mode 100644
index 0000000000..1831728f07
--- /dev/null
+++ b/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/DomainManagerConfiguration.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.domain.manager.impl;
+
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+
+/**
+ * Domain manager configuration service interface.
+ *
+ * @version $Rev$ $Date$
+ */
+public interface DomainManagerConfiguration {
+
+ /**
+ * Sets the domain manager root directory.
+ *
+ * @param rootDirectory
+ */
+ void setRootDirectory(String rootDirectory);
+
+ /**
+ * Returns the domain manager root directory.
+ *
+ * @return the domain manager root directory
+ */
+ String getRootDirectory();
+
+ /**
+ * Returns the extension point registry used in the
+ * domain manager.
+ *
+ * @return
+ */
+ ExtensionPointRegistry getExtensionPoints();
+
+}
diff --git a/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/DomainManagerConfigurationImpl.java b/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/DomainManagerConfigurationImpl.java
new file mode 100644
index 0000000000..a5ce6e12d6
--- /dev/null
+++ b/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/DomainManagerConfigurationImpl.java
@@ -0,0 +1,85 @@
+/*
+ * 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.manager.impl;
+
+import org.apache.tuscany.sca.core.DefaultExtensionPointRegistry;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.core.ModuleActivator;
+import org.apache.tuscany.sca.core.ModuleActivatorExtensionPoint;
+import org.osoa.sca.annotations.Destroy;
+import org.osoa.sca.annotations.Init;
+import org.osoa.sca.annotations.Scope;
+import org.osoa.sca.annotations.Service;
+
+/**
+ * Implementation of a domain manager configuration component.
+ *
+ * @version $Rev$ $Date$
+ */
+@Scope("COMPOSITE")
+@Service(DomainManagerConfiguration.class)
+public class DomainManagerConfigurationImpl implements DomainManagerConfiguration {
+
+ private String rootDirectory = ".";
+ private ExtensionPointRegistry extensionPoints;
+
+ @Init
+ public void initialize() {
+
+ // Create extension point registry
+ extensionPoints = new DefaultExtensionPointRegistry();
+
+ // Initialize module activators
+ ModuleActivatorExtensionPoint moduleActivators = extensionPoints.getExtensionPoint(ModuleActivatorExtensionPoint.class);
+ for (ModuleActivator activator: moduleActivators.getModuleActivators()) {
+ try {
+ activator.start(extensionPoints);
+ } catch (Exception e) {
+ //FIXME fix the module activators that have cross module dependencies
+ // and currently fail when the whole runtime is not present
+ }
+ }
+ }
+
+ @Destroy
+ public void destroy() {
+ ModuleActivatorExtensionPoint moduleActivators = extensionPoints.getExtensionPoint(ModuleActivatorExtensionPoint.class);
+ for (ModuleActivator activator: moduleActivators.getModuleActivators()) {
+ try {
+ activator.stop(extensionPoints);
+ } catch (Exception e) {
+ //FIXME fix the module activators that have cross module dependencies
+ // and currently fail when the whole runtime is not present
+ }
+ }
+ }
+
+ public String getRootDirectory() {
+ return rootDirectory;
+ }
+
+ public void setRootDirectory(String rootDirectory) {
+ this.rootDirectory = rootDirectory;
+ }
+
+ public ExtensionPointRegistry getExtensionPoints() {
+ return extensionPoints;
+ }
+}
diff --git a/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/DomainManagerUtil.java b/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/DomainManagerUtil.java
new file mode 100644
index 0000000000..c015689cf1
--- /dev/null
+++ b/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/DomainManagerUtil.java
@@ -0,0 +1,295 @@
+/*
+ * 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.manager.impl;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLConnection;
+
+import javax.xml.namespace.QName;
+
+import org.apache.tuscany.sca.assembly.AssemblyFactory;
+import org.apache.tuscany.sca.assembly.Binding;
+import org.apache.tuscany.sca.assembly.Composite;
+import org.apache.tuscany.sca.core.assembly.CompositeActivator;
+import org.apache.tuscany.sca.core.context.ServiceReferenceImpl;
+import org.apache.tuscany.sca.core.invocation.ProxyFactory;
+import org.apache.tuscany.sca.interfacedef.InterfaceContract;
+import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceFactory;
+import org.apache.tuscany.sca.runtime.RuntimeComponent;
+import org.apache.tuscany.sca.runtime.RuntimeComponentReference;
+import org.osoa.sca.ServiceReference;
+import org.osoa.sca.ServiceRuntimeException;
+
+/**
+ * Common functions and constants used by the admin components.
+ *
+ * @version $Rev$ $Date$
+ */
+public final class DomainManagerUtil {
+
+ static final String DEPLOYMENT_CONTRIBUTION_URI = "http://tuscany.apache.org/cloud";
+
+ /**
+ * Extracts a qname from a key expressed as contributionURI;namespace;localpart.
+ * @param key
+ * @return
+ */
+ static QName compositeQName(String key) {
+ int i = key.indexOf(';');
+ key = key.substring(i + 1);
+ i = key.indexOf(';');
+ return new QName(key.substring(0, i), key.substring(i + 1));
+ }
+
+ /**
+ * Returns a composite title expressed as contributionURI - namespace;localpart.
+ * @param qname
+ * @return
+ */
+ static String compositeTitle(String uri, QName qname) {
+ if (uri.equals(DEPLOYMENT_CONTRIBUTION_URI)) {
+ return qname.getLocalPart();
+ } else {
+ return uri + " - " + qname.getNamespaceURI() + ";" + qname.getLocalPart();
+ }
+ }
+
+ /**
+ * Extracts a contribution uri from a key expressed as contributionURI;namespace;localpart.
+ * @param key
+ * @return
+ */
+ static String contributionURI(String key) {
+ int i = key.indexOf(';');
+ return key.substring("composite:".length(), i);
+ }
+
+ /**
+ * Returns a composite key expressed as contributionURI;namespace;localpart.
+ * @param qname
+ * @return
+ */
+ static String compositeKey(String uri, QName qname) {
+ return "composite:" + uri + ';' + qname.getNamespaceURI() + ';' + qname.getLocalPart();
+ }
+
+ /**
+ * Returns a link to the source of a composite
+ * @param contributionURI
+ * @param qname
+ * @return
+ */
+ static String compositeSourceLink(String contributionURI, QName qname) {
+ return "/composite-source/" + compositeKey(contributionURI, qname);
+ }
+
+ /**
+ * Returns a composite title expressed as contributionURI - namespace;localpart.
+ * @param qname
+ * @return
+ */
+ static String compositeSimpleTitle(String uri, QName qname) {
+ if (uri.equals(DomainManagerUtil.DEPLOYMENT_CONTRIBUTION_URI)) {
+ return qname.getLocalPart();
+ } else {
+ return qname.getNamespaceURI() + ";" + qname.getLocalPart();
+ }
+ }
+
+ /**
+ * Returns a URL from a location string.
+ * @param location
+ * @return
+ * @throws MalformedURLException
+ */
+ static URL locationURL(String location) throws MalformedURLException {
+ String scheme = null;
+ URI uri = null;
+
+ IllegalArgumentException uriException = null;
+ try {
+ uri = URI.create(location);
+ scheme = uri.getScheme();
+ }catch (java.lang.IllegalArgumentException e) {
+ uriException = e;
+ }
+
+ if (scheme == null) {
+ File file = new File(location);
+ return file.toURI().toURL();
+ } else if (scheme.equals("file")) {
+ File file = new File(location.substring(5));
+ return file.toURI().toURL();
+ } else if(uri == null){
+ throw uriException;
+ } else {
+ return uri.toURL();
+ }
+ }
+
+ /**
+ * Returns a link to a deployable composite.
+ *
+ * If the containing contribution is a local directory, return the URI of the local composite file
+ * inside the contribution.
+ *
+ * If the containing contribution is a local or remote file, return a URI of the form:
+ * jar: contribution URI !/ composite URI.
+ *
+ * @param contributionLocation
+ * @param deployableURI
+ * @return
+ */
+ static String compositeAlternateLink(String contributionLocation, String deployableURI) {
+ if (deployableURI == null) {
+ return null;
+ }
+ URI u = URI.create(contributionLocation);
+ String uri;
+ if ("file".equals(u.getScheme())) {
+ String path = u.toString().substring(5);
+ File file = new File(path);
+ if (file.isDirectory()) {
+ if (contributionLocation.endsWith("/")) {
+ uri = contributionLocation + deployableURI;
+ } else {
+ uri = contributionLocation + "/" + deployableURI;
+ }
+ } else {
+ uri = contributionLocation + "!/" + deployableURI;
+ }
+ } else {
+ uri = contributionLocation + "!/" + deployableURI;
+ }
+ int e = uri.indexOf("!/");
+ if (e != -1) {
+ int s = uri.lastIndexOf('/', e - 2) +1;
+ if (uri.substring(s, e).contains(".")) {
+ uri = "jar:" + uri;
+ } else {
+ uri = uri.substring(0, e) + uri.substring(e + 1);
+ }
+ }
+ return uri;
+ }
+
+ /**
+ * Extract a node URI from an ATOM entry content.
+ *
+ * @param content
+ * @return
+ */
+ static String nodeURI(String content) {
+ if (content != null) {
+ int bs = content.indexOf("<span id=\"nodeURI\">");
+ if (bs != -1) {
+ content = content.substring(bs + 19);
+ int es = content.indexOf("</span>");
+ if (es != -1) {
+ return content.substring(0, es);
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Create a new service reference dynamically.
+ *
+ * @param <B>
+ * @param businessInterface
+ * @param binding
+ * @param assemblyFactory
+ * @param compositeActivator
+ * @return
+ */
+ static <B> ServiceReference<B> dynamicReference(Class<B> businessInterface, Binding binding, AssemblyFactory assemblyFactory, CompositeActivator compositeActivator) {
+ try {
+
+ Composite composite = assemblyFactory.createComposite();
+ composite.setName(new QName("http://tuscany.apache.org/xmlns/sca/1.0", "default"));
+ RuntimeComponent component = (RuntimeComponent)assemblyFactory.createComponent();
+ component.setName("default");
+ component.setURI("default");
+ compositeActivator.configureComponentContext(component);
+ composite.getComponents().add(component);
+ RuntimeComponentReference reference = (RuntimeComponentReference)assemblyFactory.createComponentReference();
+ reference.setName("default");
+ JavaInterfaceFactory javaInterfaceFactory = compositeActivator.getJavaInterfaceFactory();
+ InterfaceContract interfaceContract = javaInterfaceFactory.createJavaInterfaceContract();
+ interfaceContract.setInterface(javaInterfaceFactory.createJavaInterface(businessInterface));
+ reference.setInterfaceContract(interfaceContract);
+ component.getReferences().add(reference);
+ reference.setComponent(component);
+ reference.getBindings().add(binding);
+
+ ProxyFactory proxyFactory = compositeActivator.getProxyFactory();
+ return new ServiceReferenceImpl<B>(businessInterface, component, reference, binding, proxyFactory, compositeActivator);
+
+ } catch (Exception e) {
+ throw new ServiceRuntimeException(e);
+ }
+ }
+
+ /**
+ * Returns the last modified time of the content at the given URL.
+ *
+ * @param url
+ * @return
+ * @throws IOException
+ */
+ static long lastModified(URL url) throws IOException {
+
+ if (url.getProtocol() == null || "file".equals(url.getProtocol())) {
+ return lastModified(new File(url.getPath()));
+ } else {
+ URLConnection connection = url.openConnection();
+ long lastModified = connection.getLastModified();
+ return lastModified;
+ }
+ }
+
+ /**
+ * Returns the last modified time of the given file or directory.
+ *
+ * @param file
+ * @return
+ */
+ static long lastModified(File file) {
+ if (file.isDirectory()) {
+ long lastModified = file.lastModified();
+
+ for (File child: file.listFiles()) {
+ long m = lastModified(child);
+ if (m > lastModified) {
+ lastModified = m;
+ }
+ }
+ return lastModified;
+
+ } else {
+ return file.lastModified();
+ }
+ }
+}
diff --git a/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/FileCollectionImpl.java b/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/FileCollectionImpl.java
new file mode 100644
index 0000000000..a53250515a
--- /dev/null
+++ b/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/FileCollectionImpl.java
@@ -0,0 +1,136 @@
+/*
+ * 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.manager.impl;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Logger;
+
+import org.apache.tuscany.sca.data.collection.Entry;
+import org.apache.tuscany.sca.data.collection.Item;
+import org.apache.tuscany.sca.data.collection.ItemCollection;
+import org.apache.tuscany.sca.data.collection.NotFoundException;
+import org.osoa.sca.annotations.Init;
+import org.osoa.sca.annotations.Property;
+import org.osoa.sca.annotations.Reference;
+import org.osoa.sca.annotations.Scope;
+import org.osoa.sca.annotations.Service;
+
+/**
+ * Implementation of a file collection service component.
+ *
+ * @version $Rev$ $Date$
+ */
+@Scope("COMPOSITE")
+@Service(ItemCollection.class)
+public class FileCollectionImpl implements ItemCollection {
+
+ private static final Logger logger = Logger.getLogger(FileCollectionImpl.class.getName());
+
+ @Property
+ public String directoryName;
+
+ @Reference
+ public DomainManagerConfiguration domainManagerConfiguration;
+
+ /**
+ * Initialize the component.
+ */
+ @Init
+ public void initialize() throws IOException {
+ }
+
+ public Entry<String, Item>[] getAll() {
+ logger.fine("getAll");
+
+ String rootDirectory = domainManagerConfiguration.getRootDirectory();
+
+ // Return all the files
+ List<Entry<String, Item>> entries = new ArrayList<Entry<String, Item>>();
+ File directory = new File(rootDirectory + "/" + directoryName);
+ if (directory.exists()) {
+ for (File file: directory.listFiles()) {
+ if (file.getName().startsWith(".")) {
+ continue;
+ }
+ entries.add(entry(file.getName()));
+ }
+ }
+ return entries.toArray(new Entry[entries.size()]);
+ }
+
+ public Item get(String key) throws NotFoundException {
+ logger.fine("get " + key);
+ return item(key);
+ }
+
+ public String post(String key, Item item) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void put(String key, Item item) throws NotFoundException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void delete(String key) throws NotFoundException {
+ logger.fine("delete " + key);
+
+ String rootDirectory = domainManagerConfiguration.getRootDirectory();
+ File directory = new File(rootDirectory + "/" + directoryName);
+ File file = new File(directory, key);
+ if (file.exists()) {
+ file.delete();
+ } else {
+ throw new NotFoundException(key);
+ }
+ }
+
+ public Entry<String, Item>[] query(String queryString) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Returns an entry representing a file.
+ *
+ * @param fileName
+ * @return
+ */
+ private static Entry<String, Item> entry(String fileName) {
+ Entry<String, Item> entry = new Entry<String, Item>();
+ entry.setKey(fileName);
+ entry.setData(item(fileName));
+ return entry;
+ }
+
+ /**
+ * Returns an item representing a file.
+ *
+ * @param fileName
+ * @return
+ */
+ private static Item item(String fileName) {
+ Item item = new Item();
+ item.setTitle(fileName);
+ item.setLink("/files/" + fileName);
+ return item;
+ }
+}
diff --git a/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/FileServiceImpl.java b/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/FileServiceImpl.java
new file mode 100644
index 0000000000..1493b73248
--- /dev/null
+++ b/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/FileServiceImpl.java
@@ -0,0 +1,210 @@
+/*
+ * 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.manager.impl;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URLConnection;
+import java.net.URLDecoder;
+import java.util.List;
+import java.util.logging.Logger;
+
+import javax.servlet.Servlet;
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.fileupload.FileItem;
+import org.apache.commons.fileupload.disk.DiskFileItemFactory;
+import org.apache.commons.fileupload.servlet.ServletFileUpload;
+import org.apache.tuscany.sca.data.collection.Item;
+import org.apache.tuscany.sca.data.collection.LocalItemCollection;
+import org.apache.tuscany.sca.data.collection.NotFoundException;
+import org.osoa.sca.annotations.Init;
+import org.osoa.sca.annotations.Property;
+import org.osoa.sca.annotations.Reference;
+import org.osoa.sca.annotations.Scope;
+import org.osoa.sca.annotations.Service;
+
+/**
+ * Implementation of a servlet component supporting file upload/download.
+ *
+ * @version $Rev$ $Date$
+ */
+@Scope("COMPOSITE")
+@Service(Servlet.class)
+public class FileServiceImpl extends HttpServlet {
+ private static final long serialVersionUID = -4560385595481971616L;
+
+ private static final Logger logger = Logger.getLogger(FileServiceImpl.class
+ .getName());
+
+ @Property
+ public String directoryName;
+
+ @Reference
+ public DomainManagerConfiguration domainManagerConfiguration;
+
+ @Reference
+ public LocalItemCollection contributionCollection;
+
+ private ServletFileUpload upload;
+
+ /**
+ * Initialize the component.
+ */
+ @Init
+ public void initialize() throws IOException {
+ upload = new ServletFileUpload(new DiskFileItemFactory());
+ }
+
+ @Override
+ public void doPost(HttpServletRequest request, HttpServletResponse response)
+ throws IOException {
+
+ // Upload files
+ String rootDirectory = domainManagerConfiguration.getRootDirectory();
+ try {
+ for (FileItem item : (List<FileItem>) upload.parseRequest(request)) {
+ if (!item.isFormField()) {
+ File directory = new File(rootDirectory + "/"
+ + directoryName);
+ if (!directory.exists()) {
+ directory.mkdirs();
+ }
+ logger.fine("post " + item.getName());
+ item.write(new File(directory, item.getName()));
+ }
+ }
+
+ // Redirect to the admin page
+ response.sendRedirect("/ui/files");
+ } catch (Exception e) {
+ throw new IOException(e.toString());
+ }
+ }
+
+ @Override
+ protected void doGet(HttpServletRequest request,
+ HttpServletResponse response) throws ServletException, IOException {
+
+ // Download a file
+ String requestURI = URLDecoder.decode(request.getRequestURI(), "UTF-8");
+ String path = requestURI.substring(request.getServletPath().length());
+ if (path.startsWith("/")) {
+ path = path.substring(1);
+ }
+ logger.fine("get " + path);
+
+ try {
+
+ // Analyze the given path
+ String artifactURI;
+ if (path.startsWith("contribution=")) {
+ int semicolonIndex = path.indexOf(';');
+ String contributionName = path.substring("contribution="
+ .length(), semicolonIndex);
+ artifactURI = path.substring(semicolonIndex + 1);
+
+ try {
+ Item item = this.contributionCollection
+ .get(contributionName);
+
+ if (item == null) {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+
+ return;
+
+ }
+
+ path = item.getAlternate();
+
+ } catch (NotFoundException e) {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+
+ return;
+
+ }
+
+ if (path.endsWith(".jar") || path.endsWith(".zip")) {
+ path = "jar:" + (path.startsWith("file:") ? "" : "file:") + path + '!' + (artifactURI.startsWith("/") ? "" : "/") + artifactURI;
+
+ } else {
+ path += (path.endsWith("/") ? "" : "/") + artifactURI;
+ }
+
+ } else {
+ artifactURI = null;
+ }
+
+ URI uri = URI.create(path);
+ String scheme = uri.getScheme();
+ if (scheme == null) {
+
+ if (artifactURI != null) {
+ uri = URI.create("file:" + uri.toString());
+
+ } else {
+
+ // If no scheme is specified then the path identifies file
+ // inside our directory
+ String rootDirectory = domainManagerConfiguration
+ .getRootDirectory();
+ uri = new File(rootDirectory + "/" + directoryName, path)
+ .toURI();
+
+ }
+
+ } else if (!scheme.equals("file") && !scheme.equals("jar")) {
+
+ // If the scheme does not identify a local file, just redirect
+ // to the server
+ // hosting the file
+ response.sendRedirect(path);
+ }
+
+ // Read the file and write to response
+ URLConnection connection = uri.toURL().openConnection();
+ connection.setUseCaches(false);
+ connection.connect();
+ InputStream is = connection.getInputStream();
+ ServletOutputStream os = response.getOutputStream();
+ byte[] buffer = new byte[4096];
+ for (;;) {
+ int n = is.read(buffer);
+ if (n < 0) {
+ break;
+ }
+ os.write(buffer, 0, n);
+ }
+ is.close();
+ os.flush();
+
+ } catch (FileNotFoundException e) {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ }
+ }
+
+}
diff --git a/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/NodeConfigurationServiceImpl.java b/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/NodeConfigurationServiceImpl.java
new file mode 100644
index 0000000000..06d28b0502
--- /dev/null
+++ b/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/NodeConfigurationServiceImpl.java
@@ -0,0 +1,96 @@
+/*
+ * 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.manager.impl;
+
+import static org.apache.tuscany.sca.domain.manager.impl.DomainManagerUtil.compositeQName;
+
+import java.io.IOException;
+import java.net.URLDecoder;
+import java.util.logging.Logger;
+
+import javax.servlet.Servlet;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.xml.namespace.QName;
+
+import org.apache.tuscany.sca.data.collection.Entry;
+import org.apache.tuscany.sca.data.collection.Item;
+import org.apache.tuscany.sca.data.collection.LocalItemCollection;
+import org.osoa.sca.annotations.Reference;
+import org.osoa.sca.annotations.Scope;
+import org.osoa.sca.annotations.Service;
+
+/**
+ * Implementation of a service that returns a node configuration.
+ *
+ * @version $Rev$ $Date$
+ */
+@Scope("COMPOSITE")
+@Service(Servlet.class)
+public class NodeConfigurationServiceImpl extends HttpServlet implements Servlet {
+ private static final long serialVersionUID = 6913769467386954463L;
+
+ private static final Logger logger = Logger.getLogger(NodeConfigurationServiceImpl.class.getName());
+
+ @Reference
+ public LocalItemCollection contributionCollection;
+
+ @Reference
+ public LocalItemCollection cloudCollection;
+
+ @Override
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+
+ // Get the request path
+ String path = URLDecoder.decode(request.getRequestURI().substring(request.getServletPath().length()), "UTF-8");
+ String key = path.startsWith("/")? path.substring(1) : path;
+ logger.fine("get " + key);
+
+ // The key contains a node name, redirect
+ // to the corresponding composite config
+
+ // Get the collection of cloud composites
+ Entry<String, Item>[] cloudEntries = cloudCollection.getAll();
+
+ // Find the specified node
+ for (Entry<String, Item> cloudEntry: cloudEntries) {
+ QName qname = compositeQName(cloudEntry.getKey());
+ if (qname.getLocalPart().equals(key)) {
+
+ // Found the specified node
+ String related = cloudEntry.getData().getRelated();
+ int i = related.indexOf("composite:");
+ if (i != -1) {
+
+ // Redirect to its composite config
+ String compositeConfiguration = "/composite-config/?composite=" + related.substring(i);
+ response.sendRedirect(compositeConfiguration);
+ return;
+ }
+ }
+ }
+
+ // Node not found
+ response.sendError(HttpServletResponse.SC_NOT_FOUND, key);
+ return;
+ }
+}
diff --git a/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/NodeProcessCollectionFacadeImpl.java b/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/NodeProcessCollectionFacadeImpl.java
new file mode 100644
index 0000000000..d68cfa3786
--- /dev/null
+++ b/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/NodeProcessCollectionFacadeImpl.java
@@ -0,0 +1,251 @@
+/*
+ * 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.manager.impl;
+
+import static org.apache.tuscany.sca.domain.manager.impl.DomainManagerUtil.compositeQName;
+import static org.apache.tuscany.sca.domain.manager.impl.DomainManagerUtil.nodeURI;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Logger;
+
+import javax.xml.namespace.QName;
+
+import org.apache.tuscany.sca.assembly.AssemblyFactory;
+import org.apache.tuscany.sca.binding.atom.AtomBindingFactory;
+import org.apache.tuscany.sca.contribution.ModelFactoryExtensionPoint;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.core.assembly.CompositeActivator;
+import org.apache.tuscany.sca.data.collection.Entry;
+import org.apache.tuscany.sca.data.collection.Item;
+import org.apache.tuscany.sca.data.collection.ItemCollection;
+import org.apache.tuscany.sca.data.collection.LocalItemCollection;
+import org.apache.tuscany.sca.data.collection.NotFoundException;
+import org.osoa.sca.ServiceRuntimeException;
+import org.osoa.sca.annotations.Init;
+import org.osoa.sca.annotations.Reference;
+import org.osoa.sca.annotations.Scope;
+import org.osoa.sca.annotations.Service;
+
+/**
+ * Implementation of a node process collection service.
+ *
+ * @version $Rev$ $Date$
+ */
+@Scope("COMPOSITE")
+@Service(interfaces={ItemCollection.class, LocalItemCollection.class})
+public class NodeProcessCollectionFacadeImpl implements ItemCollection, LocalItemCollection {
+
+ private static final Logger logger = Logger.getLogger(NodeProcessCollectionFacadeImpl.class.getName());
+
+ @Reference
+ public LocalItemCollection cloudCollection;
+
+ @Reference
+ public ItemCollection processCollection;
+
+ @Reference
+ public DomainManagerConfiguration domainManagerConfiguration;
+
+ private AssemblyFactory assemblyFactory;
+ private AtomBindingFactory atomBindingFactory;
+ private CompositeActivator compositeActivator;
+
+ /**
+ * Initialize the component.
+ */
+ @Init
+ public void initialize() {
+
+ // Get its composite activator
+ //FIXME
+ //compositeActivator = runtime.getCompositeActivator();
+
+ // Get the model factories
+ ExtensionPointRegistry extensionPoints = domainManagerConfiguration.getExtensionPoints();
+ ModelFactoryExtensionPoint modelFactories = extensionPoints.getExtensionPoint(ModelFactoryExtensionPoint.class);
+ assemblyFactory = modelFactories.getFactory(AssemblyFactory.class);
+ atomBindingFactory = modelFactories.getFactory(AtomBindingFactory.class);
+ }
+
+ public Entry<String, Item>[] getAll() {
+ logger.fine("getAll");
+
+ // Get the collection of nodes
+ Entry<String, Item>[] nodeEntries = cloudCollection.getAll();
+
+ // Dispatch to the hosts hosting these nodes
+ List<Entry<String, Item>> entries = new ArrayList<Entry<String,Item>>();
+ for (String host: hosts(nodeEntries)) {
+ ItemCollection processCollection = processCollection(host);
+ for (Entry<String, Item> remoteEntry: processCollection.getAll()) {
+ entries.add(remoteEntry);
+ }
+ break;
+ }
+
+ return entries.toArray(new Entry[entries.size()]);
+ }
+
+ public Item get(String key) throws NotFoundException {
+ logger.fine("get " + key);
+
+ // Get the host hosting the given node
+ String host = host(key);
+
+ // Dispatch the request to that host
+ ItemCollection processCollection = processCollection(host);
+ return processCollection.get(key);
+ }
+
+ public String post(String key, Item item) {
+ logger.fine("post " + key);
+
+ // Get the host hosting the given node
+ String host;
+ try {
+ host = host(key);
+ } catch (NotFoundException e) {
+ throw new ServiceRuntimeException(e);
+ }
+
+ // Dispatch the request to that host
+ ItemCollection processCollection = processCollection(host);
+ return processCollection.post(key, item);
+ }
+
+ public void put(String key, Item item) throws NotFoundException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void delete(String key) throws NotFoundException {
+ logger.fine("delete " + key);
+
+ // Get the host hosting the given node
+ String host = host(key);
+
+ // Dispatch the request to that host
+ ItemCollection processCollection = processCollection(host);
+ processCollection.delete(key);
+ }
+
+ public Entry<String, Item>[] query(String queryString) {
+ logger.fine("query " + queryString);
+
+ if (queryString.startsWith("node=")) {
+ String key = queryString.substring(queryString.indexOf('=') + 1);
+
+ // Get the host hosting the given node
+ String host;
+ try {
+ host = host(key);
+ } catch (NotFoundException e) {
+ return new Entry[0];
+ }
+
+ // Dispatch the request to that host
+ ItemCollection processCollection = processCollection(host);
+ return processCollection.query(queryString);
+
+ } else {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ private String host(String nodeName) throws NotFoundException {
+
+ // Get the entry representing the given node
+ Entry<String, Item> nodeEntry = nodeEntry(cloudCollection.getAll(), nodeName);
+ if (nodeEntry == null) {
+ throw new NotFoundException(nodeName);
+ }
+
+ // Get the host hosting it
+ return host(nodeEntry.getData());
+ }
+
+ /**
+ * Returns the entry representing the given node.
+ *
+ * @param entries
+ * @param name
+ * @return
+ */
+ private static Entry<String, Item> nodeEntry(Entry<String, Item>[] entries, String name) {
+ for (Entry<String, Item> entry: entries) {
+ QName qname = compositeQName(entry.getKey());
+ if (qname.getLocalPart().equals(name)) {
+ return entry;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the lists of hosts hosting the nodes in the given entries.
+ *
+ * @param entries
+ * @return
+ */
+ private static List<String> hosts(Entry<String, Item>[] entries) {
+ List<String> hosts = new ArrayList<String>();
+ for (Entry<String, Item> entry: entries) {
+ String host = host(entry.getData());
+ if (!hosts.contains(host)) {
+ hosts.add(host);
+ }
+ }
+ return hosts;
+ }
+
+ /**
+ * Returns the host of the node represented by the given item.
+ *
+ * @param item
+ * @return
+ */
+ private static String host(Item item) {
+ String uri = nodeURI(item.getContents());
+ if (uri != null) {
+ return URI.create(uri).getHost();
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Returns a proxy to the process collection service on the specified
+ * host.
+ *
+ * @param host
+ * @return
+ */
+ private ItemCollection processCollection(String host) {
+ return processCollection;
+
+//FIXME
+// AtomBinding binding = atomBindingFactory.createAtomBinding();
+// binding.setURI("http://" + host + ":9990/node/processes");
+// ServiceReference<ItemCollection> reference = dynamicReference(ItemCollection.class, binding, assemblyFactory, compositeActivator);
+// return reference.getService();
+ }
+
+}
diff --git a/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/QuickStartServiceImpl.java b/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/QuickStartServiceImpl.java
new file mode 100644
index 0000000000..9c2092656e
--- /dev/null
+++ b/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/QuickStartServiceImpl.java
@@ -0,0 +1,242 @@
+/*
+ * 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.manager.impl;
+
+import static org.apache.tuscany.sca.domain.manager.impl.DomainManagerUtil.compositeKey;
+import static org.apache.tuscany.sca.domain.manager.impl.DomainManagerUtil.compositeQName;
+import static org.apache.tuscany.sca.domain.manager.impl.DomainManagerUtil.contributionURI;
+import static org.apache.tuscany.sca.domain.manager.impl.DomainManagerUtil.nodeURI;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URLDecoder;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.servlet.Servlet;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.xml.namespace.QName;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.tuscany.sca.data.collection.Entry;
+import org.apache.tuscany.sca.data.collection.Item;
+import org.apache.tuscany.sca.data.collection.LocalItemCollection;
+import org.apache.tuscany.sca.data.collection.NotFoundException;
+import org.osoa.sca.annotations.Init;
+import org.osoa.sca.annotations.Reference;
+import org.osoa.sca.annotations.Scope;
+import org.osoa.sca.annotations.Service;
+
+/**
+ * Implementation of a component that provides a quick start path for a
+ * composite in a contribution.
+ *
+ * @version $Rev$ $Date$
+ */
+@Scope("COMPOSITE")
+@Service(interfaces={Servlet.class})
+public class QuickStartServiceImpl extends HttpServlet {
+ private static final long serialVersionUID = -3477992129462720901L;
+
+ private static final Logger logger = Logger.getLogger(QuickStartServiceImpl.class.getName());
+
+ @Reference
+ public LocalItemCollection contributionCollection;
+
+ @Reference
+ public LocalItemCollection deployableCollection;
+
+ @Reference
+ public LocalItemCollection domainCompositeCollection;
+
+ @Reference
+ public LocalItemCollection cloudCollection;
+
+ @Reference
+ public LocalItemCollection processCollection;
+
+ /**
+ * Initialize the component.
+ */
+ @Init
+ public void initialize() throws ParserConfigurationException {
+ }
+
+ @Override
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ try {
+
+ // Get the request path
+ String path = URLDecoder.decode(request.getRequestURI().substring(request.getServletPath().length()), "UTF-8");
+ if (path.startsWith("/")) {
+ path = path.substring(1);
+ }
+
+ // Get the request parameters
+ String contributionURI = request.getParameter("contribution");
+ String contributionLocation = request.getParameter("location");
+ String compositeURI = request.getParameter("composite");
+ String start = request.getParameter("start");
+
+ logger.info("Composite Quick Start.");
+ logger.info("Contribution URI: " + contributionURI);
+ logger.info("Contribution location: " + contributionLocation);
+ logger.info("Composite URI: " + compositeURI);
+
+ // Look for the contribution in the workspace
+ Entry<String, Item>[] contributionEntries = contributionCollection.getAll();
+ Entry<String, Item> contributionEntry = null;
+ for (Entry<String, Item> entry: contributionEntries) {
+ if (entry.getKey() != null &&
+ contributionURI.equals(entry.getKey())) {
+ contributionEntry = entry;
+ break;
+ }
+ }
+
+ // Add the contribution if necessary
+ if (contributionEntry == null) {
+ Item item = new Item();
+ item.setLink(contributionLocation);
+ contributionCollection.post(contributionURI, item);
+ }
+
+ // Look for the specified deployable composite in the contribution
+ String compositeKey = null;
+ Entry<String, Item>[] deployableEntries = deployableCollection.query("contribution=" + contributionURI);
+ for (Entry<String, Item> entry: deployableEntries) {
+ Item item = entry.getData();
+ String compositeFileName = compositeURI.substring(compositeURI.lastIndexOf("/") + 1);
+ if (contributionURI.equals(contributionURI(entry.getKey())) &&
+ (item.getAlternate().endsWith(compositeURI) ||
+ item.getAlternate().endsWith(compositeFileName))) {
+ compositeKey = entry.getKey();
+ break;
+ }
+ }
+
+ if (compositeKey == null) {
+ logger.info("Composite not found");
+ response.sendError(HttpServletResponse.SC_NOT_FOUND, compositeURI);
+ return;
+ }
+
+ // Look for the deployable composite in the domain composite
+ try {
+ domainCompositeCollection.get(compositeKey);
+ } catch (NotFoundException e) {
+
+ // Add the deployable composite to the domain composite
+ Item item = new Item();
+ domainCompositeCollection.post(compositeKey, item);
+ }
+
+ // Check if the deployable composite is already assigned a node
+ Entry<String, Item>[] nodeEntries = cloudCollection.getAll();
+ String nodeName = null;
+ for (Entry<String, Item> entry: nodeEntries) {
+ Item item = entry.getData();
+ String related = item.getRelated();
+ if (related != null) {
+ int c = related.indexOf("composite:");
+ related = related.substring(c);
+ if (compositeKey.equals(related)) {
+ nodeName = compositeQName(entry.getKey()).getLocalPart();
+ }
+ }
+ }
+
+ // Create a new node for the composite if necessary
+ if (nodeName == null) {
+
+ // Construct node name and key
+ QName compositeName = compositeQName(compositeKey);
+ nodeName = compositeName.getLocalPart() + "Node";
+ String nodeKey = compositeKey("http://tuscany.apache.org/cloud", new QName("http://tuscany.apache.org/cloud", nodeName));
+
+ // Find a free node port
+ Set<Integer> nodePorts = new HashSet<Integer>();
+ for (Entry<String, Item> entry: nodeEntries) {
+ Item item = entry.getData();
+ String uri = nodeURI(item.getContents());
+ if (uri != null) {
+ URI u = URI.create(uri);
+ int port = u.getPort();
+ if (port != -1) {
+ nodePorts.add(port);
+ }
+ }
+ }
+ String nodeURI = null;
+ for (int port = 8100; port<8200; port++) {
+ if (!nodePorts.contains(port)) {
+ nodeURI = "http://localhost:" + port;
+ break;
+ }
+ }
+ if (nodeURI == null) {
+ throw new RuntimeException("Couldn't find a free port for new node: " + nodeName);
+ }
+
+ // Build the entry describing the node
+ Item item = new Item();
+ String content =
+ "<composite xmlns=\"http://www.osoa.org/xmlns/sca/1.0\"\n" +
+ " xmlns:t=\"http://tuscany.apache.org/xmlns/sca/1.0\"\n" +
+ " targetNamespace=\"http://tuscany.apache.org/cloud\"\n" +
+ " xmlns:c=\"" + compositeName.getNamespaceURI() + "\"\n" +
+ " name=\"" + nodeName + "\">\n" +
+ "\n" +
+ " <component name=\"" + nodeName + "\">\n" +
+ " <t:implementation.node uri=\"" + contributionURI + "\" composite=\"c:" + compositeName.getLocalPart() + "\"/>\n" +
+ " <service name=\"Node\">\n" +
+ " <binding.sca uri=\"" + nodeURI + "\"/>\n" +
+ " <binding.ws uri=\"" + nodeURI + "\"/>\n" +
+ " <t:binding.http uri=\"" + nodeURI + "\"/>\n" +
+ " <t:binding.jsonrpc uri=\"" + nodeURI + "\"/>\n" +
+ " <t:binding.atom uri=\"" + nodeURI + "\"/>\n" +
+ " </service>\n" +
+ " </component>\n" +
+ "</composite>";
+ item.setContents(content);
+
+ // Create the new node
+ cloudCollection.post(nodeKey, item);
+ }
+
+ // Finally, start the node
+ if ("true".equals(start)) {
+ processCollection.post(nodeName, new Item());
+ }
+
+ response.getWriter().print("<html><body>Node <span id=\"node\">" + nodeName + "</span> OK.</body></html>");
+
+ } catch (Exception e) {
+ logger.log(Level.SEVERE, "Could not start composite", e);
+ response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.toString());
+ }
+ }
+
+}
diff --git a/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/Searcher.java b/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/Searcher.java
new file mode 100644
index 0000000000..38a23f9023
--- /dev/null
+++ b/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/impl/Searcher.java
@@ -0,0 +1,461 @@
+package org.apache.tuscany.sca.domain.manager.impl;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Map;
+
+import org.apache.commons.lang.StringEscapeUtils;
+import org.apache.tuscany.sca.contribution.Contribution;
+import org.apache.tuscany.sca.data.collection.Entry;
+import org.apache.tuscany.sca.data.collection.Item;
+import org.apache.tuscany.sca.data.collection.ItemCollection;
+import org.apache.tuscany.sca.data.collection.LocalItemCollection;
+import org.apache.tuscany.sca.data.collection.NotFoundException;
+import org.apache.tuscany.sca.domain.search.DomainSearch;
+import org.apache.tuscany.sca.domain.search.IndexException;
+import org.apache.tuscany.sca.domain.search.Result;
+import org.apache.tuscany.sca.domain.search.impl.DomainSearchFormatter;
+import org.apache.tuscany.sca.domain.search.impl.HighlightingUtil;
+import org.apache.tuscany.sca.domain.search.impl.SearchFields;
+import org.osoa.sca.annotations.Reference;
+import org.osoa.sca.annotations.Scope;
+import org.osoa.sca.annotations.Service;
+
+@Scope("COMPOSITE")
+@Service(interfaces = {ItemCollection.class, LocalItemCollection.class})
+public class Searcher implements ItemCollection, LocalItemCollection {
+ static char[] characters = {'\u0001'/*  */, '\u0003'/*  */, '\u0004'/*  */,};
+
+ final private static String HTML_NEW_LINE = "<BR/>";
+
+ final private static String PATH_SEPARATOR = "/";
+
+ final private static int MAX_CONTENT_LINE_WIDTH = 300;
+
+ final private static String HIGHLIGHT_START = "<font color='#FF0000'>";
+
+ final private static String HIGHLIGHT_END = "</font>";
+
+ @Reference
+ public ContributionsReader contributionReader;
+
+ @Reference
+ public LocalItemCollection contributionCollection;
+
+ @Reference
+ public DomainSearch domainSearch;
+
+ private int elementCounter;
+
+ public void delete(String key) throws NotFoundException {
+
+ }
+
+ private static void startIndentation(int size, StringWriter writer) {
+ writer.write("<p style='margin-top:0em;margin-bottom:0em;padding:0em;margin-left:");
+ writer.write(Integer.toString(size));
+ writer.write("em'>");
+
+ }
+
+ private static void endIndentation(StringWriter writer) {
+ writer.write("</p>");
+ }
+
+ public Item get(String key) throws NotFoundException {
+
+ try {
+
+ if (key.startsWith("highlight")) {
+ int lastSemicolonIndex = key.lastIndexOf(";");
+ String artifact = key.substring(lastSemicolonIndex + 1);
+ int secondLastSemicolonIndex = key.lastIndexOf(";", lastSemicolonIndex - 1);
+ String contribution = key.substring(secondLastSemicolonIndex + 1, lastSemicolonIndex);
+ String query = key.substring("highlight".length(), secondLastSemicolonIndex);
+
+ return highlightArtifact(contribution, artifact, query);
+
+ } else if (key.startsWith("query")) {
+ return executeQuery(key.substring("query".length()));
+
+ } else {
+ throw new NotFoundException("Invalid operation!");
+ }
+
+ } catch (Exception t) {
+ if (t instanceof NotFoundException) {
+ throw (NotFoundException)t;
+ }
+ throw new NotFoundException("Internal error!");
+ }
+
+ }
+
+ private Item highlightArtifact(String contribution, String artifact, String query) throws NotFoundException {
+
+ Item item = this.contributionCollection.get(contribution);
+
+ if (item == null) {
+ throw new NotFoundException("contribution not found: " + contribution);
+ }
+
+ String location = item.getAlternate();
+
+ if (location.endsWith(".jar") || location.endsWith(".zip")) {
+ location =
+ "jar:" + (location.startsWith("file:") ? "" : "file:")
+ + location
+ + '!'
+ + (artifact.startsWith("/") ? "" : "/")
+ + artifact;
+
+ } else {
+ location += (location.endsWith("/") ? "" : "/") + artifact;
+ }
+
+ try {
+ Reader reader = new InputStreamReader(new URL(location).openStream());
+ StringBuilder sb = new StringBuilder();
+ int c;
+
+ // TODO: load the chars into an array buffer instead of one
+ // at a
+ // time
+ while ((c = reader.read()) != -1) {
+ char character = (char)c;
+
+ if (!Character.isIdentifierIgnorable(character)) {
+ sb.append(character);
+ }
+
+ }
+
+ String highlightedText = this.domainSearch.highlight(SearchFields.FILE_CONTENT_FIELD, sb.toString(), query);
+ highlightedText = highlightedText.replaceAll("\n", "<br/>");
+ highlightedText = highlightedText.replaceAll(" ", "&nbsp;");
+ highlightedText =
+ HighlightingUtil.replaceHighlightMarkupBy(highlightedText, HIGHLIGHT_START, HIGHLIGHT_END);
+
+ item = new Item();
+ item.setTitle(contribution + ";" + artifact);
+ item.setContents(highlightedText);
+
+ return item;
+
+ } catch (Exception e) {
+ throw new NotFoundException("Could not highlight artifact: " + e.getMessage(), e);
+ }
+
+ }
+
+ private Item executeQuery(String query) throws NotFoundException {
+
+ if (!this.domainSearch.indexExists()) {
+ Contribution[] contributions = this.contributionReader.readContributions();
+
+ for (Contribution contribution : contributions) {
+ if (!contribution.getURI().equals(DomainManagerUtil.DEPLOYMENT_CONTRIBUTION_URI)) {
+
+ try {
+ this.domainSearch.updateContribution(contribution, contribution);
+ } catch (IndexException e) {
+
+ }
+
+ }
+ }
+ }
+
+ Result[] results;
+ try {
+ results = this.domainSearch.parseAndSearch(query, true);
+ } catch (Exception e1) {
+ throw new NotFoundException("Exception while searching: " + e1.getMessage(), e1);
+ }
+
+ Item item = new Item();
+ item.setTitle("Results");
+
+ StringWriter sw = new StringWriter();
+ this.elementCounter = 0;
+
+ if (results.length > 0) {
+ for (Result result : results) {
+ try {
+ writeToHTML(0, result, sw);
+ } catch (IOException e) {
+ // ignore result
+ }
+ }
+
+ String contents = HighlightingUtil.replaceHighlightMarkupBy(sw.getBuffer(), HIGHLIGHT_START, HIGHLIGHT_END);
+
+ item.setContents(replaceAll(contents, 40));
+
+ } else {
+ item.setContents("No results match: <u>" + query + "</u>");
+ }
+
+ // System.out.println(item.getContents());
+
+ return item;
+
+ }
+
+ private static String replaceAll(CharSequence c, int less) {
+ StringBuilder sb = new StringBuilder();
+ // HashSet<Character> set = new HashSet<Character>();
+ Arrays.sort(characters);
+ // int start = 0, end = 4;
+ // char[] chars = new char[end - start];
+ // System.arraycopy(characters, start, chars, 0, end - start);
+
+ for (int i = 0; i < c.length(); i++) {
+ char actual = c.charAt(i);
+
+ // if (Arrays.binarySearch(characters, actual) < 0) {
+
+ // if (actual != '\u000b' && actual != '\u0020' &&
+ // actual != '\u000c' && actual != '\u0009' &&
+ // actual != ')' && actual != '(') {
+
+ if (actual > less || actual == '&'
+ || actual == '#'
+ || actual == '\''
+ || actual == ' '
+ || actual == '%'
+ || actual == ':'
+ || actual == '('
+ || actual == ')'
+ || actual == '"') {
+
+ sb.append(actual);
+
+ } else {
+ // sb.append('0');
+ }
+
+ }
+
+ return sb.toString();
+
+ }
+
+ private static String getIconLocationForResult(Result result) {
+
+ if (SearchFields.COMPONENT_FIELD.equals(result.getField())) {
+ return "icons/component.png' title='Component";
+
+ } else if (SearchFields.COMPOSITE_FIELD.equals(result.getField())) {
+ return "icons/composite.png' title='Composite";
+
+ } else if (SearchFields.ARTIFACT_FIELD.equals(result.getField())) {
+ return "icons/artifact.png' title='Artifact";
+ }
+
+ return "icons/feed-icon.png";
+
+ }
+
+ private static void writeResultIcon(Writer writer, Result result) throws IOException {
+ writer.write("<img src='");
+ writer.write(getIconLocationForResult(result));
+ writer.write("'/> ");
+
+ }
+
+ private static Result writeFileContentResultToHTML(int indentation, Result result, StringWriter writer)
+ throws IOException {
+
+ Map<String, Result> contents = result.getContents();
+ writeResultIcon(writer, result);
+
+ if (contents.size() == 1 && SearchFields.ARTIFACT_FIELD.equals(contents.values().iterator().next().getField())) {
+
+ writer.write(result.getValue());
+ contents = result.getContents();
+
+ while (contents.size() == 1 && SearchFields.ARTIFACT_FIELD.equals(contents.values().iterator().next()
+ .getField())) {
+
+ result = contents.values().iterator().next();
+
+ writer.write(PATH_SEPARATOR);
+ StringEscapeUtils.escapeHtml(writer, result.getValue());
+
+ contents = result.getContents();
+
+ }
+
+ } else {
+ StringEscapeUtils.escapeHtml(writer, result.getValue());
+ }
+
+ return result;
+
+ }
+
+ private static String removeHighlighting(String text) {
+ return HighlightingUtil.replaceHighlightMarkupBy(text, "", "");
+ }
+
+ private static void writeResultName(Result result, StringWriter writer) throws IOException {
+
+ if (SearchFields.CONTRIBUTION_FIELD.equals(result.getField())) {
+ writer.write("<a href='/contribution/");
+ writer.write(removeHighlighting(result.getValue()));
+ writer.write("'>");
+ writer.write(StringEscapeUtils.escapeHtml(result.getValue()));
+ writer.write("</a>");
+
+ } else if (SearchFields.COMPOSITE_FIELD.equals(result.getField())) {
+ writer.write("<a href='/composite-source/composite:");
+ writer.write(getContributionURI(result));
+ writer.write(';');
+ writer.write(removeHighlighting(result.getValue()));
+ writer.write("'>");
+ writer.write(StringEscapeUtils.escapeHtml(result.getValue()));
+ writer.write("</a>");
+
+ } else {
+ StringEscapeUtils.escapeHtml(writer, result.getValue());
+ }
+
+ }
+
+ private static String getContributionURI(Result result) {
+
+ if (result == null) {
+ return "";
+
+ } else if (SearchFields.CONTRIBUTION_FIELD.equals(result.getField())) {
+ return removeHighlighting(result.getValue());
+
+ } else {
+ return getContributionURI(result.getContainer());
+ }
+
+ }
+
+ private void writeToHTML(int indentation, Result result, StringWriter writer) throws IOException {
+
+ startIndentation(indentation++, writer);
+ String field = result.getField();
+
+ if (SearchFields.FILE_CONTENT_FIELD.equals(field)) {
+ String content = result.getValue();
+
+ if (content != null && content.length() > 0 && DomainSearchFormatter.isHighlighted(content)) {
+ String contributionPlusArtifact =
+ getContributionURI(result) + ";" + removeHighlighting(result.getContainer().getValue());
+
+ writer.write(HTML_NEW_LINE);
+
+ this.elementCounter++;
+ writer.write("<div style='margin-top:0em;margin-left:");
+ writer.write(Integer.toString(indentation));
+ writer.write("em;background-color:#FFE175;max-width:100%;border-style:dashed;border-width:1px;padding:5px' id='");
+ writer.write(contributionPlusArtifact);
+ writer.write("'>");
+ writer.write("<p style='margin:0px;padding:0px;font-size:70%'>");
+ // + "<a style='margin:0px;padding:0px' href='#filecontent");
+ // writer.write(Integer.toString(this.elementCounter));
+
+
+
+ // writer.write("' onclick='search");
+ // writer.write("'>view all</a>&nbsp;&nbsp;<a href='/files/contribution=");
+ writer.write("<a style='margin:0px;padding:0px' href='javascript:getHighlighted(\"");
+ writer.write(contributionPlusArtifact);
+ writer.write("\");'>view all</a>&nbsp;&nbsp;");
+
+ writer.write("<a href='/files/contribution=");
+ writer.write(contributionPlusArtifact);
+ writer.write("'>download</a></p><div id='");
+ writer.write("test");
+ writer.write("' style='margin:8px 0px 0px 0px;padding:0px'>");
+
+ int i = 0;
+ while (i < content.length()) {
+ StringEscapeUtils.escapeHtml(writer, content.substring(i, Math.min(i + MAX_CONTENT_LINE_WIDTH,
+ content.length())));
+ writer.write(HTML_NEW_LINE);
+ i += MAX_CONTENT_LINE_WIDTH;
+ }
+
+ writer.write("</div>");
+ writer.write("</div>");
+
+ }
+
+ } else if (SearchFields.ARTIFACT_FIELD.equals(field)) {
+ result = writeFileContentResultToHTML(indentation, result, writer);
+ } else {
+ writeResultIcon(writer, result);
+ writeResultName(result, writer);
+ }
+
+ endIndentation(writer);
+
+ for (Result actualResult : result.getContents().values()) {
+ writeToHTML(indentation, actualResult, writer);
+ }
+ }
+
+ public Entry<String, Item>[] getAll() {
+ System.out.println("getAll");
+ return null;
+ }
+
+ public String post(String key, Item item) {
+ System.out.println("post");
+ return null;
+ }
+
+ public void put(String key, Item item) throws NotFoundException {
+ System.out.println("put");
+ }
+
+ @SuppressWarnings("unchecked")
+ public Entry<String, Item>[] query(String queryString) {
+
+ try {
+
+ Item item;
+ String key;
+
+ if (queryString.startsWith("highlight")) {
+ int lastSemicolonIndex = queryString.lastIndexOf(";");
+ String artifact = queryString.substring(lastSemicolonIndex + 1);
+ int secondLastSemicolonIndex = queryString.lastIndexOf(";", lastSemicolonIndex - 1);
+ String contribution = queryString.substring(secondLastSemicolonIndex + 1, lastSemicolonIndex);
+ String query = queryString.substring("highlight".length(), secondLastSemicolonIndex);
+
+ item = highlightArtifact(contribution, artifact, query);
+ key = queryString.substring("highlight".length());
+
+ } else if (queryString.startsWith("query")) {
+ key = queryString.substring("query".length());
+ item = executeQuery(key);
+
+ } else {
+ throw new NotFoundException("Invalid operation!");
+ }
+
+ Entry<String, Item>[] returnArray = new Entry[1];
+ returnArray[0] = new Entry<String, Item>(key, item);
+
+ return returnArray;
+
+ } catch (Exception t) {
+ return new Entry[0];
+ }
+
+ }
+
+}
diff --git a/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/launcher/DomainManagerLauncherBootstrap.java b/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/launcher/DomainManagerLauncherBootstrap.java
new file mode 100644
index 0000000000..f96e19ed72
--- /dev/null
+++ b/sca-java-1.x/trunk/modules/domain-manager/src/main/java/org/apache/tuscany/sca/domain/manager/launcher/DomainManagerLauncherBootstrap.java
@@ -0,0 +1,95 @@
+/*
+ * 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.manager.launcher;
+
+import org.apache.tuscany.sca.domain.manager.impl.DomainManagerConfiguration;
+import org.apache.tuscany.sca.node.SCAClient;
+import org.apache.tuscany.sca.node.SCANode;
+import org.apache.tuscany.sca.node.SCANodeFactory;
+
+/**
+ * Bootstrap class for the SCA domain manager.
+ *
+ * @version $Rev$ $Date$
+ */
+public class DomainManagerLauncherBootstrap {
+ private SCANode node;
+
+ /**
+ * A node wrappering an instance of a domain manager.
+ */
+ public static class NodeFacade implements SCANode {
+ private ClassLoader threadContextClassLoader;
+ private ClassLoader runtimeClassLoader;
+ private SCANode node;
+ private String rootDirectory;
+
+ private NodeFacade(String rootDirectory) {
+ this.rootDirectory = rootDirectory;
+ runtimeClassLoader = Thread.currentThread().getContextClassLoader();
+ }
+
+ public void start() {
+ threadContextClassLoader = Thread.currentThread().getContextClassLoader();
+ boolean started = false;
+ try {
+ Thread.currentThread().setContextClassLoader(runtimeClassLoader);
+ SCANodeFactory factory = SCANodeFactory.newInstance();
+ node = factory.createSCANodeFromClassLoader("DomainManager.composite", getClass().getClassLoader());
+ node.start();
+
+ // Set the domain manager's root directory
+ DomainManagerConfiguration domainManagerConfiguration = ((SCAClient) node).getService(DomainManagerConfiguration.class, "DomainManagerConfigurationComponent");
+ domainManagerConfiguration.setRootDirectory(rootDirectory);
+
+ started = true;
+ } finally {
+ if (!started) {
+ Thread.currentThread().setContextClassLoader(threadContextClassLoader);
+ }
+ }
+ }
+
+ public void stop() {
+ try {
+ Thread.currentThread().setContextClassLoader(runtimeClassLoader);
+ node.stop();
+ } finally {
+ Thread.currentThread().setContextClassLoader(threadContextClassLoader);
+ }
+ }
+ }
+
+ /**
+ * Constructs a new domain manager bootstrap.
+ */
+ public DomainManagerLauncherBootstrap(String rootDirectory) throws Exception {
+ node = new NodeFacade(rootDirectory);
+ }
+
+ /**
+ * Returns the node representing the domain manager.
+ * @return
+ */
+ public SCANode getNode() {
+ return node;
+ }
+
+}