summaryrefslogtreecommitdiffstats
path: root/sca-java-1.x/branches/sca-java-0.91/modules/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/service/impl
diff options
context:
space:
mode:
Diffstat (limited to 'sca-java-1.x/branches/sca-java-0.91/modules/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/service/impl')
-rw-r--r--sca-java-1.x/branches/sca-java-0.91/modules/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/service/impl/ArtifactTypeDescriberImpl.java106
-rw-r--r--sca-java-1.x/branches/sca-java-0.91/modules/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/service/impl/ContributionMetadataLoaderImpl.java132
-rw-r--r--sca-java-1.x/branches/sca-java-0.91/modules/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/service/impl/ContributionRepositoryImpl.java266
-rw-r--r--sca-java-1.x/branches/sca-java-0.91/modules/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/service/impl/ContributionServiceImpl.java340
-rw-r--r--sca-java-1.x/branches/sca-java-0.91/modules/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/service/impl/InvalidContributionMetadataException.java57
-rw-r--r--sca-java-1.x/branches/sca-java-0.91/modules/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/service/impl/InvalidContributionURIException.java57
-rw-r--r--sca-java-1.x/branches/sca-java-0.91/modules/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/service/impl/InvalidValueException.java46
-rw-r--r--sca-java-1.x/branches/sca-java-0.91/modules/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/service/impl/PackageTypeDescriberImpl.java98
8 files changed, 1102 insertions, 0 deletions
diff --git a/sca-java-1.x/branches/sca-java-0.91/modules/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/service/impl/ArtifactTypeDescriberImpl.java b/sca-java-1.x/branches/sca-java-0.91/modules/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/service/impl/ArtifactTypeDescriberImpl.java
new file mode 100644
index 0000000000..174a09a0c6
--- /dev/null
+++ b/sca-java-1.x/branches/sca-java-0.91/modules/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/service/impl/ArtifactTypeDescriberImpl.java
@@ -0,0 +1,106 @@
+/*
+ * 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.contribution.service.impl;
+
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.tuscany.sca.contribution.ContentType;
+import org.apache.tuscany.sca.contribution.Contribution;
+import org.apache.tuscany.sca.contribution.service.TypeDescriber;
+import org.apache.tuscany.sca.contribution.service.util.FileHelper;
+
+/**
+ * Implementation of the content describer for files
+ *
+ * @version $Rev$ $Date$
+ */
+public class ArtifactTypeDescriberImpl implements TypeDescriber {
+ private final Map<String, String> contentTypeRegistry = new HashMap<String, String>();
+
+ public ArtifactTypeDescriberImpl() {
+ super();
+ init();
+ }
+
+ /**
+ * Initialize contentType registry with know types based on known file extensions
+ */
+ private void init() {
+ contentTypeRegistry.put("COMPOSITE", ContentType.COMPOSITE);
+ contentTypeRegistry.put("SCDL", ContentType.COMPOSITE);
+ contentTypeRegistry.put("WSDL", ContentType.WSDL);
+ contentTypeRegistry.put("JAR", ContentType.JAR);
+ }
+
+ protected String resolveContentyTypeByExtension(URL resourceURL) {
+ String artifactExtension = FileHelper.getExtension(resourceURL.getPath());
+ if (artifactExtension == null) {
+ return null;
+ }
+ return contentTypeRegistry.get(artifactExtension.toUpperCase());
+ }
+
+ /**
+ * Build contentType for a specific resource. We first check if the file is
+ * a supported one (looking into our registry based on resource extension)
+ * If not found, we try to check file contentType Or we return
+ * defaultContentType provided
+ *
+ * @param resourceURL The artifact url
+ * @param defaultContentType The default content type if we can't find the correc one
+ * @return The content type
+ */
+ public String getType(URL resourceURL, String defaultContentType) {
+ URLConnection connection = null;
+ String contentType = defaultContentType;
+
+ if (resourceURL.getProtocol().equals("file") && FileHelper.toFile(resourceURL).isDirectory()) {
+ // Special case : contribution is a folder
+ contentType = ContentType.FOLDER;
+ } else if (resourceURL.toExternalForm().endsWith(Contribution.SCA_CONTRIBUTION_META)
+ || resourceURL.toExternalForm().endsWith(Contribution.SCA_CONTRIBUTION_GENERATED_META)) {
+ // Special case : contribution metadata
+ contentType = ContentType.CONTRIBUTION_METADATA;
+ } else {
+ contentType = resolveContentyTypeByExtension(resourceURL);
+ if (contentType == null) {
+ try {
+ connection = resourceURL.openConnection();
+ contentType = connection.getContentType();
+
+ if (contentType == null || contentType.equals("content/unknown")) {
+ // here we couldn't figure out from our registry or from URL and it's not a special file
+ // return defaultContentType if provided
+ contentType = defaultContentType;
+ }
+ } catch (IOException io) {
+ // could not access artifact, just ignore and we will return
+ // null contentType
+ }
+ }
+ }
+ return contentType == null ? defaultContentType : contentType;
+ }
+
+}
diff --git a/sca-java-1.x/branches/sca-java-0.91/modules/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/service/impl/ContributionMetadataLoaderImpl.java b/sca-java-1.x/branches/sca-java-0.91/modules/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/service/impl/ContributionMetadataLoaderImpl.java
new file mode 100644
index 0000000000..a089756308
--- /dev/null
+++ b/sca-java-1.x/branches/sca-java-0.91/modules/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/service/impl/ContributionMetadataLoaderImpl.java
@@ -0,0 +1,132 @@
+/*
+ * 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.contribution.service.impl;
+
+import static javax.xml.stream.XMLStreamConstants.START_ELEMENT;
+
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import org.apache.tuscany.sca.assembly.AssemblyFactory;
+import org.apache.tuscany.sca.assembly.Composite;
+import org.apache.tuscany.sca.contribution.Contribution;
+import org.apache.tuscany.sca.contribution.ContributionExport;
+import org.apache.tuscany.sca.contribution.ContributionFactory;
+import org.apache.tuscany.sca.contribution.ContributionImport;
+import org.apache.tuscany.sca.contribution.service.ContributionMetadataLoader;
+import org.apache.tuscany.sca.contribution.service.ContributionMetadataLoaderException;
+
+/**
+ * Loader that handles contribution metadata files
+ *
+ * @version $Rev: 515261 $ $Date: 2007-03-06 11:22:46 -0800 (Tue, 06 Mar 2007) $
+ */
+public class ContributionMetadataLoaderImpl implements ContributionMetadataLoader {
+ private static final String SCA10_NS = "http://www.osoa.org/xmlns/sca/1.0";
+ private static final String TARGET_NAMESPACE = "targetNamespace";
+
+ private static final QName CONTRIBUTION = new QName(SCA10_NS, "contribution");
+ private static final QName DEPLOYABLE = new QName(SCA10_NS, "deployable");
+ private static final QName IMPORT = new QName(SCA10_NS, "import");
+ private static final QName EXPORT = new QName(SCA10_NS, "export");
+
+ private final AssemblyFactory assemblyFactory;
+ private final ContributionFactory contributionFactory;
+
+ public ContributionMetadataLoaderImpl(AssemblyFactory assemblyFactory, ContributionFactory contributionFactory) {
+ super();
+ this.assemblyFactory = assemblyFactory;
+ this.contributionFactory = contributionFactory;
+ }
+
+ public QName getXMLType() {
+ return CONTRIBUTION;
+ }
+
+ public void load(Contribution contribution, XMLStreamReader reader) throws XMLStreamException, ContributionMetadataLoaderException {
+ String targetNameSpaceURI = null;
+
+ while (true) {
+ int event = reader.next();
+ switch (event) {
+ case START_ELEMENT:
+ QName element = reader.getName();
+ if (CONTRIBUTION.equals(element)) {
+ targetNameSpaceURI = reader.getAttributeValue(null, TARGET_NAMESPACE);
+ } else if (DEPLOYABLE.equals(element)) {
+ String name = reader.getAttributeValue(null, "composite");
+ if (name == null) {
+ throw new InvalidValueException("Attribute 'composite' is missing");
+ }
+ QName compositeName = null;
+
+ int index = name.indexOf(':');
+ if (index != -1) {
+ String prefix = name.substring(0, index);
+ String localPart = name.substring(index + 1);
+ String ns = reader.getNamespaceContext().getNamespaceURI(prefix);
+ if (ns == null) {
+ throw new InvalidValueException("Invalid prefix: " + prefix);
+ }
+ compositeName = new QName(targetNameSpaceURI, localPart, prefix);
+ } else {
+ String prefix = "";
+ String localPart = name;
+ compositeName = new QName(targetNameSpaceURI, localPart, prefix);
+ }
+
+ Composite composite = assemblyFactory.createComposite();
+ composite.setName(compositeName);
+ composite.setUnresolved(true);
+
+ contribution.getDeployables().add(composite);
+ } else if (IMPORT.equals(element)) {
+ String ns = reader.getAttributeValue(null, "namespace");
+ if (ns == null) {
+ throw new InvalidValueException("Attribute 'namespace' is missing");
+ }
+ String location = reader.getAttributeValue(null, "location");
+ ContributionImport contributionImport = this.contributionFactory.createContributionImport();
+ if (location != null) {
+ contributionImport.setLocation(location);
+ }
+ contributionImport.setNamespace(ns);
+ contribution.getImports().add(contributionImport);
+ } else if (EXPORT.equals(element)) {
+ String ns = reader.getAttributeValue(null, "namespace");
+ if (ns == null) {
+ throw new InvalidValueException("Attribute 'namespace' is missing");
+ }
+ ContributionExport contributionExport = this.contributionFactory.createContributionExport();
+ contributionExport.setNamespace(ns);
+ contribution.getExports().add(contributionExport);
+ }
+ break;
+ case XMLStreamConstants.END_ELEMENT:
+ if (CONTRIBUTION.equals(reader.getName())) {
+ return;
+ }
+ break;
+
+ }
+ }
+ }
+}
diff --git a/sca-java-1.x/branches/sca-java-0.91/modules/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/service/impl/ContributionRepositoryImpl.java b/sca-java-1.x/branches/sca-java-0.91/modules/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/service/impl/ContributionRepositoryImpl.java
new file mode 100644
index 0000000000..e2dc89782d
--- /dev/null
+++ b/sca-java-1.x/branches/sca-java-0.91/modules/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/service/impl/ContributionRepositoryImpl.java
@@ -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.
+ */
+
+package org.apache.tuscany.sca.contribution.service.impl;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamReader;
+
+import org.apache.tuscany.sca.contribution.service.ContributionRepository;
+import org.apache.tuscany.sca.contribution.service.util.FileHelper;
+import org.apache.tuscany.sca.contribution.service.util.IOHelper;
+
+/**
+ * The default implementation of ContributionRepository
+ *
+ * @version $Rev$ $Date$
+ */
+public class ContributionRepositoryImpl implements ContributionRepository {
+ private static final String NS = "http://tuscany.apache.org/xmlns/1.0-SNAPSHOT";
+ private static final String DOMAIN_INDEX_FILENAME = "sca-domain.xml";
+ private final File rootFile;
+ private Map<String, String> contributionMap = new HashMap<String, String>();
+
+ private URI domain;
+ private XMLInputFactory factory;
+
+ /**
+ * Constructor with repository root
+ *
+ * @param repository
+ */
+ public ContributionRepositoryImpl(final String repository) throws IOException {
+ String root = repository;
+ if (repository == null) {
+ root = AccessController.doPrivileged(new PrivilegedAction<String>() {
+ public String run() {
+ // Default to <user.home>/.tuscany/domains/local/
+ String userHome = System.getProperty("user.home");
+ String slash = File.separator;
+ return userHome + slash + ".tuscany" + slash + "domains" + slash + "local" + slash;
+ }
+ });
+ }
+ this.rootFile = new File(root);
+ this.domain = rootFile.toURI();
+ FileHelper.forceMkdir(rootFile);
+ if (!rootFile.exists() || !rootFile.isDirectory() || !rootFile.canRead()) {
+ throw new IOException("The root is not a directory: " + repository);
+ }
+ factory = XMLInputFactory.newInstance("javax.xml.stream.XMLInputFactory", getClass().getClassLoader());
+ }
+
+ public URI getDomain() {
+ return domain;
+ }
+
+ /**
+ * Resolve contribution location in the repository -> root repository /
+ * contribution file -> contribution group id / artifact id / version
+ *
+ * @param contribution
+ * @return
+ */
+ private File mapToFile(URL sourceURL) {
+ String fileName = FileHelper.toFile(sourceURL).getName();
+ return new File(rootFile, "contributions" + File.separator + fileName);
+ }
+
+ /**
+ * Write a specific source inputstream to a file on disk
+ *
+ * @param source contents of the file to be written to disk
+ * @param target file to be written
+ * @throws IOException
+ */
+ public static void copy(InputStream source, File target) throws IOException {
+ BufferedOutputStream out = null;
+ BufferedInputStream in = null;
+
+ try {
+ out = new BufferedOutputStream(new FileOutputStream(target));
+ in = new BufferedInputStream(source);
+ IOHelper.copy(in, out);
+ } finally {
+ IOHelper.closeQuietly(out);
+ IOHelper.closeQuietly(in);
+ }
+ }
+
+ public URL store(String contribution, URL sourceURL, InputStream contributionStream) throws IOException {
+ // where the file should be stored in the repository
+ File location = mapToFile(sourceURL);
+ FileHelper.forceMkdir(location.getParentFile());
+
+ copy(contributionStream, location);
+
+ // add contribution to repositoryContent
+ URL contributionURL = location.toURL();
+ URI relative = rootFile.toURI().relativize(location.toURI());
+ contributionMap.put(contribution, relative.toString());
+ saveMap();
+
+ return contributionURL;
+ }
+
+ public URL store(String contribution, URL sourceURL) throws IOException {
+ // where the file should be stored in the repository
+ File location = mapToFile(sourceURL);
+ File source = FileHelper.toFile(sourceURL);
+ if (source == null || source.isFile()) {
+ InputStream is = sourceURL.openStream();
+ try {
+ return store(contribution, sourceURL, is);
+ } finally {
+ IOHelper.closeQuietly(is);
+ }
+ }
+
+ FileHelper.forceMkdir(location);
+ FileHelper.copyDirectory(source, location);
+
+ // add contribution to repositoryContent
+ URI relative = rootFile.toURI().relativize(location.toURI());
+ contributionMap.put(contribution, relative.toString());
+ saveMap();
+
+ return location.toURL();
+ }
+
+ public URL find(String contribution) {
+ if (contribution == null) {
+ return null;
+ }
+ String location = contributionMap.get(contribution);
+ if (location == null) {
+ return null;
+ }
+ try {
+ return new File(rootFile, location).toURL();
+ } catch (MalformedURLException e) {
+ // Should not happen
+ throw new AssertionError(e);
+ }
+ }
+
+ public void remove(String contribution) {
+ URL contributionURL = this.find(contribution);
+ if (contributionURL != null) {
+ // remove
+ try {
+ FileHelper.forceDelete(FileHelper.toFile(contributionURL));
+ this.contributionMap.remove(contribution);
+ saveMap();
+ } catch (IOException ioe) {
+ // handle file could not be removed
+ }
+ }
+ }
+
+ public List<String> list() {
+ return new ArrayList<String>(contributionMap.keySet());
+ }
+
+ public void init() {
+ File domainFile = new File(rootFile, "sca-domain.xml");
+ if (!domainFile.isFile()) {
+ return;
+ }
+ FileInputStream is;
+ try {
+ is = new FileInputStream(domainFile);
+ } catch (FileNotFoundException e) {
+ return;
+ }
+ try {
+ XMLStreamReader reader = factory.createXMLStreamReader(new InputStreamReader(is, "UTF-8"));
+ while (reader.hasNext()) {
+ switch (reader.getEventType()) {
+ case XMLStreamConstants.START_ELEMENT:
+ String name = reader.getName().getLocalPart();
+ if ("domain".equals(name)) {
+ String uri = reader.getAttributeValue(null, "uri");
+ if (uri != null) {
+ domain = URI.create(uri);
+ }
+ }
+ if ("contribution".equals(name)) {
+ String uri = reader.getAttributeValue(null, "uri");
+ String location = reader.getAttributeValue(null, "location");
+ contributionMap.put(uri, location);
+ }
+ break;
+ default:
+ break;
+ }
+ reader.next();
+ }
+ } catch (Exception e) {
+ // Ignore
+ } finally {
+ IOHelper.closeQuietly(is);
+ }
+ }
+
+ private void saveMap() {
+ File domainFile = new File(rootFile, DOMAIN_INDEX_FILENAME);
+ FileOutputStream os = null;
+ try {
+ os = new FileOutputStream(domainFile);
+ PrintWriter writer = new PrintWriter(new OutputStreamWriter(os, "UTF-8"));
+ writer.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
+ writer.println("<domain uri=\"" + getDomain() + "\" xmlns=\"" + NS + "\">");
+ for (Map.Entry<String, String> e : contributionMap.entrySet()) {
+ writer.println(" <contribution uri=\"" + e.getKey() + "\" location=\"" + e.getValue() + "\"/>");
+ }
+ writer.println("</domain>");
+ writer.flush();
+ } catch (IOException e) {
+ throw new IllegalArgumentException(e);
+ } finally {
+ IOHelper.closeQuietly(os);
+ }
+ }
+
+ public void destroy() {
+ }
+
+}
diff --git a/sca-java-1.x/branches/sca-java-0.91/modules/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/service/impl/ContributionServiceImpl.java b/sca-java-1.x/branches/sca-java-0.91/modules/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/service/impl/ContributionServiceImpl.java
new file mode 100644
index 0000000000..73bf678e04
--- /dev/null
+++ b/sca-java-1.x/branches/sca-java-0.91/modules/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/service/impl/ContributionServiceImpl.java
@@ -0,0 +1,340 @@
+/*
+ * 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.contribution.service.impl;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import org.apache.tuscany.sca.assembly.AssemblyFactory;
+import org.apache.tuscany.sca.assembly.Composite;
+import org.apache.tuscany.sca.contribution.Contribution;
+import org.apache.tuscany.sca.contribution.ContributionFactory;
+import org.apache.tuscany.sca.contribution.DeployedArtifact;
+import org.apache.tuscany.sca.contribution.processor.PackageProcessor;
+import org.apache.tuscany.sca.contribution.processor.URLArtifactProcessor;
+import org.apache.tuscany.sca.contribution.resolver.ModelResolver;
+import org.apache.tuscany.sca.contribution.service.ContributionException;
+import org.apache.tuscany.sca.contribution.service.ContributionMetadataLoaderException;
+import org.apache.tuscany.sca.contribution.service.ContributionRepository;
+import org.apache.tuscany.sca.contribution.service.ContributionService;
+import org.apache.tuscany.sca.contribution.service.util.IOHelper;
+
+/**
+ * Service interface that manages artifacts contributed to a Tuscany runtime.
+ *
+ * @version $Rev$ $Date$
+ */
+public class ContributionServiceImpl implements ContributionService {
+
+ /**
+ * Repository where contributions are stored. Usually set by injection.
+ */
+ private ContributionRepository contributionRepository;
+
+ /**
+ * Registry of available package processors.
+ */
+ private PackageProcessor packageProcessor;
+
+ /**
+ * Registry of available artifact processors
+ */
+
+ private URLArtifactProcessor artifactProcessor;
+
+ /**
+ * xml factory used to create reader instance to load contribution metadata
+ */
+ private XMLInputFactory xmlFactory;
+
+ /**
+ * contribution metadata loader
+ */
+ private ContributionMetadataLoaderImpl contributionLoader;
+
+ /**
+ * Contribution registry This is a registry of processed Contributions indexed by URI
+ */
+ private Map<String, Contribution> contributionRegistry = new ConcurrentHashMap<String, Contribution>();
+
+ /**
+ * Contribution model facotry
+ */
+ private ContributionFactory contributionFactory;
+
+
+ public ContributionServiceImpl(ContributionRepository repository,
+ PackageProcessor packageProcessor,
+ URLArtifactProcessor artifactProcessor,
+ AssemblyFactory assemblyFactory,
+ ContributionFactory contributionFactory,
+ XMLInputFactory xmlFactory) {
+ super();
+ this.contributionRepository = repository;
+ this.packageProcessor = packageProcessor;
+ this.artifactProcessor = artifactProcessor;
+ this.xmlFactory = xmlFactory;
+
+ this.contributionFactory = contributionFactory;
+ this.contributionLoader = new ContributionMetadataLoaderImpl(assemblyFactory, contributionFactory);
+ }
+
+ public Contribution contribute(String contributionURI, URL sourceURL, ModelResolver modelResolver, boolean storeInRepository) throws ContributionException,
+ IOException {
+ if (contributionURI == null) {
+ throw new IllegalArgumentException("URI for the contribution is null");
+ }
+ if (sourceURL == null) {
+ throw new IllegalArgumentException("Source URL for the contribution is null");
+ }
+
+ return addContribution(contributionURI, sourceURL, null, modelResolver, storeInRepository);
+ }
+
+ public Contribution contribute(String contributionURI, URL sourceURL, InputStream input, ModelResolver modelResolver)
+ throws ContributionException, IOException {
+
+ return addContribution(contributionURI, sourceURL, input, modelResolver, true);
+ }
+
+ private Contribution initializeContributionMetadata(URL sourceURL, ModelResolver modelResolver) throws ContributionException {
+ Contribution contributionMetadata = null;
+ URL contributionMetadataURL;
+ URL generatedContributionMetadataURL;
+ InputStream metadataStream = null;
+
+ URL[] clUrls = {sourceURL};
+ URLClassLoader cl = new URLClassLoader(clUrls, null);
+
+ contributionMetadataURL = cl.getResource(Contribution.SCA_CONTRIBUTION_META);
+ generatedContributionMetadataURL = cl.getResource(Contribution.SCA_CONTRIBUTION_GENERATED_META);
+
+ try {
+ contributionMetadata = this.contributionFactory.createContribution();
+ contributionMetadata.setModelResolver(modelResolver);
+ if (contributionMetadataURL != null || generatedContributionMetadataURL != null) {
+ URL metadataURL = contributionMetadataURL != null ? contributionMetadataURL
+ : generatedContributionMetadataURL;
+
+ try {
+ metadataStream = metadataURL.openStream();
+ XMLStreamReader xmlReader = this.xmlFactory.createXMLStreamReader(metadataStream);
+ this.contributionLoader.load(contributionMetadata, xmlReader);
+
+ } catch (IOException ioe) {
+ throw new InvalidContributionMetadataException(ioe.getMessage(), metadataURL.toExternalForm(), ioe);
+ } catch (XMLStreamException xmle) {
+ throw new InvalidContributionMetadataException(xmle.getMessage(), metadataURL.toExternalForm(),
+ xmle);
+ } catch (ContributionMetadataLoaderException le) {
+ throw new InvalidContributionMetadataException(le.getMessage(), metadataURL.toExternalForm(), le);
+ }
+ }
+ } finally {
+ IOHelper.closeQuietly(metadataStream);
+ metadataStream = null;
+ }
+
+ if (contributionMetadata == null) {
+ contributionMetadata = this.contributionFactory.createContribution();
+ }
+
+ return contributionMetadata;
+
+ }
+
+ public Contribution getContribution(String id) {
+ return this.contributionRegistry.get(id);
+ }
+
+ public void remove(String contribution) throws ContributionException {
+ this.contributionRegistry.remove(contribution);
+ }
+
+ public void addDeploymentComposite(Contribution contribution, Composite composite) throws ContributionException {
+ DeployedArtifact artifact = this.contributionFactory.createDeployedArtifact();
+ artifact.setURI(composite.getURI());
+ artifact.setModel(composite);
+
+ contribution.getArtifacts().add(artifact);
+
+ contribution.getDeployables().add(composite);
+ }
+
+ /**
+ * Utility/Helper methods for contribution service
+ */
+
+ /**
+ * Note:
+ *
+ * @param contributionURI ContributionID
+ * @param sourceURL contribution location
+ * @param contributionStream contribution content
+ * @param storeInRepository flag if we store the contribution into the
+ * repository or not
+ * @return the contribution model representing the contribution
+ * @throws IOException
+ * @throws DeploymentException
+ */
+ private Contribution addContribution(String contributionURI,
+ URL sourceURL,
+ InputStream contributionStream,
+ ModelResolver modelResolver,
+ boolean storeInRepository) throws IOException, ContributionException {
+
+ if (contributionStream == null && sourceURL == null) {
+ throw new IllegalArgumentException("The content of the contribution is null");
+ }
+
+ // store the contribution in the contribution repository
+ URL locationURL = sourceURL;
+ if (contributionRepository != null && storeInRepository) {
+ if (contributionStream == null) {
+ locationURL = contributionRepository.store(contributionURI, sourceURL);
+ } else {
+ locationURL = contributionRepository.store(contributionURI, sourceURL, contributionStream);
+ }
+ }
+
+ Contribution contribution = initializeContributionMetadata(locationURL, modelResolver);
+ contribution.setURI(contributionURI.toString());
+ contribution.setLocation(locationURL.toString());
+
+ List<URI> contributionArtifacts = null;
+
+ //NOTE: if a contribution is stored on the repository
+ //the stream would be consumed at this point
+ if (storeInRepository || contributionStream == null) {
+ contributionStream = sourceURL.openStream();
+ try {
+ // process the contribution
+ contributionArtifacts = this.packageProcessor.getArtifacts(locationURL, contributionStream);
+ } finally {
+ IOHelper.closeQuietly(contributionStream);
+ contributionStream = null;
+ }
+ } else {
+ // process the contribution
+ contributionArtifacts = this.packageProcessor.getArtifacts(locationURL, contributionStream);
+ }
+
+ // Read all artifacts in the contribution
+ processReadPhase(contribution, contributionArtifacts);
+
+ // Resolve them
+ processResolvePhase(contribution);
+
+ // Add all composites under META-INF/sca-deployables to the
+ // list of deployables
+ String prefix = Contribution.SCA_CONTRIBUTION_DEPLOYABLES;
+ for (DeployedArtifact artifact : contribution.getArtifacts()) {
+ if (artifact.getModel() instanceof Composite) {
+ if (artifact.getURI().startsWith(prefix)) {
+ Composite composite = (Composite)artifact.getModel();
+ if (!contribution.getDeployables().contains(composite)) {
+ contribution.getDeployables().add(composite);
+ }
+ }
+ }
+ }
+
+ // store the contribution on the registry
+ this.contributionRegistry.put(contribution.getURI(), contribution);
+
+ return contribution;
+ }
+
+ /**
+ * This utility method process each artifact and delegates to proper
+ * artifactProcessor to read the model and generate the in-memory representation
+ *
+ * @param contribution
+ * @param artifacts
+ * @throws ContributionException
+ * @throws MalformedURLException
+ */
+ private void processReadPhase(Contribution contribution, List<URI> artifacts) throws ContributionException,
+ MalformedURLException {
+
+ ModelResolver modelResolver = contribution.getModelResolver();
+ URL contributionURL = new URL(contribution.getLocation());
+ for (URI a : artifacts) {
+ URL artifactURL = packageProcessor.getArtifactURL(new URL(contribution.getLocation()), a);
+
+ // Add the deployed artifact model to the resolver
+ DeployedArtifact artifact = this.contributionFactory.createDeployedArtifact();
+ artifact.setURI(a.toString());
+ artifact.setLocation(artifactURL.toString());
+ contribution.getArtifacts().add(artifact);
+ modelResolver.addModel(artifact);
+
+ // Let the artifact processor read the artifact into a model
+ Object model = this.artifactProcessor.read(contributionURL, a, artifactURL);
+ if (model != null) {
+ artifact.setModel(model);
+
+ // Add the loaded model to the model resolver
+ modelResolver.addModel(model);
+ }
+
+ }
+ }
+
+ /**
+ * This utility method process each artifact and delegates to proper
+ * artifactProcessor to resolve the model references
+ *
+ * @param contribution
+ * @throws ContributionException
+ */
+ @SuppressWarnings("unchecked")
+ private void processResolvePhase(Contribution contribution) throws ContributionException {
+ // for each artifact that was processed on the contribution
+ for (DeployedArtifact artifact : contribution.getArtifacts()) {
+ // resolve the model object
+ if (artifact.getModel() != null) {
+ this.artifactProcessor.resolve(artifact.getModel(), contribution.getModelResolver());
+ }
+ }
+
+ //resolve deployables from contribution metadata
+ List<Composite> resolvedDeployables = new ArrayList<Composite>();
+ for (Composite deployableComposite : contribution.getDeployables()) {
+ Composite resolvedDeployable = contribution.getModelResolver().resolveModel(Composite.class, deployableComposite);
+ resolvedDeployables.add(resolvedDeployable);
+ }
+
+ contribution.getDeployables().clear();
+ contribution.getDeployables().addAll(resolvedDeployables);
+ }
+
+}
diff --git a/sca-java-1.x/branches/sca-java-0.91/modules/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/service/impl/InvalidContributionMetadataException.java b/sca-java-1.x/branches/sca-java-0.91/modules/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/service/impl/InvalidContributionMetadataException.java
new file mode 100644
index 0000000000..a7e0e2f2f5
--- /dev/null
+++ b/sca-java-1.x/branches/sca-java-0.91/modules/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/service/impl/InvalidContributionMetadataException.java
@@ -0,0 +1,57 @@
+/*
+ * 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.contribution.service.impl;
+
+import org.apache.tuscany.sca.contribution.service.ContributionException;
+
+/**
+ * Exception that indicates that the supplied XML Document invalid.
+ *
+ * @version $Rev: 511466 $ $Date: 2007-02-25 00:45:22 -0800 (Sun, 25 Feb 2007) $
+ */
+public class InvalidContributionMetadataException extends ContributionException {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -3184477070625689942L;
+
+ protected InvalidContributionMetadataException() {
+ }
+
+ protected InvalidContributionMetadataException(String message) {
+ super(message);
+ }
+
+ protected InvalidContributionMetadataException(String message, String identifier) {
+ super(message, identifier);
+ }
+
+ protected InvalidContributionMetadataException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ protected InvalidContributionMetadataException(String message, String identifier, Throwable cause) {
+ super(message, identifier, cause);
+ }
+
+ protected InvalidContributionMetadataException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/sca-java-1.x/branches/sca-java-0.91/modules/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/service/impl/InvalidContributionURIException.java b/sca-java-1.x/branches/sca-java-0.91/modules/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/service/impl/InvalidContributionURIException.java
new file mode 100644
index 0000000000..e3109e795b
--- /dev/null
+++ b/sca-java-1.x/branches/sca-java-0.91/modules/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/service/impl/InvalidContributionURIException.java
@@ -0,0 +1,57 @@
+/*
+ * 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.contribution.service.impl;
+
+import org.apache.tuscany.sca.contribution.service.ContributionException;
+
+/**
+ * Exception that indicates that the supplied contribution URI is invalid or inexistent.
+ *
+ * @version $Rev: 511466 $ $Date: 2007-02-25 00:45:22 -0800 (Sun, 25 Feb 2007) $
+ */
+public class InvalidContributionURIException extends ContributionException {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -3184477070625689942L;
+
+ protected InvalidContributionURIException() {
+ }
+
+ protected InvalidContributionURIException(String message) {
+ super(message);
+ }
+
+ protected InvalidContributionURIException(String message, String identifier) {
+ super(message, identifier);
+ }
+
+ protected InvalidContributionURIException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ protected InvalidContributionURIException(String message, String identifier, Throwable cause) {
+ super(message, identifier, cause);
+ }
+
+ protected InvalidContributionURIException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/sca-java-1.x/branches/sca-java-0.91/modules/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/service/impl/InvalidValueException.java b/sca-java-1.x/branches/sca-java-0.91/modules/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/service/impl/InvalidValueException.java
new file mode 100644
index 0000000000..ce0fb59476
--- /dev/null
+++ b/sca-java-1.x/branches/sca-java-0.91/modules/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/service/impl/InvalidValueException.java
@@ -0,0 +1,46 @@
+/*
+ * 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.contribution.service.impl;
+
+import org.apache.tuscany.sca.contribution.service.ContributionMetadataLoaderException;
+
+/**
+ * Denotate invalid value found during parsing of the contribution metadata sidefile
+ *
+ * @version $Rev$ $Date$
+ */
+public class InvalidValueException extends ContributionMetadataLoaderException {
+ /**
+ *
+ */
+ private static final long serialVersionUID = -1447696740893397938L;
+
+ public InvalidValueException(String message) {
+ super(message);
+ }
+
+ public InvalidValueException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public InvalidValueException(String message, String identifier, Throwable cause) {
+ super(message, identifier, cause);
+ }
+}
diff --git a/sca-java-1.x/branches/sca-java-0.91/modules/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/service/impl/PackageTypeDescriberImpl.java b/sca-java-1.x/branches/sca-java-0.91/modules/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/service/impl/PackageTypeDescriberImpl.java
new file mode 100644
index 0000000000..165c9d0616
--- /dev/null
+++ b/sca-java-1.x/branches/sca-java-0.91/modules/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/service/impl/PackageTypeDescriberImpl.java
@@ -0,0 +1,98 @@
+/*
+ * 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.contribution.service.impl;
+
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.tuscany.sca.contribution.ContentType;
+import org.apache.tuscany.sca.contribution.service.TypeDescriber;
+import org.apache.tuscany.sca.contribution.service.util.FileHelper;
+
+/**
+ * Implementation of the content describer for contribution packages
+ *
+ * @version $Rev$ $Date$
+ */
+public class PackageTypeDescriberImpl implements TypeDescriber {
+ private final Map<String, String> contentTypeRegistry = new HashMap<String, String>();
+
+ public PackageTypeDescriberImpl() {
+ super();
+ init();
+ }
+
+ /**
+ * Initialize contentType registry with know types based on known file extensions
+ */
+ private void init() {
+ contentTypeRegistry.put("JAR", ContentType.JAR);
+ }
+
+ protected String resolveContentyTypeByExtension(URL resourceURL) {
+ String artifactExtension = FileHelper.getExtension(resourceURL.getPath());
+ if (artifactExtension == null) {
+ return null;
+ }
+ return contentTypeRegistry.get(artifactExtension.toUpperCase());
+ }
+
+ /**
+ * Build contentType for a specific resource. We first check if the file is
+ * a supported one (looking into our registry based on resource extension)
+ * If not found, we try to check file contentType Or we return
+ * defaultContentType provided
+ *
+ * @param resourceURL The artifact url
+ * @param defaultContentType The default content type if we can't find the correc one
+ * @return The content type
+ */
+ public String getType(URL resourceURL, String defaultContentType) {
+ URLConnection connection = null;
+ String contentType = defaultContentType;
+
+ if (resourceURL.getProtocol().equals("file") && FileHelper.toFile(resourceURL).isDirectory()) {
+ // Special case : contribution is a folder
+ contentType = ContentType.FOLDER;
+ } else {
+ contentType = resolveContentyTypeByExtension(resourceURL);
+ if (contentType == null) {
+ try {
+ connection = resourceURL.openConnection();
+ contentType = connection.getContentType();
+
+ if (contentType == null || contentType.equals("content/unknown")) {
+ // here we couldn't figure out from our registry or from URL and it's not a special file
+ // return defaultContentType if provided
+ contentType = defaultContentType;
+ }
+ } catch (IOException io) {
+ // could not access artifact, just ignore and we will return
+ // null contentType
+ }
+ }
+ }
+ return contentType == null ? defaultContentType : contentType;
+ }
+
+}