diff options
Diffstat (limited to 'sca-java-1.x/tags/1.2/modules/workspace-admin/src/main')
19 files changed, 3984 insertions, 0 deletions
diff --git a/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/java/org/apache/tuscany/sca/workspace/admin/impl/CompositeImageCollectionImpl.java b/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/java/org/apache/tuscany/sca/workspace/admin/impl/CompositeImageCollectionImpl.java new file mode 100644 index 0000000000..787b7aca08 --- /dev/null +++ b/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/java/org/apache/tuscany/sca/workspace/admin/impl/CompositeImageCollectionImpl.java @@ -0,0 +1,175 @@ +/* + * 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.workspace.admin.impl; + +import static org.apache.tuscany.sca.workspace.admin.impl.DomainAdminUtil.compositeKey; +import static org.apache.tuscany.sca.workspace.admin.impl.DomainAdminUtil.compositeQName; +import static org.apache.tuscany.sca.workspace.admin.impl.DomainAdminUtil.compositeTitle; +import static org.apache.tuscany.sca.workspace.admin.impl.DomainAdminUtil.contributionURI; + +import java.io.IOException; +import java.net.URLDecoder; +import java.util.ArrayList; +import java.util.List; +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.assembly.Component; +import org.apache.tuscany.sca.assembly.Composite; +import org.apache.tuscany.sca.implementation.data.collection.Entry; +import org.apache.tuscany.sca.implementation.data.collection.Item; +import org.apache.tuscany.sca.implementation.data.collection.ItemCollection; +import org.apache.tuscany.sca.implementation.data.collection.LocalItemCollection; +import org.apache.tuscany.sca.implementation.data.collection.NotFoundException; +import org.apache.tuscany.sca.implementation.node.NodeImplementation; +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 composite install image collection service. + * + * @version $Rev$ $Date$ + */ +@Scope("COMPOSITE") +@Service(interfaces={ItemCollection.class, LocalItemCollection.class, Servlet.class}) +public class CompositeImageCollectionImpl extends HttpServlet implements ItemCollection, LocalItemCollection, Servlet { + private static final long serialVersionUID = 1L; + + private final static Logger logger = Logger.getLogger(CompositeImageCollectionImpl.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.info("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(); + } + } + + @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.info("get " + key); + + // The key contains a node name, redirect + // to the corresponding composite image + + // 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 image + String compositeImage = "/composite-image/?composite=" + related.substring(i); + response.sendRedirect(compositeImage); + return; + } + } + } + + // Node not found + response.sendError(HttpServletResponse.SC_NOT_FOUND, key); + return; + } +} diff --git a/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/java/org/apache/tuscany/sca/workspace/admin/impl/ContributionCollectionImpl.java b/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/java/org/apache/tuscany/sca/workspace/admin/impl/ContributionCollectionImpl.java new file mode 100644 index 0000000000..6b8541b279 --- /dev/null +++ b/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/java/org/apache/tuscany/sca/workspace/admin/impl/ContributionCollectionImpl.java @@ -0,0 +1,515 @@ +/* + * 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.workspace.admin.impl; + +import static org.apache.tuscany.sca.workspace.admin.impl.DomainAdminUtil.DEPLOYMENT_CONTRIBUTION_URI; +import static org.apache.tuscany.sca.workspace.admin.impl.DomainAdminUtil.compositeSimpleTitle; +import static org.apache.tuscany.sca.workspace.admin.impl.DomainAdminUtil.compositeSourceLink; +import static org.apache.tuscany.sca.workspace.admin.impl.DomainAdminUtil.locationURL; + +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.net.MalformedURLException; +import java.net.URI; +import java.net.URL; +import java.net.URLDecoder; +import java.util.ArrayList; +import java.util.List; +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.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.builder.Problem; +import org.apache.tuscany.sca.assembly.xml.CompositeDocumentProcessor; +import org.apache.tuscany.sca.assembly.xml.CompositeProcessor; +import org.apache.tuscany.sca.contribution.Contribution; +import org.apache.tuscany.sca.contribution.ContributionFactory; +import org.apache.tuscany.sca.contribution.DefaultModelFactoryExtensionPoint; +import org.apache.tuscany.sca.contribution.ModelFactoryExtensionPoint; +import org.apache.tuscany.sca.contribution.processor.DefaultStAXArtifactProcessorExtensionPoint; +import org.apache.tuscany.sca.contribution.processor.DefaultURLArtifactProcessorExtensionPoint; +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.DefaultModelResolverExtensionPoint; +import org.apache.tuscany.sca.contribution.resolver.ModelResolverExtensionPoint; +import org.apache.tuscany.sca.contribution.xml.ContributionGeneratedMetadataDocumentProcessor; +import org.apache.tuscany.sca.contribution.xml.ContributionMetadataDocumentProcessor; +import org.apache.tuscany.sca.contribution.xml.ContributionMetadataProcessor; +import org.apache.tuscany.sca.implementation.data.collection.Entry; +import org.apache.tuscany.sca.implementation.data.collection.Item; +import org.apache.tuscany.sca.implementation.data.collection.ItemCollection; +import org.apache.tuscany.sca.implementation.data.collection.LocalItemCollection; +import org.apache.tuscany.sca.implementation.data.collection.NotFoundException; +import org.apache.tuscany.sca.policy.PolicyFactory; +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.ContributionDependencyBuilderMonitor; +import org.apache.tuscany.sca.workspace.builder.impl.ContributionDependencyBuilderImpl; +import org.apache.tuscany.sca.workspace.processor.impl.ContributionInfoProcessor; +import org.apache.tuscany.sca.workspace.xml.WorkspaceProcessor; +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.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, Servlet.class}) +public class ContributionCollectionImpl extends HttpServlet implements ItemCollection, LocalItemCollection { + private static final long serialVersionUID = -4759297945439322773L; + + private final static Logger logger = Logger.getLogger(ContributionCollectionImpl.class.getName()); + + @Property + public String workspaceFile; + + @Property + public String deploymentContributionDirectory; + + private ContributionFactory contributionFactory; + private AssemblyFactory assemblyFactory; + private WorkspaceFactory workspaceFactory; + private StAXArtifactProcessor<Object> staxProcessor; + private URLArtifactProcessor<Object> urlProcessor; + private URLArtifactProcessor<Contribution> contributionInfoProcessor; + private XMLInputFactory inputFactory; + private XMLOutputFactory outputFactory; + private DocumentBuilder documentBuilder; + + /** + * Initialize the component. + */ + @Init + public void initialize() throws ParserConfigurationException { + + // Create model factories + ModelFactoryExtensionPoint modelFactories = new DefaultModelFactoryExtensionPoint(); + outputFactory = modelFactories.getFactory(XMLOutputFactory.class); + outputFactory.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true); + contributionFactory = modelFactories.getFactory(ContributionFactory.class); + assemblyFactory = modelFactories.getFactory(AssemblyFactory.class); + workspaceFactory = modelFactories.getFactory(WorkspaceFactory.class); + PolicyFactory policyFactory = modelFactories.getFactory(PolicyFactory.class); + + // Create model resolvers + ModelResolverExtensionPoint modelResolvers = new DefaultModelResolverExtensionPoint(); + + // Create artifact processors + inputFactory = modelFactories.getFactory(XMLInputFactory.class); + StAXArtifactProcessorExtensionPoint staxProcessors = new DefaultStAXArtifactProcessorExtensionPoint(modelFactories); + staxProcessor = new ExtensibleStAXArtifactProcessor(staxProcessors, inputFactory, outputFactory); + staxProcessors.addArtifactProcessor(new ContributionMetadataProcessor(assemblyFactory, contributionFactory, staxProcessor)); + staxProcessors.addArtifactProcessor(new WorkspaceProcessor(workspaceFactory, contributionFactory, staxProcessor)); + staxProcessors.addArtifactProcessor(new CompositeProcessor(contributionFactory, assemblyFactory, policyFactory, staxProcessor)); + + URLArtifactProcessorExtensionPoint urlProcessors = new DefaultURLArtifactProcessorExtensionPoint(modelFactories); + urlProcessor = new ExtensibleURLArtifactProcessor(urlProcessors); + urlProcessors.addArtifactProcessor(new ContributionMetadataDocumentProcessor(staxProcessor, inputFactory)); + urlProcessors.addArtifactProcessor(new ContributionGeneratedMetadataDocumentProcessor(staxProcessor, inputFactory)); + urlProcessors.addArtifactProcessor(new CompositeDocumentProcessor(staxProcessor, inputFactory, null)); + + // Create contribution info processor + contributionInfoProcessor = new ContributionInfoProcessor(modelFactories, modelResolvers, urlProcessor); + + // Create a document builder (used to pretty print XML) + documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + } + + public Entry<String, Item>[] getAll() { + logger.info("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.info("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); + } + + @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.info("get " + key); + + // Get the item describing the composite + Item item; + try { + item = get(key); + } catch (NotFoundException e) { + response.sendError(HttpServletResponse.SC_NOT_FOUND, key); + return; + } + + // Redirect to the actual contribution location + response.sendRedirect("/files/" + item.getAlternate()); + } + + public String post(String key, Item item) { + logger.info("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); + + 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.info("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++) { + if (contributions.get(i).getURI().equals(key)) { + contributions.remove(i); + + // Write the workspace + writeWorkspace(workspace); + return; + } + } + throw new NotFoundException(key); + } + + public Entry<String, Item>[] query(String queryString) { + logger.info("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(null); + List<Contribution> dependencies = analyzer.buildContributionDependencies(workspace, contribution); + + // 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()]); + + } 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>(); + ContributionDependencyBuilderMonitor monitor = new ContributionDependencyBuilderMonitor() { + public void problem(Problem problem) { + problems.add(problem.getMessage() + " " + problem.getModel()); + } + }; + + StringBuffer sb = new StringBuffer(); + ContributionDependencyBuilderImpl analyzer = new ContributionDependencyBuilderImpl(monitor); + List<Contribution> dependencies = analyzer.buildContributionDependencies(workspace, contribution); + 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 (problems.size() > 1) { + 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 + */ + private Workspace readWorkspace() { + Workspace workspace; + File file = new File(workspaceFile); + if (file.exists()) { + 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); + } + } else { + workspace = workspaceFactory.createWorkspace(); + } + + // 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(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 { + // 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 + FileOutputStream os = new FileOutputStream(new File(workspaceFile)); + XMLSerializer serializer = new XMLSerializer(os, format); + serializer.serialize(document); + os.close(); + } 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 dependencyWorkspace = workspaceFactory.createWorkspace(); + try { + for (Contribution c: workspace.getContributions()) { + URI uri = URI.create(c.getURI()); + URL url = locationURL(c.getLocation()); + Contribution contribution = (Contribution)contributionInfoProcessor.read(null, uri, url); + dependencyWorkspace.getContributions().add(contribution); + } + } catch (Exception e) { + throw new ServiceRuntimeException(e); + } + return dependencyWorkspace; + } + +} diff --git a/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/java/org/apache/tuscany/sca/workspace/admin/impl/DeployableCompositeCollectionImpl.java b/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/java/org/apache/tuscany/sca/workspace/admin/impl/DeployableCompositeCollectionImpl.java new file mode 100644 index 0000000000..2aeeb14727 --- /dev/null +++ b/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/java/org/apache/tuscany/sca/workspace/admin/impl/DeployableCompositeCollectionImpl.java @@ -0,0 +1,699 @@ +/* + * 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.workspace.admin.impl; + +import static org.apache.tuscany.sca.workspace.admin.impl.DomainAdminUtil.compositeAlternateLink; +import static org.apache.tuscany.sca.workspace.admin.impl.DomainAdminUtil.compositeKey; +import static org.apache.tuscany.sca.workspace.admin.impl.DomainAdminUtil.compositeQName; +import static org.apache.tuscany.sca.workspace.admin.impl.DomainAdminUtil.compositeSourceLink; +import static org.apache.tuscany.sca.workspace.admin.impl.DomainAdminUtil.compositeTitle; +import static org.apache.tuscany.sca.workspace.admin.impl.DomainAdminUtil.contributionURI; +import static org.apache.tuscany.sca.workspace.admin.impl.DomainAdminUtil.locationURL; +import static org.apache.tuscany.sca.workspace.admin.impl.DomainAdminUtil.newRuntime; + +import java.io.IOException; +import java.io.InputStream; +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.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 javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamWriter; + +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.ComponentService; +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.CompositeBuilderMonitor; +import org.apache.tuscany.sca.assembly.builder.Problem; +import org.apache.tuscany.sca.assembly.builder.Problem.Severity; +import org.apache.tuscany.sca.assembly.builder.impl.CompositeBuilderImpl; +import org.apache.tuscany.sca.assembly.builder.impl.CompositeConfigurationBuilderImpl; +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.ContributionFactory; +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.ExtensibleModelResolver; +import org.apache.tuscany.sca.contribution.resolver.ModelResolver; +import org.apache.tuscany.sca.contribution.resolver.ModelResolverExtensionPoint; +import org.apache.tuscany.sca.contribution.service.ContributionListener; +import org.apache.tuscany.sca.contribution.service.ContributionListenerExtensionPoint; +import org.apache.tuscany.sca.contribution.service.ContributionReadException; +import org.apache.tuscany.sca.contribution.service.ContributionRepository; +import org.apache.tuscany.sca.contribution.service.ContributionResolveException; +import org.apache.tuscany.sca.contribution.xml.ContributionGeneratedMetadataDocumentProcessor; +import org.apache.tuscany.sca.contribution.xml.ContributionMetadataDocumentProcessor; +import org.apache.tuscany.sca.contribution.xml.ContributionMetadataProcessor; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.assembly.ActivationException; +import org.apache.tuscany.sca.host.embedded.impl.ReallySmallRuntime; +import org.apache.tuscany.sca.implementation.data.collection.Entry; +import org.apache.tuscany.sca.implementation.data.collection.Item; +import org.apache.tuscany.sca.implementation.data.collection.ItemCollection; +import org.apache.tuscany.sca.implementation.data.collection.LocalItemCollection; +import org.apache.tuscany.sca.implementation.data.collection.NotFoundException; +import org.apache.tuscany.sca.implementation.node.NodeImplementation; +import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper; +import org.apache.tuscany.sca.interfacedef.impl.InterfaceContractMapperImpl; +import org.apache.tuscany.sca.policy.IntentAttachPointTypeFactory; +import org.apache.tuscany.sca.policy.PolicyFactory; +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 deployable composite collection service. + * + * @version $Rev$ $Date$ + */ +@Scope("COMPOSITE") +@Service(interfaces={ItemCollection.class, LocalItemCollection.class, Servlet.class}) +public class DeployableCompositeCollectionImpl extends HttpServlet implements ItemCollection, LocalItemCollection { + private static final long serialVersionUID = -8809641932774129151L; + + private final static Logger logger = Logger.getLogger(DeployableCompositeCollectionImpl.class.getName()); + + @Reference + public LocalItemCollection contributionCollection; + + @Reference + public LocalItemCollection domainCompositeCollection; + + @Reference + public LocalItemCollection cloudCollection; + + private ModelFactoryExtensionPoint modelFactories; + private ModelResolverExtensionPoint modelResolvers; + private AssemblyFactory assemblyFactory; + private URLArtifactProcessor<Contribution> contributionContentProcessor; + private StAXArtifactProcessor<Composite> compositeProcessor; + private XMLOutputFactory outputFactory; + private CompositeBuilder compositeBuilder; + private CompositeConfigurationBuilderImpl compositeConfigurationBuilder; + private List<ContributionListener> contributionListeners; + + /** + * Initialize the component. + */ + @Init + public void initialize() throws ParserConfigurationException { + + // Bootstrap a runtime to get a populated registry + // FIXME Remove this later + ReallySmallRuntime runtime = newRuntime(); + ExtensionPointRegistry registry = runtime.getExtensionPointRegistry(); + + // Get model factories + modelFactories = registry.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); + ContributionFactory contributionFactory = modelFactories.getFactory(ContributionFactory.class); + PolicyFactory policyFactory = modelFactories.getFactory(PolicyFactory.class); + + // Get and initialize artifact processors + StAXArtifactProcessorExtensionPoint staxProcessors = registry.getExtensionPoint(StAXArtifactProcessorExtensionPoint.class); + StAXArtifactProcessor<Object> staxProcessor = new ExtensibleStAXArtifactProcessor(staxProcessors, inputFactory, outputFactory); + staxProcessors.addArtifactProcessor(new ContributionMetadataProcessor(assemblyFactory, contributionFactory, staxProcessor)); + compositeProcessor = (StAXArtifactProcessor<Composite>)staxProcessors.getProcessor(Composite.class); + + URLArtifactProcessorExtensionPoint urlProcessors = registry.getExtensionPoint(URLArtifactProcessorExtensionPoint.class); + URLArtifactProcessor<Object> urlProcessor = new ExtensibleURLArtifactProcessor(urlProcessors); + urlProcessors.addArtifactProcessor(new ContributionMetadataDocumentProcessor(staxProcessor, inputFactory)); + urlProcessors.addArtifactProcessor(new ContributionGeneratedMetadataDocumentProcessor(staxProcessor, inputFactory)); + + // Create contribution processor + modelResolvers = registry.getExtensionPoint(ModelResolverExtensionPoint.class); + contributionContentProcessor = new ContributionContentProcessor(modelFactories, modelResolvers, urlProcessor); + contributionListeners = registry.getExtensionPoint(ContributionListenerExtensionPoint.class).getContributionListeners(); + + // Create composite builder + SCABindingFactory scaBindingFactory = modelFactories.getFactory(SCABindingFactory.class); + IntentAttachPointTypeFactory intentAttachPointTypeFactory = modelFactories.getFactory(IntentAttachPointTypeFactory.class); + InterfaceContractMapper contractMapper = new InterfaceContractMapperImpl(); + + // TODO need to get these messages back to the browser + CompositeBuilderMonitor monitor = new CompositeBuilderMonitor() { + public void problem(Problem problem) { + if (problem.getSeverity() == Severity.INFO) { + logger.info(problem.toString()); + } else if (problem.getSeverity() == Severity.WARNING) { + logger.warning(problem.toString()); + } else if (problem.getSeverity() == Severity.ERROR) { + if (problem.getCause() != null) { + logger.log(Level.SEVERE, problem.toString(), problem.getCause()); + } else { + logger.severe(problem.toString()); + } + } + } + }; + + compositeBuilder = new CompositeBuilderImpl(assemblyFactory, scaBindingFactory, intentAttachPointTypeFactory, + contractMapper, monitor); + + compositeConfigurationBuilder = new CompositeConfigurationBuilderImpl(assemblyFactory, + scaBindingFactory, + intentAttachPointTypeFactory, + contractMapper, + monitor); + } + + public Entry<String, Item>[] getAll() { + logger.info("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 Item get(String key) throws NotFoundException { + logger.info("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())) { + 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.info("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(); + } + } + + @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.info("get " + key); + + // Expect a key in the form + // composite:contributionURI;namespace;localName + // and return the corresponding resolved composite + + // Extract the composite qname from the key + QName qname = compositeQName(key); + + // Somewhere to store the composite we expect to write out at the end + Composite compositeImage = 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 + List<Contribution> loadedContributions = new ArrayList<Contribution>(); + 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 contributionItem = entry.getData(); + + // Read the contribution + Contribution c; + try { + c = contribution(loadedContributions, entry.getKey(), contributionItem.getAlternate()); + } catch (ContributionReadException e) { + continue; + } + loadedContributions.add(c); + if (contributionURI.equals(entry.getKey())) { + contribution = c; + contributionMap.put(contributionURI, contribution); + } + } + } + + 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); + + // store away the composite we are generating the deployable XML for. + if (qname.equals(deployable.getName())){ + compositeImage = deployable; + } + } + + // Composite not found + if (compositeImage == 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 node = 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)) { + node = nc; + break; + } + } + } + + if (node != null) { + try { + List<Binding> defaultBindings = node.getServices().get(0).getBindings(); + compositeConfigurationBuilder.configureBindingURIs(composite, null, defaultBindings); + } catch (CompositeBuilderException e) { + throw new ServletException(e); + } + } + } + + // build the domain composite + try { + compositeBuilder.build(domainComposite); + } catch (CompositeBuilderException e) { + response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.toString()); + return; + } + + // rebuild the requested composite from the domain composite + // we have to reverse the flatterning that went on when the domain + // composite was built + List<Component> tempComponentList = new ArrayList<Component>(); + tempComponentList.addAll(compositeImage.getComponents()); + compositeImage.getComponents().clear(); + + for (Component inputComponent : tempComponentList){ + for (Component deployComponent : domainComposite.getComponents()){ + if (deployComponent.getName().equals(inputComponent.getName())){ + compositeImage.getComponents().add(deployComponent); + } + } + } + + // Write the deployable composite + try { + response.setContentType("text/xml"); + XMLStreamWriter writer = outputFactory.createXMLStreamWriter(response.getOutputStream()); + compositeProcessor.write(compositeImage, 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 composites + List<Contribution> loadedContributions = new ArrayList<Contribution>(); + Map<String, Contribution> contributionMap = new HashMap<String, Contribution>(); + for (Entry<String, Item> cloudEntry: cloudEntries) { + String key = cloudEntry.getKey(); + String contributionURI = contributionURI(key); + QName qname = compositeQName(key); + + // Load the contribution + Contribution contribution = contributionMap.get(contributionURI); + if (contribution == null) { + Item contributionItem = contributionCollection.get(contributionURI); + + // Read the contribution + try { + contribution = contribution(loadedContributions, contributionURI, contributionItem.getAlternate()); + } catch (ContributionReadException e) { + continue; + } + loadedContributions.add(contribution); + contributionMap.put(contributionURI, contribution); + } + + // Include the composite in the clouds composite + 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 contributions + * @param contributionURI + * @param contributionLocation + * @return + * @throws NotFoundException + */ + private Contribution contribution(List<Contribution> contributions, String contributionURI, String contributionLocation) throws ContributionReadException { + try { + URI uri = URI.create(contributionURI); + URL location = locationURL(contributionLocation); + Contribution contribution = (Contribution)contributionContentProcessor.read(null, uri, location); + + // FIXME simplify this later + // Fix up contribution imports + ContributionRepository dummyRepository = new DummyContributionRepository(contributions); + for (ContributionListener listener: contributionListeners) { + listener.contributionAdded(dummyRepository, contribution); + } + + ModelResolver modelResolver = new ExtensibleModelResolver(contribution, modelResolvers, modelFactories); + contributionContentProcessor.resolve(contribution, modelResolver); + + return contribution; + + } catch (ContributionReadException e) { + throw e; + } catch (ContributionResolveException e) { + throw new ContributionReadException(e); + } catch (MalformedURLException e) { + throw new ContributionReadException(e); + } + } + + /** + * Returns the contribution with the given URI. + * + * @param contributionURI + * @param contributionLocation + * @return + * @throws NotFoundException + */ + private Contribution contribution(String contributionURI, String contributionLocation) throws ContributionReadException { + return contribution(new ArrayList<Contribution>(), contributionURI, contributionLocation); + } + + /** + * 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(DomainAdminUtil.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; + } + + /** + * FIXME Remove this later + * DummyContributionRepository + */ + private class DummyContributionRepository implements ContributionRepository { + + private List<Contribution> contributions; + + public DummyContributionRepository(List<Contribution> contributions) { + this.contributions = contributions; + } + + public void addContribution(Contribution contribution) {} + public URL find(String contribution) { return null; } + public Contribution getContribution(String uri) { return null; } + public List<Contribution> getContributions() { return contributions; } + public URI getDomain() { return null; } + public List<String> list() { return null; } + public void remove(String contribution) {} + public void removeContribution(Contribution contribution) {} + public URL store(String contribution, URL sourceURL, InputStream contributionStream) throws IOException { return null; } + public URL store(String contribution, URL sourceURL) throws IOException { return null;} + public void updateContribution(Contribution contribution) {} + } +} diff --git a/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/java/org/apache/tuscany/sca/workspace/admin/impl/DeployedCompositeCollectionImpl.java b/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/java/org/apache/tuscany/sca/workspace/admin/impl/DeployedCompositeCollectionImpl.java new file mode 100644 index 0000000000..fe5a3fe7e1 --- /dev/null +++ b/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/java/org/apache/tuscany/sca/workspace/admin/impl/DeployedCompositeCollectionImpl.java @@ -0,0 +1,399 @@ +/* + * 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.workspace.admin.impl; + +import static org.apache.tuscany.sca.workspace.admin.impl.DomainAdminUtil.DEPLOYMENT_CONTRIBUTION_URI; +import static org.apache.tuscany.sca.workspace.admin.impl.DomainAdminUtil.compositeKey; +import static org.apache.tuscany.sca.workspace.admin.impl.DomainAdminUtil.compositeQName; +import static org.apache.tuscany.sca.workspace.admin.impl.DomainAdminUtil.contributionURI; +import static org.apache.tuscany.sca.workspace.admin.impl.DomainAdminUtil.compositeTitle; +import static org.apache.tuscany.sca.workspace.admin.impl.DomainAdminUtil.compositeSourceLink; + +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.InputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLDecoder; +import java.util.ArrayList; +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 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.CompositeProcessor; +import org.apache.tuscany.sca.assembly.xml.Constants; +import org.apache.tuscany.sca.contribution.ContributionFactory; +import org.apache.tuscany.sca.contribution.DefaultModelFactoryExtensionPoint; +import org.apache.tuscany.sca.contribution.ModelFactoryExtensionPoint; +import org.apache.tuscany.sca.implementation.data.collection.Entry; +import org.apache.tuscany.sca.implementation.data.collection.Item; +import org.apache.tuscany.sca.implementation.data.collection.ItemCollection; +import org.apache.tuscany.sca.implementation.data.collection.LocalItemCollection; +import org.apache.tuscany.sca.implementation.data.collection.NotFoundException; +import org.apache.tuscany.sca.policy.PolicyFactory; +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: 632617 $ $Date: 2008-03-01 08:24:33 -0800 (Sat, 01 Mar 2008) $ + */ +@Scope("COMPOSITE") +@Service(interfaces={ItemCollection.class,LocalItemCollection.class, Servlet.class}) +public class DeployedCompositeCollectionImpl extends HttpServlet implements ItemCollection, LocalItemCollection { + private static final long serialVersionUID = -3477992129462720901L; + + private final static Logger logger = Logger.getLogger(DeployedCompositeCollectionImpl.class.getName()); + + @Property + public String compositeFile; + + @Property + public String deploymentContributionDirectory; + + @Reference + public LocalItemCollection deployableCollection; + + @Reference(required=false) + public LocalItemCollection processCollection; + + private ModelFactoryExtensionPoint modelFactories; + private AssemblyFactory assemblyFactory; + private CompositeProcessor compositeProcessor; + private XMLOutputFactory outputFactory; + private DocumentBuilder documentBuilder; + + /** + * Initialize the component. + */ + @Init + public void initialize() throws ParserConfigurationException { + + // Create factories + modelFactories = new DefaultModelFactoryExtensionPoint(); + assemblyFactory = modelFactories.getFactory(AssemblyFactory.class); + outputFactory = modelFactories.getFactory(XMLOutputFactory.class); + outputFactory.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true); + + // Create composite processor + ContributionFactory contributionFactory = modelFactories.getFactory(ContributionFactory.class); + PolicyFactory policyFactory = modelFactories.getFactory(PolicyFactory.class); + compositeProcessor = new CompositeProcessor(contributionFactory, assemblyFactory, policyFactory, null); + + // Create a document builder (used to pretty print XML) + documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + } + + public Entry<String, Item>[] getAll() { + logger.info("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.info("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); + } + + @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.info("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; + } + + // Support reading source composite file inside a JAR + String uri = item.getAlternate(); + 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); + } + } + + // Read the composite file and write to response + response.setContentType("text/xml"); + URLConnection connection = new URL(uri).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(); + } + + public String post(String key, Item item) { + logger.info("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) { + File directory = new File(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); + + return key; + } + + public void put(String key, Item item) throws NotFoundException { + logger.info("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); + + return; + } + } + throw new NotFoundException(key); + } + + public void delete(String key) throws NotFoundException { + logger.info("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); + break; + } + } + + // Delete the file too if it is in the deployment contribution directory + if (deploymentContributionDirectory != null && contributionURI.equals(DEPLOYMENT_CONTRIBUTION_URI)) { + File file = new File(deploymentContributionDirectory, qname.getLocalPart() + ".composite"); + if (file.exists()) { + file.delete(); + } + } + + if (deleted == null) { + throw new NotFoundException(key); + } + } + + 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 { + Composite compositeCollection; + File file = new File(compositeFile); + if (file.exists()) { + 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); + } + } 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)); + } + return compositeCollection; + } + + /** + * Write the domain composite back to disk. + * + * @param compositeCollection + */ + private void writeCompositeCollection(Composite compositeCollection) { + try { + // 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 + FileOutputStream os = new FileOutputStream(new File(compositeFile)); + XMLSerializer serializer = new XMLSerializer(os, format); + serializer.serialize(document); + } catch (Exception e) { + throw new ServiceRuntimeException(e); + } + } + +} diff --git a/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/java/org/apache/tuscany/sca/workspace/admin/impl/DomainAdminUtil.java b/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/java/org/apache/tuscany/sca/workspace/admin/impl/DomainAdminUtil.java new file mode 100644 index 0000000000..39fec24e92 --- /dev/null +++ b/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/java/org/apache/tuscany/sca/workspace/admin/impl/DomainAdminUtil.java @@ -0,0 +1,249 @@ +/* + * 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.workspace.admin.impl; + +import java.io.File; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; + +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.contribution.ModelFactoryExtensionPoint; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.assembly.ActivationException; +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.core.invocation.ProxyFactoryExtensionPoint; +import org.apache.tuscany.sca.host.embedded.impl.ReallySmallRuntime; +import org.apache.tuscany.sca.interfacedef.InterfaceContract; +import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceFactory; +import org.apache.tuscany.sca.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 DomainAdminUtil { + + 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(DomainAdminUtil.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 { + URI uri = URI.create(location); + String scheme = uri.getScheme(); + 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 { + 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) { + URI uri = URI.create(contributionLocation); + if ("file".equals(uri.getScheme())) { + String path = uri.toString().substring(5); + File file = new File(path); + if (file.isDirectory()) { + if (contributionLocation.endsWith("/")) { + return contributionLocation + deployableURI; + } else { + return contributionLocation + "/" + deployableURI; + } + } else { + return contributionLocation + "!/" + deployableURI; + } + } else { + return contributionLocation + "!/" + deployableURI; + } + } + + /** + * 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://tempuri.org", "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); + } + } + + /** + * Temporary instantiation of a dummy Tuscany runtime. + * FIXME We need a better way to bootstrap without having to create + * a runtime instance at all. + * + * @return + */ + static ReallySmallRuntime newRuntime() { + try { + ReallySmallRuntime runtime = new ReallySmallRuntime(Thread.currentThread().getContextClassLoader()); + runtime.start(); + return runtime; + } catch (ActivationException e) { + throw new ServiceRuntimeException(e); + } + } +} diff --git a/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/java/org/apache/tuscany/sca/workspace/admin/impl/FileCollectionImpl.java b/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/java/org/apache/tuscany/sca/workspace/admin/impl/FileCollectionImpl.java new file mode 100644 index 0000000000..241dc6f55b --- /dev/null +++ b/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/java/org/apache/tuscany/sca/workspace/admin/impl/FileCollectionImpl.java @@ -0,0 +1,129 @@ +/* + * 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.workspace.admin.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.implementation.data.collection.Entry; +import org.apache.tuscany.sca.implementation.data.collection.Item; +import org.apache.tuscany.sca.implementation.data.collection.ItemCollection; +import org.apache.tuscany.sca.implementation.data.collection.NotFoundException; +import org.osoa.sca.annotations.Init; +import org.osoa.sca.annotations.Property; +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 final static Logger logger = Logger.getLogger(FileCollectionImpl.class.getName()); + + @Property + public String directoryName; + + /** + * Initialize the component. + */ + @Init + public void initialize() throws IOException { + } + + public Entry<String, Item>[] getAll() { + logger.info("getAll"); + + // Return all the files + List<Entry<String, Item>> entries = new ArrayList<Entry<String, Item>>(); + File directory = new File(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.info("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.info("delete " + key); + + File directory = new File(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/tags/1.2/modules/workspace-admin/src/main/java/org/apache/tuscany/sca/workspace/admin/impl/FileServiceImpl.java b/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/java/org/apache/tuscany/sca/workspace/admin/impl/FileServiceImpl.java new file mode 100644 index 0000000000..fe0fc9e415 --- /dev/null +++ b/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/java/org/apache/tuscany/sca/workspace/admin/impl/FileServiceImpl.java @@ -0,0 +1,147 @@ +/* + * 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.workspace.admin.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.osoa.sca.annotations.Init; +import org.osoa.sca.annotations.Property; +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 final static Logger logger = Logger.getLogger(FileServiceImpl.class.getName()); + + @Property + public String directoryName; + + 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 + try { + for (FileItem item: (List<FileItem>)upload.parseRequest(request)) { + if (!item.isFormField()) { + File directory = new File(directoryName); + if (!directory.exists()) { + directory.mkdirs(); + } + logger.info("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.info("get " + path); + + try { + + // Analyze the given path + URI uri = URI.create(path); + String scheme = uri.getScheme(); + if (scheme == null) { + + // If no scheme is specified then the path identifies file + // inside our directory + uri = new File(directoryName, path).toURI(); + + } else if (!scheme.equals("file")) { + + // 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/tags/1.2/modules/workspace-admin/src/main/java/org/apache/tuscany/sca/workspace/admin/impl/NodeProcessCollectionFacadeImpl.java b/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/java/org/apache/tuscany/sca/workspace/admin/impl/NodeProcessCollectionFacadeImpl.java new file mode 100644 index 0000000000..251f6cd410 --- /dev/null +++ b/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/java/org/apache/tuscany/sca/workspace/admin/impl/NodeProcessCollectionFacadeImpl.java @@ -0,0 +1,249 @@ +/* + * 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.workspace.admin.impl; + +import static org.apache.tuscany.sca.workspace.admin.impl.DomainAdminUtil.compositeQName; +import static org.apache.tuscany.sca.workspace.admin.impl.DomainAdminUtil.dynamicReference; +import static org.apache.tuscany.sca.workspace.admin.impl.DomainAdminUtil.newRuntime; +import static org.apache.tuscany.sca.workspace.admin.impl.DomainAdminUtil.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.AtomBinding; +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.host.embedded.impl.ReallySmallRuntime; +import org.apache.tuscany.sca.implementation.data.collection.Entry; +import org.apache.tuscany.sca.implementation.data.collection.Item; +import org.apache.tuscany.sca.implementation.data.collection.ItemCollection; +import org.apache.tuscany.sca.implementation.data.collection.LocalItemCollection; +import org.apache.tuscany.sca.implementation.data.collection.NotFoundException; +import org.osoa.sca.ServiceReference; +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 final static Logger logger = Logger.getLogger(NodeProcessCollectionFacadeImpl.class.getName()); + + @Reference + public LocalItemCollection cloudCollection; + + private AssemblyFactory assemblyFactory; + private AtomBindingFactory atomBindingFactory; + private CompositeActivator compositeActivator; + + /** + * Initialize the component. + */ + @Init + public void initialize() { + + // Get a runtime + ReallySmallRuntime runtime = newRuntime(); + + // Get its composite activator + compositeActivator = runtime.getCompositeActivator(); + + // Get the model factories + ExtensionPointRegistry registry = runtime.getExtensionPointRegistry(); + ModelFactoryExtensionPoint modelFactories = registry.getExtensionPoint(ModelFactoryExtensionPoint.class); + assemblyFactory = modelFactories.getFactory(AssemblyFactory.class); + atomBindingFactory = modelFactories.getFactory(AtomBindingFactory.class); + } + + public Entry<String, Item>[] getAll() { + logger.info("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.info("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.info("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.info("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.info("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) { + 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/tags/1.2/modules/workspace-admin/src/main/java/org/apache/tuscany/sca/workspace/admin/impl/QuickStartServiceImpl.java b/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/java/org/apache/tuscany/sca/workspace/admin/impl/QuickStartServiceImpl.java new file mode 100644 index 0000000000..550f97c2ad --- /dev/null +++ b/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/java/org/apache/tuscany/sca/workspace/admin/impl/QuickStartServiceImpl.java @@ -0,0 +1,236 @@ +/* + * 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.workspace.admin.impl; + +import static org.apache.tuscany.sca.workspace.admin.impl.DomainAdminUtil.compositeKey; +import static org.apache.tuscany.sca.workspace.admin.impl.DomainAdminUtil.compositeQName; +import static org.apache.tuscany.sca.workspace.admin.impl.DomainAdminUtil.contributionURI; +import static org.apache.tuscany.sca.workspace.admin.impl.DomainAdminUtil.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.implementation.data.collection.Entry; +import org.apache.tuscany.sca.implementation.data.collection.Item; +import org.apache.tuscany.sca.implementation.data.collection.LocalItemCollection; +import org.apache.tuscany.sca.implementation.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 final static 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 (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(); + if (contributionURI.equals(contributionURI(entry.getKey())) && item.getAlternate().endsWith(compositeURI)) { + compositeKey = entry.getKey(); + break; + } + } + + if (compositeKey == null) { + 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.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/tags/1.2/modules/workspace-admin/src/main/java/org/apache/tuscany/sca/workspace/admin/launcher/DomainManagerLauncherBootstrap.java b/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/java/org/apache/tuscany/sca/workspace/admin/launcher/DomainManagerLauncherBootstrap.java new file mode 100644 index 0000000000..7b23951aef --- /dev/null +++ b/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/java/org/apache/tuscany/sca/workspace/admin/launcher/DomainManagerLauncherBootstrap.java @@ -0,0 +1,84 @@ +/* + * 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.workspace.admin.launcher; + +import org.apache.tuscany.sca.host.embedded.SCADomain; +import org.apache.tuscany.sca.node.SCANode2; + +/** + * Bootstrap class for the SCA domain manager. + * + * @version $Rev$ $Date$ + */ +public class DomainManagerLauncherBootstrap { + private SCANode2 node; + + /** + * A node wrappering an instance of a domain manager. + */ + public static class NodeFacade implements SCANode2 { + private ClassLoader threadContextClassLoader; + private ClassLoader runtimeClassLoader; + private SCADomain domainManager; + + private NodeFacade() { + runtimeClassLoader = Thread.currentThread().getContextClassLoader(); + } + + public void start() { + threadContextClassLoader = Thread.currentThread().getContextClassLoader(); + boolean started = false; + try { + Thread.currentThread().setContextClassLoader(runtimeClassLoader); + domainManager = SCADomain.newInstance("DomainManager.composite"); + started = true; + } finally { + if (!started) { + Thread.currentThread().setContextClassLoader(threadContextClassLoader); + } + } + } + + public void stop() { + try { + Thread.currentThread().setContextClassLoader(runtimeClassLoader); + domainManager.close(); + } finally { + Thread.currentThread().setContextClassLoader(threadContextClassLoader); + } + } + } + + /** + * Constructs a new domain manager bootstrap. + */ + public DomainManagerLauncherBootstrap() throws Exception { + node = new NodeFacade(); + } + + /** + * Returns the node representing the domain manager. + * @return + */ + public SCANode2 getNode() { + return node; + } + +} diff --git a/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/resources/DomainManager.composite b/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/resources/DomainManager.composite new file mode 100644 index 0000000000..3f793405b1 --- /dev/null +++ b/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/resources/DomainManager.composite @@ -0,0 +1,188 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * 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. +--> +<composite xmlns="http://www.osoa.org/xmlns/sca/1.0" + xmlns:t="http://tuscany.apache.org/xmlns/sca/1.0" + targetNamespace="http://tuscany.apache.org/xmlns/sca/1.0" + name="DomainManager"> + + <component name="AdminUI"> + <t:implementation.widget location="home.html"/> + <service name="Widget"> + <t:binding.http uri="http://localhost:9990/ui/home"/> + </service> + </component> + + <component name="ContributionUI"> + <t:implementation.widget location="workspace.html"/> + <service name="Widget"> + <t:binding.http uri="http://localhost:9990/ui/workspace"/> + </service> + <reference name="workspace" target="ContributionCollectionComponent/ItemCollection"> + <t:binding.atom/> + </reference> + </component> + + <component name="FilesUI"> + <t:implementation.widget location="files.html"/> + <service name="Widget"> + <t:binding.http uri="http://localhost:9990/ui/files"/> + </service> + <reference name="files" target="FileCollectionComponent"> + <t:binding.atom/> + </reference> + </component> + + <component name="DomainCompositeUI"> + <t:implementation.widget location="composite.html"/> + <service name="Widget"> + <t:binding.http uri="http://localhost:9990/ui/composite"/> + </service> + <reference name="domainComposite" target="DomainCompositeCollectionComponent/ItemCollection"> + <t:binding.atom/> + </reference> + </component> + + <component name="CloudUI"> + <t:implementation.widget location="cloud.html"/> + <service name="Widget"> + <t:binding.http uri="http://localhost:9990/ui/cloud"/> + </service> + <reference name="cloudComposite" target="CloudCollectionComponent/ItemCollection"> + <t:binding.atom/> + </reference> + <reference name="processCollection" target="NodeProcessCollectionFacadeComponent/ItemCollection"> + <t:binding.atom/> + </reference> + </component> + + <component name="ContributionCollectionComponent"> + <implementation.java class="org.apache.tuscany.sca.workspace.admin.impl.ContributionCollectionImpl"/> + <property name="workspaceFile">workspace.xml</property> + <property name="deploymentContributionDirectory">cloud</property> + <service name="ItemCollection"> + <t:binding.atom uri="http://localhost:9990/workspace" title="Contributions"/> + </service> + <service name="Servlet"> + <t:binding.http uri="http://localhost:9990/contribution"/> + </service> + </component> + + <component name="FileCollectionComponent"> + <implementation.java class="org.apache.tuscany.sca.workspace.admin.impl.FileCollectionImpl"/> + <property name="directoryName">files</property> + <service name="ItemCollection"> + <t:binding.atom uri="http://localhost:9990/feed/files" title="Files"/> + </service> + </component> + + <component name="FileServiceComponent"> + <implementation.java class="org.apache.tuscany.sca.workspace.admin.impl.FileServiceImpl"/> + <property name="directoryName">files</property> + <service name="Servlet"> + <t:binding.http uri="http://localhost:9990/files"/> + </service> + </component> + + <component name="DomainCompositeCollectionComponent"> + <implementation.java class="org.apache.tuscany.sca.workspace.admin.impl.DeployedCompositeCollectionImpl"/> + <property name="compositeFile">domain.composite</property> + <service name="ItemCollection"> + <t:binding.atom uri="http://localhost:9990/composite" title="Domain Composites"/> + </service> + <service name="Servlet"> + <t:binding.http uri="http://localhost:9990/composite-source"/> + </service> + <reference name="deployableCollection" target="DeployableCompositeCollectionComponent/LocalItemCollection"/> + </component> + + <component name="DeployableCompositeCollectionComponent"> + <implementation.java class="org.apache.tuscany.sca.workspace.admin.impl.DeployableCompositeCollectionImpl"/> + <service name="ItemCollection"> + <t:binding.atom uri="http://localhost:9990/deployable" title="Deployable Composites"/> + </service> + <service name="Servlet"> + <t:binding.http uri="http://localhost:9990/composite-resolved"/> + </service> + <reference name="contributionCollection" target="ContributionCollectionComponent/LocalItemCollection"/> + <reference name="domainCompositeCollection" target="DomainCompositeCollectionComponent/LocalItemCollection"/> + <reference name="cloudCollection" target="CloudCollectionComponent/LocalItemCollection"/> + </component> + + <component name="CloudCollectionComponent"> + <implementation.java class="org.apache.tuscany.sca.workspace.admin.impl.DeployedCompositeCollectionImpl"/> + <property name="compositeFile">cloud.composite</property> + <property name="deploymentContributionDirectory">cloud</property> + <service name="ItemCollection"> + <t:binding.atom uri="http://localhost:9990/cloud" title="Nodes"/> + </service> + <service name="Servlet"> + <t:binding.http uri="http://localhost:9990/cloud-source"/> + </service> + <reference name="deployableCollection" target="DeployableCompositeCollectionComponent/LocalItemCollection"/> + <reference name="processCollection" target="NodeProcessCollectionFacadeComponent/LocalItemCollection"/> + </component> + + <component name="CompositeImageCollectionComponent"> + <implementation.java class="org.apache.tuscany.sca.workspace.admin.impl.CompositeImageCollectionImpl"/> + <service name="ItemCollection"> + <t:binding.atom uri="http://localhost:9990/composite-image" title="Install Image"/> + </service> + <service name="Servlet"> + <t:binding.http uri="http://localhost:9990/node-image"/> + </service> + <reference name="contributionCollection" target="ContributionCollectionComponent/LocalItemCollection"/> + <reference name="cloudCollection" target="CloudCollectionComponent/LocalItemCollection"/> + </component> + + <component name="QuickStartServiceComponent"> + <implementation.java class="org.apache.tuscany.sca.workspace.admin.impl.QuickStartServiceImpl"/> + <service name="Servlet"> + <t:binding.http uri="http://localhost:9990/quickstart"/> + </service> + <reference name="contributionCollection" target="ContributionCollectionComponent/LocalItemCollection"/> + <reference name="deployableCollection" target="DeployableCompositeCollectionComponent/LocalItemCollection"/> + <reference name="domainCompositeCollection" target="DomainCompositeCollectionComponent/LocalItemCollection"/> + <reference name="cloudCollection" target="CloudCollectionComponent/LocalItemCollection"/> + <reference name="processCollection" target="NodeProcessCollectionComponent/LocalItemCollection"/> + </component> + + <component name="NodeProcessCollectionFacadeComponent"> + <implementation.java class="org.apache.tuscany.sca.workspace.admin.impl.NodeProcessCollectionFacadeImpl"/> + <service name="ItemCollection"> + <t:binding.atom uri="http://localhost:9990/processes" title="Log"/> + </service> + <reference name="cloudCollection" target="CloudCollectionComponent/LocalItemCollection"/> + </component> + + <component name="NodeProcessCollectionComponent"> + <implementation.java class="org.apache.tuscany.sca.implementation.node.launcher.NodeProcessCollectionImpl"/> + <service name="ItemCollection"> + <t:binding.atom uri="http://localhost:9990/node/processes" title="Log"/> + </service> + </component> + + <component name="PingServiceComponent"> + <implementation.java class="org.apache.tuscany.sca.implementation.node.launcher.PingServiceImpl"/> + <service name="Servlet"> + <t:binding.http uri="http://localhost:9990/ping"/> + </service> + </component> + +</composite> diff --git a/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/resources/admin.css b/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/resources/admin.css new file mode 100644 index 0000000000..aa6e910f85 --- /dev/null +++ b/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/resources/admin.css @@ -0,0 +1,73 @@ +/* + * 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. + */ + +body { + white-space: nowrap +} + +table { + border: 1px; border-collapse: separate +} + +th { + font-weight: bold; white-space: nowrap; background-color: #e5ecf9; color: #598edd; + text-align: left; padding-left: 2px; padding-right: 20px; padding-top: 2px; padding-bottom: 2px; vertical-align: text-top; + border-top: 1px; border-bottom: 1px; border-left: 0px; border-right: 0px; + border-style: solid; border-top-color: #a2bae7; border-bottom-color: #d1d3d4 +} + +td { + padding-left: 2px; padding-top: 2px; padding-right: 20px; white-space: nowrap; vertical-align: text-top +} + +input { + vertical-align: middle +} + +a:link { + color: blue +} + +a:visited { + color: blue +} + +.tdw { + padding-left: 2px; padding-top: 2px; padding-right: 20px; white-space: normal; vertical-align: text-top +} + +.hd1 { + font-size:150%; font-weight: bold +} + +.tbar { + margin: 0px; + padding-top: 0px; padding-left: 0px; padding-right: 0px; padding-bottom: 3px; + border-bottom: 1px solid #a2bae7 +} + +.ltbar { + padding-left: 0px; padding-top: 0px; padding-right: 20px; white-space: nowrap; vertical-align: top +} + +.rtbar { + padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap; vertical-align: top; + text-align: right +} + diff --git a/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/resources/cloud.html b/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/resources/cloud.html new file mode 100644 index 0000000000..193e30bb49 --- /dev/null +++ b/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/resources/cloud.html @@ -0,0 +1,266 @@ +<!-- + * 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. +--> +<html> +<head> +<title>SCA Domain - Cloud</title> + +<script type="text/javascript" src="cloud.js"></script> +<script type="text/javascript" src="utils.js"></script> + +<script language="JavaScript"> + + //@Reference + var cloudComposite = new Reference("cloudComposite"); + + //@Reference + var processCollection = new Reference("processCollection"); + + function getComposites() { + cloudComposite.get("", getCompositesResponse); + } + + function contributionURI(id) { + var i = id.indexOf(';'); + return id.substring(10, i); + } + + function compositeName(id) { + var i = id.indexOf(';'); + return id.substring(i + 1); + } + + function compositeLocalName(id) { + name = compositeName(id); + var i = name.indexOf(';'); + return name.substring(i + 1); + } + + var nodeNames; + + function getCompositesResponse(feed) { + nodeNames = new Array(); + if (feed != null) { + var entries = feed.getElementsByTagName("entry"); + var composites = ""; + composites += '<table width="100%">'; + composites += '<tr><th>Node</th><th>Composite</th><th>Contribution</th><th>Install Image</th>' + + '<th>Log</th></tr>'; + + for (var i=0; i<entries.length; i++) { + var nodeId = entries[i].getElementsByTagName("id")[0].firstChild.nodeValue; + var links = entries[i].getElementsByTagName("link"); + var nodeLink = undefined; + var compositeLink = undefined; + var compositeId = "composite:undefined;undefined;undefined"; + var uri = '<span style="color: red">unknown</span>'; + var qname = undefined; + for (var l = 0; l < links.length; l++) { + var a = links[l].getAttribute('rel'); + if (a == undefined) { + nodeLink = links[l].getAttribute('href'); + } else if (a == 'related') { + compositeLink = links[l].getAttribute('href'); + var c = compositeLink.indexOf('composite:'); + compositeId = compositeLink.substring(c); + uri = contributionURI(compositeId); + qname = compositeName(compositeId); + } + } + + var nodeName = compositeLocalName(nodeId); + nodeNames[i] = nodeName; + + var content = ""; + if (entries[i].getElementsByTagName("content")[0].firstChild != null) { + content = entries[i].getElementsByTagName("content")[0].firstChild.nodeValue; + } + + composites += '<tr>' + if (content.indexOf('<span id="problem"') != -1) { + composites += '<td><input name="composites" type="checkbox" value="' + nodeId + '">' + + '<a href=\"' + nodeLink + '\">' + nodeName + '</a></td>'; + composites += '<td>' + content + '</td>'; + composites += '<td>' + uri + '</td>'; + } else { + composites += '<td><input name="composites" type="checkbox" value="' + nodeId + '">' + + '<a href=\"' + nodeLink + '\">' + nodeName + '</a></td>'; + composites += '<td><a href=\"' + compositeLink + '\">' + qname + '</a></td>'; + composites += '<td><a href="/contribution/' + uri + '">' + uri + '</a></td>'; + } + composites += '<td><a href="/node-image/' + nodeName + '"><img src="icons/feed-icon.png" border="0"></a></td>'; + composites += '<td><a href="/processes/?node=' + nodeName + '"><img src="icons/feed-icon.png" border="0"></a></td>'; + composites += '</tr>'; + } + composites += '</table>'; + document.getElementById("composites").innerHTML = composites; + } + } + + function deleteComposite() { + var composites = array(document.cloudCompositeForm.composites); + for (var i = 0; i < composites.length; i++) { + if (composites[i].checked) { + var id = composites[i].value; + cloudComposite.del(id, deleteCompositeResponse); + } + } + } + + function deleteCompositeResponse() { + getComposites(); + } + + function addComposite() { + var nodeName = document.newCompositeForm.nodeName.value; + var nodeURI = document.newCompositeForm.nodeURI.value; + var compositeNamespace = document.newCompositeForm.compositeNamespace.value; + var compositeName = document.newCompositeForm.compositeName.value; + var contributionURI = document.newCompositeForm.contributionURI.value; + var id = 'composite:' + + 'http://tuscany.apache.org/cloud' + ';' + + 'http://tuscany.apache.org/cloud' + ';' + + nodeName; + + var entry = '<entry xmlns="http://www.w3.org/2005/Atom">\n' + + '<id>' + id + '</id>\n' + + '<content type="text/xml">\n' + + '<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="' + compositeNamespace + '"\n' + + ' name="' + nodeName + '">\n' + + '\n' + + ' <component name="' + nodeName + '">\n' + + ' <t:implementation.node uri="' + contributionURI + '" composite="c:' + compositeName + '"/>\n' + + ' <service name="Node">\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>' + + '</content>' + + '</entry>'; + cloudComposite.post(entry, addCompositeResponse); + } + + function addCompositeResponse() { + document.newCompositeForm.nodeName.value = ""; + document.newCompositeForm.nodeURI.value = ""; + document.newCompositeForm.compositeNamespace.value = ""; + document.newCompositeForm.compositeName.value = ""; + document.newCompositeForm.contributionURI.value = ""; + getComposites(); + } + + function startComposite() { + var composites = array(document.cloudCompositeForm.composites); + for (var i = 0; i < composites.length; i++) { + if (composites[i].checked) { + var id = nodeNames[i]; + + var entry = '<entry xmlns="http://www.w3.org/2005/Atom">' + + '<id>' + id + '</id>' + + '</entry>'; + processCollection.post(entry, startCompositeResponse); + } + } + } + + function startCompositeResponse() { + for (var i = 0; i < composites.length; i++) { + if (composites[i].checked) { + composites[i].checked = false; + } + } + } + + function stopComposite() { + var composites = array(document.cloudCompositeForm.composites); + for (var i = 0; i < composites.length; i++) { + if (composites[i].checked) { + var id = nodeNames[i]; + processCollection.del(id, stopCompositeResponse); + } + } + } + + function stopCompositeResponse() { + for (var i = 0; i < composites.length; i++) { + if (composites[i].checked) { + composites[i].checked = false; + } + } + } + + function init() { + toolbar(); + getComposites(); + } + +</script> + +<link rel="stylesheet" type="text/css" href="admin.css"> +</head> + +<body onload="init()"> + <div id="toolbar"></div> + + <div id="cloudComposite"> + <br> + <span class=hd1> + SCA Domain<br><br> + Cloud</b> <a href="/cloud/"><img src="icons/feed-icon.png" border="0"></a> + </span> + <br><br> + Here is the list of SCA nodes configured in your SCA domain cloud. + <br><br> + + <form name="cloudCompositeForm"> + <div id="composites" ></div> + <br> + <input type="button" onClick="startComposite()" value="Start" /> + <input type="button" onClick="stopComposite()" value="Stop" /> + + <input type="button" onClick="deleteComposite()" value="Delete" /> + </form> + + <br><br> + + <form name="newCompositeForm"> + <table width="100%"> + <tr><th>Add a Node</th></tr> + <tr><td>Add a node to the cloud. The node will run the SCA components declared in the specified composite.</td></tr> + </table> + <br> + <table> + <tr><td>Node name:</td><td><input type="text" name="nodeName" size="50"/></td><td>e.g. MyNode</td></tr> + <tr><td>Node URI:</td><td><input type="text" name="nodeURI" size="50"/></td></td><td>e.g. http://host:8080</td></tr> + <tr><td>Composite namespace:</td><td><input type="text" name="compositeNamespace" size="50"/></td></td><td>e.g. http://my/namespace</td></tr> + <tr><td>Composite name:</td><td><input type="text" name="compositeName" size="50"/></td></td><td>e.g. mycomposite</td></tr> + <tr><td>Contribution URI:</td><td><input type="text" name="contributionURI" size="50"/></td></td><td>e.g. mycontrib, http://mycontrib</td></tr> + </table> + <input type="button" onClick="addComposite()" value="Add" /> + </form> + + </div> +</body> + +</html> diff --git a/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/resources/composite.html b/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/resources/composite.html new file mode 100644 index 0000000000..96cf59c7c2 --- /dev/null +++ b/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/resources/composite.html @@ -0,0 +1,172 @@ +<!-- + * 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. +--> +<html> +<head> +<title>SCA Domain - Domain Composite</title> + +<script type="text/javascript" src="composite.js"></script> +<script type="text/javascript" src="utils.js"></script> + +<script language="JavaScript"> + + //@Reference + var domainComposite = new Reference("domainComposite"); + + function getComposites() { + domainComposite.get("", getCompositesResponse); + } + + function contributionURI(id) { + var i = id.indexOf(';'); + return id.substring(10, i); + } + + function compositeName(id) { + var i = id.indexOf(';'); + return id.substring(i + 1); + } + + function getCompositesResponse(feed) { + if (feed != null) { + var entries = feed.getElementsByTagName("entry"); + var composites = ""; + composites += '<table width="100%">'; + composites += '<tr><th>Composite</th>' + + '<th>Contribution</th>' + + '<th>Components</th>' + + '</tr>'; + //'<th>Composite Install Image</th>' + + + for (var i=0; i<entries.length; i++) { + var id = entries[i].getElementsByTagName("id")[0].firstChild.nodeValue; + var link = entries[i].getElementsByTagName("link")[0].getAttribute("href"); + var uri = contributionURI(id); + var qname = compositeName(id); + + var content = ""; + if (entries[i].getElementsByTagName("content")[0].firstChild != null) { + content = entries[i].getElementsByTagName("content")[0].firstChild.nodeValue; + } + var components = ''; + var bs = content.indexOf('<span id="components">'); + if (bs != -1) { + var es = content.indexOf('</span>', bs); + components = content.substring(bs, es + 7); + } else { + bs = content.indexOf('<span id="problem"'); + if (bs != -1) { + var es = content.indexOf('</span>', bs); + components = content.substring(bs, es + 7); + } + } + + composites += '<tr>' + composites += '<td><input name="composites" type="checkbox" value="' + id + '">'; + composites += '<a href=\"' + link + '\">' + qname + '</a></td>'; + composites += '<td><a href="/contribution/' + uri + '">' + uri + '</a></td>'; + composites += '<td class=tdw>' + components + '</td>'; + //composites += '<td><a href="/composite-image/?composite=' + id + '"><img src="icons/feed-icon.png" border="0"></a></td>'; + composites += '</tr>'; + } + composites += '</table>'; + document.getElementById("composites").innerHTML = composites; + } + } + + function deleteComposite() { + var composites = array(document.domainCompositeForm.composites); + for (var i = 0; i < composites.length; i++) { + if (composites[i].checked) { + var id = composites[i].value; + domainComposite.del(id, deleteCompositeResponse); + } + } + } + + function deleteCompositeResponse() { + getComposites(); + } + + function addComposite() { + var id = 'composite:' + + document.newCompositeForm.contributionURI.value + ';' + + document.newCompositeForm.compositeNamespace.value + ';' + + document.newCompositeForm.compositeName.value; + var entry = '<entry xmlns="http://www.w3.org/2005/Atom">' + + '<title>' + id +'</title>' + + '<id>' + id + '</id>' + + '</entry>'; + domainComposite.post(entry, addCompositeResponse); + } + + function addCompositeResponse() { + document.newCompositeForm.compositeNamespace.value = ""; + document.newCompositeForm.compositeName.value = ""; + document.newCompositeForm.contributionURI.value = ""; + getComposites(); + } + + function init() { + toolbar(); + getComposites(); + } + +</script> + +<link rel="stylesheet" type="text/css" href="admin.css"> +</head> + +<body onload="init()"> + <div id="toolbar"></div> + + <div id="domainComposite"> + <br> + <span class=hd1> + SCA Domain<br><br> + Domain Composite <a href="/composite/"><img src="icons/feed-icon.png" border="0"></a> + </span> + <br><br> + Here is the list of SCA composites currently included as top-level composites in your SCA domain. + <br><br> + + <form name="domainCompositeForm"> + <div id="composites" ></div> + <br> + <input type="button" onClick="deleteComposite()" value="Delete" /> + </form> + + <br><br> + + <form name="newCompositeForm"> + <table width="100%"> + <tr><th>Add Composite</th></tr> + <tr><td>Add an SCA composite describing your SCA service components.</td></tr> + </table> + <br> + <table> + <tr><td>Composite namespace:</td><td><input type="text" name="compositeNamespace" size="50"/></td><td>e.g. http://my/namespace</td></tr> + <tr><td>Composite name:</td><td><input type="text" name="compositeName" size="50"/></td><td>e.g. mycomposite</td></tr> + <tr><td>Contribution URI:</td><td><input type="text" name="contributionURI" size="50"/></td><td>e.g. mycontrib, http://mycontrib</td></tr> + </table> + <input type="button" onClick="addComposite()" value="Add" /> + </form> + + </div> +</body> +</html> diff --git a/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/resources/files.html b/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/resources/files.html new file mode 100644 index 0000000000..d29b913bf5 --- /dev/null +++ b/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/resources/files.html @@ -0,0 +1,114 @@ +<!-- + * 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. +--> +<html> +<head> +<title>SCA Domain - Contribution File Server</title> + +<script type="text/javascript" src="files.js"></script> +<script type="text/javascript" src="utils.js"></script> + +<script language="JavaScript"> + + //@Reference + var files = new Reference("files"); + + function getFiles() { + files.get("", getFilesResponse); + } + + function getFilesResponse(feed) { + if (feed != null) { + var entries = feed.getElementsByTagName("entry"); + var list = '<table width="100%"><tr><th>Files</th></tr>'; + for (var i=0; i<entries.length; i++) { + var id = entries[i].getElementsByTagName("id")[0].firstChild.nodeValue; + var location = entries[i].getElementsByTagName("link")[0].getAttribute("href"); + list += '<tr><td><input name="files" type="checkbox" value="' + id + '">' + + '<a href=\"' + location + '\">' + id + '</a></td></tr>'; + } + list += "</table>"; + document.getElementById("files").innerHTML = list; + } + } + + function deleteFile() { + var list = array(document.filesForm.files); + for (var i=0; i < list.length; i++) { + if (list[i].checked) { + var id = list[i].value; + files.del(id, deleteFileResponse); + } + } + } + + function deleteFileResponse() { + getFiles(); + } + + function uploadFile() { + document.uploadFileForm.submit(); + } + + function init() { + toolbar(); + getFiles(); + } + +</script> + +<link rel="stylesheet" type="text/css" href="admin.css"> +</head> + +<body onload="init()"> + <div id="toolbar"></div> + + <div id="fileServer"> + <br> + <span class=hd1> + SCA Domain<br><br> + File Server <a href="/feed/files/"><img src="icons/feed-icon.png" border="0"></a> + </span> + <br><br> + This is a simple ATOM-based file server useful to share files if you don't have an FTP, SVN or Maven repository. + <br><br> + + <form name="filesForm"> + <div id="files" ></div> + <br/> + <input type="button" onClick="deleteFile()" value="Delete" /> + </form> + + <br><br> + + <form method="post" name="uploadFileForm" enctype='multipart/form-data' action='/files'> + <table width="100%"> + <tr><th>Upload File</th></tr> + <tr><td>Upload a file to the server.</td></tr> + </table> + <br> + <table border="0"> + <tr><td>File:</td><td><input type="file" name="file" size="50"/></td></tr> + </table> + <br/> + <input type="button" onClick="uploadFile()" value="Upload" /> + </form> + + </div> +</body> +</html> diff --git a/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/resources/home.html b/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/resources/home.html new file mode 100644 index 0000000000..02b70e688e --- /dev/null +++ b/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/resources/home.html @@ -0,0 +1,59 @@ +<!-- + * 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. +--> +<html> +<head> +<title>SCA Domain - Home</title> + +<script type="text/javascript" src="home.js"></script> +<script type="text/javascript" src="utils.js"></script> + +<script language="JavaScript"> + + function init() { + toolbar(); + } + + +</script> + +<link rel="stylesheet" type="text/css" href="admin.css"> +</head> + +<body onload="init()"> + <div id="toolbar"></div> + + <br> + <span class=hd1> + SCA Domain + </span> + + <br><br><br><br><br> + + <form> + <table border="0" align="center"> + <tr><td valign="top"><span style="font-size:150%; color: blue">Search:</span></td><td><input type="text" name="search" size="50"/></td></tr> + <tr><td></td><td align="center"><input type="button" name="search" value="Search" /></td></tr> + </table> + </form> + + <br><br><br><br><br><br><br> + <center>This page is under construction, searching the domain is not implemented yet.</center> + +</body> +</html> diff --git a/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/resources/icons/feed-icon.png b/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/resources/icons/feed-icon.png Binary files differnew file mode 100644 index 0000000000..a59728b2ad --- /dev/null +++ b/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/resources/icons/feed-icon.png diff --git a/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/resources/utils.js b/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/resources/utils.js new file mode 100644 index 0000000000..853ce5d235 --- /dev/null +++ b/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/resources/utils.js @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +function Tool(name, href) { + this.name = name; + this.href = href; +} + +Tool.prototype.print = function() { + var loc = '' + location; + if (loc.match(this.href) == null) { + return '<a href="' + this.href + '">' + this.name + '</a>'; + } else { + return '<span>' + this.name + '</span>'; + } +} + +function toolbar() { + + var toolbar = '<table width="100%" cellpadding="0" cellspacing="0" class=tbar><tr>' + + '<td class=ltbar><table border="0" cellspacing="0" cellpadding="0"><tr>'; + + for (var i = 0; i < tools.length; i++) { + toolbar = toolbar + '<td class=ltbar>' +tools[i].print() + '</td>' + } + + toolbar = toolbar + '</tr></table></td>' + + '<td class=rtbar><table border="0" cellpadding="0" cellspacing="0" align="right"><tr>' + + '<td class=rtbar>' + home.print() + '</td></tr></table></td>' + + '</tr></table>'; + + document.getElementById('toolbar').innerHTML = toolbar; +} + +function array(obj) { + if (obj.length == undefined) { + var a = new Array(); + a[0] = obj; + return a; + } + else { + return obj; + } +} + +var tools = new Array(); +tools[0] = new Tool("Contributions", "/ui/workspace"); +tools[1] = new Tool("Composites", "/ui/composite"); +tools[2] = new Tool("Cloud", "/ui/cloud"); +tools[3] = new Tool("Files", "/ui/files"); + +var home = new Tool("Home", "/ui/home"); diff --git a/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/resources/workspace.html b/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/resources/workspace.html new file mode 100644 index 0000000000..fb00b4c8c1 --- /dev/null +++ b/sca-java-1.x/tags/1.2/modules/workspace-admin/src/main/resources/workspace.html @@ -0,0 +1,162 @@ +<!-- + * 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. +--> +<html> +<head> +<title>SCA Domain - Contributions</title> + +<script type="text/javascript" src="workspace.js"></script> +<script type="text/javascript" src="utils.js"></script> + +<script language="JavaScript"> + + //@Reference + var workspace = new Reference("workspace"); + + function getContributions() { + workspace.get("", getContributionsResponse); + } + + function getContributionsResponse(feed) { + if (feed != null) { + var entries = feed.getElementsByTagName("entry"); + var contributions = ""; + contributions += '<table width="100%">'; + contributions += '<tr><th>Contribution</th><th>Dependencies</td><th>Deployable Composites</th></tr>'; + for (var i=0; i<entries.length; i++) { + var id = entries[i].getElementsByTagName("id")[0].firstChild.nodeValue; + var location = entries[i].getElementsByTagName("link")[0].getAttribute("href"); + var content = ''; + if (entries[i].getElementsByTagName("content")[0].firstChild != null) { + content = entries[i].getElementsByTagName("content")[0].firstChild.nodeValue; + } + + contributions += '<tr>'; + contributions += '<td><input name="contributions" type="checkbox" value="' + id + '">' + + '<a href=\"' + location + '\">' + id + '</a></td>'; + + var dependencies = ''; + var bs = content.indexOf('<span id="dependencies">'); + if (bs != -1) { + var es = content.indexOf('</span>', bs); + dependencies = content.substring(bs, es + 7); + } + + var deployables = ''; + var bs = content.indexOf('<span id="deployables">'); + if (bs != -1) { + var es = content.indexOf('</span>', bs); + deployables = content.substring(bs, es + 7); + } + + var problems = ""; + var bs = content.indexOf('<span id="problems" '); + if (bs != -1) { + var es = content.indexOf('</span>', bs); + if (dependencies.length != 0) { + problems = '<br>'; + } + problems += content.substring(bs, es + 7); + } + + contributions += '<td class=tdw>' + dependencies + problems + ' </td>'; + contributions += '<td class=tdw>' + deployables + '</td>'; + contributions += '</tr>'; + } + contributions += '</table>'; + document.getElementById("contributions").innerHTML = contributions; + } + } + + function deleteContribution() { + var contributions = array(document.workspaceForm.contributions); + for (var i=0; i < contributions.length; i++) { + if (contributions[i].checked) { + var id = contributions[i].value; + workspace.del(id, deleteContributionResponse); + } + } + } + + function deleteContributionResponse() { + getContributions(); + } + + function addContribution() { + var id = document.newContributionForm.contributionID.value; + var location = document.newContributionForm.contributionLocation.value; + var entry = '<entry xmlns="http://www.w3.org/2005/Atom">' + + '<title>Contribution - ' + id +'</title>' + + '<id>' + id + '</id>' + + '<link href="' + location + '" />' + + '</entry>'; + workspace.post(entry, addContributionResponse); + } + + function addContributionResponse() { + document.newContributionForm.contributionID.value = ""; + document.newContributionForm.contributionLocation.value = ""; + getContributions(); + } + + function init() { + toolbar(); + getContributions(); + } + +</script> + +<link rel="stylesheet" type="text/css" href="admin.css"> +</head> + +<body onload="init()"> + <div id="toolbar"></div> + + <div id="workspace"> + <br> + <span class=hd1> + SCA Domain<br><br> + Contributions</b> <a href="/workspace/"><img src="icons/feed-icon.png" border="0"></a> </span> + <br><br> + Here is the list of SCA contributions currently available in your SCA domain. + <br><br> + + <form name="workspaceForm"> + <div id="contributions" ></div> + <br> + <input type="button" onClick="deleteContribution()" value="Delete" /> + </form> + + <br><br> + + <form name="newContributionForm"> + <table width="100%"> + <tr><th>Add Contribution</th></tr> + <tr><td>Add an SCA contribution containing your application artifacts to the SCA domain.</td></tr> + </table> + <br> + <table> + <tr><td>Contribution URI:</td><td><input type="text" name="contributionID" size="50"/></td></td><td>e.g. mycontrib, http://mycontrib</td></tr> + <tr><td>Location:</td><td><input type="text" name="contributionLocation" size="50"/></td></td><td>e.g. http://host/myjar.jar, file:/mydir, file:/myjar.jar</td></tr> + </table> + <input type="button" onClick="addContribution()" value="Add" /> + </form> + + </div> +</body> +</html> |