Return-Path:
X-Original-To: apmail-ace-commits-archive@www.apache.org
Delivered-To: apmail-ace-commits-archive@www.apache.org
Received: from mail.apache.org (hermes.apache.org [140.211.11.3])
by minotaur.apache.org (Postfix) with SMTP id 60C61F82F
for ;
Thu, 4 Apr 2013 09:52:46 +0000 (UTC)
Received: (qmail 59893 invoked by uid 500); 4 Apr 2013 09:44:52 -0000
Delivered-To: apmail-ace-commits-archive@ace.apache.org
Received: (qmail 59723 invoked by uid 500); 4 Apr 2013 09:44:47 -0000
Mailing-List: contact commits-help@ace.apache.org; run by ezmlm
Precedence: bulk
List-Help:
List-Unsubscribe:
List-Post:
List-Id:
Reply-To: dev@ace.apache.org
Delivered-To: mailing list commits@ace.apache.org
Received: (qmail 59011 invoked by uid 99); 4 Apr 2013 09:44:17 -0000
Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230)
by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 04 Apr 2013 09:44:17 +0000
X-ASF-Spam-Status: No, hits=-2000.0 required=5.0
tests=ALL_TRUSTED
X-Spam-Check-By: apache.org
Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4)
by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 04 Apr 2013 09:44:06 +0000
Received: from eris.apache.org (localhost [127.0.0.1])
by eris.apache.org (Postfix) with ESMTP id 5E0842388A36;
Thu, 4 Apr 2013 09:43:43 +0000 (UTC)
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Subject: svn commit: r1464402 [2/11] - in /ace/trunk:
org.apache.ace.deployment.api/
org.apache.ace.deployment.deploymentadmin/ org.apache.ace.deployment.itest/
org.apache.ace.deployment.itest/src/org/apache/ace/it/deployment/
org.apache.ace.deployment.provider...
Date: Thu, 04 Apr 2013 09:43:37 -0000
To: commits@ace.apache.org
From: marrs@apache.org
X-Mailer: svnmailer-1.0.8-patched
Message-Id: <20130404094343.5E0842388A36@eris.apache.org>
X-Virus-Checked: Checked by ClamAV on apache.org
Added: ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/provider/repositorybased/BaseRepositoryHandler.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/provider/repositorybased/BaseRepositoryHandler.java?rev=1464402&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/provider/repositorybased/BaseRepositoryHandler.java (added)
+++ ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/provider/repositorybased/BaseRepositoryHandler.java Thu Apr 4 09:43:34 2013
@@ -0,0 +1,293 @@
+/*
+ * 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.ace.deployment.provider.repositorybased;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.osgi.framework.Version;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * Provides a SAX-based push parser for obtaining all versions of the deployment packages of a certain target.
+ */
+class BaseRepositoryHandler extends DefaultHandler {
+
+ private final String m_targetID;
+
+ /** Denotes the current tag in the XML structure. */
+ private XmlTag m_currentTag;
+ /** Denotes the current version of the found target. */
+ private Version m_currentVersion;
+ /** Denotes whether or not the requested target is found. */
+ private boolean m_targetFound;
+ /** Denotes the current deployment artifact. */
+ private XmlDeploymentArtifact m_currentArtifact;
+ /** Denotes the directive key of the current deployment artifact. */
+ private String m_currentDirectiveKey;
+
+ /**
+ * Creates a new {@link BaseRepositoryHandler} instance.
+ *
+ * @param targetID the target ID to search for, cannot be null
.
+ */
+ public BaseRepositoryHandler(String targetID) {
+ m_targetID = targetID;
+ m_currentTag = XmlTag.unknown;
+ }
+
+ /**
+ * Parses the given text as {@link Version}.
+ *
+ * @param text the text to parse as version, can not be null
.
+ * @return a {@link Version} if the given text represent a correct version, never null
.
+ */
+ static final Version parseVersion(String text) {
+ try {
+ if (text != null) {
+ return Version.parseVersion(text);
+ }
+ }
+ catch (Exception e) {
+ // Ignore; simply return an empty version to denote this invalid version...
+ }
+ return Version.emptyVersion;
+ }
+
+ @Override
+ public void startDocument() throws SAXException {
+ m_currentTag = XmlTag.unknown;
+ m_currentVersion = null;
+ m_targetFound = false;
+ m_currentArtifact = null;
+ m_currentDirectiveKey = null;
+ }
+
+ @Override
+ public void characters(char[] ch, int start, int length) throws SAXException {
+ if (XmlTag.targetID.equals(m_currentTag)) {
+ // verify whether we're in the DP for the requested target...
+ m_targetFound = m_targetID.equals(new String(ch, start, length));
+ }
+ else if (XmlTag.version.equals(m_currentTag)) {
+ // Don't assume we've got the desired version (yet)...
+ m_currentVersion = null;
+
+ if (m_targetFound) {
+ m_currentVersion = parseAsVersion(new String(ch, start, length));
+ }
+ }
+ else if (XmlTag.url.equals(m_currentTag)) {
+ try {
+ URL artifactUrl = new URL(new String(ch, start, length));
+ m_currentArtifact = new XmlDeploymentArtifact(artifactUrl);
+ }
+ catch (MalformedURLException e) {
+ throw new SAXException("Unexpected URL!", e);
+ }
+ }
+ else if (XmlTag.directives.equals(m_currentTag)) {
+ if (m_currentArtifact == null) {
+ throw new SAXException("Unexpected directive tag!");
+ }
+ String value = new String(ch, start, length).trim();
+ if (m_currentDirectiveKey != null && !value.equals("")) {
+ m_currentArtifact.m_directives.put(m_currentDirectiveKey, value);
+ }
+ }
+ }
+
+ @Override
+ public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
+ XmlTag tag = XmlTag.asXmlTag(qName);
+ // If the given element is an expected child of the current tag, we
+ // traverse deeper into the XML-hierarchy; otherwise, consider it an
+ // "unknown"/uninteresting child and keep the current tag as-is...
+ if (m_currentTag.isExpectedChild(tag)) {
+ m_currentTag = tag;
+ }
+
+ m_currentDirectiveKey = null;
+ // If we're parsing the directives of an artifact, take the name for
+ // later use (the literal text in this tag will be used as value)...
+ if (XmlTag.directives.equals(m_currentTag)) {
+ m_currentDirectiveKey = qName;
+ }
+ }
+
+ @Override
+ public void endElement(String uri, String localName, String qName) throws SAXException {
+ XmlTag tag = XmlTag.asXmlTag(qName);
+ // When we're ending the current tag, traverse up to its parent...
+ if (!XmlTag.unknown.equals(tag) && (m_currentTag == tag)) {
+ m_currentTag = tag.getParent();
+ }
+
+ // Invoke the callbacks for events we're interested in...
+ if (XmlTag.version.equals(tag)) {
+ if (m_currentVersion != null && !Version.emptyVersion.equals(m_currentVersion)) {
+ // Let the version be handled (if needed)...
+ handleVersion(m_currentVersion);
+ }
+
+ // Let the currentVersion field as-is! We want to reuse it for the artifacts...
+ }
+ else if (XmlTag.deploymentArtifact.equals(tag)) {
+ if (m_currentArtifact != null) {
+ // push out the current deployment artifact...
+ handleArtifact(m_currentVersion, m_currentArtifact);
+ }
+
+ m_currentArtifact = null;
+ }
+ else if (XmlTag.directives.equals(tag)) {
+ m_currentDirectiveKey = null;
+ }
+ }
+
+ /**
+ * Allows subclasses to handle the given version of a target's deployment package.
+ * By default, this method does nothing.
+ *
+ * @param version the version found, never null
.
+ */
+ protected void handleVersion(Version version) {
+ // NO-op
+ }
+
+ /**
+ * Allows subclasses to handle the given deployment artifact for the given version of the deployment package.
+ * By default, this method does nothing.
+ *
+ * @param version the version of the deployment package;
+ * @param artifact the deployment artifact itself.
+ */
+ protected void handleArtifact(Version version, XmlDeploymentArtifact artifact) {
+ // NO-op
+ }
+
+ /**
+ * Parses the given text as {@link Version}.
+ *
+ * @param text the text to parse as version, can not be null
.
+ * @return a {@link Version} if the given text represent a correct version,
+ * can be null
in case of an incorrect/empty version..
+ */
+ protected final Version parseAsVersion(String text) {
+ Version result = parseVersion(text);
+ if (Version.emptyVersion.equals(result)) {
+ return null;
+ }
+ return result;
+ }
+
+ /**
+ * Helper class to store a pair of URL and directive, in which the directive may be empty.
+ */
+ public static class XmlDeploymentArtifact {
+ final private URL m_url;
+ final private Map m_directives;
+
+ private XmlDeploymentArtifact(URL url) {
+ m_url = url;
+ m_directives = new HashMap();
+ }
+
+ public URL getUrl() {
+ return m_url;
+ }
+
+ public Map getDirective() {
+ return m_directives;
+ }
+ }
+
+ /**
+ * Defines the structure of our XML (only the parts we're interested in).
+ */
+ public static enum XmlTag {
+ targetID,
+ version,
+ attributes(targetID, version),
+ url,
+ directives,
+ deploymentArtifact(url, directives),
+ artifacts(deploymentArtifact),
+ tags,
+ deploymentversion(attributes, tags, artifacts),
+ deploymentversions(deploymentversion),
+ repository(deploymentversions),
+ unknown(repository);
+
+ private final XmlTag[] m_children;
+ private XmlTag m_parent;
+
+ private XmlTag(XmlTag... possibleChildren) {
+ m_children = possibleChildren;
+ // Update the children's parent...
+ for (int i = 0; i < m_children.length; i++) {
+ m_children[i].m_parent = this;
+ }
+ }
+
+ /**
+ * Returns the parent tag of this tag.
+ *
+ * @return a parent tag, can be null
.
+ */
+ public XmlTag getParent() {
+ return m_parent;
+ }
+
+ /**
+ * Returns whether the given XML tag is an expected child of this tag.
+ *
+ * @param xmlTag the XML tag to test, cannot be null
.
+ * @return true
if the given tag is an expected child of this tag, false
otherwise.
+ */
+ public boolean isExpectedChild(XmlTag xmlTag) {
+ for (int i = 0; i < m_children.length; i++) {
+ if (xmlTag.equals(m_children[i])) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Provides a "safe" way of representing the given tag name as instance of this enum. If the given name does not represent a defined tag, "unknown" will be returned.
+ *
+ * @param name the XML tag-name to represent as enum value, cannot be null
.
+ * @return a {@link XmlTag} representation of the given tag-name, never null
.
+ */
+ public static XmlTag asXmlTag(String name) {
+ XmlTag[] values = { artifacts, attributes, deploymentArtifact, deploymentversion, deploymentversions, directives, repository, tags, targetID, url, version };
+ for (int i = 0; i < values.length; i++) {
+ if (values[i].name().equals(name)) {
+ return values[i];
+ }
+ }
+ return XmlTag.unknown;
+ }
+ }
+}
\ No newline at end of file
Added: ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/provider/repositorybased/DeploymentArtifactCollector.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/provider/repositorybased/DeploymentArtifactCollector.java?rev=1464402&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/provider/repositorybased/DeploymentArtifactCollector.java (added)
+++ ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/provider/repositorybased/DeploymentArtifactCollector.java Thu Apr 4 09:43:34 2013
@@ -0,0 +1,93 @@
+/*
+ * 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.ace.deployment.provider.repositorybased;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.osgi.framework.Version;
+
+/**
+ * Provides {@link BaseRepositoryHandler} implementation that gathers all deployment
+ * artifacts of deployment packages for a specific target with a specific version.
+ */
+public class DeploymentArtifactCollector extends BaseRepositoryHandler {
+
+ private final List m_expectedVersions;
+ private final Map> m_artifacts;
+
+ /**
+ * @param targetID the identification of the target to gather all artifacts for;
+ * @param versions the version of the deployment package to gather all artifacts for.
+ */
+ public DeploymentArtifactCollector(String targetID, String... versions) {
+ super(targetID);
+
+ m_artifacts = new HashMap>();
+
+ m_expectedVersions = new ArrayList(versions.length);
+ for (int i = 0; i < versions.length; i++) {
+ Version v = parseVersion(versions[i]);
+ if (Version.emptyVersion.equals(v)) {
+ throw new IllegalArgumentException("Expected real version for " + versions[i]);
+ }
+ m_expectedVersions.add(v);
+ }
+ }
+
+ /**
+ * Returns all deployment artifacts of the requested target's deployment package.
+ *
+ * @return an array with lists of all found deployment artifacts, never null
.
+ * The array contains the deployment artifacts per requested version, in the same
+ * order as given in the class constructor.
+ */
+ public List[] getArtifacts() {
+ List[] result = new List[m_expectedVersions.size()];
+ int i = 0;
+ for (Version version : m_expectedVersions) {
+ List list = m_artifacts.get(version);
+ if (list == null) {
+ throw new IllegalArgumentException("No artifacts found for version " + version);
+ }
+ result[i++] = list;
+ }
+ return result;
+ }
+
+ @Override
+ protected void handleVersion(Version version) {
+ if (m_expectedVersions.contains(version)) {
+ List artifacts = m_artifacts.get(version);
+ if (artifacts == null) {
+ artifacts = new ArrayList();
+ m_artifacts.put(version, artifacts);
+ }
+ }
+ }
+
+ @Override
+ protected void handleArtifact(Version version, XmlDeploymentArtifact artifact) {
+ if (m_expectedVersions.contains(version)) {
+ m_artifacts.get(version).add(artifact);
+ }
+ }
+}
Added: ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/provider/repositorybased/DeploymentPackageVersionCollector.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/provider/repositorybased/DeploymentPackageVersionCollector.java?rev=1464402&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/provider/repositorybased/DeploymentPackageVersionCollector.java (added)
+++ ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/provider/repositorybased/DeploymentPackageVersionCollector.java Thu Apr 4 09:43:34 2013
@@ -0,0 +1,55 @@
+/*
+ * 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.ace.deployment.provider.repositorybased;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.osgi.framework.Version;
+
+/**
+ * Provides {@link BaseRepositoryHandler} implementation that gathers all versions of deployment packages for a specific target.
+ */
+public class DeploymentPackageVersionCollector extends BaseRepositoryHandler {
+
+ private final List m_versions;
+
+ /**
+ * @param targetID the target to gather all deployment package versions for.
+ */
+ public DeploymentPackageVersionCollector(String targetID) {
+ super(targetID);
+
+ m_versions = new ArrayList();
+ }
+
+ /**
+ * Returns a list of all found deployment package versions.
+ *
+ * @return a list of {@link Version}s, never null
.
+ */
+ public List getVersions() {
+ return m_versions;
+ }
+
+ @Override
+ protected void handleVersion(Version version) {
+ m_versions.add(version);
+ }
+}
Added: ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/provider/repositorybased/LRUMap.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/provider/repositorybased/LRUMap.java?rev=1464402&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/provider/repositorybased/LRUMap.java (added)
+++ ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/provider/repositorybased/LRUMap.java Thu Apr 4 09:43:34 2013
@@ -0,0 +1,36 @@
+/*
+ * 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.ace.deployment.provider.repositorybased;
+
+import java.util.LinkedHashMap;
+
+public class LRUMap extends LinkedHashMap {
+ private static final int INITIAL = 64;
+ private static final int MAX = 1024;
+ private static final float LOADFACTOR = 0.75f;
+
+ public LRUMap() {
+ super(INITIAL, LOADFACTOR, true);
+ }
+
+ @Override
+ protected boolean removeEldestEntry(java.util.Map.Entry eldest) {
+ return size() > MAX;
+ }
+}
Added: ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/provider/repositorybased/RepositoryBasedProvider.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/provider/repositorybased/RepositoryBasedProvider.java?rev=1464402&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/provider/repositorybased/RepositoryBasedProvider.java (added)
+++ ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/provider/repositorybased/RepositoryBasedProvider.java Thu Apr 4 09:43:34 2013
@@ -0,0 +1,479 @@
+/*
+ * 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.ace.deployment.provider.repositorybased;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.parsers.SAXParserFactory;
+
+import org.apache.ace.deployment.provider.ArtifactData;
+import org.apache.ace.deployment.provider.DeploymentProvider;
+import org.apache.ace.deployment.provider.impl.ArtifactDataImpl;
+import org.apache.ace.deployment.provider.repositorybased.BaseRepositoryHandler.XmlDeploymentArtifact;
+import org.apache.ace.connectionfactory.ConnectionFactory;
+import org.apache.ace.range.RangeIterator;
+import org.apache.ace.repository.Repository;
+import org.apache.ace.repository.ext.BackupRepository;
+import org.apache.ace.repository.ext.CachedRepository;
+import org.apache.ace.repository.ext.impl.CachedRepositoryImpl;
+import org.apache.ace.repository.ext.impl.FilebasedBackupRepository;
+import org.apache.ace.repository.ext.impl.RemoteRepository;
+import org.apache.felix.dm.DependencyManager;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Version;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedService;
+import org.osgi.service.log.LogService;
+
+/**
+ * The RepositoryBasedProvider provides version information and bundle data by the DeploymentProvider interface. It uses a
+ * Repository to get its information from, which it parses using a SAX parser.
+ */
+public class RepositoryBasedProvider implements DeploymentProvider, ManagedService {
+ private static final String URL = "url";
+ private static final String NAME = "name";
+ private static final String CUSTOMER = "customer";
+
+ /**
+ * Key, intended to be used for artifacts which are bundles and will publish
+ * a resource processor (see OSGi compendium section 114.10).
+ */
+ public static final String DIRECTIVE_ISCUSTOMIZER = "DeploymentPackage-Customizer";
+
+ /**
+ * Key, intended to be used for resources which require a resource processor
+ * (see OSGi compendium section 114.10).
+ */
+ public static final String DIRECTIVE_KEY_PROCESSORID = "Resource-Processor";
+
+ /**
+ * Key, intended to be used for artifacts which have a resourceID that's different
+ * from their generated name (based on URL).
+ */
+ public static final String DIRECTIVE_KEY_RESOURCE_ID = "Resource-ID";
+
+ /**
+ * Key, intended to be used for matching processed (see ArtifactPreprocessor) to their
+ * 'original' one.
+ */
+ public static final String DIRECTIVE_KEY_BASEURL = "Base-Url";
+
+ public static final String REPOSITORY_PATH = "ACE-RepositoryPath";
+
+ public static final String KEY_SYMBOLICNAME = Constants.BUNDLE_SYMBOLICNAME;
+ public static final String KEY_NAME = Constants.BUNDLE_NAME;
+ public static final String KEY_VERSION = Constants.BUNDLE_VERSION;
+ public static final String KEY_VENDOR = Constants.BUNDLE_VENDOR;
+ public static final String KEY_RESOURCE_PROCESSOR_PID = "Deployment-ProvidesResourceProcessor";
+
+ public static final String MIMETYPE = "application/vnd.osgi.bundle";
+
+
+ private volatile LogService m_log;
+
+ /** This variable is volatile since it can be changed by the Updated() method. */
+ private volatile CachedRepository m_cachedRepository;
+
+ /**
+ * This variable is volatile since it can be changed by the updated() method. Furthermore, it will be used to inject a
+ * custom repository in the integration test.
+ */
+ private volatile Repository m_directRepository;
+ private volatile DependencyManager m_manager;
+
+ private final SAXParserFactory m_saxParserFactory;
+ private final Map> m_cachedVersionLists;
+
+ public RepositoryBasedProvider() {
+ m_saxParserFactory = SAXParserFactory.newInstance();
+ m_cachedVersionLists = new LRUMap>();
+ }
+
+ public List getBundleData(String targetId, String version) throws IllegalArgumentException, IOException {
+ return getBundleData(targetId, null, version);
+ }
+
+ public List getBundleData(String targetId, String versionFrom, String versionTo) throws IllegalArgumentException, IOException {
+ try {
+ if (versionFrom != null) {
+ Version.parseVersion(versionFrom);
+ }
+ Version.parseVersion(versionTo);
+ }
+ catch (NumberFormatException nfe) {
+ throw new IllegalArgumentException(nfe);
+ }
+
+ InputStream input = null;
+ List dataVersionTo = null;
+ List dataVersionFrom = null;
+
+ List[] pairs = null;
+ try {
+ // ACE-240: do NOT allow local/remote repositories to be empty. If we're
+ // asking for real artifacts, it means we must have a repository...
+ input = getRepositoryStream(true /* fail */);
+ if (versionFrom == null) {
+ pairs = getDeploymentArtifactPairs(input, targetId, new String[] { versionTo });
+ }
+ else {
+ pairs = getDeploymentArtifactPairs(input, targetId, new String[] { versionFrom, versionTo });
+ }
+ }
+ catch (IOException ioe) {
+ m_log.log(LogService.LOG_WARNING, "Problem parsing source version.", ioe);
+ throw ioe;
+ }
+ finally {
+ if (input != null) {
+ try {
+ input.close();
+ }
+ catch (IOException e) {
+ m_log.log(LogService.LOG_DEBUG, "Error closing stream", e);
+ }
+ }
+ }
+
+ if ((pairs != null) && (pairs.length > 1)) {
+ dataVersionFrom = getAllArtifactData(pairs[0]);
+ dataVersionTo = getAllArtifactData(pairs[1]);
+ Iterator it = dataVersionTo.iterator();
+ while (it.hasNext()) {
+ ArtifactDataImpl bundleDataVersionTo = (ArtifactDataImpl) it.next();
+ // see if there was previously a version of this bundle, and update the 'changed' property accordingly.
+ if (bundleDataVersionTo.isBundle()) {
+ ArtifactData bundleDataVersionFrom = getArtifactData(bundleDataVersionTo.getSymbolicName(), dataVersionFrom);
+ bundleDataVersionTo.setChanged(!bundleDataVersionTo.equals(bundleDataVersionFrom));
+ }
+ else {
+ ArtifactData bundleDataVersionFrom = getArtifactData(bundleDataVersionTo.getUrl(), dataVersionFrom);
+ bundleDataVersionTo.setChanged(bundleDataVersionFrom == null);
+ }
+ }
+ }
+ else {
+ dataVersionTo = getAllArtifactData(pairs[0]);
+ }
+
+ return dataVersionTo != null ? dataVersionTo : new ArrayList();
+ }
+
+ @SuppressWarnings("unchecked")
+ public List getVersions(String targetId) throws IllegalArgumentException, IOException {
+ // check if cache is up to date
+ if (isCacheUpToDate()) {
+ List result = m_cachedVersionLists.get(targetId);
+ if (result != null) {
+ return result;
+ }
+ }
+ else {
+ m_cachedVersionLists.clear();
+ }
+
+ List stringVersionList = new ArrayList();
+ InputStream input = null;
+
+ try {
+ // ACE-240: allow local/remote repositories to be empty; as the target
+ // might be new & unregistered, it can have no repository yet...
+ input = getRepositoryStream(false /* fail */);
+ List versionList = getAvailableVersions(input, targetId);
+ if (versionList.isEmpty()) {
+ m_log.log(LogService.LOG_DEBUG, "No versions found for target: " + targetId);
+ }
+ else {
+ // now sort the list of versions and convert all values to strings.
+ Collections.sort(versionList);
+ Iterator it = versionList.iterator();
+ while (it.hasNext()) {
+ String version = (it.next()).toString();
+ stringVersionList.add(version);
+ }
+ }
+ }
+ catch (IllegalArgumentException iae) {
+ // just move on.
+ }
+ catch (IOException ioe) {
+ m_log.log(LogService.LOG_DEBUG, "Problem parsing DeploymentRepository", ioe);
+ throw ioe;
+ }
+ finally {
+ if (input != null) {
+ try {
+ input.close();
+ }
+ catch (IOException e) {
+ m_log.log(LogService.LOG_DEBUG, "Error closing stream", e);
+ }
+ }
+ }
+
+ m_log.log(LogService.LOG_DEBUG, "Cache added for " + targetId);
+
+ m_cachedVersionLists.put(targetId, stringVersionList);
+ return stringVersionList;
+ }
+
+ /**
+ * Helper method to get the bundledata given an inputstream to a repository xml file
+ *
+ * @param input An input stream to the XML data to be parsed.
+ * @return A list of ArtifactData object representing this version.
+ */
+ private List getAllArtifactData(List deploymentArtifacts) throws IllegalArgumentException {
+ List result = new ArrayList();
+
+ // get the bundledata for each URL
+ for (XmlDeploymentArtifact pair : deploymentArtifacts) {
+ Map directives = pair.getDirective();
+
+ if (directives.get(DIRECTIVE_KEY_PROCESSORID) == null) {
+ // this is a bundle.
+ String symbolicName = directives.get(KEY_SYMBOLICNAME);
+ String bundleVersion = directives.get(KEY_VERSION);
+ if (symbolicName != null) {
+ // it is the right symbolic name
+ if (symbolicName.trim().equals("")) {
+ m_log.log(LogService.LOG_WARNING, "Invalid bundle:" + pair.toString() + " the symbolic name is empty.");
+ }
+ else {
+ result.add(new ArtifactDataImpl(pair.getUrl(), directives, symbolicName, bundleVersion, true));
+ }
+ }
+ }
+ else {
+ // it is an artifact.
+ String filename = directives.get(DIRECTIVE_KEY_RESOURCE_ID);
+ result.add(new ArtifactDataImpl(filename, pair.getUrl(), directives, true));
+ }
+
+ }
+ return result;
+ }
+
+ /**
+ * Helper method check for the existence of artifact data in the collection for a bundle with the given url.
+ *
+ * @param url The url to be found.
+ * @return The ArtifactData
object that has this url
, or null
if none can be
+ * found.
+ */
+ private ArtifactData getArtifactData(URL url, Collection data) {
+ ArtifactData bundle = null;
+ URI uri = null;
+ try {
+ uri = url.toURI();
+ }
+ catch (URISyntaxException e) {
+ m_log.log(LogService.LOG_ERROR, "Could not convert URL " + url + " to a URI");
+ return null;
+ }
+ Iterator it = data.iterator();
+ while (it.hasNext()) {
+ bundle = it.next();
+ try {
+ if (uri.equals(bundle.getUrl().toURI())) {
+ return bundle;
+ }
+ }
+ catch (URISyntaxException e) {
+ m_log.log(LogService.LOG_ERROR, "Could not convert bundle URL for " + bundle.getFilename() + " to a URI");
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Helper method check for the existence of artifact data in the collection for a bundle with the given symbolic name.
+ *
+ * @param symbolicName The symbolic name to be found.
+ * @return The ArtifactData
object that has this symbolicName
, or null
if none
+ * can be found.
+ */
+ private ArtifactData getArtifactData(String symbolicName, Collection data) {
+ ArtifactData bundle = null;
+ Iterator it = data.iterator();
+ while (it.hasNext()) {
+ bundle = it.next();
+ String bsn = bundle.getSymbolicName();
+ if ((bsn != null) && bsn.equals(symbolicName)) {
+ return bundle;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the available deployment versions for a target
+ *
+ * @param input A dom document representation of the repository
+ * @param targetId The target identifier
+ * @return A list of available versions
+ */
+ private List getAvailableVersions(InputStream input, String targetId) throws IllegalArgumentException {
+ DeploymentPackageVersionCollector collector = new DeploymentPackageVersionCollector(targetId);
+
+ try {
+ m_saxParserFactory.newSAXParser().parse(input, collector);
+
+ return collector.getVersions();
+ }
+ catch (Exception e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ /**
+ * Helper method to retrieve urls and directives for a target-version combination.
+ *
+ * @param input An input stream from which an XML representation of a deployment repository can be read.
+ * @param targetId The target identifier to be used
+ * @param versions An array of versions.
+ * @return An array of lists of URLDirectivePairs. For each version in versions
, a separate list will be
+ * created; the index of a version in the versions
array is equal to the index of its result in the
+ * result array.
+ * @throws IllegalArgumentException if the targetId or versions cannot be found in the input stream, or if
+ * input
does not contain an XML stream.
+ */
+ private List[] getDeploymentArtifactPairs(InputStream input, String targetId, String[] versions) throws IllegalArgumentException {
+ final DeploymentArtifactCollector collector = new DeploymentArtifactCollector(targetId, versions);
+
+ try {
+ m_saxParserFactory.newSAXParser().parse(input, collector);
+
+ return collector.getArtifacts();
+ }
+ catch (Exception e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ /**
+ * Helper to get an input stream to the currently used deployment repository.
+ *
+ * @return An input stream to the repository document. Will return an empty stream if none can be found.
+ * @throws java.io.IOException if there is a problem communicating with the local or remote repository.
+ */
+ private InputStream getRepositoryStream(boolean fail) throws IOException {
+ // cache the repositories, since we do not want them to change while we're in this method.
+ CachedRepository cachedRepository = m_cachedRepository;
+ Repository repository = m_directRepository;
+ InputStream result;
+
+ if (cachedRepository != null) {
+ // we can use the cached repository
+ if (cachedRepository.isCurrent()) {
+ result = cachedRepository.getLocal(fail);
+ }
+ else {
+ result = cachedRepository.checkout(fail);
+ }
+ }
+ else {
+ RangeIterator ri = repository.getRange().iterator();
+ long resultVersion = 0;
+ while (ri.hasNext()) {
+ resultVersion = ri.next();
+ }
+ if (resultVersion != 0) {
+ result = repository.checkout(resultVersion);
+ }
+ else {
+ throw new IllegalArgumentException("There is no deployment information available.");
+ }
+ }
+
+ return result;
+ }
+
+ private boolean isCacheUpToDate() {
+ CachedRepository cachedRepository = m_cachedRepository;
+ try {
+ return (cachedRepository != null && cachedRepository.isCurrent());
+ }
+ catch (IOException ioe) {
+ m_log.log(LogService.LOG_WARNING, "Failed to check if cache is current. Assuming it's not.", ioe);
+ return false;
+ }
+ }
+
+ public void updated(Dictionary settings) throws ConfigurationException {
+ if (settings != null) {
+ String url = getNotNull(settings, URL, "DeploymentRepository URL not configured.");
+ String name = getNotNull(settings, NAME, "RepositoryName not configured.");
+ String customer = getNotNull(settings, CUSTOMER, "RepositoryCustomer not configured.");
+
+ // create the remote repository and set it.
+ try {
+ BackupRepository backup = new FilebasedBackupRepository(File.createTempFile("currentrepository", null), File.createTempFile("backuprepository", null));
+
+ // We always create the remote repository. If we can create a backup repository, we will wrap a CachedRepository
+ // around it.
+ m_directRepository = new RemoteRepository(new URL(url), customer, name);
+
+ m_manager.add(m_manager.createComponent()
+ .setImplementation(m_directRepository)
+ .add(m_manager.createServiceDependency()
+ .setService(ConnectionFactory.class)
+ .setRequired(true)));
+
+ m_cachedRepository = null;
+ if (backup != null) {
+ m_cachedRepository = new CachedRepositoryImpl(m_directRepository, backup, CachedRepositoryImpl.UNCOMMITTED_VERSION);
+ }
+ }
+ catch (IllegalArgumentException e) {
+ throw new ConfigurationException("Authentication", e.getMessage());
+ }
+ catch (MalformedURLException mue) {
+ throw new ConfigurationException(URL, mue.getMessage());
+ }
+ catch (IOException e) {
+ m_log.log(LogService.LOG_WARNING, "Unable to create temporary files for FilebasedBackupRepository");
+ }
+ }
+ }
+
+ /**
+ * Convenience method for getting settings from a configuration dictionary.
+ */
+ private String getNotNull(Dictionary settings, String id, String errorMessage) throws ConfigurationException {
+ String result = (String) settings.get(id);
+ if (result == null) {
+ throw new ConfigurationException(id, errorMessage);
+ }
+ return result;
+ }
+}
\ No newline at end of file
Added: ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/service/DeploymentService.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/service/DeploymentService.java?rev=1464402&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/service/DeploymentService.java (added)
+++ ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/service/DeploymentService.java Thu Apr 4 09:43:34 2013
@@ -0,0 +1,82 @@
+/*
+ * 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.ace.deployment.service;
+
+import java.io.IOException;
+import java.util.SortedSet;
+
+import org.osgi.framework.Version;
+
+/**
+ * Deployment service can be used to talk to the management agent about deployment packages,
+ * versions and updates, and to actually perform them. This interface coexists with the
+ * tasks that are also published by the management agent and that are probably more convenient
+ * if you just want to schedule (checks for) updates.
+ */
+public interface DeploymentService {
+
+ /**
+ * Returns the highest version that is available locally (already installed).
+ *
+ * @return The highest installed version, can be null
if no version is locally available.
+ */
+ Version getHighestLocalVersion();
+
+ /**
+ * Returns the highest version that is available remotely.
+ *
+ * @param url The URL to be used to retrieve the versions available on the remote.
+ * @return The highest version available on the remote or null
if no versions were available or the remote could not be reached.
+ * @throws IOException in case of I/O problems obtaining the remote version.
+ */
+ Version getHighestRemoteVersion() throws IOException;
+
+ /**
+ * Returns all versions that are available remotely.
+ *
+ * @return the remote versions, sorted, can be null
.
+ * @throws IOException in case of I/O problems obtaining the remote versions.
+ */
+ SortedSet getRemoteVersions() throws IOException;
+
+ /**
+ * Installs the version specified by the highestRemoteVersion.
+ *
+ * @param remoteVersion the version to retrieve and install;
+ * @param localVersion the current (local) version, can be null
in case of no version is yet installed.
+ * @throws IOException in case of I/O problems installing the version;
+ * @throws Exception in case of other problems installing the version.
+ */
+ void installVersion(Version remoteVersion, Version localVersion) throws IOException, Exception;
+
+ /**
+ * Updates from the current local version to the given remote version.
+ *
+ * This method is the same as calling:
+ *
+ * installVersion(toVersion, getHighestLocalVersion());
+ *
+ *
+ *
+ * @param toVersion the (remote) version to update to, cannot be null
.
+ * @throws Exception in case of other problems updating to the requested version.
+ */
+ void update(Version toVersion) throws Exception;
+
+}
Added: ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/service/impl/Activator.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/service/impl/Activator.java?rev=1464402&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/service/impl/Activator.java (added)
+++ ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/service/impl/Activator.java Thu Apr 4 09:43:34 2013
@@ -0,0 +1,154 @@
+/*
+ * 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.ace.deployment.service.impl;
+
+import java.util.Dictionary;
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.ace.connectionfactory.ConnectionFactory;
+import org.apache.ace.deployment.Deployment;
+import org.apache.ace.deployment.service.DeploymentService;
+import org.apache.ace.discovery.Discovery;
+import org.apache.ace.identification.Identification;
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyActivatorBase;
+import org.apache.felix.dm.DependencyManager;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedServiceFactory;
+import org.osgi.service.event.EventAdmin;
+import org.osgi.service.log.LogService;
+
+/**
+ * Provides an activator for the deployment service.
+ */
+public class Activator extends DependencyActivatorBase implements ManagedServiceFactory {
+
+ private static final String PID_NAME = "org.apache.ace.deployment.task.base.factory";
+
+ private static final String MA_NAME = "ma";
+ private static final String DEFAULT_MA_NAME = null;
+
+ private final Map m_instances = new ConcurrentHashMap();
+
+ private volatile DependencyManager m_manager;
+
+ /**
+ * @see org.osgi.service.cm.ManagedServiceFactory#deleted(java.lang.String)
+ */
+ public void deleted(String pid) {
+ Component component;
+ synchronized (m_instances) {
+ component = m_instances.remove(pid);
+ }
+
+ if (component != null) {
+ m_manager.remove(component);
+ }
+ }
+
+ /**
+ * @see org.apache.felix.dm.DependencyActivatorBase#destroy(org.osgi.framework.BundleContext, org.apache.felix.dm.DependencyManager)
+ */
+ public void destroy(BundleContext context, DependencyManager manager) throws Exception {
+ // do nothing
+ }
+
+ /**
+ * @see org.osgi.service.cm.ManagedServiceFactory#getName()
+ */
+ public String getName() {
+ return "Deployment Service - base";
+ }
+
+ /**
+ * @see org.apache.felix.dm.DependencyActivatorBase#init(org.osgi.framework.BundleContext, org.apache.felix.dm.DependencyManager)
+ */
+ public void init(BundleContext context, DependencyManager manager) throws Exception {
+ m_manager = manager;
+
+ // Create a default deployment service instance...
+ m_manager.add(createService(DEFAULT_MA_NAME));
+
+ Properties props = new Properties();
+ props.put(Constants.SERVICE_PID, PID_NAME);
+
+ m_manager.add(createComponent()
+ .setInterface(ManagedServiceFactory.class.getName(), props)
+ .setImplementation(this)
+ );
+ }
+
+ /**
+ * @see org.osgi.service.cm.ManagedServiceFactory#updated(java.lang.String, java.util.Dictionary)
+ */
+ public void updated(String pid, Dictionary dict) throws ConfigurationException {
+ final String ma = (String) dict.get(MA_NAME);
+
+ Component component = m_instances.get(pid);
+ if (component == null) {
+ component = createService(ma);
+ synchronized (m_instances) {
+ m_instances.put(pid, component);
+ }
+ m_manager.add(component);
+ }
+ else {
+ // TODO do we want to deal with changes here?
+ }
+ }
+
+ /**
+ * Creates the {@link DeploymentService} component for the given management agent name.
+ *
+ * @param ma the name of the management agent to create the service for, can be null
.
+ * @return a {@link Component} instance for the {@link DeploymentService}, never null
.
+ */
+ private Component createService(String ma) {
+ Dictionary deploymentProperties = new Properties();
+
+ String identificationFilter = "(" + Constants.OBJECTCLASS + "=" + Identification.class.getName() + ")";
+ String discoveryFilter = "(" + Constants.OBJECTCLASS + "=" + Discovery.class.getName() + ")";
+
+ if (ma == null || "".equals(ma.trim())) {
+ identificationFilter = String.format("(&%s(!(%s=*)))", identificationFilter, MA_NAME);
+ discoveryFilter = String.format("(&%s(!(%s=*)))", discoveryFilter, MA_NAME); ;
+ }
+ else {
+ identificationFilter = String.format("(&%s(%s=%s))", identificationFilter, MA_NAME, ma);
+ discoveryFilter = String.format("(&%s(%s=%s))", discoveryFilter, MA_NAME, ma);
+ deploymentProperties.put(MA_NAME, ma);
+ }
+
+ DeploymentServiceImpl deploymentService = new DeploymentServiceImpl();
+
+ return createComponent()
+ .setInterface(DeploymentService.class.getName(), deploymentProperties)
+ .setImplementation(deploymentService)
+ .add(createServiceDependency().setService(Deployment.class).setRequired(true))
+ .add(createServiceDependency().setService(ConnectionFactory.class).setRequired(true))
+ .add(createServiceDependency().setService(Identification.class, identificationFilter).setRequired(true))
+ .add(createServiceDependency().setService(Discovery.class, discoveryFilter).setRequired(true))
+ .add(createServiceDependency().setService(EventAdmin.class).setRequired(false))
+ .add(createServiceDependency().setService(LogService.class).setRequired(false));
+ }
+}
\ No newline at end of file
Added: ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/service/impl/DeploymentServiceImpl.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/service/impl/DeploymentServiceImpl.java?rev=1464402&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/service/impl/DeploymentServiceImpl.java (added)
+++ ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/service/impl/DeploymentServiceImpl.java Thu Apr 4 09:43:34 2013
@@ -0,0 +1,300 @@
+/*
+ * 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.ace.deployment.service.impl;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Properties;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import org.apache.ace.connectionfactory.ConnectionFactory;
+import org.apache.ace.deployment.Deployment;
+import org.apache.ace.deployment.service.DeploymentService;
+import org.apache.ace.discovery.Discovery;
+import org.apache.ace.identification.Identification;
+import org.osgi.framework.Version;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventAdmin;
+import org.osgi.service.log.LogService;
+
+/**
+ * Provides an implementation for {@link DeploymentService}.
+ */
+public class DeploymentServiceImpl implements DeploymentService {
+
+ private final String TOPIC_DEPLOYMENTPACKAGE_INSTALL = "org/apache/ace/deployment/INSTALL";
+
+ // injected by dependencymanager
+ protected volatile Deployment m_deployer;
+ protected volatile Identification m_identification;
+ protected volatile Discovery m_discovery;
+ protected volatile LogService m_log;
+ protected volatile EventAdmin m_eventAdmin;
+ protected volatile ConnectionFactory m_connectionFactory;
+
+ /**
+ * @see org.apache.ace.deployment.service.DeploymentService#getHighestLocalVersion()
+ */
+ public Version getHighestLocalVersion() {
+ Object[] installedPackages = m_deployer.list();
+ List versions = new ArrayList();
+ for (int i = 0; i < installedPackages.length; i++) {
+ if (m_deployer.getName(installedPackages[i]).equals(m_identification.getID())) {
+ versions.add(m_deployer.getVersion(installedPackages[i]));
+ }
+ }
+ return getHighestVersion(versions);
+ }
+
+ /**
+ * @see org.apache.ace.deployment.service.DeploymentService#getHighestRemoteVersion()
+ */
+ public Version getHighestRemoteVersion() throws IOException {
+ SortedSet versions = getRemoteVersions(getURL());
+ return ((versions == null) || versions.isEmpty()) ? null : versions.last();
+ }
+
+ /**
+ * @see org.apache.ace.deployment.service.DeploymentService#getRemoteVersions()
+ */
+ public SortedSet getRemoteVersions() throws IOException {
+ return getRemoteVersions(getURL());
+ }
+
+ /**
+ * @see org.apache.ace.deployment.service.DeploymentService#installVersion(org.osgi.framework.Version, org.osgi.framework.Version)
+ */
+ public void installVersion(Version highestRemoteVersion, Version highestLocalVersion) throws IOException, Exception {
+ InputStream inputStream = null;
+
+ m_log.log(LogService.LOG_INFO, "Installing version: " + highestRemoteVersion);
+
+ try {
+ String version = highestRemoteVersion.toString();
+ URL baseURL = getURL();
+ boolean isFileBasedProtocol = "file".equals(baseURL.getProtocol());
+ if (highestLocalVersion != null && !isFileBasedProtocol) {
+ version += "?current=" + highestLocalVersion.toString();
+ }
+ URL dataURL = new URL(baseURL, version);
+ if (isFileBasedProtocol) {
+ File file = urlToFile(dataURL);
+ inputStream = new FileInputStream(file);
+ }
+ else {
+ inputStream = getContents(dataURL);
+ }
+
+ // Post event for auditlog
+ m_eventAdmin.postEvent(createEvent(version, dataURL));
+
+ m_deployer.install(inputStream);
+ }
+ finally {
+ if (inputStream != null) {
+ try {
+ inputStream.close();
+ }
+ catch (Exception ex) {
+ // Not much we can do.
+ }
+ }
+ }
+ }
+
+ /**
+ * @see org.apache.ace.deployment.service.DeploymentService#update(org.osgi.framework.Version)
+ */
+ public void update(Version toVersion) throws Exception {
+ installVersion(toVersion, getHighestLocalVersion());
+ }
+
+ /**
+ * @param url
+ * @return
+ * @throws IOException
+ */
+ final SortedSet getRemoteVersions(URL url) throws IOException {
+ if (url == null) {
+ return null;
+ }
+
+ if ("file".equals(url.getProtocol())) {
+ return getVersionsFromDirectory(url);
+ }
+ else {
+ return getVersionsFromServer(url);
+ }
+ }
+
+ /**
+ * @param version
+ * @param dataURL
+ * @return
+ */
+ private Event createEvent(String version, URL dataURL) {
+ Dictionary properties = new Properties();
+ properties.put("deploymentpackage.url", dataURL.toString());
+ properties.put("deploymentpackage.version", version);
+ Event event = new Event(TOPIC_DEPLOYMENTPACKAGE_INSTALL, properties);
+ return event;
+ }
+
+ /**
+ * @param versions
+ * @return
+ */
+ private Version getHighestVersion(List versions) {
+ Version highestVersion = null;
+ for (Iterator i = versions.iterator(); i.hasNext();) {
+ Version version = (Version) i.next();
+ if (highestVersion == null) {
+ highestVersion = version;
+ }
+ else if (version.compareTo(highestVersion) > 0) {
+ highestVersion = version;
+ }
+ }
+ return highestVersion;
+ }
+
+ /**
+ * @return
+ */
+ private URL getURL() {
+ URL host = m_discovery.discover();
+ if (host == null) {
+ return null;
+ }
+ try {
+ return new URL(host, "deployment/" + m_identification.getID() + "/versions/");
+ }
+ catch (MalformedURLException e) {
+ m_log.log(LogService.LOG_WARNING, "Malformed URL", e);
+ return null;
+ }
+ }
+
+ /**
+ * @param url
+ * @return
+ */
+ private SortedSet getVersionsFromDirectory(URL url) {
+ File file = urlToFile(url);
+ if (!file.isDirectory()) {
+ return null;
+ }
+
+ final File[] files = file.listFiles();
+ SortedSet versions = new TreeSet();
+ for (File f : files) {
+ try {
+ Version version = Version.parseVersion(f.getName());
+ if (version != Version.emptyVersion) {
+ versions.add(version);
+ }
+ }
+ catch (IllegalArgumentException e) {
+ // if the file is not a valid version, we skip it
+ }
+ }
+ return versions;
+ }
+
+ /**
+ * @param url
+ * @return
+ */
+ private SortedSet getVersionsFromServer(URL url) {
+ BufferedReader bufReader = null;
+ try {
+ bufReader = new BufferedReader(new InputStreamReader(getContents(url)));
+ SortedSet versions = new TreeSet();
+
+ String versionString;
+ while ((versionString = bufReader.readLine()) != null) {
+ try {
+ Version version = Version.parseVersion(versionString);
+ if (version != Version.emptyVersion) {
+ versions.add(version);
+ }
+ }
+ catch (IllegalArgumentException iae) {
+ m_log.log(LogService.LOG_WARNING, "Received malformed version, ignoring: " + versionString);
+ }
+ }
+
+ return versions;
+ }
+ catch (IOException ioe) {
+ m_log.log(LogService.LOG_DEBUG, "I/O error accessing server!", ioe);
+ return null;
+ }
+ finally {
+ if (bufReader != null) {
+ try {
+ bufReader.close();
+ }
+ catch (Exception ex) {
+ // not much we can do
+ }
+ }
+ }
+ }
+
+ /**
+ * @param url
+ * @return
+ */
+ private File urlToFile(URL url) {
+ File file;
+ // See: http://weblogs.java.net/blog/kohsuke/archive/2007/04/how_to_convert.html
+ // makes a best effort to convert a file URL to a File
+ try {
+ file = new File(url.toURI());
+ }
+ catch (URISyntaxException e) {
+ file = new File(url.getPath());
+ }
+ return file;
+ }
+
+ /**
+ * @param url the remote URL to connect to, cannot be null
.
+ * @return an {@link InputStream} to the remote URL, never null
.
+ * @throws IOException in case of I/O problems opening the remote connection.
+ */
+ private InputStream getContents(URL url) throws IOException {
+ URLConnection conn = m_connectionFactory.createConnection(url);
+ return conn.getInputStream();
+ }
+}
\ No newline at end of file
Added: ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/service/packageinfo
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/service/packageinfo?rev=1464402&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/service/packageinfo (added)
+++ ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/service/packageinfo Thu Apr 4 09:43:34 2013
@@ -0,0 +1 @@
+version 1.0
\ No newline at end of file
Added: ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/AceRestException.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/AceRestException.java?rev=1464402&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/AceRestException.java (added)
+++ ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/AceRestException.java Thu Apr 4 09:43:34 2013
@@ -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.ace.deployment.servlet;
+
+import java.io.IOException;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * Handle common rest problems here.
+ * This can be thrown by services (unaware of how to handle it in the end) and handeled inside the catching servlet.
+ */
+public class AceRestException extends Exception {
+ private final int m_statusCode;
+ private final String m_description;
+
+ public AceRestException(int statusCode, String description) {
+ super(statusCode + ":" + description);
+ m_statusCode = statusCode;
+ m_description = description;
+ }
+
+ /**
+ * handling code where we turn this
into http error.
+ *
+ * @param response
+ */
+ public void handleAsHttpError(HttpServletResponse response) throws IOException {
+ response.sendError(m_statusCode, m_description);
+ }
+}
\ No newline at end of file
Added: ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/Activator.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/Activator.java?rev=1464402&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/Activator.java (added)
+++ ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/Activator.java Thu Apr 4 09:43:34 2013
@@ -0,0 +1,51 @@
+/*
+ * 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.ace.deployment.servlet;
+
+import javax.servlet.Servlet;
+
+import org.apache.ace.deployment.processor.DeploymentProcessor;
+import org.apache.ace.deployment.provider.DeploymentProvider;
+import org.apache.ace.deployment.streamgenerator.StreamGenerator;
+import org.apache.felix.dm.DependencyActivatorBase;
+import org.apache.felix.dm.DependencyManager;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.log.LogService;
+
+public class Activator extends DependencyActivatorBase {
+ public static final String PID = "org.apache.ace.deployment.servlet";
+
+ @Override
+ public void init(BundleContext context, DependencyManager manager) throws Exception {
+ manager.add(createComponent()
+ .setInterface(Servlet.class.getName(), null)
+ .setImplementation(DeploymentServlet.class)
+ .add(createConfigurationDependency().setPropagate(true).setPid(PID))
+ .add(createServiceDependency().setService(StreamGenerator.class).setRequired(true))
+ .add(createServiceDependency().setService(DeploymentProvider.class).setRequired(true))
+ .add(createServiceDependency().setService(DeploymentProcessor.class).setRequired(false).setCallbacks("addProcessor", "removeProcessor"))
+ .add(createServiceDependency().setService(LogService.class).setRequired(false))
+ );
+ }
+
+ @Override
+ public void destroy(BundleContext context, DependencyManager manager) throws Exception {
+ // do nothing
+ }
+}
\ No newline at end of file
Added: ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/DeploymentServlet.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/DeploymentServlet.java?rev=1464402&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/DeploymentServlet.java (added)
+++ ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/DeploymentServlet.java Thu Apr 4 09:43:34 2013
@@ -0,0 +1,311 @@
+/*
+ * 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.ace.deployment.servlet;
+
+import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Dictionary;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+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.ace.authentication.api.AuthenticationService;
+import org.apache.ace.deployment.processor.DeploymentProcessor;
+import org.apache.ace.deployment.provider.DeploymentProvider;
+import org.apache.ace.deployment.streamgenerator.StreamGenerator;
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedService;
+import org.osgi.service.log.LogService;
+import org.osgi.service.useradmin.User;
+
+/**
+ * The DeploymentServlet class provides in a list of versions available for a target and a stream
+ * of data containing the DeploymentPackage (or fix package) for a specific target and version.
+ */
+public class DeploymentServlet extends HttpServlet implements ManagedService {
+ private static final long serialVersionUID = 1L;
+
+ /** A boolean denoting whether or not authentication is enabled. */
+ private static final String KEY_USE_AUTHENTICATION = "authentication.enabled";
+
+ public static final String CURRENT = "current";
+ public static final String PROCESSOR = "processor";
+ public static final String VERSIONS = "versions";
+ public static final String DP_MIMETYPE = "application/vnd.osgi.dp";
+ public static final String TEXT_MIMETYPE = "text/plain";
+
+ private final ConcurrentMap m_processors = new ConcurrentHashMap();
+
+ // injected by Dependency Manager
+ private volatile DependencyManager m_dm;
+ private volatile LogService m_log;
+ private volatile StreamGenerator m_streamGenerator;
+ private volatile DeploymentProvider m_provider;
+ private volatile AuthenticationService m_authService;
+
+ private volatile boolean m_useAuth = false;
+
+ /**
+ * Responds to GET requests sent to this endpoint, the response depends on the requested path:
+ * http://host/endpoint/targetid/versions/ returns a list of versions available for the specified target
+ * http://host/endpoint/targetid/versions/x.y.z returns a deployment package stream for the specified target and version
+ *
+ * The status code of the response can be one of the following:
+ * HttpServletResponse.SC_BAD_REQUEST
- If no target is specified or the request is malformed in a different way.
+ * HttpServletResponse.SC_NOT_FOUND
- If the specified target or version does not exist.
+ * HttpServletResponse.SC_INTERNAL_SERVER_ERROR
- If there was a problem processing the request.
+ * HttpServletResponse.SC_OK
- If all went fine
+ */
+ @Override
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ try {
+ String[] pathElements = verifyAndGetPathElements(request.getPathInfo());
+ String targetID = pathElements[1];
+ List versions = getVersions(targetID);
+ int numberOfElements = pathElements.length;
+
+ if (numberOfElements == 3) {
+ handleVersionsRequest(versions, response);
+ }
+ else {
+ String version = pathElements[3];
+ handlePackageDelivery(targetID, version, versions, request, response);
+ }
+ }
+ catch (AceRestException e) {
+ m_log.log(LogService.LOG_WARNING, e.getMessage(), e);
+ e.handleAsHttpError(response);
+ }
+ }
+
+ /**
+ * Called by Dependency Manager upon initialization of this component.
+ *
+ * @param comp the component to initialize, cannot be null
.
+ */
+ protected void init(Component comp) {
+ comp.add(m_dm.createServiceDependency()
+ .setService(AuthenticationService.class)
+ .setRequired(m_useAuth)
+ .setInstanceBound(true)
+ );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ if (!authenticate(req)) {
+ // Authentication failed; don't proceed with the original request...
+ resp.sendError(SC_UNAUTHORIZED);
+ } else {
+ // Authentication successful, proceed with original request...
+ super.service(req, resp);
+ }
+ }
+
+ /**
+ * Authenticates, if needed the user with the information from the given request.
+ *
+ * @param request the request to obtain the credentials from, cannot be null
.
+ * @return true
if the authentication was successful, false
otherwise.
+ */
+ private boolean authenticate(HttpServletRequest request) {
+ if (m_useAuth) {
+ User user = m_authService.authenticate(request);
+ if (user == null) {
+ m_log.log(LogService.LOG_INFO, "Authentication failure!");
+ }
+ return (user != null);
+ }
+ return true;
+ }
+
+ /**
+ * Serve the case where requested path is like:
+ * http://host/endpoint/targetid/versions/ returns a list of versions available for the specified target
+ *
+ * @param versions versions to be put into response
+ * @param response response object.
+ */
+ private void handleVersionsRequest(List versions, HttpServletResponse response) throws AceRestException {
+ ServletOutputStream output = null;
+
+ response.setContentType(TEXT_MIMETYPE);
+ try {
+ output = response.getOutputStream();
+ for (String version : versions) {
+ output.print(version);
+ output.print("\n");
+ }
+ }
+ catch (IOException e) {
+ throw new AceRestException(HttpServletResponse.SC_BAD_REQUEST, "Request URI is invalid");
+ }
+ finally {
+ tryClose(output);
+ }
+ }
+
+ private void handlePackageDelivery(final String targetID, final String version, final List versions, final HttpServletRequest request, final HttpServletResponse response) throws AceRestException {
+ ServletOutputStream output = null;
+
+ try {
+ if (!versions.contains(version)) {
+ throw new AceRestException(HttpServletResponse.SC_NOT_FOUND, "Unknown version (" + version + ")");
+ }
+ String current = request.getParameter(CURRENT);
+ String processor = request.getParameter(PROCESSOR);
+
+ InputStream inputStream;
+ if (current != null) {
+ inputStream = m_streamGenerator.getDeploymentPackage(targetID, current, version);
+ }
+ else {
+ inputStream = m_streamGenerator.getDeploymentPackage(targetID, version);
+ }
+
+ if (processor != null) {
+ DeploymentProcessor deploymentProcessor = m_processors.get(processor);
+ if (deploymentProcessor != null) {
+ deploymentProcessor.process(inputStream, request, response);
+ return;
+ }
+ else {
+ throw new AceRestException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Could not find a deployment processor called: " + processor);
+ }
+ }
+ response.setContentType(DP_MIMETYPE);
+ output = response.getOutputStream();
+ byte[] buffer = new byte[1024 * 32];
+ for (int bytesRead = inputStream.read(buffer); bytesRead != -1; bytesRead = inputStream.read(buffer)) {
+ output.write(buffer, 0, bytesRead);
+ }
+ }
+ catch (IllegalArgumentException e) {
+ throw (AceRestException) new AceRestException(HttpServletResponse.SC_BAD_REQUEST, "Request URI is invalid").initCause(e);
+ }
+ catch (IOException e) {
+ throw (AceRestException) new AceRestException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Could not deliver package").initCause(e);
+ }
+ finally {
+ tryClose(output);
+ }
+ }
+
+ private List getVersions(String targetID) throws AceRestException {
+ try {
+ return m_provider.getVersions(targetID);
+ }
+ catch (IllegalArgumentException iae) {
+ throw new AceRestException(HttpServletResponse.SC_NOT_FOUND, "Unknown target (" + targetID + ")");
+ }
+ catch (IOException ioe) {
+ m_log.log(LogService.LOG_WARNING, "Error getting available versions.", ioe);
+ throw new AceRestException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Error getting available versions.");
+ }
+ }
+
+ private void tryClose(OutputStream output) {
+ try {
+ if (output != null) {
+ output.close();
+ }
+ }
+ catch (IOException e) {
+ m_log.log(LogService.LOG_WARNING, "Exception trying to close stream after request. ", e);
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Make sure the path is valid.
+ * Also returns the splited version of #path.
+ *
+ * @param path http request path
+ *
+ * @return splitted version of #path. Split delim is "/"
+ *
+ * @throws org.apache.ace.deployment.servlet.AceRestException if path is not valid or cannot be processed.
+ */
+ private String[] verifyAndGetPathElements(String path) throws AceRestException {
+ if (path == null) {
+ throw new AceRestException(HttpServletResponse.SC_BAD_REQUEST, "Request URI is invalid");
+ }
+ String[] elements = path.split("/");
+ int numberOfElements = elements.length;
+
+ if ((numberOfElements < 3) || (numberOfElements > 4) || !VERSIONS.equals(elements[2])) {
+ throw new AceRestException(HttpServletResponse.SC_BAD_REQUEST, "Request URI is invalid");
+ }
+ return elements;
+ }
+
+ @Override
+ public String getServletInfo() {
+ return "Ace Deployment Servlet Endpoint";
+ }
+
+ public void updated(Dictionary settings) throws ConfigurationException {
+ if (settings != null) {
+ String useAuthString = (String) settings.get(KEY_USE_AUTHENTICATION);
+ if (useAuthString == null
+ || !("true".equalsIgnoreCase(useAuthString) || "false".equalsIgnoreCase(useAuthString))) {
+ throw new ConfigurationException(KEY_USE_AUTHENTICATION, "Missing or invalid value!");
+ }
+ boolean useAuth = Boolean.parseBoolean(useAuthString);
+
+ m_useAuth = useAuth;
+ }
+ else {
+ m_useAuth = false;
+ }
+ }
+
+ public void addProcessor(ServiceReference ref, DeploymentProcessor processor) {
+ String key = (String) ref.getProperty(PROCESSOR);
+ if (key == null) {
+ m_log.log(LogService.LOG_WARNING, "Deployment processor ignored, required service property '" + PROCESSOR + "' is missing.");
+ return;
+ }
+ m_processors.putIfAbsent(key, processor);
+ }
+
+ public void removeProcessor(ServiceReference ref, DeploymentProcessor processor) {
+ String key = (String) ref.getProperty(PROCESSOR);
+ if (key == null) {
+ // we do not log this here again, we already did so in 'addProcessor'
+ return;
+ }
+ m_processors.remove(key);
+ }
+}
\ No newline at end of file
Added: ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/streamgenerator/StreamGenerator.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/streamgenerator/StreamGenerator.java?rev=1464402&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/streamgenerator/StreamGenerator.java (added)
+++ ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/streamgenerator/StreamGenerator.java Thu Apr 4 09:43:34 2013
@@ -0,0 +1,47 @@
+/*
+ * 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.ace.deployment.streamgenerator;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+public interface StreamGenerator
+{
+
+ /**
+ * Returns an input stream with the requested deployment package.
+ *
+ * @param id the ID of the package
+ * @param version the version of the package
+ * @return an input stream
+ * @throws java.io.IOException when the stream could not be generated
+ */
+ public InputStream getDeploymentPackage(String id, String version) throws IOException;
+
+ /**
+ * Returns an input stream with the requested deployment fix package.
+ *
+ * @param id the ID of the package.
+ * @param fromVersion the version of the target.
+ * @param toVersion the version the target should be in after applying the package.
+ * @return an input stream.
+ * @throws java.io.IOException when the stream could not be generated.
+ */
+ public InputStream getDeploymentPackage(String id, String fromVersion, String toVersion) throws IOException;
+}
\ No newline at end of file
Added: ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/streamgenerator/impl/Activator.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/streamgenerator/impl/Activator.java?rev=1464402&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/streamgenerator/impl/Activator.java (added)
+++ ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/streamgenerator/impl/Activator.java Thu Apr 4 09:43:34 2013
@@ -0,0 +1,48 @@
+/*
+ * 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.ace.deployment.streamgenerator.impl;
+
+import org.apache.ace.connectionfactory.ConnectionFactory;
+import org.apache.ace.deployment.provider.DeploymentProvider;
+import org.apache.ace.deployment.streamgenerator.StreamGenerator;
+import org.apache.felix.dm.DependencyActivatorBase;
+import org.apache.felix.dm.DependencyManager;
+import org.osgi.framework.BundleContext;
+
+public class Activator extends DependencyActivatorBase {
+ @Override
+ public void init(BundleContext context, DependencyManager manager) throws Exception {
+ manager.add(createComponent()
+ .setInterface(StreamGenerator.class.getName(), null)
+ .setImplementation(StreamGeneratorImpl.class)
+ .add(createServiceDependency()
+ .setService(DeploymentProvider.class)
+ .setRequired(true)
+ )
+ .add(createServiceDependency()
+ .setService(ConnectionFactory.class)
+ .setRequired(true)
+ )
+ );
+ }
+
+ @Override
+ public void destroy(BundleContext context, DependencyManager manager) throws Exception {
+ }
+}
\ No newline at end of file