You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by ma...@apache.org on 2008/01/30 17:46:39 UTC
svn commit: r616813 [2/9] - in /felix/trunk/deploymentadmin: ./ src/
src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/
src/main/java/org/apache/felix/
src/main/java/org/apache/felix/deploymentadmin/
src/main/java/org/apache/felix/de...
Added: felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/ExplodingOutputtingInputStream.java
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/ExplodingOutputtingInputStream.java?rev=616813&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/ExplodingOutputtingInputStream.java (added)
+++ felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/ExplodingOutputtingInputStream.java Wed Jan 30 08:46:24 2008
@@ -0,0 +1,243 @@
+/*
+ * 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.felix.deploymentadmin;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+import java.util.jar.Attributes.Name;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.GZIPOutputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+/**
+ * This class will write all entries encountered in an inputstream to disk. An index of files written to disk is kept in an index file in the
+ * order they were encountered. Each file is compressed using GZIP. All the work is done on a separate thread.
+ */
+class ExplodingOutputtingInputStream extends OutputtingInputStream implements Runnable {
+
+ private final Thread m_task;
+ private final File m_contentDir;
+ private final File m_indexFile;
+ private final PipedInputStream m_input;
+
+ /**
+ * Creates an instance of this class.
+ *
+ * @param inputStream The input stream that will be written to disk as individual entries as it's read.
+ * @param indexFile File to be used to write the index of all encountered files.
+ * @param contentDir File to be used as the directory to hold all files encountered in the stream.
+ * @throws IOException If a problem occurs reading the stream resources.
+ */
+ public ExplodingOutputtingInputStream(InputStream inputStream, File indexFile, File contentDir) throws IOException {
+ this(inputStream, new PipedOutputStream(), indexFile, contentDir);
+ }
+
+ public void close() throws IOException {
+ super.close();
+ waitFor();
+ }
+
+ private ExplodingOutputtingInputStream(InputStream inputStream, PipedOutputStream output, File index, File root) throws IOException {
+ super(inputStream, output);
+ m_contentDir = root;
+ m_indexFile = index;
+ m_input = new PipedInputStream(output);
+ m_task = new Thread(this, "LiQ - ExplodingIncomingThread");
+ m_task.start();
+ }
+
+ public void waitFor() {
+ try {
+ m_task.join();
+ }
+ catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+
+ public void run() {
+ ZipInputStream input = null;
+ PrintWriter writer = null;
+ try {
+ input = new ZipInputStream(m_input);
+ writer = new PrintWriter(new FileWriter(m_indexFile));
+ for (ZipEntry entry = input.getNextEntry(); entry != null; entry = input.getNextEntry()) {
+ File current = new File(m_contentDir, entry.getName());
+ if (entry.isDirectory()) {
+ current.mkdirs();
+ }
+ else {
+ writer.println(entry.getName());
+ File parent = current.getParentFile();
+ if (parent != null) {
+ parent.mkdirs();
+ }
+ OutputStream output = null;
+ try {
+ output = new GZIPOutputStream(new FileOutputStream(current));
+ byte[] buffer = new byte[4096];
+ for (int i = input.read(buffer); i > -1; i = input.read(buffer)) {
+ output.write(buffer, 0, i);
+ }
+ }
+ finally {
+ output.close();
+ }
+ }
+ input.closeEntry();
+ writer.flush();
+ }
+ } catch (IOException ex) {
+ // TODO: log this
+ }
+ finally {
+ if (input != null) {
+ try {
+ input.close();
+ }
+ catch (IOException e) {
+ // Not much we can do
+ }
+ }
+ if (writer != null) {
+ writer.close();
+ }
+ }
+ }
+
+
+ public static void replace(File target, File source) {
+ delete(target, true);
+ source.renameTo(target);
+ }
+
+ private static void delete(File root, boolean deleteRoot) {
+ if (root.isDirectory()) {
+ File[] childs = root.listFiles();
+ for (int i = 0; i < childs.length; i++) {
+ delete(childs[i], true);
+ }
+ }
+ if (deleteRoot) {
+ root.delete();
+ }
+ }
+
+ public static void merge(File targetIndex, File target, File sourceIndex, File source) throws IOException {
+ List targetFiles = readIndex(targetIndex);
+ List sourceFiles = readIndex(sourceIndex);
+ List result = new ArrayList(targetFiles);
+
+ File manifestFile = new File(source, (String) sourceFiles.remove(0));
+ Manifest resultManifest = new Manifest(new GZIPInputStream(new FileInputStream(manifestFile)));
+
+ resultManifest.getMainAttributes().remove(new Name(Constants.DEPLOYMENTPACKAGE_FIXPACK));
+
+ for (Iterator i = result.iterator(); i.hasNext();) {
+ String targetFile = (String) i.next();
+ if(!resultManifest.getEntries().containsKey(targetFile) && !targetFile.equals("META-INF/MANIFEST.MF")) {
+ i.remove();
+ }
+ }
+
+ for (Iterator iter = sourceFiles.iterator(); iter.hasNext();) {
+ String path = (String) iter.next();
+ if (targetFiles.contains(path)) {
+ (new File(target, path)).delete();
+ }
+ else {
+ result.add(path);
+ }
+ (new File(source, path)).renameTo(new File(target, path));
+ }
+
+ targetFiles.removeAll(sourceFiles);
+
+ for (Iterator iter = resultManifest.getEntries().keySet().iterator(); iter.hasNext();) {
+ String path = (String) iter.next();
+ Attributes sourceAttribute = (Attributes) resultManifest.getEntries().get(path);
+ if ("true".equals(sourceAttribute.remove(new Name(Constants.DEPLOYMENTPACKAGE_MISSING)))) {
+ targetFiles.remove(path);
+ }
+ }
+
+ for (Iterator iter = targetFiles.iterator(); iter.hasNext();) {
+ String path = (String) iter.next();
+ (new File(target, path)).delete();
+ }
+
+ GZIPOutputStream outputStream = new GZIPOutputStream(new FileOutputStream(new File(target, "META-INF/MANIFEST.MF")));
+ resultManifest.write(outputStream);
+ outputStream.close();
+ writeIndex(targetIndex, result);
+ }
+
+ public static List readIndex(File index) throws IOException {
+ BufferedReader reader = null;
+ try {
+ reader = new BufferedReader(new FileReader(index));
+ List result = new ArrayList();
+ for (String line = reader.readLine(); line != null; line = reader.readLine()) {
+ result.add(line);
+ }
+ return result;
+ }
+ finally {
+ if (reader != null) {
+ try {
+ reader.close();
+ }
+ catch (IOException e) {
+ // Not much we can do
+ }
+ }
+ }
+ }
+
+ private static void writeIndex(File index, List input) throws IOException {
+ PrintWriter writer = null;
+ try {
+ writer = new PrintWriter(new FileWriter(index));
+ for (Iterator iterator = input.iterator(); iterator.hasNext();) {
+ writer.println(iterator.next());
+ }
+ }
+ finally {
+ if (writer != null) {
+ writer.close();
+ }
+ }
+ }
+}
Added: felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/FileDeploymentPackage.java
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/FileDeploymentPackage.java?rev=616813&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/FileDeploymentPackage.java (added)
+++ felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/FileDeploymentPackage.java Wed Jan 30 08:46:24 2008
@@ -0,0 +1,99 @@
+/*
+ * 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.felix.deploymentadmin;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.jar.Manifest;
+import java.util.zip.GZIPInputStream;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.service.deploymentadmin.DeploymentException;
+
+/**
+ * Implementation of a <code>DeploymentPackage</code> that is persisted on disk.
+ */
+class FileDeploymentPackage extends AbstractDeploymentPackage {
+
+ private final List m_index;
+ private final File m_contentsDir;
+
+ /**
+ * Creates a new instance of a deployment package stored on disk.
+ *
+ * @param index Reference to the index file that contains the order in which all the resources of this deployment package were received
+ * @param packageDir Reference to the directory in which the index and package cotents are stored.
+ * @param bundleContext The bundle context
+ * @throws DeploymentException Thrown if the disk contents do not resemble a valid deployment package.
+ * @throws IOException Thrown if there was a problem reading the resources from disk.
+ */
+ public FileDeploymentPackage(File index, File packageDir, BundleContext bundleContext) throws DeploymentException, IOException {
+ this(ExplodingOutputtingInputStream.readIndex(index), packageDir, bundleContext);
+ }
+
+ private FileDeploymentPackage(List index, File packageDir, BundleContext bundleContext) throws DeploymentException, IOException {
+ super(new Manifest(new GZIPInputStream(new FileInputStream(new File(packageDir, (String) index.remove(0))))), bundleContext);
+ m_index = index;
+ m_contentsDir = packageDir;
+ }
+
+ public BundleInfoImpl[] getOrderedBundleInfos() {
+ List result = new ArrayList();
+ for(Iterator i = m_index.iterator(); i.hasNext();) {
+ AbstractInfo bundleInfo = getBundleInfoByPath((String) i.next());
+ if (bundleInfo != null) {
+ result.add(bundleInfo);
+ }
+ }
+ return (BundleInfoImpl[]) result.toArray(new BundleInfoImpl[result.size()]);
+ }
+
+ public InputStream getBundleStream(String symbolicName) throws IOException {
+ BundleInfoImpl bundleInfo = getBundleInfoByName(symbolicName);
+ if (bundleInfo != null) {
+ return new GZIPInputStream(new FileInputStream(new File(m_contentsDir, bundleInfo.getPath())));
+ }
+ return null;
+ }
+
+ public ResourceInfoImpl[] getOrderedResourceInfos() {
+ List result = new ArrayList();
+ for(Iterator i = m_index.iterator(); i.hasNext();) {
+ AbstractInfo resourceInfo = getResourceInfoByPath((String) i.next());
+ if (resourceInfo != null) {
+ result.add(resourceInfo);
+ }
+ }
+ return (ResourceInfoImpl[]) result.toArray(new ResourceInfoImpl[result.size()]);
+ }
+
+ public InputStream getCurrentEntryStream() {
+ throw new UnsupportedOperationException("Not implemented for file-based deployment package");
+ }
+
+ public AbstractInfo getNextEntry() throws IOException {
+ throw new UnsupportedOperationException("Not implemented for file-based deployment package");
+ }
+
+}
\ No newline at end of file
Added: felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/OutputtingInputStream.java
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/OutputtingInputStream.java?rev=616813&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/OutputtingInputStream.java (added)
+++ felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/OutputtingInputStream.java Wed Jan 30 08:46:24 2008
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.deploymentadmin;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * This extension of the <code>InputStream</code> writes every byte that is read to an
+ * <code>OutputStream</code> of choice. The outputstream is closed automatically when
+ * the end of the inputstream is reached.
+ */
+public class OutputtingInputStream extends InputStream {
+
+ private final InputStream m_inputStream;
+ private final OutputStream m_outputStream;
+
+ /**
+ * Creates an instance of the <code>OutputtingInputStream</code>.
+ *
+ * @param inputStream The inputstream from which bytes will be read.
+ * @param outputStream The outputstream to which every byte that is read should be outputted.
+ */
+ public OutputtingInputStream(InputStream inputStream, OutputStream outputStream) {
+ super();
+ m_inputStream = inputStream;
+ m_outputStream = outputStream;
+ }
+
+ public int read() throws IOException {
+ int i = m_inputStream.read();
+ if (i != -1) {
+ m_outputStream.write(i);
+ }
+ return i;
+ }
+
+ public int read(byte[] buffer) throws IOException {
+ int i = m_inputStream.read(buffer);
+ if (i != -1) {
+ m_outputStream.write(buffer, 0, i);
+ }
+ return i;
+ }
+
+ public int read(byte[] buffer, int off, int len) throws IOException {
+ int i = m_inputStream.read(buffer, off, len);
+ if (i != -1) {
+ m_outputStream.write(buffer, off, i);
+ }
+ return i;
+ }
+
+ public void close() throws IOException {
+ try {
+ m_inputStream.close();
+ }
+ finally {
+ try {
+ m_outputStream.close();
+ }
+ catch (Exception e) {
+ // not much we can do
+ }
+ }
+ }
+
+}
Added: felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/ResourceInfoImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/ResourceInfoImpl.java?rev=616813&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/ResourceInfoImpl.java (added)
+++ felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/ResourceInfoImpl.java Wed Jan 30 08:46:24 2008
@@ -0,0 +1,52 @@
+/*
+ * 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.felix.deploymentadmin;
+
+import java.util.jar.Attributes;
+
+import org.osgi.service.deploymentadmin.DeploymentException;
+
+/**
+ * This class represents the meta data of a processed resource as used by the Deployment Admin.
+ */
+public class ResourceInfoImpl extends AbstractInfo {
+
+ private String m_resourceProcessor;
+
+ /**
+ * Create an instance of this class.
+ *
+ * @param path String containing the path / resource-id of the processed resource.
+ * @param attributes Attributes containing the meta data of the resource.
+ * @throws DeploymentException If the specified attributes do not describe a processed resource.
+ */
+ public ResourceInfoImpl(String path, Attributes attributes) throws DeploymentException {
+ super(path, attributes);
+ m_resourceProcessor = attributes.getValue(Constants.RESOURCE_PROCESSOR);
+ }
+
+ /**
+ * Determines the resource processor for this processed resource.
+ *
+ * @return String containing the PID of the resource processor that should handle this processed resource.
+ */
+ public String getResourceProcessor() {
+ return m_resourceProcessor;
+ }
+}
Added: felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/Semaphore.java
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/Semaphore.java?rev=616813&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/Semaphore.java (added)
+++ felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/Semaphore.java Wed Jan 30 08:46:24 2008
@@ -0,0 +1,121 @@
+/*
+ * 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.felix.deploymentadmin;
+
+/**
+ * A semaphore, that maintains one single permit. An <code>acquire()</code> blocks until a permit is
+ * available, whilst <code>release()</code> will unblock it.
+ */
+public class Semaphore {
+ private boolean m_available;
+
+ /**
+ * Creates a new semaphore that is available.
+ */
+ public Semaphore() {
+ m_available = true;
+ }
+
+ /**
+ * Creates a new semaphore and allows you to specify if it's available or not.
+ *
+ * @param isAvailable should the semaphore be available or not
+ */
+ public Semaphore(boolean isAvailable) {
+ m_available = isAvailable;
+ }
+
+ /**
+ * Acquires the semaphore, or blocks until it's available or the thread is interrupted.
+ *
+ * @throws InterruptedException when the thread is interrupted
+ */
+ public void acquire() throws InterruptedException {
+ if (Thread.interrupted()) {
+ throw new InterruptedException();
+ }
+ synchronized (this) {
+ try {
+ if (!m_available) {
+ wait();
+ }
+ m_available = false;
+ }
+ catch (InterruptedException ie) {
+ notify();
+ throw ie;
+ }
+ }
+ }
+
+ /**
+ * Tries to acquire the semaphore and waits for the duration of the specified timeout
+ * until it becomes available.
+ *
+ * @param timeout the number of milliseconds to wait
+ * @return <code>true</code> if the semaphore was acquired, <code>false</code> if it was
+ * not after waiting for the specified amount of time
+ * @throws InterruptedException when the thread is interrupted
+ */
+ public boolean tryAcquire(long timeout) throws InterruptedException {
+ if (Thread.interrupted()) {
+ throw new InterruptedException();
+ }
+ synchronized (this) {
+ if (m_available) {
+ m_available = false;
+ return true;
+ }
+ else if (timeout <= 0) {
+ return false;
+ }
+ else {
+ long startTime = System.currentTimeMillis();
+ try {
+ while (true) {
+ wait(timeout);
+ if (m_available) {
+ m_available = false;
+ return true;
+ }
+ else {
+ timeout -= (System.currentTimeMillis() - startTime);
+ if (timeout <= 0) {
+ return false;
+ }
+ }
+ }
+ }
+ catch (InterruptedException ie) {
+ notify();
+ throw ie;
+ }
+ }
+ }
+ }
+
+ /**
+ * Releases the semaphore. If threads were waiting, one of them is
+ * notified.
+ */
+ public synchronized void release() {
+ m_available = true;
+ notify();
+ }
+}
Added: felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/StreamDeploymentPackage.java
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/StreamDeploymentPackage.java?rev=616813&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/StreamDeploymentPackage.java (added)
+++ felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/StreamDeploymentPackage.java Wed Jan 30 08:46:24 2008
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.deploymentadmin;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.jar.JarInputStream;
+import java.util.zip.ZipEntry;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.service.deploymentadmin.DeploymentException;
+
+/**
+ * This class represents a deployment package that is read from a jar stream.
+ */
+class StreamDeploymentPackage extends AbstractDeploymentPackage {
+
+ private final JarInputStream m_input;
+ private final List m_names = new ArrayList();
+
+ /**
+ * Creates an instance of this class.
+ *
+ * @param input The stream from which the deployment package can be read.
+ * @param bundleContext The bundle context.
+ * @throws DeploymentException If it was not possible to read a valid deployment package from the specified stream.
+ */
+ public StreamDeploymentPackage(JarInputStream input, BundleContext bundleContext) throws DeploymentException {
+ super(input.getManifest(), bundleContext);
+ m_input = input;
+ }
+
+ public InputStream getBundleStream(String symbolicName) {
+ throw new UnsupportedOperationException("Not applicable for stream-based deployment package");
+ }
+
+ // This only works for those resources that have been read from the stream already, no guarantees for remainder of stream
+ public BundleInfoImpl[] getOrderedBundleInfos() {
+ List result = new ArrayList();
+
+ // add all bundle resources ordered by location in stream
+ for(Iterator i = m_names.iterator(); i.hasNext();) {
+ String indexEntry = (String) i.next();
+ AbstractInfo bundleInfo = getBundleInfoByPath(indexEntry);
+ if (bundleInfo != null) {
+ result.add(bundleInfo);
+ }
+ }
+
+ // add bundle resources marked missing to the end of the result
+ BundleInfoImpl[] bundleInfoImpls = getBundleInfoImpls();
+ for (int i = 0; i < bundleInfoImpls.length; i++) {
+ if(bundleInfoImpls[i].isMissing()) {
+ result.add(bundleInfoImpls[i]);
+ }
+ }
+ return (BundleInfoImpl[]) result.toArray(new BundleInfoImpl[result.size()]);
+ }
+
+ public ResourceInfoImpl[] getOrderedResourceInfos() {
+ throw new UnsupportedOperationException("Not applicable for stream-based deployment package");
+ }
+
+ public AbstractInfo getNextEntry() throws IOException {
+ ZipEntry nextEntry = m_input.getNextJarEntry();
+ if (nextEntry == null) {
+ return null;
+ }
+ String name = nextEntry.getName();
+ m_names.add(name);
+ AbstractInfo abstractInfoByPath = getAbstractInfoByPath(name);
+ return abstractInfoByPath;
+ }
+
+ public InputStream getCurrentEntryStream() {
+ return m_input;
+ }
+
+}
\ No newline at end of file
Added: felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/VersionRange.java
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/VersionRange.java?rev=616813&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/VersionRange.java (added)
+++ felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/VersionRange.java Wed Jan 30 08:46:24 2008
@@ -0,0 +1,156 @@
+/*
+ * 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.felix.deploymentadmin;
+
+import org.osgi.framework.Version;
+
+/**
+ * This class represents a version range as defined in section 3.2.5 of the OSGi r4 specification.
+ */
+public class VersionRange {
+
+ public static final VersionRange infiniteRange = new VersionRange(Version.emptyVersion, true, null, true);
+
+ private Version m_low = null;
+ private boolean m_isLowInclusive = false;
+ private Version m_high = null;
+ private boolean m_isHighInclusive = false;
+ private String m_toString = null;
+
+ /**
+ * Create an instance of the VersionRange class.
+ *
+ * @param low Lower bound version
+ * @param isLowInclusive True if lower bound should be included in the range
+ * @param high Upper bound version
+ * @param isHighInclusive True if upper bound should be included in the range
+ */
+ public VersionRange(Version low, boolean isLowInclusive, Version high, boolean isHighInclusive) {
+ m_low = low;
+ m_isLowInclusive = isLowInclusive;
+ m_high = high;
+ m_isHighInclusive = isHighInclusive;
+ }
+
+ /**
+ * Creates an instance of the VersionRange class which resembles [version,*)
+ *
+ * @param version The lower boundary of the version range
+ */
+ public VersionRange(Version version) {
+ this(version, true, null, false);
+ }
+
+ /**
+ * Get the lower boundary of the version range, the boundary being inclusive or not is not taken into account.
+ *
+ * @return Version resembling the lower boundary of the version range
+ */
+ public Version getLow() {
+ return m_low;
+ }
+
+ /**
+ * Determines whether the lower boundary is inclusive or not.
+ *
+ * @return True if the lower boundary is inclusive, false otherwise.
+ */
+ public boolean isLowInclusive() {
+ return m_isLowInclusive;
+ }
+
+ /**
+ * Get the upper boundary of the version range, the boundary being inclusive or not is not taken in to account.
+ *
+ * @return Version resembling the upper boundary of the version range.
+ */
+ public Version getHigh() {
+ return m_high;
+ }
+
+ /**
+ * Determines whether the upper boundary is inclusive or not.
+ *
+ * @return True if the upper boundary is inclusive, false otherwise.
+ */
+ public boolean isHighInclusive() {
+ return m_isHighInclusive;
+ }
+
+ /**
+ * Determine if the specified version is part of the version range or not.
+ *
+ * @param version The version to verify
+ * @return True if the specified version is included in this version range, false otherwise.
+ */
+ public boolean isInRange(Version version) {
+ // We might not have an upper end to the range.
+ if (m_high == null) {
+ return (version.compareTo(m_low) >= 0);
+ }
+ else if (isLowInclusive() && isHighInclusive()) {
+ return (version.compareTo(m_low) >= 0) && (version.compareTo(m_high) <= 0);
+ }
+ else if (isHighInclusive()) {
+ return (version.compareTo(m_low) > 0) && (version.compareTo(m_high) <= 0);
+ }
+ else if (isLowInclusive()) {
+ return (version.compareTo(m_low) >= 0) && (version.compareTo(m_high) < 0);
+ }
+ return (version.compareTo(m_low) > 0) && (version.compareTo(m_high) < 0);
+ }
+
+ /**
+ * Parses a version range from the specified string.
+ *
+ * @param range String representation of the version range.
+ * @return A <code>VersionRange</code> object representing the version range.
+ * @throws IllegalArgumentException If <code>range</code> is improperly formatted.
+ */
+ public static VersionRange parse(String range) throws IllegalArgumentException {
+ // Check if the version is an interval.
+ if (range.indexOf(',') >= 0) {
+ String s = range.substring(1, range.length() - 1);
+ String vlo = s.substring(0, s.indexOf(',')).trim();
+ String vhi = s.substring(s.indexOf(',') + 1, s.length()).trim();
+ return new VersionRange(new Version(vlo), (range.charAt(0) == '['), new Version(vhi), (range.charAt(range.length() - 1) == ']'));
+ }
+ else {
+ return new VersionRange(new Version(range), true, null, false);
+ }
+ }
+
+ public String toString() {
+ if (m_toString == null) {
+ if (m_high != null) {
+ StringBuffer sb = new StringBuffer();
+ sb.append(m_isLowInclusive ? '[' : '(');
+ sb.append(m_low.toString());
+ sb.append(',');
+ sb.append(m_high.toString());
+ sb.append(m_isHighInclusive ? ']' : ')');
+ m_toString = sb.toString();
+ }
+ else {
+ m_toString = m_low.toString();
+ }
+ }
+ return m_toString;
+ }
+}
Added: felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/Command.java
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/Command.java?rev=616813&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/Command.java (added)
+++ felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/Command.java Wed Jan 30 08:46:24 2008
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.deploymentadmin.spi;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ListIterator;
+
+import org.osgi.service.deploymentadmin.DeploymentException;
+
+/**
+ * Commands describe a group of tasks to be executed within the execution a deployment session.
+ * A command that has already executed can be rolled back and a command that is currently in progress
+ * can be signaled to stop it's activities by canceling it.
+ */
+public abstract class Command {
+
+ private final List m_rollback = new ArrayList();
+ private final List m_commit = new ArrayList();
+ private volatile boolean m_cancelled;
+
+ /**
+ * Executes the command, the specified <code>DeploymentSession</code> can be used to obtain various
+ * information about the deployment session which the command is part of.
+ *
+ * @param session The deployment session this command is part of.
+ * @throws DeploymentException Thrown if the command could not successfully execute.
+ */
+ public abstract void execute(DeploymentSessionImpl session) throws DeploymentException;
+
+ /**
+ * Rolls back all actions that were added through the <code>addRollback(Runnable r)</code> method (in reverse
+ * adding order). It is not guaranteed that the state of everything related to the command will be as if the
+ * command was never executed, a best effort should be made though.
+ */
+ public void rollback() {
+ for (ListIterator i = m_rollback.listIterator(); i.hasPrevious();) {
+ Runnable runnable = (Runnable) i.previous();
+ runnable.run();
+ }
+ cleanUp();
+ }
+
+ /**
+ * Commits all changes the command may have defined when it was executed by calling the <code>execute()</code> method.
+ */
+ protected void commit() {
+ for (ListIterator i = m_commit.listIterator(); i.hasPrevious();) {
+ Runnable runnable = (Runnable) i.previous();
+ runnable.run();
+ }
+ cleanUp();
+ }
+
+ private void cleanUp() {
+ m_rollback.clear();
+ m_commit.clear();
+ m_cancelled = false;
+ }
+
+ /**
+ * Determines if the command was canceled. This method should be used regularly by implementing classes to determine if
+ * their command was canceled, if so they should return as soon as possible from their operations.
+ *
+ * @return true if the command was canceled, false otherwise.
+ */
+ protected boolean isCancelled() {
+ return m_cancelled;
+ }
+
+ /**
+ * Adds an action to be executed in case of a roll back.
+ *
+ * @param runnable The runnable to be executed in case of a roll back.
+ */
+ protected void addRollback(Runnable runnable) {
+ m_rollback.add(runnable);
+ }
+
+ /**
+ * Adds an action to be executed in case of a commit
+ *
+ * @param runnable The runnable to be executes in case of a commit.
+ */
+ protected void addCommit(Runnable runnable) {
+ m_commit.add(runnable);
+ }
+
+ /**
+ * Sets the command to being cancelled, this does not have an immediate effect. Commands that are executing should
+ * check regularly if they were cancelled and if so they should make an effort to stop their operations as soon as possible
+ * followed by throwing an <code>DeploymentException.CODE_CANCELLED</code> exception.
+ */
+ public void cancel() {
+ m_cancelled = true;
+ }
+
+}
Added: felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/CommitResourceCommand.java
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/CommitResourceCommand.java?rev=616813&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/CommitResourceCommand.java (added)
+++ felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/CommitResourceCommand.java Wed Jan 30 08:46:24 2008
@@ -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.felix.deploymentadmin.spi;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
+import org.osgi.service.deploymentadmin.DeploymentException;
+import org.osgi.service.deploymentadmin.spi.ResourceProcessor;
+import org.osgi.service.deploymentadmin.spi.ResourceProcessorException;
+import org.osgi.service.log.LogService;
+
+/**
+ * Command that commits all the resource processors that were added to the command.
+ */
+public class CommitResourceCommand extends Command implements Runnable {
+
+ private final List m_processors = new ArrayList();
+
+ public void execute(DeploymentSessionImpl session) throws DeploymentException {
+ for (ListIterator i = m_processors.listIterator(); i.hasPrevious();) {
+ ResourceProcessor processor = (ResourceProcessor) i.previous();
+ try {
+ processor.prepare();
+ }
+ catch (ResourceProcessorException e) {
+ session.getLog().log(LogService.LOG_ERROR, "Preparing commit for resource processor failed", e);
+ throw new DeploymentException(DeploymentException.CODE_OTHER_ERROR, "Preparing commit for resource processor failed", e);
+ }
+ }
+ for (ListIterator i = m_processors.listIterator(); i.hasPrevious();) {
+ ResourceProcessor processor = (ResourceProcessor) i.previous();
+ try {
+ processor.commit();
+ }
+ catch (Exception e) {
+ session.getLog().log(LogService.LOG_ERROR, "Committing resource processor '" + processor + "' failed", e);
+ // TODO Throw exception?
+ }
+ }
+ }
+
+ public void rollback() {
+ for (ListIterator i = m_processors.listIterator(); i.hasPrevious();) {
+ ResourceProcessor processor = (ResourceProcessor) i.previous();
+ try {
+ processor.rollback();
+ }
+ catch (Exception e) {
+ // TODO Log this?
+ }
+ i.remove();
+ }
+ }
+
+ /**
+ * Add a resource processor, all resource processors that are added will be committed when the command is executed.
+ *
+ * @param processor The resource processor to add.
+ */
+ public void addResourceProcessor(ResourceProcessor processor) {
+ for (Iterator i = m_processors.iterator(); i.hasNext();) {
+ ResourceProcessor proc = (ResourceProcessor) i.next();
+ if (proc == processor) {
+ return;
+ }
+ }
+ m_processors.add(processor);
+ }
+
+ public void run() {
+ rollback();
+ }
+
+}
Added: felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/DeploymentSessionImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/DeploymentSessionImpl.java?rev=616813&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/DeploymentSessionImpl.java (added)
+++ felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/DeploymentSessionImpl.java Wed Jan 30 08:46:24 2008
@@ -0,0 +1,178 @@
+/*
+ * 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.felix.deploymentadmin.spi;
+
+import java.io.File;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
+import org.apache.felix.deploymentadmin.AbstractDeploymentPackage;
+import org.apache.felix.deploymentadmin.DeploymentAdminImpl;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.deploymentadmin.DeploymentException;
+import org.osgi.service.deploymentadmin.DeploymentPackage;
+import org.osgi.service.deploymentadmin.spi.DeploymentSession;
+import org.osgi.service.log.LogService;
+import org.osgi.service.packageadmin.PackageAdmin;
+
+public class DeploymentSessionImpl implements DeploymentSession {
+
+ private final AbstractDeploymentPackage m_target;
+ private final AbstractDeploymentPackage m_source;
+ private final List m_commands;
+ private final DeploymentAdminImpl m_admin;
+ private volatile Command m_currentCommand = null;
+ private volatile boolean m_cancelled;
+
+ public DeploymentSessionImpl(AbstractDeploymentPackage source, AbstractDeploymentPackage target, List commands, DeploymentAdminImpl admin) {
+ m_source = source;
+ m_target = target;
+ m_commands = commands;
+ m_admin = admin;
+ }
+
+ /**
+ * Calling this method will cause the commands specified for this session to be executed. the commands will be rolled back if the session is
+ * canceled or if an exception is caused by one of the commands.
+ *
+ * @throws DeploymentException If the session was canceled (<code>DeploymentException.CODE_CANCELLED</code>) or if one of the commands caused an exception (<code>DeploymentException.*</code>)
+ */
+ public void call() throws DeploymentException {
+ List executedCommands = new ArrayList();
+ for (Iterator i = m_commands.iterator(); i.hasNext();) {
+ if (m_cancelled) {
+ // previous command did not pick up on cancel
+ rollback(executedCommands);
+ throw new DeploymentException(DeploymentException.CODE_CANCELLED);
+ }
+ m_currentCommand = (Command) i.next();
+ try {
+ executedCommands.add(m_currentCommand);
+ m_currentCommand.execute(this);
+ }
+ catch (DeploymentException de) {
+ rollback(executedCommands);
+ throw de;
+ }
+ }
+ for (Iterator i = m_commands.iterator(); i.hasNext();) {
+ ((Command) i.next()).commit();
+ }
+ m_currentCommand = null;
+ }
+
+ private void rollback(List executedCommands) {
+ for (ListIterator i = executedCommands.listIterator(); i.hasPrevious();) {
+ Command command = (Command) i.previous();
+ command.rollback();
+ }
+ }
+
+ /**
+ * Cancels the session if it is in progress.
+ *
+ * @return true if a session was in progress and now canceled, false otherwise.
+ */
+ public boolean cancel() {
+ m_cancelled = true;
+ if (m_currentCommand != null) {
+ m_currentCommand.cancel();
+ return true;
+ }
+ return false;
+ }
+
+ public File getDataFile(Bundle bundle) {
+ BundleContext context = null;
+ try {
+ Method getBundleContext = bundle.getClass().getDeclaredMethod("getBundleContext", null);
+ getBundleContext.setAccessible(true);
+ context = (BundleContext) getBundleContext.invoke(bundle, null);
+ }
+ catch (Exception ex) {
+ // TODO: log this
+ }
+ File result = null;
+ if (context != null) {
+ result = context.getDataFile("");
+ }
+ if (result == null) {
+ // TODO: log this
+ throw new IllegalStateException("");
+ }
+ return result;
+ }
+
+ public DeploymentPackage getSourceDeploymentPackage() {
+ return m_source;
+ }
+
+ public DeploymentPackage getTargetDeploymentPackage() {
+ return m_target;
+ }
+
+ /**
+ * Returns the bundle context of the bundle this class is part of.
+ *
+ * @return The <code>BundleContext</code>.
+ */
+ public BundleContext getBundleContext() {
+ return m_admin.getBundleContext();
+ }
+
+ /**
+ * Returns the currently present log service.
+ *
+ * @return The <code>LogService</code>.
+ */
+ public LogService getLog() {
+ return m_admin.getLog();
+ }
+
+ /**
+ * Returns the currently present package admin.
+ *
+ * @return The <code>PackageAdmin</code>
+ */
+ public PackageAdmin getPackageAdmin() {
+ return m_admin.getPackageAdmin();
+ }
+
+ /**
+ * Returns the target deployment package as an <code>AbstractDeploymentPackage</code>.
+ *
+ * @return The target deployment package of the session.
+ */
+ public AbstractDeploymentPackage getTargetAbstractDeploymentPackage() {
+ return m_target;
+ }
+
+ /**
+ * Returns the source deployment package as an <code>AbstractDeploymentPackage</code>.
+ *
+ * @return The source deployment packge of the session.
+ */
+ public AbstractDeploymentPackage getSourceAbstractDeploymentPackage() {
+ return m_source;
+ }
+}
\ No newline at end of file
Added: felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/DropBundleCommand.java
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/DropBundleCommand.java?rev=616813&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/DropBundleCommand.java (added)
+++ felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/DropBundleCommand.java Wed Jan 30 08:46:24 2008
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.deploymentadmin.spi;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.felix.deploymentadmin.AbstractDeploymentPackage;
+import org.apache.felix.deploymentadmin.BundleInfoImpl;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleException;
+import org.osgi.service.deploymentadmin.DeploymentException;
+import org.osgi.service.log.LogService;
+
+/**
+ * Command that uninstalls bundles, if rolled back the bundles are restored.
+ */
+public class DropBundleCommand extends Command {
+
+ public void execute(DeploymentSessionImpl session) throws DeploymentException {
+ AbstractDeploymentPackage target = session.getTargetAbstractDeploymentPackage();
+ AbstractDeploymentPackage source = session.getSourceAbstractDeploymentPackage();
+ LogService log = session.getLog();
+
+ BundleInfoImpl[] orderedTargetBundles = target.getOrderedBundleInfos();
+ for (int i = orderedTargetBundles.length - 1; i >= 0; i--) {
+ BundleInfoImpl bundleInfo = orderedTargetBundles[i];
+ if (source.getBundleInfoByPath(bundleInfo.getPath()) == null) {
+ // stale bundle, save a copy for rolling back and uninstall it
+ String symbolicName = bundleInfo.getSymbolicName();
+ try {
+ Bundle bundle = target.getBundle(symbolicName);
+ bundle.uninstall();
+ addRollback(new InstallBundleRunnable(bundle, target.getBundleStream(symbolicName), log));
+ }
+ catch (BundleException be) {
+ log.log(LogService.LOG_WARNING, "Bundle '" + symbolicName + "' could not be uninstalled", be);
+ }
+ catch (IOException e) {
+ log.log(LogService.LOG_WARNING, "Could not get bundle data stream for bundle '" + symbolicName + "'", e);
+ throw new DeploymentException(DeploymentException.CODE_OTHER_ERROR, "Could not prepare rollback for uninstalling bundle '" + symbolicName + "'");
+ }
+ }
+ }
+ }
+
+ private static class InstallBundleRunnable implements Runnable {
+
+ private final InputStream m_bundleStream;
+ private final Bundle m_bundle;
+ private final LogService m_log;
+
+ public InstallBundleRunnable(Bundle bundle, InputStream bundleStream, LogService log) {
+ m_bundle = bundle;
+ m_bundleStream = bundleStream;
+ m_log = log;
+ }
+
+ public void run() {
+ try {
+ m_bundle.update(m_bundleStream);
+ }
+ catch (BundleException e) {
+ m_log.log(LogService.LOG_WARNING, "Could not rollback uninstallation of bundle '" + m_bundle.getSymbolicName() + "'", e);
+ }
+ }
+ }
+}
Added: felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/DropResourceCommand.java
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/DropResourceCommand.java?rev=616813&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/DropResourceCommand.java (added)
+++ felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/DropResourceCommand.java Wed Jan 30 08:46:24 2008
@@ -0,0 +1,74 @@
+/*
+ * 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.felix.deploymentadmin.spi;
+
+import org.apache.felix.deploymentadmin.AbstractDeploymentPackage;
+import org.apache.felix.deploymentadmin.ResourceInfoImpl;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.deploymentadmin.spi.ResourceProcessor;
+import org.osgi.service.deploymentadmin.spi.ResourceProcessorException;
+import org.osgi.service.log.LogService;
+
+/**
+ * Command that drops resources.
+ */
+public class DropResourceCommand extends Command {
+
+ private final CommitResourceCommand m_commitCommand;
+
+ /**
+ * Creates an instance of this command. The commit command is used to make sure
+ * the resource processors used to drop resources will be committed at a later stage in the process.
+ *
+ * @param commitCommand The commit command that will be executed at a later stage in the process.
+ */
+ public DropResourceCommand(CommitResourceCommand commitCommand) {
+ m_commitCommand = commitCommand;
+ addRollback(m_commitCommand);
+ }
+
+ public void execute(DeploymentSessionImpl session) {
+ AbstractDeploymentPackage target = session.getTargetAbstractDeploymentPackage();
+ AbstractDeploymentPackage source = session.getSourceAbstractDeploymentPackage();
+ BundleContext context = session.getBundleContext();
+ LogService log = session.getLog();
+
+ ResourceInfoImpl[] orderedTargetResources = target.getOrderedResourceInfos();
+ for (int i = orderedTargetResources.length - 1; i >= 0; i--) {
+ ResourceInfoImpl resourceInfo = orderedTargetResources[i];
+ String path = resourceInfo.getPath();
+ if (source.getResourceInfoByPath(path) == null) {
+ ServiceReference ref = target.getResourceProcessor(path);
+ if (ref != null) {
+ ResourceProcessor resourceProcessor = (ResourceProcessor) context.getService(ref);
+ if (resourceProcessor != null) {
+ try {
+ m_commitCommand.addResourceProcessor(resourceProcessor);
+ resourceProcessor.dropped(path);
+ }
+ catch (ResourceProcessorException e) {
+ log.log(LogService.LOG_WARNING, "Not allowed to drop resource '" + path + "'", e);
+ }
+ }
+ }
+ }
+ }
+ }
+}
Added: felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/GetStorageAreaCommand.java
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/GetStorageAreaCommand.java?rev=616813&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/GetStorageAreaCommand.java (added)
+++ felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/GetStorageAreaCommand.java Wed Jan 30 08:46:24 2008
@@ -0,0 +1,70 @@
+/*
+ * 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.felix.deploymentadmin.spi;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+
+
+import org.osgi.framework.Bundle;
+import org.osgi.service.deploymentadmin.BundleInfo;
+import org.osgi.service.deploymentadmin.DeploymentException;
+import org.osgi.service.deploymentadmin.DeploymentPackage;
+import org.osgi.service.log.LogService;
+
+/**
+ * Command that determines the storage area's of all bundles in the source deployment
+ * package of a deployment session.
+ */
+public class GetStorageAreaCommand extends Command {
+
+ private final Map m_storageAreas = new HashMap();
+
+ public void execute(DeploymentSessionImpl session) throws DeploymentException {
+ DeploymentPackage target = session.getTargetDeploymentPackage();
+ BundleInfo[] infos = target.getBundleInfos();
+ for (int i = 0; i < infos.length; i++) {
+ if (isCancelled()) {
+ throw new DeploymentException(DeploymentException.CODE_CANCELLED);
+ }
+ Bundle bundle = target.getBundle(infos[i].getSymbolicName());
+ if (bundle != null) {
+ try {
+ File root = session.getDataFile(bundle);
+ m_storageAreas.put(bundle.getSymbolicName(), root);
+ }
+ catch (IllegalStateException ise) {
+ session.getLog().log(LogService.LOG_WARNING, "Could not get reference to storage area of bundle '" + bundle.getSymbolicName() +"'");
+ }
+ }
+ }
+ }
+
+ /**
+ * Determines the storage area's of all bundles in the source deployment package of
+ * a deployment session.
+ *
+ * @return <code>Map</code> with <code>File</code> object references to the storage area's, they bundle symbolic name is used as a key in the <code>Map</code>.
+ */
+ public Map getStorageAreas() {
+ return m_storageAreas;
+ }
+
+}
Added: felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/ProcessResourceCommand.java
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/ProcessResourceCommand.java?rev=616813&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/ProcessResourceCommand.java (added)
+++ felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/ProcessResourceCommand.java Wed Jan 30 08:46:24 2008
@@ -0,0 +1,122 @@
+/*
+ * 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.felix.deploymentadmin.spi;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.felix.deploymentadmin.AbstractDeploymentPackage;
+import org.apache.felix.deploymentadmin.AbstractInfo;
+import org.apache.felix.deploymentadmin.ResourceInfoImpl;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.deploymentadmin.DeploymentException;
+import org.osgi.service.deploymentadmin.spi.ResourceProcessor;
+import org.osgi.service.deploymentadmin.spi.ResourceProcessorException;
+
+/**
+ * Command that processes all the processed resources in the source deployment package
+ * of a deployment session by finding their Resource Processors and having those process
+ * the resources.
+ */
+public class ProcessResourceCommand extends Command {
+
+ private final CommitResourceCommand m_commitCommand;
+
+ /**
+ * Creates an instance of this command, the <code>CommitCommand</code> is used
+ * to ensure that all used <code>ResourceProcessor</code>s will be committed at a later
+ * stage in the deployment session.
+ *
+ * @param commitCommand The <code>CommitCommand</code> that will commit all resource processors used in this command.
+ */
+ public ProcessResourceCommand(CommitResourceCommand commitCommand) {
+ m_commitCommand = commitCommand;
+ addRollback(m_commitCommand);
+ }
+
+ public void execute(DeploymentSessionImpl session) throws DeploymentException {
+ AbstractDeploymentPackage source = session.getSourceAbstractDeploymentPackage();
+ BundleContext context = session.getBundleContext();
+
+ Map expectedResources = new HashMap();
+ AbstractInfo[] resourceInfos = (AbstractInfo[]) source.getBundleInfos();
+ for (int i = 0; i < resourceInfos.length; i++) {
+ AbstractInfo resourceInfo = resourceInfos[i];
+ if(!resourceInfo.isMissing()) {
+ expectedResources.put(resourceInfo.getPath(), resourceInfo);
+ }
+ }
+
+ try {
+ for (AbstractInfo jarEntry = source.getNextEntry(); (jarEntry != null) && (!expectedResources.isEmpty()); jarEntry = source.getNextEntry()) {
+ String name = jarEntry.getPath();
+
+ if (!expectedResources.containsKey(name)) {
+ throw new DeploymentException(DeploymentException.CODE_OTHER_ERROR, "Resource '" + name + "' is not described in the manifest.");
+ }
+
+ ResourceInfoImpl resourceInfo = (ResourceInfoImpl) expectedResources.remove(name);
+
+ String resourceProcessorPID = resourceInfo.getResourceProcessor();
+ if (resourceProcessorPID == null) {
+ // no resource processor specified, resource can be ignored
+ continue;
+ }
+
+ ServiceReference ref = source.getResourceProcessor(resourceProcessorPID);
+ if (ref != null) {
+ String serviceOwnerSymName = ref.getBundle().getSymbolicName();
+ if (source.getBundleInfoByName(serviceOwnerSymName) != null) {
+ ResourceProcessor resourceProcessor = (ResourceProcessor) context.getService(ref);
+ if (resourceProcessor != null) {
+ resourceProcessor.begin(session);
+ try {
+ m_commitCommand.addResourceProcessor(resourceProcessor);
+ resourceProcessor.process(name, source.getCurrentEntryStream());
+ }
+ catch (ResourceProcessorException rpe) {
+ if (rpe.getCode() == ResourceProcessorException.CODE_RESOURCE_SHARING_VIOLATION) {
+ throw new DeploymentException(DeploymentException.CODE_RESOURCE_SHARING_VIOLATION, "Violation while processing resource '" + name + "'", rpe);
+ }
+ else {
+ throw new DeploymentException(DeploymentException.CODE_OTHER_ERROR, "Error while processing resource '" + name + "'", rpe);
+ }
+ }
+ }
+ else {
+ throw new DeploymentException(DeploymentException.CODE_PROCESSOR_NOT_FOUND, "No resource processor for resource: '" + name + "'");
+ }
+ }
+ else {
+ throw new DeploymentException(DeploymentException.CODE_FOREIGN_CUSTOMIZER, "Resource processor for resource '" + name + "' belongs to foreign deployment package");
+ }
+ }
+ else {
+ throw new DeploymentException(DeploymentException.CODE_PROCESSOR_NOT_FOUND, "No resource processor for resource: '" + name + "'");
+ }
+ }
+ }
+ catch (IOException e) {
+ throw new DeploymentException(DeploymentException.CODE_OTHER_ERROR, "Problem while reading stream", e);
+ }
+ }
+
+}
Added: felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/SnapshotCommand.java
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/SnapshotCommand.java?rev=616813&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/SnapshotCommand.java (added)
+++ felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/SnapshotCommand.java Wed Jan 30 08:46:24 2008
@@ -0,0 +1,224 @@
+/*
+ * 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.felix.deploymentadmin.spi;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Map;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
+
+import org.apache.felix.deploymentadmin.AbstractDeploymentPackage;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.deploymentadmin.BundleInfo;
+import org.osgi.service.deploymentadmin.DeploymentException;
+import org.osgi.service.log.LogService;
+
+public class SnapshotCommand extends Command {
+
+ private final GetStorageAreaCommand m_getStorageAreaCommand;
+
+ public SnapshotCommand(GetStorageAreaCommand getStorageAreaCommand) {
+ m_getStorageAreaCommand = getStorageAreaCommand;
+ }
+
+ public void execute(DeploymentSessionImpl session) throws DeploymentException {
+ AbstractDeploymentPackage target = session.getTargetAbstractDeploymentPackage();
+ BundleContext context = session.getBundleContext();
+
+ BundleInfo[] infos = target.getBundleInfos();
+ Map storageAreas = m_getStorageAreaCommand.getStorageAreas();
+ for (int i = 0; i < infos.length; i++) {
+ if (isCancelled()) {
+ throw new DeploymentException(DeploymentException.CODE_CANCELLED);
+ }
+ Bundle bundle = target.getBundle(infos[i].getSymbolicName());
+ if (bundle != null) {
+ File root = (File) storageAreas.get(bundle.getSymbolicName());
+ if (root != null) {
+ File snapshot = context.getDataFile("snapshots");
+ snapshot.mkdirs();
+ snapshot = new File(snapshot, infos[i].getSymbolicName());
+ try {
+ snapshot.createNewFile();
+ store(root, snapshot);
+ addRollback(new RestoreSnapshotRunnable(snapshot, root));
+ addCommit(new DeleteSnapshotRunnable(snapshot));
+ }
+ catch (IOException e) {
+ snapshot.delete();
+ }
+ } else {
+ session.getLog().log(LogService.LOG_WARNING, "Could not retrieve storage area of bundle '" + bundle.getSymbolicName() + "', skipping it.");
+ }
+ }
+ }
+ }
+
+ private void delete(File root, boolean deleteRoot) {
+ if (root.isDirectory()) {
+ File[] childs = root.listFiles();
+ for (int i = 0; i < childs.length; i++) {
+ delete(childs[i], true);
+ }
+ }
+ if (deleteRoot) {
+ root.delete();
+ }
+ }
+
+ private void store(File source, File target) throws IOException {
+ ZipOutputStream output = null;
+ try {
+ File[] children = source.listFiles();
+ output = new ZipOutputStream(new FileOutputStream(target));
+ for (int i = 0; i < children.length; i++) {
+ storeRecursive(target, new File(children[i].getName()), output);
+ }
+ }
+ finally {
+ if (output != null) {
+ try {
+ output.close();
+ }
+ catch (Exception ex) {
+ // Not much we can do
+ }
+ }
+ }
+ }
+
+ private void storeRecursive(File current, File path, ZipOutputStream output) throws IOException {
+ output.putNextEntry(new ZipEntry(path.getPath()));
+ if (current.isDirectory()) {
+ output.closeEntry();
+ File[] childs = current.listFiles();
+ for (int i = 0; i < childs.length; i++) {
+ storeRecursive(childs[i], new File(path, childs[i].getName()), output);
+ }
+ }
+ else {
+ InputStream input = null;
+ try {
+ input = new FileInputStream(current);
+ byte[] buffer = new byte[4096];
+ for (int i = input.read(buffer); i != -1; i = input.read(buffer)) {
+ output.write(buffer, 0, i);
+ }
+ output.closeEntry();
+ }
+ finally {
+ try {
+ if (input != null) {
+ input.close();
+ }
+ }
+ catch (Exception ex) {
+ // Not much we can do
+ }
+ }
+ }
+ }
+
+ private void unpack(File source, File target) throws IOException {
+ ZipInputStream input = null;
+ try {
+ input = new ZipInputStream(new FileInputStream(source));
+ for (ZipEntry entry = input.getNextEntry(); entry != null; entry = input.getNextEntry()) {
+ if (entry.isDirectory()) {
+ (new File(target, entry.getName())).mkdirs();
+ }
+ else {
+ OutputStream output = null;
+ try {
+ output = new FileOutputStream(target);
+ byte[] buffer = new byte[4096];
+ for (int i = input.read(buffer); i > -1; i = input.read(buffer)) {
+ output.write(buffer, 0, i);
+ }
+ }
+ finally {
+ if (output != null) {
+ try {
+ output.close();
+ }
+ catch (Exception ex) {
+ // Not much we can do
+ }
+ }
+ }
+ }
+ input.closeEntry();
+ }
+ }
+ finally {
+ if (input != null) {
+ try {
+ input.close();
+ }
+ catch (Exception ex) {
+ // Not much we can do
+ }
+ }
+ }
+ }
+
+ class DeleteSnapshotRunnable implements Runnable {
+
+ private final File m_snapshot;
+
+ private DeleteSnapshotRunnable(File snapshot) {
+ m_snapshot = snapshot;
+ }
+
+ public void run() {
+ m_snapshot.delete();
+ }
+ }
+
+ private class RestoreSnapshotRunnable implements Runnable {
+
+ private final File m_snapshot;
+ private final File m_root;
+
+ private RestoreSnapshotRunnable(File snapshot, File root) {
+ m_snapshot = snapshot;
+ m_root = root;
+ }
+
+ public void run() {
+ try {
+ delete(m_root, false);
+ unpack(m_snapshot, m_root);
+ }
+ catch (Exception ex) {
+ // TODO: log this
+ }
+ finally {
+ m_snapshot.delete();
+ }
+ }
+ }
+}
\ No newline at end of file
Added: felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/StartBundleCommand.java
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/StartBundleCommand.java?rev=616813&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/StartBundleCommand.java (added)
+++ felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/StartBundleCommand.java Wed Jan 30 08:46:24 2008
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.deploymentadmin.spi;
+
+import org.apache.felix.deploymentadmin.AbstractDeploymentPackage;
+import org.apache.felix.deploymentadmin.BundleInfoImpl;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.FrameworkEvent;
+import org.osgi.framework.FrameworkListener;
+import org.osgi.service.log.LogService;
+import org.osgi.service.packageadmin.PackageAdmin;
+
+/**
+ * Command that starts all bundles described in the source deployment package of a deployment session.
+ */
+public class StartBundleCommand extends Command {
+
+ private final RefreshPackagesMonitor m_refreshMonitor = new RefreshPackagesMonitor();
+ private static final int REFRESH_TIMEOUT = 10000;
+
+ public void execute(DeploymentSessionImpl session) {
+ AbstractDeploymentPackage source = session.getSourceAbstractDeploymentPackage();
+ BundleContext context = session.getBundleContext();
+ PackageAdmin packageAdmin = session.getPackageAdmin();
+ RefreshPackagesListener listener = new RefreshPackagesListener();
+ LogService log = session.getLog();
+
+ context.addFrameworkListener(listener);
+ packageAdmin.refreshPackages(null);
+ m_refreshMonitor.waitForRefresh();
+ context.removeFrameworkListener(listener);
+
+ // start source bundles
+ BundleInfoImpl[] bundleInfos = source.getOrderedBundleInfos();
+ for (int i = 0; i < bundleInfos.length; i++) {
+ BundleInfoImpl bundleInfoImpl = bundleInfos[i];
+ if(!bundleInfoImpl.isCustomizer()) {
+ Bundle bundle = source.getBundle(bundleInfoImpl.getSymbolicName());
+ if (bundle != null) {
+ try {
+ bundle.start();
+ }
+ catch (BundleException be) {
+ log.log(LogService.LOG_WARNING, "Could not start bundle '" + bundle.getSymbolicName() + "'", be);
+ }
+ }
+ else {
+ log.log(LogService.LOG_WARNING, "Could not start bundle '" + bundleInfoImpl.getSymbolicName() + "' because it is no defined in the framework");
+ }
+ }
+ }
+ }
+
+ /**
+ * RefreshPackagesListener is only listing to FrameworkEvents of the type PACKAGES_REFRESHED. It will
+ * notify any object waiting the completion of a refreshpackages() call.
+ */
+ private class RefreshPackagesListener implements FrameworkListener {
+ public void frameworkEvent(FrameworkEvent event) {
+ if (event.getType() == FrameworkEvent.PACKAGES_REFRESHED) {
+ // TODO: m_log.log(LogService.LOG_INFO, "Packages refreshed event received");
+ m_refreshMonitor.proceed();
+ }
+ }
+ }
+
+ /**
+ * Use this monitor when its desired to wait for the completion of the asynchronous PackageAdmin.refreshPackages() call.
+ */
+ private class RefreshPackagesMonitor {
+ private boolean m_alreadyNotified = false;
+
+ /**
+ * Waits for the completion of the PackageAdmin.refreshPackages() call. Because
+ * its not sure whether all OSGi framework implementations implement this method as
+ * specified we have build in a timeout. So if a event about the completion of the
+ * refreshpackages() is never received, we continue after the timeout whether the refresh
+ * was done or not.
+ */
+ public synchronized void waitForRefresh() {
+ if (!m_alreadyNotified) {
+ // TODO: m_log.log(LogService.LOG_DEBUG, "wait for Packages refreshed event");
+ try {
+ wait(REFRESH_TIMEOUT);
+ }
+ catch (InterruptedException ie) {
+ // TODO: m_log.log(LogService.LOG_INFO, "interrupted while waiting for packages refreshed event", ie);
+ }
+ finally {
+ // just reset the misted notification variable, this Monitor object might be reused.
+ m_alreadyNotified = false;
+ }
+ }
+ else {
+ // TODO: m_log.log(LogService.LOG_DEBUG, "won't wait for Packages refreshed event, event is already received");
+ // just reset the misted notification variable, this Monitor object might be reused.
+ m_alreadyNotified = false;
+ }
+ }
+
+ /**
+ * After a PACKAGES_REFRESHED event notify all the parties interested in the completion of
+ * the PackageAdmin.refreshPackages() call.
+ */
+ public synchronized void proceed() {
+ m_alreadyNotified = true;
+ notifyAll();
+ }
+ }
+
+}
Added: felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/StartCustomizerCommand.java
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/StartCustomizerCommand.java?rev=616813&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/StartCustomizerCommand.java (added)
+++ felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/StartCustomizerCommand.java Wed Jan 30 08:46:24 2008
@@ -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.felix.deploymentadmin.spi;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.apache.felix.deploymentadmin.AbstractDeploymentPackage;
+import org.apache.felix.deploymentadmin.BundleInfoImpl;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleException;
+import org.osgi.service.deploymentadmin.DeploymentException;
+
+/**
+ * Command that starts all customizer bundles defined in the source deployment packages of a deployment
+ * session. In addition all customizer bundles of the target deployment package that are not present in the source
+ * deployment package are started as well.
+ */
+public class StartCustomizerCommand extends Command {
+
+ public void execute(DeploymentSessionImpl session) throws DeploymentException {
+ AbstractDeploymentPackage target = session.getTargetAbstractDeploymentPackage();
+ AbstractDeploymentPackage source = session.getSourceAbstractDeploymentPackage();
+ Set bundles = new HashSet();
+ Set sourceBundlePaths = new HashSet();
+ BundleInfoImpl[] targetInfos = target.getBundleInfoImpls();
+ BundleInfoImpl[] sourceInfos = source.getBundleInfoImpls();
+ for(int i = 0; i < sourceInfos.length; i++) {
+ if (sourceInfos[i].isCustomizer()) {
+ sourceBundlePaths.add(sourceInfos[i].getPath());
+ Bundle bundle = source.getBundle(sourceInfos[i].getSymbolicName());
+ if (bundle != null) {
+ bundles.add(bundle);
+ }
+ }
+ }
+ for(int i = 0; i < targetInfos.length; i++) {
+ if (targetInfos[i].isCustomizer() && !sourceBundlePaths.contains(targetInfos[i].getPath())) {
+ Bundle bundle = target.getBundle(targetInfos[i].getSymbolicName());
+ if (bundle != null) {
+ bundles.add(bundle);
+ }
+ }
+ }
+ for(Iterator i = bundles.iterator(); i.hasNext(); ) {
+ Bundle bundle = (Bundle) i.next();
+ try {
+ bundle.start();
+ }
+ catch (BundleException be) {
+ throw new DeploymentException(DeploymentException.CODE_OTHER_ERROR, "Could not start customizer bundle '" + bundle.getSymbolicName() + "'", be);
+ }
+ addRollback(new StopCustomizerRunnable(bundle));
+ }
+ }
+
+ private static class StopCustomizerRunnable implements Runnable {
+
+ private final Bundle m_bundle;
+
+ public StopCustomizerRunnable(Bundle bundle) {
+ m_bundle = bundle;
+ }
+
+ public void run() {
+ try {
+ m_bundle.stop();
+ }
+ catch (BundleException e) {
+ // TODO log this
+ e.printStackTrace();
+ }
+ }
+
+ }
+}