You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ace.apache.org by ja...@apache.org on 2014/12/18 16:48:42 UTC
svn commit: r1646482 - in
/ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace:
Workspace.java impl/DPHelper.java impl/WorkspaceImpl.java
Author: jawi
Date: Thu Dec 18 15:48:41 2014
New Revision: 1646482
URL: http://svn.apache.org/r1646482
Log:
ACE-502 - Allow import of DPs from other ACE server
- import all new/non-existing artifacts;
- recreate the features and distributions and link them to
the artifacts as mentioned in the DP;
- added support for fix-packages and ensure that no artifacts
are missing that are not available in the OBR.
Added:
ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/impl/DPHelper.java (with props)
Modified:
ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/Workspace.java
ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/impl/WorkspaceImpl.java
Modified: ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/Workspace.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/Workspace.java?rev=1646482&r1=1646481&r2=1646482&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/Workspace.java (original)
+++ ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/Workspace.java Thu Dec 18 15:48:41 2014
@@ -392,4 +392,25 @@ public interface Workspace {
public boolean isCurrent() throws IOException;
+ /*** deployment package ***/
+
+ /**
+ * Imports a deployment package from a given URL and commits all changes to the workspace.
+ *
+ * @param dpURL
+ * the URL to the deployment package to import.
+ * @see #idp(String, boolean)
+ */
+ public void idp(String dpURL) throws Exception;
+
+ /**
+ * Imports a deployment package from a given URL.
+ *
+ * @param dpURL
+ * the URL to the deployment package to import;
+ * @param autoCommit
+ * <code>true</code> if changes to the workspace should be committed automatically, <code>false</code>
+ * otherwise.
+ */
+ public void idp(String dpURL, boolean autoCommit) throws Exception;
}
Added: ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/impl/DPHelper.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/impl/DPHelper.java?rev=1646482&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/impl/DPHelper.java (added)
+++ ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/impl/DPHelper.java Thu Dec 18 15:48:41 2014
@@ -0,0 +1,323 @@
+/*
+ * 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.client.workspace.impl;
+
+import static org.apache.ace.client.workspace.Workspace.*;
+
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URL;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarInputStream;
+
+import org.apache.ace.client.repository.object.Artifact2FeatureAssociation;
+import org.apache.ace.client.repository.object.ArtifactObject;
+import org.apache.ace.client.repository.object.DistributionObject;
+import org.apache.ace.client.repository.object.Feature2DistributionAssociation;
+import org.apache.ace.client.repository.object.FeatureObject;
+import org.osgi.service.log.LogService;
+
+/**
+ * Utility class that allows a deployment package to be imported in a workspace in such way that it recreates all
+ * artifacts, features, distributions and their associations.
+ * <p>
+ * This functionality uploads all artifacts from the given deployment package, and for each feature and distribution
+ * will recreate(!) all associations. This means that associations that were made by hand are <b>not</b> preserved!<br>
+ * In addition, no attempt is made to clean up artifacts that are no longer used (which is currently not possible with
+ * the default OBR in ACE).
+ * </p>
+ */
+class DPHelper {
+ private static final Map<String, String> NO_TAGS = Collections.<String, String> emptyMap();
+
+ private static final String ARTIFACT_NAME = "artifactName";
+ private static final String ACE_REPOSITORY_PATH = "ACE-RepositoryPath";
+ private static final String BUNDLE_VERSION = "Bundle-Version";
+ private static final String BUNDLE_SYMBOLIC_NAME = "Bundle-SymbolicName";
+ private static final String DEPLOYMENT_PACKAGE_CUSTOMIZER = "DeploymentPackage-Customizer";
+ private static final String DEPLOYMENT_PACKAGE_MISSING = "DeploymentPackage-Missing";
+
+ private final WorkspaceImpl m_workspace;
+ private final LogService m_log;
+
+ /**
+ * Creates a new DPHelper instance.
+ */
+ public DPHelper(WorkspaceImpl workspace, LogService log) {
+ m_workspace = workspace;
+ m_log = log;
+ }
+
+ public void importDeploymentPackage(String dpURL, boolean autoCommit) throws Exception {
+ URL url = URI.create(dpURL).toURL();
+
+ InputStream is = null;
+ JarInputStream jis = null;
+
+ try {
+ is = url.openStream();
+ jis = new JarInputStream(is);
+
+ importDeploymentPackage(jis, autoCommit);
+ }
+ finally {
+ closeSilently(is);
+ closeSilently(jis);
+ }
+ }
+
+ protected void importDeploymentPackage(JarInputStream is, boolean autoCommit) throws Exception {
+ Map<ArtifactObject, FeatureObject> a2fMap = new HashMap<ArtifactObject, FeatureObject>();
+ Map<FeatureObject, DistributionObject> f2dMap = new HashMap<FeatureObject, DistributionObject>();
+
+ // Upload all (new) artifact...
+ JarEntry jarEntry;
+ while ((jarEntry = is.getNextJarEntry()) != null) {
+ String name = jarEntry.getName();
+ Attributes attributes = jarEntry.getAttributes();
+
+ // Create & upload artifact...
+ ArtifactObject artifact = createArtifact(name, attributes, is);
+ if (artifact == null) {
+ throw new RuntimeException("Failed to import deployment package! Missing artifact: " + name + " in fix package which is also not present in the OBR!");
+ }
+
+ String repositoryPath = attributes.getValue(ACE_REPOSITORY_PATH);
+ if (repositoryPath == null) {
+ m_log.log(LogService.LOG_WARNING, String.format("No ACE-RepositoryPath attribute present for '%s'; not creating assocations...", name));
+ continue;
+ }
+ String[] names = repositoryPath.split(";");
+
+ // Create feature...
+ FeatureObject feature = createFeature(names[0]);
+
+ // Create distribution...
+ DistributionObject distribution = createDistribution(names[1]);
+
+ a2fMap.put(artifact, feature);
+ f2dMap.put(feature, distribution);
+
+ is.closeEntry();
+ }
+
+ // Pre-fill...
+ for (Map.Entry<String, Attributes> entry : is.getManifest().getEntries().entrySet()) {
+ String name = entry.getKey();
+ Attributes attributes = entry.getValue();
+ boolean missing = Boolean.parseBoolean(attributes.getValue(DEPLOYMENT_PACKAGE_MISSING));
+
+ ArtifactObject artifact = findArtifact(name, attributes);
+ if (artifact == null && missing) {
+ throw new RuntimeException("Failed to import deployment package! Artifact: " + name + " is missing in fix package, but not present in the OBR!");
+ }
+
+ String repositoryPath = attributes.getValue(ACE_REPOSITORY_PATH);
+ if (repositoryPath == null) {
+ m_log.log(LogService.LOG_WARNING, String.format("No ACE-RepositoryPath attribute present for '%s'; not creating assocations...", name));
+ continue;
+ }
+ String[] names = repositoryPath.split(";");
+
+ // Create feature...
+ FeatureObject feature = createFeature(names[0]);
+
+ // Create distribution...
+ DistributionObject distribution = createDistribution(names[1]);
+
+ a2fMap.put(artifact, feature);
+ f2dMap.put(feature, distribution);
+ }
+
+ // Remove existing associations for feature & distribution...
+ for (FeatureObject feature : f2dMap.keySet()) {
+ disassociateArtifactsFromFeature(feature);
+ }
+ for (DistributionObject distribution : f2dMap.values()) {
+ disassociateFeaturesFromDistribution(distribution);
+ }
+
+ // Create associations...
+ for (Map.Entry<ArtifactObject, FeatureObject> entry : a2fMap.entrySet()) {
+ associateArtifactToFeature(entry.getKey(), entry.getValue());
+ }
+
+ for (Map.Entry<FeatureObject, DistributionObject> entry : f2dMap.entrySet()) {
+ associateFeatureToDistribution(entry.getKey(), entry.getValue());
+ }
+
+ if (autoCommit) {
+ m_workspace.commit();
+ }
+ }
+
+ private void associateArtifactToFeature(ArtifactObject artifact, FeatureObject feature) throws Exception {
+ if (artifact.getAssociationsWith(feature).isEmpty()) {
+ m_log.log(LogService.LOG_DEBUG, String.format("Creating assocation between artifact '%s' and feature '%s'...", artifact.getName(), feature.getName()));
+
+ m_workspace.createAssocation(ARTIFACT2FEATURE, artifact.getAssociationFilter(null), feature.getAssociationFilter(null), "1", "1");
+ }
+ }
+
+ private void associateFeatureToDistribution(FeatureObject feature, DistributionObject distribution) throws Exception {
+ if (feature.getAssociationsWith(distribution).isEmpty()) {
+ m_log.log(LogService.LOG_DEBUG, String.format("Creating assocation between feature '%s' and distribution '%s'...", feature.getName(), distribution.getName()));
+
+ m_workspace.createAssocation(FEATURE2DISTRIBUTION, feature.getAssociationFilter(null), distribution.getAssociationFilter(null), "1", "1");
+ }
+ }
+
+ private void closeSilently(Closeable resource) {
+ try {
+ if (resource != null) {
+ resource.close();
+ }
+ }
+ catch (IOException exception) {
+ m_log.log(LogService.LOG_DEBUG, "Failed to close resource!", exception);
+ }
+ }
+
+ private ArtifactObject createArtifact(String name, Attributes attrs, InputStream is) throws Exception {
+ // Check what we've got, if it already exists in our repository...
+ ArtifactObject artifact = findArtifact(name, attrs);
+
+ if (artifact != null) {
+ return artifact;
+ }
+ else if (Boolean.parseBoolean(attrs.getValue(DEPLOYMENT_PACKAGE_MISSING))) {
+ m_log.log(LogService.LOG_WARNING, String.format("Unable to create artifact '%s' as it is missing...", name));
+ return null;
+ }
+ else {
+ m_log.log(LogService.LOG_INFO, String.format("Creating artifact '%s'...", name));
+
+ File file = storeArtifactContents(name, is);
+ try {
+ return m_workspace.createArtifact(file.toURI().toURL().toExternalForm(), true /* upload */);
+ }
+ finally {
+ file.delete();
+ }
+ }
+ }
+
+ private DistributionObject createDistribution(String name) throws Exception {
+ String keyName = DistributionObject.KEY_NAME;
+ List<DistributionObject> dists = m_workspace.ld(String.format("(%s=%s)", keyName, name));
+ if (dists.size() > 1) {
+ throw new RuntimeException("Multiple distributions found for: " + name + "!");
+ }
+ else if (dists.size() == 1) {
+ return dists.get(0);
+ }
+ return m_workspace.createDistribution(Collections.singletonMap(keyName, name), NO_TAGS);
+ }
+
+ private FeatureObject createFeature(String name) throws Exception {
+ String keyName = FeatureObject.KEY_NAME;
+ List<FeatureObject> feats = m_workspace.lf(String.format("(%s=%s)", keyName, name));
+ if (feats.size() > 1) {
+ throw new RuntimeException("Multiple features found for: " + name + "!");
+ }
+ else if (feats.size() == 1) {
+ return feats.get(0);
+ }
+ return m_workspace.createFeature(Collections.singletonMap(keyName, name), NO_TAGS);
+ }
+
+ private void disassociateArtifactsFromFeature(FeatureObject feature) {
+ for (ArtifactObject artifact : feature.getArtifacts()) {
+ for (Artifact2FeatureAssociation association : artifact.getAssociationsWith(feature)) {
+ m_workspace.da2f(association);
+ }
+ }
+ }
+
+ private void disassociateFeaturesFromDistribution(DistributionObject distribution) {
+ for (FeatureObject feature : distribution.getFeatures()) {
+ for (Feature2DistributionAssociation association : feature.getAssociationsWith(distribution)) {
+ m_workspace.df2d(association);
+ }
+ }
+ }
+
+ private ArtifactObject findArtifact(String name, Attributes attrs) throws Exception {
+ List<ArtifactObject> objs;
+
+ String customizer = attrs.getValue(DEPLOYMENT_PACKAGE_CUSTOMIZER);
+ String bsn = attrs.getValue(BUNDLE_SYMBOLIC_NAME);
+ String version = attrs.getValue(BUNDLE_VERSION);
+
+ if (bsn != null) {
+ String filter = String.format("(&(%s=%s)(%s=%s))", BUNDLE_SYMBOLIC_NAME, bsn, BUNDLE_VERSION, version);
+ if (customizer != null) {
+ // Resource processor...
+ objs = m_workspace.lrp(filter);
+ }
+ else {
+ // Plain bundle...
+ objs = m_workspace.la(filter);
+ }
+ }
+ else {
+ // Other artifact...
+ objs = m_workspace.la(String.format("(%s=%s)", ARTIFACT_NAME, name));
+ }
+
+ if (objs.size() > 1) {
+ throw new RuntimeException("Multiple artifacts found for: " + name + "!");
+ }
+ else if (objs.size() == 1) {
+ return objs.get(0);
+ }
+
+ return null;
+ }
+
+ private File storeArtifactContents(String name, InputStream is) throws IOException {
+ String tmpDir = System.getProperty("java.io.tmpdir");
+ File tempFile = new File(tmpDir, name);
+ FileOutputStream fos = null;
+
+ try {
+ fos = new FileOutputStream(tempFile);
+
+ byte[] buffer = new byte[4096];
+ int len;
+ while ((len = is.read(buffer)) > 0) {
+ fos.write(buffer, 0, len);
+ }
+ }
+ finally {
+ closeSilently(fos);
+ }
+
+ return tempFile;
+ }
+}
Propchange: ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/impl/DPHelper.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/impl/WorkspaceImpl.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/impl/WorkspaceImpl.java?rev=1646482&r1=1646481&r2=1646482&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/impl/WorkspaceImpl.java (original)
+++ ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/impl/WorkspaceImpl.java Thu Dec 18 15:48:41 2014
@@ -58,8 +58,6 @@ import org.osgi.framework.Filter;
import org.osgi.service.log.LogService;
import org.osgi.service.useradmin.User;
-import com.sun.corba.se.impl.oa.poa.AOMEntry;
-
public class WorkspaceImpl implements Workspace {
private final String m_sessionID;
@@ -277,6 +275,17 @@ public class WorkspaceImpl implements Wo
updateAssociationAttributes(entityType, repositoryObject);
updateTags(tags, repositoryObject);
}
+
+ @Override
+ public void idp(String dpURL) throws Exception {
+ idp(dpURL, true /* autoCommit */);
+ }
+
+ @Override
+ public void idp(String dpURL, boolean autoCommit) throws Exception {
+ // Delegate all complexity to a separate helper class...
+ new DPHelper(this, m_log).importDeploymentPackage(dpURL, autoCommit);
+ }
private void updateTags(Map<String, String> tags, RepositoryObject repositoryObject) {
Enumeration<String> keys;
@@ -491,7 +500,11 @@ public class WorkspaceImpl implements Wo
@Override
public void ca(String url, boolean upload) throws Exception {
- m_artifactRepository.importArtifact(new URL(url), upload);
+ createArtifact(url, upload);
+ }
+
+ public ArtifactObject createArtifact(String url, boolean upload) throws Exception {
+ return m_artifactRepository.importArtifact(new URL(url), upload);
}
@Override
@@ -586,7 +599,11 @@ public class WorkspaceImpl implements Wo
@Override
public void cf(Map<String, String> attrs, Map<String, String> tags) {
- createRepositoryObject(FEATURE, attrs, tags);
+ createFeature(attrs, tags);
+ }
+
+ public FeatureObject createFeature(Map<String, String> attrs, Map<String, String> tags) {
+ return (FeatureObject) createRepositoryObject(FEATURE, attrs, tags);
}
@Override
@@ -659,7 +676,11 @@ public class WorkspaceImpl implements Wo
@Override
public void cd(Map<String, String> attrs, Map<String, String> tags) {
- createRepositoryObject(DISTRIBUTION, attrs, tags);
+ createDistribution(attrs, tags);
+ }
+
+ public DistributionObject createDistribution(Map<String, String> attrs, Map<String, String> tags) {
+ return (DistributionObject) createRepositoryObject(DISTRIBUTION, attrs, tags);
}
@Override