You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by gn...@apache.org on 2010/04/02 11:43:00 UTC

svn commit: r930209 [1/2] - in /incubator/aries/trunk/subsystem: ./ org.osgi.service.composite/ org.osgi.service.composite/src/ org.osgi.service.composite/src/main/ org.osgi.service.composite/src/main/java/ org.osgi.service.composite/src/main/java/org/...

Author: gnodet
Date: Fri Apr  2 09:42:59 2010
New Revision: 930209

URL: http://svn.apache.org/viewvc?rev=930209&view=rev
Log:
[subsystem] check-in initial implementation

Added:
    incubator/aries/trunk/subsystem/org.osgi.service.composite/
    incubator/aries/trunk/subsystem/org.osgi.service.composite/pom.xml
    incubator/aries/trunk/subsystem/org.osgi.service.composite/src/
    incubator/aries/trunk/subsystem/org.osgi.service.composite/src/main/
    incubator/aries/trunk/subsystem/org.osgi.service.composite/src/main/java/
    incubator/aries/trunk/subsystem/org.osgi.service.composite/src/main/java/org/
    incubator/aries/trunk/subsystem/org.osgi.service.composite/src/main/java/org/osgi/
    incubator/aries/trunk/subsystem/org.osgi.service.composite/src/main/java/org/osgi/service/
    incubator/aries/trunk/subsystem/org.osgi.service.composite/src/main/java/org/osgi/service/composite/
    incubator/aries/trunk/subsystem/org.osgi.service.composite/src/main/java/org/osgi/service/composite/CompositeAdmin.java
    incubator/aries/trunk/subsystem/org.osgi.service.composite/src/main/java/org/osgi/service/composite/CompositeBundle.java
    incubator/aries/trunk/subsystem/org.osgi.service.composite/src/main/java/org/osgi/service/composite/CompositeConstants.java
    incubator/aries/trunk/subsystem/org.osgi.service.composite/src/main/java/org/osgi/service/composite/package.html
    incubator/aries/trunk/subsystem/org.osgi.service.composite/src/main/java/org/osgi/service/composite/packageinfo
    incubator/aries/trunk/subsystem/subsystem-core/
    incubator/aries/trunk/subsystem/subsystem-core/pom.xml
    incubator/aries/trunk/subsystem/subsystem-core/src/
    incubator/aries/trunk/subsystem/subsystem-core/src/main/
    incubator/aries/trunk/subsystem/subsystem-core/src/main/java/
    incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/
    incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/
    incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/
    incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/
    incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/
    incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/
    incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/Activator.java
    incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/BundleResourceProcessor.java
    incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/DictionaryBuilder.java
    incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/FileUtils.java
    incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/NoOpResolver.java
    incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/ResourceImpl.java
    incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemAdminImpl.java
    incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemImpl.java
    incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemResourceProcessor.java
    incubator/aries/trunk/subsystem/subsystem-install/
    incubator/aries/trunk/subsystem/subsystem-install/pom.xml
    incubator/aries/trunk/subsystem/subsystem-install/src/
    incubator/aries/trunk/subsystem/subsystem-install/src/main/
    incubator/aries/trunk/subsystem/subsystem-install/src/main/java/
    incubator/aries/trunk/subsystem/subsystem-install/src/main/java/org/
    incubator/aries/trunk/subsystem/subsystem-install/src/main/java/org/apache/
    incubator/aries/trunk/subsystem/subsystem-install/src/main/java/org/apache/aries/
    incubator/aries/trunk/subsystem/subsystem-install/src/main/java/org/apache/aries/subsystem/
    incubator/aries/trunk/subsystem/subsystem-install/src/main/java/org/apache/aries/subsystem/install/
    incubator/aries/trunk/subsystem/subsystem-install/src/main/java/org/apache/aries/subsystem/install/internal/
    incubator/aries/trunk/subsystem/subsystem-install/src/main/java/org/apache/aries/subsystem/install/internal/SubsystemInstaller.java
    incubator/aries/trunk/subsystem/subsystem-install/src/main/resources/
    incubator/aries/trunk/subsystem/subsystem-install/src/main/resources/OSGI-INF/
    incubator/aries/trunk/subsystem/subsystem-install/src/main/resources/OSGI-INF/blueprint/
    incubator/aries/trunk/subsystem/subsystem-install/src/main/resources/OSGI-INF/blueprint/subsystem-install.xml
Modified:
    incubator/aries/trunk/subsystem/pom.xml

Added: incubator/aries/trunk/subsystem/org.osgi.service.composite/pom.xml
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/subsystem/org.osgi.service.composite/pom.xml?rev=930209&view=auto
==============================================================================
--- incubator/aries/trunk/subsystem/org.osgi.service.composite/pom.xml (added)
+++ incubator/aries/trunk/subsystem/org.osgi.service.composite/pom.xml Fri Apr  2 09:42:59 2010
@@ -0,0 +1,49 @@
+<!--
+ 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.aries.subsystem</groupId>
+        <artifactId>subsystem</artifactId>
+        <version>0.1-incubating-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>org.osgi.service.composite</artifactId>
+    <packaging>bundle</packaging>
+    <name>OSGi Composite API</name>
+    <description>
+      OSGi Composite API.
+    </description>
+
+    <properties>
+        <aries.osgi.export>
+            org.osgi.service.composite;version=1.0
+        </aries.osgi.export>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+</project>

Added: incubator/aries/trunk/subsystem/org.osgi.service.composite/src/main/java/org/osgi/service/composite/CompositeAdmin.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/subsystem/org.osgi.service.composite/src/main/java/org/osgi/service/composite/CompositeAdmin.java?rev=930209&view=auto
==============================================================================
--- incubator/aries/trunk/subsystem/org.osgi.service.composite/src/main/java/org/osgi/service/composite/CompositeAdmin.java (added)
+++ incubator/aries/trunk/subsystem/org.osgi.service.composite/src/main/java/org/osgi/service/composite/CompositeAdmin.java Fri Apr  2 09:42:59 2010
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) OSGi Alliance (2009). All Rights Reserved.
+ * 
+ * Licensed 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.osgi.service.composite;
+
+import java.util.Map;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleException;
+
+/**
+ * The composite admin service is registered by a framework which supports
+ * composite bundles.  The composite admin service is used to install
+ * composite bundles.
+ * 
+ * @ThreadSafe
+ * @version $Revision: 8585 $
+ */
+public interface CompositeAdmin {
+	/**
+	 * Installs a composite bundle into the parent framework with which this 
+	 * composite admin service is registered.
+	 * <p>
+	 * The following steps are required to install a composite:
+	 * <ol>
+	 * <li>The composite manifest is verified.  If this fails, a {@linkplain BundleException}
+	 * is thrown.</li>
+	 * <li>If a bundle containing the same location identifier is already installed, if 
+	 * that bundle is a composite bundle the CompositeBundle object for that bundle is returned
+	 * otherwise a {@link BundleException} is thrown.</li>
+	 * <li>The composite's associated resources are allocated.  The associated resources 
+	 * minimally consist of a unique identifier and a composite framework.  If this 
+	 * step fails, a {@linkplain BundleException} is thrown.</li>
+	 * <li>The composite framework is initialized and its start-level is set to 0.
+	 * At this point no constituent bundles are installed in the composite framework.</li>
+	 * <li>A bundle event of type {@linkplain BundleEvent#INSTALLED} is fired.</li>
+	 * <li>The <code>CompositeBundle</code> object for the newly installed composite is 
+	 * returned</li>
+	 * </ol>
+	 *
+	 * <b>Postconditions, no exceptions thrown </b>
+	 * <ul>
+	 * <li><code>getState()</code> in &#x007B; <code>INSTALLED</code>,
+	 * <code>RESOLVED</code> &#x007D;.</li>
+	 * <li>Composite has a unique ID.</li>
+	 * <li>The composite framework is initialized, in the {@linkplain Bundle#STARTING} 
+	 * state and its start-level is set to 0.</li>
+	 * </ul>
+	 * <b>Postconditions, when an exception is thrown </b>
+	 * <ul>
+	 * <li>Composite is not installed and no trace of the composite exists.</li>
+	 * </ul>
+	 * @param location The location identifier of the composite to install. 
+	 * @param compositeManifest The meta-data describing the composite.  This includes
+	 *        the symbolic name and version and the sharing policy.
+	 * @param configuration The configuration parameters to the composite framework.  See
+	 *        {@link CompositeConstants} for the supported configuration parameters.
+	 * @return the installed composite bundle.
+	 * @throws BundleException if the installation failed.
+	 * @throws SecurityException If the caller does not have
+	 *         <code>AllPermission</code>.
+	 * @throws IllegalStateException If this composite admin service is no longer valid.  
+	 *         For example, if the framework has shutdown.
+	 */
+	CompositeBundle installCompositeBundle(String location,
+			Map<String, String> compositeManifest,
+			Map<String, String> configuration)
+			throws BundleException;
+
+	/**
+	 * Returns the parent composite bundle associated with the framework with which 
+	 * this composite admin service is registered.  The composite admin service
+	 * registered in the root framework must return <code>null</code>.
+	 * @return The parent composite bundle or <code>null</code>.
+	 */
+	CompositeBundle getParentCompositeBundle();
+}

Added: incubator/aries/trunk/subsystem/org.osgi.service.composite/src/main/java/org/osgi/service/composite/CompositeBundle.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/subsystem/org.osgi.service.composite/src/main/java/org/osgi/service/composite/CompositeBundle.java?rev=930209&view=auto
==============================================================================
--- incubator/aries/trunk/subsystem/org.osgi.service.composite/src/main/java/org/osgi/service/composite/CompositeBundle.java (added)
+++ incubator/aries/trunk/subsystem/org.osgi.service.composite/src/main/java/org/osgi/service/composite/CompositeBundle.java Fri Apr  2 09:42:59 2010
@@ -0,0 +1,310 @@
+/*
+ * Copyright (c) OSGi Alliance (2009). All Rights Reserved.
+ * 
+ * Licensed 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.osgi.service.composite;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.Map;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.FrameworkEvent;
+
+/**
+ * A composite bundle is a bundle for which the content is composed of meta-data 
+ * describing the composite and a set of bundles called constituent bundles.
+ * Constituent bundles are isolated from other bundles which are not 
+ * constituents of the same composite bundle.  Composites provide isolation
+ * for constituent bundles in the following ways.
+ * <ul>
+ * <li>Class space: Constraints specified by constituent bundles (e.g.
+ *     Import-Package, Require-Bundle, Fragment-Host) can only be resolved
+ *     against capabilities provided by other constituents within the same 
+ *     composite bundle (Export-Package, Bundle-SymbolicName/Bundle-Version).</li>
+ * <li>Service Registry: Constituent bundles only have access to services 
+ *     registered by other constituents within the same composite bundle.  
+ *     This includes service events and service references.</li>
+ * <li>Bundles: Constituent bundles only have access to other Bundle objects 
+ *     that represent constituents within the same composite bundle.  This 
+ *     includes bundle events and core API like BundleContext.getBundles, 
+ *     PackageAdmin and StartLevel.</li>
+ * </ul>
+ * <p>
+ * A parent framework refers to the OSGi framework where a composite bundle 
+ * is installed.  A composite framework refers the framework where the 
+ * constituent bundles are installed and provides the isolation for the
+ * constituent bundles.  Constituent bundles are isolated
+ * but there are many cases where capabilities (packages and services) need 
+ * to be shared between bundles installed in the parent framework and the 
+ * constituents within a composite bundle.
+ * </p>
+ * <p>
+ * Through a sharing policy the composite is in control of what capabilities
+ * are shared across framework boundaries.  The sharing policy controls what
+ * capabilities provided by bundles installed in the parent framework are 
+ * imported into the composite and made available to constituent bundles.
+ * The sharing policy also controls what capabilities provided by 
+ * constituent bundles are exported out of the composite and made available
+ * to bundles installed in the parent framework.
+ * </p>
+ * <p>
+ * The lifecycle of the constituent bundles are tied to the lifecycle of 
+ * the composite bundle. See {@link #start(int)}, {@link #stop(int)}, 
+ * {@link #update(Map)} and {@link #uninstall}.
+ * </p>
+ * 
+ * @ThreadSafe
+ * @version $Revision: 8585 $
+ */
+public interface CompositeBundle extends Bundle {
+	/**
+	 * Returns the system bundle context for the composite framework.  This 
+	 * method must return a valid {@link BundleContext} as long as this 
+	 * composite bundle is installed.  Once a composite bundle is 
+	 * uninstalled this method must return <code>null</code>.  The composite system 
+	 * bundle context can be used to install and manage the constituent bundles.
+	 * @return the system bundle context for the composite framework
+	 * @throws SecurityException If the caller does not have the
+	 *         appropriate <code>AdminPermission[system.bundle,CONTEXT]</code>, and
+	 *         the Java Runtime Environment supports permissions.
+	 */
+	public BundleContext getSystemBundleContext();
+	
+	/**
+	 * Starts this composite with no options.
+	 * 
+	 * <p>
+	 * This method performs the same function as calling <code>start(0)</code>.
+	 * 
+	 * @throws BundleException If this composite could not be started.
+	 * @throws IllegalStateException If this composite has been uninstalled.
+	 * @throws SecurityException If the caller does not have the appropriate
+	 *         <code>AdminPermission[this,EXECUTE]</code>, and the Java Runtime
+	 *         Environment supports permissions.
+	 * @see #start(int)
+	 */
+	public void start() throws BundleException;
+
+	/**
+	 * Starts this composite according to {@link Bundle#start(int)}.
+	 * When the composite bundle's state is set to {@link Bundle#STARTING} and
+	 * after the {@link BundleEvent#STARTING} event has been fired for this 
+	 * composite bundle, the following steps are required to activate the 
+	 * constituents:
+	 * <ol>
+	 * <li>The composite framework start-level is set to the beginning start-level.</li>
+	 * <li>The constituent bundles are started according to the start-level 
+	 * specification.
+	 * <li>The {@link FrameworkEvent#STARTED} event is fired for the
+	 * composite framework.</li>
+	 * <li>The composite bundle state is set to {@link Bundle#ACTIVE}</li>
+	 * <li>The bundle event of type {@link BundleEvent#STARTED} is fired for this 
+	 * composite.</li>
+	 * </ol>
+	 * @param options The options for starting this composite. See
+	 *        {@link #START_TRANSIENT} and {@link #START_ACTIVATION_POLICY}. The
+	 *        Framework must ignore unrecognized options.
+	 * @throws BundleException If this composite could not be started.
+	 * @throws IllegalStateException If this composite has been uninstalled.
+	 * @throws SecurityException If the caller does not have the appropriate
+	 *         <code>AdminPermission[this,EXECUTE]</code>, and the Java Runtime
+	 *         Environment supports permissions.
+	 */
+	public void start(int options) throws BundleException;
+
+	/**
+	 * Stops this composite with no options.
+	 * 
+	 * <p>
+	 * This method performs the same function as calling <code>stop(0)</code>.
+	 * 
+	 * @throws BundleException If an error occurred while stopping this composite
+	 * @throws IllegalStateException If this composite has been uninstalled.
+	 * @throws SecurityException If the caller does not have the appropriate
+	 *         <code>AdminPermission[this,EXECUTE]</code>, and the Java Runtime
+	 *         Environment supports permissions.
+	 * @see #start(int)
+	 */
+	public void stop() throws BundleException;
+
+	/**
+	 * Stops this composite according to {@link Bundle#stop(int)}.
+	 * When the composite bundle's state is set to {@link Bundle#STOPPING}, 
+	 * the following steps are required to stop the constituents:
+	 * <ol>
+	 * <li>The composite framework start-level is set to the 0.</li>
+	 * <li>The constituent bundles are stopped according to the start-level 
+	 * specification.</li>
+	 * <li>The bundle event of type {@link BundleEvent#STARTED} is fired for the 
+	 * composite.</li>
+	 * </ol>
+	 * @param options The options for stopping this bundle. See
+	 *        {@link #STOP_TRANSIENT}. The Framework must ignore unrecognized
+	 *        options.
+	 * @throws BundleException If an error occurred while stopping this composite
+	 * @throws IllegalStateException If this composite has been uninstalled.
+	 * @throws SecurityException If the caller does not have the appropriate
+	 *         <code>AdminPermission[this,EXECUTE]</code>, and the Java Runtime
+	 *         Environment supports permissions.
+	 * @since 1.4
+	 */
+	public void stop(int options) throws BundleException;
+
+	/**
+	 * Uninstalls this composite according to {@link Bundle#uninstall()}.
+	 * When the composite bundle is uninstalled the following steps are 
+	 * required:
+	 * <ol>
+	 * <li>After a composite's state is set to {@linkplain Bundle#INSTALLED}
+	 * and before a composite's state is set to {@linkplain Bundle#UNINSTALLED},
+	 * all the constituent bundles are uninstalled.</li>
+	 * <li>When a composite's state is set to {@linkplain Bundle#UNINSTALLED},
+	 * the composite system bundle context becomes invalid.
+	 * </ol>
+	 */
+	public void uninstall() throws BundleException;
+	/**
+	 * This operation is not supported for composite bundles. A
+	 * <code>BundleException</code> of type
+	 * {@link BundleException#INVALID_OPERATION invalid operation} must be
+	 * thrown.
+	 */
+	public void update() throws BundleException;
+
+	/**
+	 * This operation is not supported for composite bundles. A
+	 * <code>BundleException</code> of type
+	 * {@link BundleException#INVALID_OPERATION invalid operation} must be
+	 * thrown.
+	 */
+	public void update(InputStream input) throws BundleException;
+
+	/**
+	 * Updates the meta-data for this composite from a <code>Map</code>.
+	 * 
+	 * <p>
+	 * The specified <code>Map</code> must not be <code>null</code>.
+	 * 
+	 * <p>
+	 * If this composite's state is <code>ACTIVE</code>, it must be stopped before
+	 * the update and started after the update successfully completes.
+	 * 
+	 * <p>
+	 * If this composite has a sharing policy for packages, any packages that are 
+	 * imported by other bundles through the current sharing policy must remain exported 
+	 * for existing importers.  A call <code>PackageAdmin.refreshPackages</code> method 
+	 * will force all constituent bundles for this composite to be refreshed, causing the 
+	 * new package sharing policy to be used for all constituent bundles.
+	 * <p>
+	 * The following steps are required to update a composite:
+	 * <ol>
+	 * <li>If this composite's state is <code>UNINSTALLED</code> then an
+	 * <code>IllegalStateException</code> is thrown.
+	 * <li>The component manifest <code>Map</code> is verified.  If this fails, 
+	 * a {@linkplain BundleException} is thrown.
+	 * 
+	 * <li>If this composite's state is <code>ACTIVE</code>, <code>STARTING</code>
+	 * or <code>STOPPING</code>, this bundle is stopped as described in the
+	 * <code>CompositeBundle.stop</code> method. If <code>CompositeBundle.stop</code>
+	 * throws an exception, the exception is rethrown terminating the update.
+	 * 
+	 * <li>The meta-data of this composite is updated from the <code>Map</code>.
+	 * 
+	 * <li>This composite's state is set to <code>INSTALLED</code>.
+	 * 
+	 * <li>If the updated version of this composite was successfully installed, a
+	 * bundle event of type {@link BundleEvent#UPDATED} is fired.
+	 * 
+	 * <li>If this composite's state was originally <code>ACTIVE</code>, the
+	 * updated composite is started as described in the <code>CompositeBundle.start</code>
+	 * method. If <code>CompositeBundle.start</code> throws an exception, a Framework
+	 * event of type {@link FrameworkEvent#ERROR} is fired containing the
+	 * exception.
+	 * </ol>
+	 * 
+	 * <b>Preconditions </b>
+	 * <ul>
+	 * <li><code>getState()</code> not in &#x007B; <code>UNINSTALLED</code>
+	 * &#x007D;.
+	 * </ul>
+	 * <b>Postconditions, no exceptions thrown </b>
+	 * <ul>
+	 * <li><code>getState()</code> in &#x007B; <code>INSTALLED</code>,
+	 * <code>RESOLVED</code>, <code>ACTIVE</code> &#x007D;.
+	 * <li>This composite has been updated.
+	 * </ul>
+	 * <b>Postconditions, when an exception is thrown </b>
+	 * <ul>
+	 * <li><code>getState()</code> in &#x007B; <code>INSTALLED</code>,
+	 * <code>RESOLVED</code>, <code>ACTIVE</code> &#x007D;.
+	 * <li>Original composite is still used; no update occurred.
+	 * </ul>
+	 * 
+	 * @param compositeManifest The <code>Map</code> from which to read the new
+	 *        composite meta-data from.  Must not be <code>null</code>.
+	 * @throws BundleException If the the update fails.
+	 * @throws IllegalStateException If this composite has been uninstalled.
+	 * @throws SecurityException If the caller does not have
+	 *         <code>AllPermission</code>.
+	 * @see #stop()
+	 * @see #start()
+	 */
+	public void update(Map<String, String> compositeManifest)
+			throws BundleException;
+
+	/**
+	 * Composite bundles do not have class content.  This method must 
+	 * throw a {@link ClassNotFoundException}
+	 * @throws ClassNotFoundException Always thrown for composite bundles.
+	 */
+	public Class< ? > loadClass(String name) throws ClassNotFoundException;
+	/**
+	 * Composite bundles do not have content.  This method must return
+	 * <code>null</code>.
+	 * @return A <code>null</code> value is always returned for composites.
+	 */
+	public URL getResource(String name);
+	/**
+	 * Composite bundles do not have content.  This method must return
+	 * <code>null</code>.
+	 * @return A <code>null</code> value is always returned for composites.
+	 */
+	public Enumeration<URL> getResources(String name) throws IOException;
+	/**
+	 * Composite bundles do not have content.  This method must return
+	 * <code>null</code>.
+	 * @return A <code>null</code> value is always returned for composites.
+	 */
+	public URL getEntry(String path);
+	/**
+	 * Composite bundles do not have content.  This method must return
+	 * <code>null</code>.
+	 * @return A <code>null</code> value is always returned for composites.
+	 */
+	public Enumeration<String> getEntryPaths(String path);
+	/**
+	 * Composite bundles do not have content.  This method must return
+	 * <code>null</code>.
+	 * @return A <code>null</code> value is always returned for composites.
+	 */
+	public Enumeration<URL> findEntries(String path, String filePattern,
+			boolean recurse);
+}

Added: incubator/aries/trunk/subsystem/org.osgi.service.composite/src/main/java/org/osgi/service/composite/CompositeConstants.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/subsystem/org.osgi.service.composite/src/main/java/org/osgi/service/composite/CompositeConstants.java?rev=930209&view=auto
==============================================================================
--- incubator/aries/trunk/subsystem/org.osgi.service.composite/src/main/java/org/osgi/service/composite/CompositeConstants.java (added)
+++ incubator/aries/trunk/subsystem/org.osgi.service.composite/src/main/java/org/osgi/service/composite/CompositeConstants.java Fri Apr  2 09:42:59 2010
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) OSGi Alliance (2009). All Rights Reserved.
+ * 
+ * Licensed 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.osgi.service.composite;
+
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+
+
+/**
+ * Defines standard names for composite constants.
+ * 
+ * @ThreadSafe
+ * @version $Revision: 8585 $
+ */
+public class CompositeConstants {
+	/**
+	 * Private constructor to prevent objects of this type.
+	 */
+	private CompositeConstants() {
+		// non-instantiable
+	}
+
+	/**
+	 * Manifest header directive identifying whether a bundle is a composite.
+	 * The default value is <code>false</code>.
+	 * 
+	 * <p>
+	 * The directive value is encoded in the Bundle-SymbolicName manifest header
+	 * like:
+	 * 
+	 * <pre>
+	 *     Bundle-SymbolicName: com.acme.composite.test; composite:=true
+	 * </pre>
+	 * 
+	 * <p>
+	 * The attribute value may be retrieved from the <code>Dictionary</code>
+	 * object returned by the <code>Bundle.getHeaders</code> method.
+	 * 
+	 * <p>
+	 * A valid manifest for a composite bundle must have this directive set
+	 * to <code>true</code>.  Any attempt to install a composite which does 
+	 * not have this directive set to <code>true</code> must result in a
+	 * {@linkplain BundleException}.
+	 * 
+	 * @see Constants#BUNDLE_SYMBOLICNAME
+	 */
+	public final static String	COMPOSITE_DIRECTIVE						= "composite";
+
+	/**
+	 * Composite manifest header (named &quot;Composite-PackageImportPolicy&quot;)
+	 * identifying a list of package constraints to import into the composite.  
+	 * Any exported package from a bundle installed in the parent framework which 
+	 * satisfies one of the specified package constraints is available to satisfy 
+	 * Import-Package constraints from constituent bundles.
+	 * <p>
+	 * This header uses the same syntax as the {@linkplain Constants#IMPORT_PACKAGE
+	 * Import-Package} header.
+	 */
+	public static final String COMPOSITE_PACKAGE_IMPORT_POLICY = "Composite-PackageImportPolicy";
+
+	/**
+	 * Composite manifest header (named &quot;Composite-PackageExportPolicy&quot;)
+	 * identifying a list of package constraints to export out of a composite.
+	 * Any exported package from a constituent bundle in the composite which 
+	 * satisfies one of the specified package constraints is available to satisfy 
+	 * Import-Package constraints from bundles installed in the parent framework.
+	 * <p>
+	 * This header uses the same syntax as the {@linkplain Constants#IMPORT_PACKAGE 
+	 * Import-Package} header.
+	 */
+	public static final String COMPOSITE_PACKAGE_EXPORT_POLICY = "Composite-PackageExportPolicy";
+
+	/**
+	 * Composite manifest header (named &quot;Composite-BundleRequirePolicy&quot;)
+	 * identifying a list of require bundle constraints to import into the composite.
+	 * Any bundle installed in the parent framework which satisfies one of the 
+	 * specified require bundle constraints is available to satisfy Require-Bundle
+	 * constraints from constituent bundles.
+	 * <p>
+	 * This header uses the same syntax as the {@linkplain Constants#REQUIRE_BUNDLE
+	 * Require-Bundle} header.
+	 */
+	public static final String COMPOSITE_BUNDLE_REQUIRE_POLICY = "Composite-BundleRequirePolicy";
+
+	/**
+	 * Composite manifest header (named &quot;Composite-ServiceImportPolicy&quot;)
+	 * identifying a service filter that controls the services to import into the
+	 * composite.  See {@link Filter} for a description of the filter syntax.  Any 
+	 * services registered by bundles installed in the parent framework that match
+	 * the specified service filter is available to constituent bundles.
+	 */
+	public static final String COMPOSITE_SERVICE_IMPORT_POLICY = "Composite-ServiceImportPolicy";
+
+	/**
+	 * Composite manifest header (named &quot;Composite-ServiceExportPolicy&quot;)
+	 * identifying a service filter that controls the services to export out of the
+	 * composite.  See {@link Filter} for a description of the filter syntax.  Any 
+	 * services registered by constituent bundles that match the specified service 
+	 * filter is available to bundles installed in the parent framework.
+	 */
+	public static final String COMPOSITE_SERVICE_EXPORT_POLICY = "Composite-ServiceExportPolicy";
+
+	/**
+	 * Manifest header directive identifying the symbolic name a sibling composite 
+	 * must have that allows capabilities exported from that composite to match 
+	 * an import sharing policy specified by {@link #COMPOSITE_PACKAGE_IMPORT_POLICY 
+	 * Composite-PackageImportPolicy} or {@link #COMPOSITE_SERVICE_IMPORT_POLICY 
+	 * Composite-ServiceImportPolicy}.
+	 * 
+	 * <p>
+	 * The directive value is encoded in the a manifest header like:
+	 * 
+	 * <pre>
+	 *     Composite-PackageImportPolicy: org.example.pkg; composite-symbolic-name=&quot;org.example.composite&quot;
+	 *     Composite-ServiceImportPolicy: &quot;(attr=somevalue)&quot;; composite-symbolic-name=&quot;org.example.composite&quot;
+	 * </pre>
+	 * 
+	 * @see #COMPOSITE_PACKAGE_IMPORT_POLICY
+	 * @see #COMPOSITE_SERVICE_IMPORT_POLICY
+	 */
+	public static final String COMPOSITE_SYMBOLICNAME_DIRECTIVE = "composite-symbolic-name";
+
+	/**
+	 * Manifest header directive identifying the version a sibling composite 
+	 * must have that allows capabilities exported from that composite to match 
+	 * an import sharing policy specified by {@link #COMPOSITE_PACKAGE_IMPORT_POLICY 
+	 * Composite-PackageImportPolicy} or {@link #COMPOSITE_SERVICE_IMPORT_POLICY 
+	 * Composite-ServiceImportPolicy}.
+	 * 
+	 * <p>
+	 * The directive value is encoded in the a manifest header like:
+	 * 
+	 * <pre>
+	 *     Composite-PackageImportPolicy: org.example.pkg; composite-version=&quot;[1.0,1.1)&quot;
+	 *     Composite-ServiceImportPolicy: &quot;(attr=somevalue)&quot;; composite-version=&quot;[1.0,1.1)&quot;
+	 * </pre>
+	 * 
+	 * <p>
+	 * In most cases a {@link #COMPOSITE_SYMBOLICNAME_DIRECTIVE composite-symbolic-name} 
+	 * directive should be specified along with the composite-version directive like:
+	 *
+	 * <pre>
+	 *     Composite-PackageImportPolicy: org.example.pkg;
+	 *      composite-symbolic-name=&quot;org.example.composite&quot;; composite-version=&quot;[1.0,1.1)&quot;
+	 *     Composite-ServiceImportPolicy: &quot;(attr=somevalue)&quot;;
+	 *      composite-symbolic-name=&quot;org.example.composite&quot;; composite-version=&quot;[1.0,1.1)&quot;
+	 * </pre>
+	 * 
+	 * @see #COMPOSITE_PACKAGE_IMPORT_POLICY
+	 * @see #COMPOSITE_SERVICE_IMPORT_POLICY
+	 */
+	public static final String COMPOSITE_VERSION_DIRECTIVE = "composite-version";
+
+	/**
+	 * A supported configuration parameter for a composite framework.
+	 * @see Constants#FRAMEWORK_BEGINNING_STARTLEVEL
+	 */
+	public final static String COMPOSITE_FRAMEWORK_BEGINNING_STARTLEVEL = Constants.FRAMEWORK_BEGINNING_STARTLEVEL;
+}

Added: incubator/aries/trunk/subsystem/org.osgi.service.composite/src/main/java/org/osgi/service/composite/package.html
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/subsystem/org.osgi.service.composite/src/main/java/org/osgi/service/composite/package.html?rev=930209&view=auto
==============================================================================
--- incubator/aries/trunk/subsystem/org.osgi.service.composite/src/main/java/org/osgi/service/composite/package.html (added)
+++ incubator/aries/trunk/subsystem/org.osgi.service.composite/src/main/java/org/osgi/service/composite/package.html Fri Apr  2 09:42:59 2010
@@ -0,0 +1,11 @@
+<!-- $Revision: 8119 $ -->
+<BODY>
+<p>Composite Admin service Package Version 1.0.
+<p>Bundles wishing to use this package must list the package
+in the Import-Package header of the bundle's manifest.
+For example:
+<pre>
+Import-Package: org.osgi.service.composite;version=&quot;[1.0,2.0)&quot;
+</pre>
+</BODY>
+

Added: incubator/aries/trunk/subsystem/org.osgi.service.composite/src/main/java/org/osgi/service/composite/packageinfo
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/subsystem/org.osgi.service.composite/src/main/java/org/osgi/service/composite/packageinfo?rev=930209&view=auto
==============================================================================
--- incubator/aries/trunk/subsystem/org.osgi.service.composite/src/main/java/org/osgi/service/composite/packageinfo (added)
+++ incubator/aries/trunk/subsystem/org.osgi.service.composite/src/main/java/org/osgi/service/composite/packageinfo Fri Apr  2 09:42:59 2010
@@ -0,0 +1 @@
+version 1.0

Modified: incubator/aries/trunk/subsystem/pom.xml
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/subsystem/pom.xml?rev=930209&r1=930208&r2=930209&view=diff
==============================================================================
--- incubator/aries/trunk/subsystem/pom.xml (original)
+++ incubator/aries/trunk/subsystem/pom.xml Fri Apr  2 09:42:59 2010
@@ -46,15 +46,33 @@
                 <version>${version}</version>
             </dependency>
             <dependency>
+                <groupId>org.apache.aries.subsystem</groupId>
+                <artifactId>org.apache.aries.subsystem.core</artifactId>
+                <version>${version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.aries.subsystem</groupId>
+                <artifactId>org.osgi.service.composite</artifactId>
+                <version>${version}</version>
+            </dependency>
+            <dependency>
                 <groupId>org.osgi</groupId>
                 <artifactId>org.osgi.core</artifactId>
                 <version>4.2.0</version>
             </dependency>
+            <dependency>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>org.apache.felix.utils</artifactId>
+                <version>1.0.0</version>
+            </dependency>
 		</dependencies>
 	</dependencyManagement>
 
 	<modules>
-		<module>subsystem-api</module>
+        <module>subsystem-api</module>
+        <module>org.osgi.service.composite</module>
+        <module>subsystem-core</module>
+        <module>subsystem-install</module>
 	</modules>
 
 </project>

Added: incubator/aries/trunk/subsystem/subsystem-core/pom.xml
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/subsystem/subsystem-core/pom.xml?rev=930209&view=auto
==============================================================================
--- incubator/aries/trunk/subsystem/subsystem-core/pom.xml (added)
+++ incubator/aries/trunk/subsystem/subsystem-core/pom.xml Fri Apr  2 09:42:59 2010
@@ -0,0 +1,65 @@
+<!--
+ 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.aries.subsystem</groupId>
+        <artifactId>subsystem</artifactId>
+        <version>0.1-incubating-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>org.apache.aries.subsystem.core</artifactId>
+    <packaging>bundle</packaging>
+    <name>Apache Aries Subsystem Core</name>
+    <description>
+      Subsystems API.
+    </description>
+
+    <properties>
+        <aries.osgi.activator>
+            org.apache.aries.subsystem.core.internal.Activator
+        </aries.osgi.activator>
+        <aries.osgi.private.pkg>
+            org.apache.aries.subsystem.core.internal,
+            org.apache.felix.utils.manifest
+        </aries.osgi.private.pkg>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.aries.subsystem</groupId>
+            <artifactId>org.apache.aries.subsystem.api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.aries.subsystem</groupId>
+            <artifactId>org.osgi.service.composite</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.utils</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>

Added: incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/Activator.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/Activator.java?rev=930209&view=auto
==============================================================================
--- incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/Activator.java (added)
+++ incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/Activator.java Fri Apr  2 09:42:59 2010
@@ -0,0 +1,109 @@
+/*
+ * Licensed 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.aries.subsystem.core.internal;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.aries.subsystem.SubsystemAdmin;
+import org.apache.aries.subsystem.SubsystemConstants;
+import org.apache.aries.subsystem.spi.ResourceProcessor;
+import org.apache.aries.subsystem.spi.ResourceResolver;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceFactory;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * The bundle activator for the this bundle.
+ * When the bundle is starting, this activator will create
+ * and register the SubsystemAdmin service.
+ */
+public class Activator implements BundleActivator {
+
+    private BundleContext context;
+    private List<ServiceRegistration> registrations = new ArrayList<ServiceRegistration>();
+
+    public void start(BundleContext context) throws Exception {
+        this.context = context;
+        register(SubsystemAdmin.class, new SubsystemAdminFactory(), null);
+        register(ResourceResolver.class,
+                 new NoOpResolver(),
+                 DictionaryBuilder.build(Constants.SERVICE_RANKING, Integer.MIN_VALUE));
+        register(ResourceProcessor.class,
+                new BundleResourceProcessor(),
+                DictionaryBuilder.build(SubsystemConstants.SERVICE_RESOURCE_TYPE, SubsystemConstants.RESOURCE_TYPE_BUNDLE));
+        register(ResourceProcessor.class,
+                new SubsystemResourceProcessor(),
+                DictionaryBuilder.build(SubsystemConstants.SERVICE_RESOURCE_TYPE, SubsystemConstants.RESOURCE_TYPE_SUBSYSTEM));
+    }
+
+    protected <T> void register(Class<T> clazz, T service, Dictionary props) {
+         registrations.add(context.registerService(clazz.getName(), service, props));
+    }
+
+    protected <T> void register(Class<T> clazz, ServiceFactory factory, Dictionary props) {
+         registrations.add(context.registerService(clazz.getName(), factory, props));
+    }
+
+    public void stop(BundleContext context) throws Exception {
+        for (ServiceRegistration r : registrations) {
+            try {
+                r.unregister();
+            } catch (Exception e) {
+                // Ignore
+            }
+        }
+    }
+
+
+    public static class SubsystemAdminFactory implements ServiceFactory {
+
+        private final Map<BundleContext, SubsystemAdminImpl> admins = new HashMap<BundleContext, SubsystemAdminImpl>();
+        private final Map<SubsystemAdminImpl, Long> references = new HashMap<SubsystemAdminImpl, Long>();
+
+        public synchronized Object getService(Bundle bundle, ServiceRegistration registration) {
+            BundleContext systemBundleContext = bundle.getBundleContext().getBundle(0).getBundleContext();
+            SubsystemAdminImpl admin = admins.get(systemBundleContext);
+            long ref = 0;
+            if (admin == null) {
+                admin = new SubsystemAdminImpl(systemBundleContext);
+                admins.put(systemBundleContext, admin);
+            } else {
+                ref = references.get(admin);
+            }
+            references.put(admin, ref + 1);
+            return admin;
+        }
+
+        public synchronized void ungetService(Bundle bundle, ServiceRegistration registration, Object service) {
+            SubsystemAdminImpl admin = (SubsystemAdminImpl) service;
+            long ref = references.get(admin) - 1;
+            if (ref == 0) {
+                admin.dispose();
+                admins.remove(admin.context);
+                references.remove(admin);
+            } else {
+                references.put(admin, ref);
+            }
+        }
+
+    }
+
+}

Added: incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/BundleResourceProcessor.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/BundleResourceProcessor.java?rev=930209&view=auto
==============================================================================
--- incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/BundleResourceProcessor.java (added)
+++ incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/BundleResourceProcessor.java Fri Apr  2 09:42:59 2010
@@ -0,0 +1,74 @@
+/*
+ * Licensed 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.aries.subsystem.core.internal;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.aries.subsystem.SubsystemException;
+import org.apache.aries.subsystem.spi.Resource;
+import org.apache.aries.subsystem.spi.ResourceProcessor;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+
+public class BundleResourceProcessor implements ResourceProcessor {
+
+    public Session createSession(BundleContext context) {
+        return new BundleSession(context);
+    }
+
+    public static class BundleSession implements Session {
+
+        private final BundleContext context;
+        private final List<Bundle> installed = new ArrayList<Bundle>();
+
+        public BundleSession(BundleContext context) {
+            this.context = context;
+        }
+
+        public void process(Resource resource) throws SubsystemException {
+            try {
+                Bundle bundle = context.installBundle(resource.getLocation(), resource.open());
+                installed.add(bundle);
+            } catch (SubsystemException e) {
+                throw e;
+            } catch (Exception e) {
+                throw new SubsystemException("Unable to process bundle resource", e);
+            }
+        }
+
+        public void dropped(Resource resource) throws SubsystemException {
+            //To change body of implemented methods use File | Settings | File Templates.
+        }
+
+        public void prepare() throws SubsystemException {
+        }
+
+        public void commit() {
+            installed.clear();
+        }
+
+        public void rollback() {
+            for (Bundle bundle : installed) {
+                try {
+                    bundle.uninstall();
+                } catch (Exception e) {
+                    // Ignore
+                }
+            }
+        }
+    }
+
+}

Added: incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/DictionaryBuilder.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/DictionaryBuilder.java?rev=930209&view=auto
==============================================================================
--- incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/DictionaryBuilder.java (added)
+++ incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/DictionaryBuilder.java Fri Apr  2 09:42:59 2010
@@ -0,0 +1,47 @@
+/*
+ * Licensed 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.aries.subsystem.core.internal;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+public class DictionaryBuilder<K,V> {
+
+    public static <K,V> Dictionary<K,V> build(K k, V v) {
+        return new DictionaryBuilder<K,V>().p(k, v).get();
+    }
+
+    public static <K,V> Dictionary<K,V> build(K k1, V v1, K k2, V v2) {
+        return new DictionaryBuilder<K,V>().p(k1, v1).p(k2, v2).get();
+    }
+
+    public static <K,V> Dictionary<K,V> build(K k1, V v1, K k2, V v2, K k3, V v3) {
+        return new DictionaryBuilder<K,V>().p(k1, v1).p(k2, v2).p(k3, v3).get();
+    }
+
+    private Dictionary<K,V> dict;
+
+    public DictionaryBuilder() {
+        dict = new Hashtable<K,V>();
+    }
+
+    DictionaryBuilder<K,V> p(K k, V v) {
+        dict.put(k, v);
+        return this;
+    }
+
+    Dictionary<K,V> get() {
+        return dict;
+    }
+}

Added: incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/FileUtils.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/FileUtils.java?rev=930209&view=auto
==============================================================================
--- incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/FileUtils.java (added)
+++ incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/FileUtils.java Fri Apr  2 09:42:59 2010
@@ -0,0 +1,93 @@
+/*
+ * Licensed 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.aries.subsystem.core.internal;
+
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+public class FileUtils {
+
+    private FileUtils() {
+    }
+
+    /**
+     * Build a directory path - creating directories if necessary
+     *
+     * @param file
+     * @return true if the directory exists, or making it was successful
+     * @throws java.io.IOException
+     */
+    public static void mkdirs(File file) throws IOException {
+        if (!file.isDirectory() && !file.mkdirs()) {
+            throw new IOException("Could not create directory: " + file);
+        }
+    }
+
+    /**
+     * Unpack an archive from an input stream
+     *
+     * @param is
+     * @param targetDir
+     * @throws IOException
+     */
+    public static void unpackArchive(InputStream is, File targetDir) throws IOException {
+        mkdirs(targetDir);
+        byte[] buf = new byte[1024];
+        ZipInputStream zis = new ZipInputStream(is);
+        try {
+            ZipEntry entry = zis.getNextEntry();
+            while (entry != null) {
+                File file = new File(targetDir, entry.getName());
+                // Take the sledgehammer approach to creating directories
+                // to work around ZIP's that incorrectly miss directories
+                mkdirs(file.getParentFile());
+                if (!entry.isDirectory()) {
+                    FileOutputStream fos = new FileOutputStream(file);
+                    try {
+                        int n;
+                        while ((n = zis.read(buf, 0, 1024)) > -1) {
+                            fos.write(buf, 0, n);
+                        }
+                    } finally {
+                        closeQuietly(fos);
+                    }
+                    zis.closeEntry();
+                    entry = zis.getNextEntry();
+                } else {
+                    mkdirs(file);
+                }
+            }//while
+        } finally {
+            closeQuietly(zis, is);
+        }
+     }
+
+    public static void closeQuietly(Closeable... closeables) {
+        for (Closeable c : closeables) {
+            try {
+                if (c != null) {
+                    c.close();
+                }
+            } catch (IOException e) {
+                // Ignore
+            }
+        }
+    }
+
+}

Added: incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/NoOpResolver.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/NoOpResolver.java?rev=930209&view=auto
==============================================================================
--- incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/NoOpResolver.java (added)
+++ incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/NoOpResolver.java Fri Apr  2 09:42:59 2010
@@ -0,0 +1,55 @@
+/*
+ * Licensed 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.aries.subsystem.core.internal;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.aries.subsystem.SubsystemConstants;
+import org.apache.aries.subsystem.SubsystemException;
+import org.apache.aries.subsystem.spi.Resource;
+import org.apache.aries.subsystem.spi.ResourceResolver;
+import org.apache.felix.utils.manifest.Clause;
+import org.apache.felix.utils.manifest.Parser;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Version;
+
+public class NoOpResolver implements ResourceResolver {
+
+    public Resource find(String resource) throws SubsystemException {
+        Clause[] clauses = Parser.parseHeader(resource);
+        if (clauses.length != 1) {
+            throw new SubsystemException("Unsupported resource: " + resource);
+        }
+
+        String bsn = clauses[0].getName();
+        String ver = clauses[0].getAttribute(Constants.VERSION_ATTRIBUTE);
+        String typ = clauses[0].getAttribute(SubsystemConstants.RESOURCE_TYPE_ATTRIBUTE);
+        String loc = clauses[0].getAttribute(SubsystemConstants.RESOURCE_LOCATION_ATTRIBUTE);
+        if (loc == null) {
+            throw new SubsystemException("Mandatory location missing on resource: " + resource);
+        }
+        return new ResourceImpl(
+                bsn,
+                ver != null ? new Version(ver) : Version.emptyVersion,
+                typ != null ? typ : SubsystemConstants.RESOURCE_TYPE_BUNDLE,
+                loc
+        );
+    }
+
+    public List<Resource> resolve(List<Resource> subsystemContent, List<Resource> subsystemResources) throws SubsystemException {
+        return Collections.emptyList();
+    }
+
+}

Added: incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/ResourceImpl.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/ResourceImpl.java?rev=930209&view=auto
==============================================================================
--- incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/ResourceImpl.java (added)
+++ incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/ResourceImpl.java Fri Apr  2 09:42:59 2010
@@ -0,0 +1,57 @@
+/*
+ * Licensed 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.aries.subsystem.core.internal;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+import org.apache.aries.subsystem.spi.Resource;
+import org.osgi.framework.Version;
+
+public class ResourceImpl implements Resource {
+
+    private final String symbolicName;
+    private final Version version;
+    private final String type;
+    private final String location;
+
+    public ResourceImpl(String symbolicName, Version version, String type, String location) {
+        this.symbolicName = symbolicName;
+        this.version = version;
+        this.type = type;
+        this.location = location;
+    }
+
+    public String getSymbolicName() {
+        return symbolicName;
+    }
+
+    public Version getVersion() {
+        return version;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public String getLocation() {
+        return location;
+    }
+
+    public InputStream open() throws IOException {
+        return new URL(location).openStream();
+    }
+
+}

Added: incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemAdminImpl.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemAdminImpl.java?rev=930209&view=auto
==============================================================================
--- incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemAdminImpl.java (added)
+++ incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemAdminImpl.java Fri Apr  2 09:42:59 2010
@@ -0,0 +1,204 @@
+/*
+ * Licensed 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.aries.subsystem.core.internal;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.Semaphore;
+
+import org.apache.aries.subsystem.Subsystem;
+import org.apache.aries.subsystem.SubsystemAdmin;
+import org.apache.aries.subsystem.SubsystemConstants;
+import org.apache.aries.subsystem.SubsystemException;
+import org.apache.aries.subsystem.spi.Resource;
+import org.apache.aries.subsystem.spi.ResourceResolver;
+import org.apache.felix.utils.manifest.Clause;
+import org.apache.felix.utils.manifest.Parser;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+import org.osgi.framework.SynchronousBundleListener;
+import org.osgi.framework.Version;
+import org.osgi.service.composite.CompositeAdmin;
+import org.osgi.service.composite.CompositeBundle;
+import org.osgi.util.tracker.ServiceTracker;
+
+public class SubsystemAdminImpl implements SubsystemAdmin {
+
+    private static final Version SUBSYSTEM_MANIFEST_VERSION = new Version("1.0");
+
+    final Semaphore lock = new Semaphore(1);
+    final BundleContext context;
+    final Map<Long, Subsystem> subsystems = new HashMap<Long, Subsystem>();
+    final ServiceTracker compositeAdminTracker;
+    final ServiceTracker resourceResolverTracker;
+
+    public SubsystemAdminImpl(BundleContext context) {
+        this.context = context;
+        this.compositeAdminTracker = new ServiceTracker(context, CompositeAdmin.class.getName(), null);
+        this.compositeAdminTracker.open();
+        this.resourceResolverTracker = new ServiceTracker(context, ResourceResolver.class.getName(), null);
+        this.resourceResolverTracker.open();
+        // Track subsystems
+        synchronized (subsystems) {
+            this.context.addBundleListener(new SynchronousBundleListener() {
+                public void bundleChanged(BundleEvent event) {
+                    SubsystemAdminImpl.this.bundleChanged(event);
+                }
+            });
+            loadSubsystems();
+        }
+    }
+
+    public void dispose() {
+        compositeAdminTracker.close();
+        resourceResolverTracker.close();
+    }
+
+    public void bundleChanged(BundleEvent event) {
+        synchronized (subsystems) {
+            if (event.getType() == BundleEvent.UPDATED || event.getType() == BundleEvent.UNINSTALLED) {
+                subsystems.remove(event.getBundle().getBundleId());
+            }
+            if (event.getType() == BundleEvent.INSTALLED || event.getType() == BundleEvent.UPDATED) {
+                Subsystem s = isSubsystem(event.getBundle());
+                if (s != null) {
+                    subsystems.put(s.getSubsystemId(), s);
+                }
+            }
+        }
+    }
+
+    protected void loadSubsystems() {
+        synchronized (subsystems) {
+            subsystems.clear();
+            for (Bundle bundle : context.getBundles()) {
+                Subsystem s = isSubsystem(bundle);
+                if (s != null) {
+                    subsystems.put(s.getSubsystemId(), s);
+                }
+            }
+        }
+    }
+
+    protected Subsystem isSubsystem(Bundle bundle) {
+        if (bundle instanceof CompositeBundle) {
+            String bsn = (String) bundle.getHeaders().get(Constants.BUNDLE_SYMBOLICNAME);
+            Clause[] bsnClauses = Parser.parseHeader(bsn);
+            if ("true".equals(bsnClauses[0].getDirective(SubsystemConstants.SUBSYSTEM_DIRECTIVE))) {
+                return new SubsystemImpl(this, (CompositeBundle) bundle);
+            }
+        }
+        return null;
+    }
+
+    public Subsystem getSubsystem(String scope) {
+        synchronized (subsystems) {
+            for (Subsystem s : subsystems.values()) {
+                if (s.getScope().equals(scope)) {
+                    return s;
+                }
+            }
+            return null;
+        }
+    }
+
+    public Map<Long, Subsystem> getSubsystems() {
+        synchronized (subsystems) {
+            return Collections.unmodifiableMap(subsystems);
+        }
+    }
+
+    public Subsystem install(String url) {
+        return install(url, null);
+    }
+
+    public synchronized Subsystem install(String url, final InputStream is) throws SubsystemException {
+        Resource subsystemResource = new ResourceImpl(null, null, SubsystemConstants.RESOURCE_TYPE_SUBSYSTEM, url) {
+            @Override
+            public InputStream open() throws IOException {
+                if (is != null) {
+                    return is;
+                }
+                return super.open();
+            }
+        };
+        SubsystemResourceProcessor processor = new SubsystemResourceProcessor();
+        SubsystemResourceProcessor.SubsystemSession session = processor.createSession(context);
+        boolean success = false;
+        try {
+            session.process(subsystemResource);
+            session.prepare();
+            session.commit();
+            success = true;
+        } finally {
+            if (!success) {
+                session.rollback();
+            }
+        }
+        for (Subsystem ss : getSubsystems().values()) {
+            if (url.equals(ss.getLocation())) {
+                return ss;
+            }
+        }
+        throw new IllegalStateException();
+    }
+
+    public void update(Subsystem subsystem) {
+        update(subsystem, null);
+    }
+
+    public synchronized void update(Subsystem subsystem, InputStream content) {
+        // TODO: update
+    }
+
+    public synchronized void uninstall(Subsystem ss) {
+        if (!(ss instanceof SubsystemImpl)) {
+            throw new IllegalArgumentException("The given subsystem is not managed by the SubsystemAdmin instance");
+        }
+        SubsystemImpl subsystem = (SubsystemImpl) ss;
+        try {
+            subsystem.composite.uninstall();
+            this.subsystems.remove(subsystem.id);
+        } catch (BundleException e) {
+            // TODO: Rollback
+            throw new SubsystemException("Error while uninstalling the subsystem", e);
+        }
+    }
+
+    public void uninstallForced(Subsystem ss) {
+        if (!(ss instanceof SubsystemImpl)) {
+            throw new IllegalArgumentException("The given subsystem is not managed by the SubsystemAdmin instance");
+        }
+        SubsystemImpl subsystem = (SubsystemImpl) ss;
+        try {
+            subsystem.composite.uninstall();
+        } catch (BundleException e) {
+            // Ignore
+        } finally {
+            this.subsystems.remove(subsystem.id);
+        }
+    }
+
+    public boolean cancel() {
+        // TODO
+        return false;
+    }
+
+}

Added: incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemImpl.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemImpl.java?rev=930209&view=auto
==============================================================================
--- incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemImpl.java (added)
+++ incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemImpl.java Fri Apr  2 09:42:59 2010
@@ -0,0 +1,114 @@
+/*
+ * Licensed 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.aries.subsystem.core.internal;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.aries.subsystem.Subsystem;
+import org.apache.aries.subsystem.SubsystemException;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Version;
+import org.osgi.service.composite.CompositeBundle;
+
+public class SubsystemImpl implements Subsystem {
+
+    final long id;
+    final SubsystemAdminImpl admin;
+    final CompositeBundle composite;
+
+    public SubsystemImpl(SubsystemAdminImpl admin, CompositeBundle composite) {
+        this.admin = admin;
+        this.composite = composite;
+        this.id = composite.getBundleId();
+    }
+
+    public State getState() {
+        switch (composite.getState())
+        {
+            case Bundle.UNINSTALLED:
+                return State.UNINSTALLED;
+            case Bundle.INSTALLED:
+                return State.INSTALLED;
+            case Bundle.RESOLVED:
+                return State.RESOLVED;
+            case Bundle.STARTING:
+                return State.STARTING;
+            case Bundle.ACTIVE:
+                return State.ACTIVE;
+            case Bundle.STOPPING:
+                return State.STOPPING;
+        }
+        throw new SubsystemException("Unable to retrieve subsystem state");
+    }
+
+    public void start() throws SubsystemException {
+        try {
+            composite.start();
+        } catch (BundleException e) {
+            throw new SubsystemException("Unable to start subsystem", e);
+        }
+    }
+
+    public void stop() throws SubsystemException {
+        try {
+            composite.stop();
+        } catch (BundleException e) {
+            throw new SubsystemException("Unable to stop subsystem", e);
+        }
+    }
+
+    public long getSubsystemId() {
+        return composite.getBundleId();
+    }
+
+    public String getLocation() {
+        return composite.getLocation();
+    }
+
+    public String getSymbolicName() {
+        return composite.getSymbolicName();
+    }
+
+    public Version getVersion() {
+        return composite.getVersion();
+    }
+
+    public String getScope() {
+        return getSymbolicName() + "_" + getVersion().toString();
+    }
+
+    public Map<String, String> getHeaders() {
+        return getHeaders(null);
+    }
+
+    public Map<String, String> getHeaders(String locale) {
+        // TODO: retrieve headers
+        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    public Collection<Bundle> getConstituents() {
+        List<Bundle> list = new ArrayList<Bundle>();
+        Bundle[] bundles = composite.getSystemBundleContext().getBundles();
+        for (Bundle bundle : bundles) {
+            if (bundle.getBundleId() != 0) {
+                list.add(bundle);
+            }
+        }
+        return list;
+    }
+}
\ No newline at end of file

Added: incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemResourceProcessor.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemResourceProcessor.java?rev=930209&view=auto
==============================================================================
--- incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemResourceProcessor.java (added)
+++ incubator/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/SubsystemResourceProcessor.java Fri Apr  2 09:42:59 2010
@@ -0,0 +1,289 @@
+/*
+ * Licensed 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.aries.subsystem.core.internal;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+
+import org.apache.aries.subsystem.Subsystem;
+import org.apache.aries.subsystem.SubsystemAdmin;
+import org.apache.aries.subsystem.SubsystemConstants;
+import org.apache.aries.subsystem.SubsystemException;
+import org.apache.aries.subsystem.spi.Resource;
+import org.apache.aries.subsystem.spi.ResourceProcessor;
+import org.apache.aries.subsystem.spi.ResourceResolver;
+import org.apache.felix.utils.manifest.Clause;
+import org.apache.felix.utils.manifest.Parser;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.Version;
+import org.osgi.service.composite.CompositeAdmin;
+import org.osgi.service.composite.CompositeBundle;
+import org.osgi.util.tracker.ServiceTracker;
+
+import static org.apache.aries.subsystem.core.internal.FileUtils.closeQuietly;
+
+import static org.osgi.framework.Constants.*;
+import static org.osgi.service.composite.CompositeConstants.*;
+import static org.apache.aries.subsystem.SubsystemConstants.*;
+
+public class SubsystemResourceProcessor implements ResourceProcessor {
+
+    private static final Version SUBSYSTEM_MANIFEST_VERSION = new Version("1.0");
+
+    public SubsystemSession createSession(BundleContext context) {
+        return new SubsystemSession(context);
+    }
+
+    public static class SubsystemSession implements Session {
+
+        private static final long TIMEOUT = 30000;
+
+        private final BundleContext context;
+        private final Map<Resource, CompositeBundle> installed = new HashMap<Resource, CompositeBundle>();
+        private final Map<Resource, CompositeBundle> removed = new HashMap<Resource, CompositeBundle>();
+        private final Map<String, ServiceTracker> trackers = new HashMap<String, ServiceTracker>();
+        private final Map<BundleContext, Map<String, Session>> sessions = new HashMap<BundleContext, Map<String, Session>>();
+
+
+        public SubsystemSession(BundleContext context) {
+            this.context = context;
+        }
+
+        public void process(Resource res) throws SubsystemException {
+            CompositeBundle composite = null;
+            boolean success = false;
+            try {
+
+                CompositeAdmin admin = getService(CompositeAdmin.class);
+                ResourceResolver resolver = getService(ResourceResolver.class);
+
+                // Unpack the subsystem archive into a temporary directory
+                File dir = File.createTempFile("subsystem", "", null);
+                if (dir == null || !dir.delete() || !dir.mkdir()) {
+                    throw new Exception("Unable to create temporary dir");
+                }
+                FileUtils.unpackArchive(res.open(), dir);
+
+                Manifest manifest = new Manifest();
+                InputStream mis = new FileInputStream(new File(dir, JarFile.MANIFEST_NAME));
+                try {
+                    manifest.read(mis);
+                } finally {
+                    closeQuietly(mis);
+                }
+
+                List<Resource> resource = new ArrayList<Resource>();
+                String resourceHeader = manifest.getMainAttributes().getValue(SUBSYSTEM_RESOURCES);
+                Clause[] resourceClauses = Parser.parseHeader(resourceHeader);
+                for (Clause c : resourceClauses) {
+                    Resource r = resolver.find(c.toString());
+                    resource.add(r);
+                }
+
+                List<Resource> content = new ArrayList<Resource>();
+                String contentHeader = manifest.getMainAttributes().getValue(SUBSYSTEM_CONTENT);
+                Clause[] contentClauses = Parser.parseHeader(contentHeader);
+                for (Clause c : contentClauses) {
+                    Resource r = resolver.find(c.toString());
+                    content.add(r);
+                }
+
+                // TODO: convert resources before calling the resolver?
+
+                List<Resource> additional = resolver.resolve(content, resource);
+
+                // Check subsystem manifest required headers
+                String mfv = manifest.getMainAttributes().getValue(SUBSYSTEM_MANIFESTVERSION);
+                if (mfv == null || mfv.length() == 0) {
+                    throw new SubsystemException("Invalid subsystem manifest version: " + mfv);
+                }
+                try {
+                    Version v = Version.parseVersion(mfv);
+                    if (!SUBSYSTEM_MANIFEST_VERSION.equals(v)) {
+                        throw new SubsystemException("Unsupported subsystem manifest version: " + mfv);
+                    }
+                } catch (IllegalArgumentException e) {
+                    throw new SubsystemException("Invalid subsystem manifest version: " + mfv, e);
+                }
+                String ssn = manifest.getMainAttributes().getValue(SUBSYSTEM_SYMBOLICNAME);
+                if (ssn == null || ssn.length() == 0) {
+                    throw new SubsystemException("Invalid subsystem symbolic name: " + ssn);
+                }
+                // TODO: check attributes / directives on the subsystem symbolic name ?
+                String sv = manifest.getMainAttributes().getValue(SUBSYSTEM_VERSION);
+                if (sv == null || sv.length() == 0) {
+                    throw new SubsystemException("Invalid subsystem version: " + sv);
+                }
+                try {
+                    new Version(sv);
+                } catch (IllegalArgumentException e) {
+                    throw new SubsystemException("Invalid subsystem version: " + sv, e);
+                }
+                // Grab all headers
+                Map<String, String> headers = new HashMap<String, String>();
+                Iterator it = manifest.getMainAttributes().entrySet().iterator();
+                while (it.hasNext()) {
+                    Map.Entry e = (Map.Entry) it.next();
+                    String name = e.getKey().toString();
+                    String value = e.getValue().toString();
+                    headers.put(name, value);
+                }
+                // Create the required composite headers
+                headers.put(BUNDLE_SYMBOLICNAME, ssn + ";" + COMPOSITE_DIRECTIVE + ":=true;" + SUBSYSTEM_DIRECTIVE + ":=true");
+                headers.put(BUNDLE_VERSION, sv);
+                // TODO: compute other composite manifest entries
+                // TODO: compute list of bundles
+
+                composite = admin.installCompositeBundle(
+                                            res.getLocation(),
+                                            headers,
+                                            Collections.<String, String>emptyMap());
+                installed.put(res, composite);
+                composite.getSystemBundleContext().registerService(SubsystemAdmin.class.getName(), new Activator.SubsystemAdminFactory(), null);
+
+                for (Resource r : additional) {
+                    getSession(context, r.getType()).process(r);
+                }
+                for (Resource r : content) {
+                    getSession(composite.getSystemBundleContext(), r.getType()).process(r);
+                }
+
+                success = true;
+
+            } catch (SubsystemException e) {
+                throw e;
+            } catch (Exception e) {
+                throw new SubsystemException("Unable to install subsystem", e);
+            } finally {
+                if (!success && composite != null) {
+                    try {
+                        composite.uninstall();
+                    } catch (Exception e) {
+                        // TODO: log error
+                    }
+                }
+            }
+        }
+
+        public void dropped(Resource resource) throws SubsystemException {
+            // TODO: find corresponding subsystem
+        }
+
+        protected Subsystem findSubsystem(Resource resource) {
+            // TODO
+            return null;
+        }
+
+        public void prepare() throws SubsystemException {
+            for (Map<String, Session> sm : sessions.values()) {
+                for (Session s : sm.values()) {
+                    s.prepare();
+                }
+            }
+        }
+
+        public void commit() {
+            for (Map<String, Session> sm : sessions.values()) {
+                for (Session s : sm.values()) {
+                    s.commit();
+                }
+            }
+            installed.clear();
+            closeTrackers();
+        }
+
+        public void rollback() {
+            for (Map<String, Session> sm : sessions.values()) {
+                for (Session s : sm.values()) {
+                    s.rollback();
+                }
+            }
+            for (CompositeBundle c : installed.values()) {
+                try {
+                    c.uninstall();
+                } catch (BundleException e) {
+                    // Ignore 
+                }
+            }
+            closeTrackers();
+        }
+
+        protected Session getSession(BundleContext context, String type) throws InvalidSyntaxException, InterruptedException {
+            Map<String, Session> sm = this.sessions.get(context);
+            if (sm == null) {
+                sm = new HashMap<String, Session>();
+                this.sessions.put(context, sm);
+            }
+            Session session = sm.get(type);
+            if (session == null) {
+                session = getProcessor(type).createSession(context);
+                sm.put(type, session);
+            }
+            return session;
+        }
+
+        protected ResourceProcessor getProcessor(String type) throws InvalidSyntaxException, InterruptedException {
+            return getService(ResourceProcessor.class, SubsystemConstants.SERVICE_RESOURCE_TYPE + "=" + type);
+        }
+
+        protected <T> T getService(Class<T> clazz) throws InvalidSyntaxException, InterruptedException {
+            return getService(clazz, null);
+        }
+
+        protected <T> T getService(Class<T> clazz, String filter) throws InvalidSyntaxException, InterruptedException {
+            Filter flt;
+            if (filter != null) {
+                if (!filter.startsWith("(")) {
+                    flt = context.createFilter("(&(" + Constants.OBJECTCLASS + "=" + clazz.getName() + ")(" + filter + "))");
+                } else {
+                    flt = context.createFilter("(&(" + Constants.OBJECTCLASS + "=" + clazz.getName() + ")" + filter + ")");
+                }
+            } else {
+                flt = context.createFilter("(" + Constants.OBJECTCLASS + "=" + clazz.getName() + ")");
+            }
+            ServiceTracker tracker = trackers.get(flt.toString());
+            if (tracker == null) {
+                tracker = new ServiceTracker(context, flt, null);
+                tracker.open();
+                trackers.put(flt.toString(), tracker);
+            }
+            T t = (T) tracker.waitForService(TIMEOUT);
+            if (t == null) {
+                throw new SubsystemException("No service available: " + flt);
+            }
+            return t;
+        }
+
+        private void closeTrackers() {
+            for (ServiceTracker t : trackers.values()) {
+                t.close();
+            }
+            trackers.clear();
+        }
+    }
+
+}
\ No newline at end of file

Added: incubator/aries/trunk/subsystem/subsystem-install/pom.xml
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/subsystem/subsystem-install/pom.xml?rev=930209&view=auto
==============================================================================
--- incubator/aries/trunk/subsystem/subsystem-install/pom.xml (added)
+++ incubator/aries/trunk/subsystem/subsystem-install/pom.xml Fri Apr  2 09:42:59 2010
@@ -0,0 +1,62 @@
+<!--
+ 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.aries.subsystem</groupId>
+        <artifactId>subsystem</artifactId>
+        <version>0.1-incubating-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>org.apache.aries.subsystem.install</artifactId>
+    <packaging>bundle</packaging>
+    <name>Apache Aries Subsystem Installer</name>
+    <description>
+      Subsystems Installer.
+    </description>
+
+    <properties>
+        <aries.osgi.private.pkg>
+            org.apache.aries.subsystem.install.internal
+        </aries.osgi.private.pkg>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.aries.subsystem</groupId>
+            <artifactId>org.apache.aries.subsystem.api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.aries.subsystem</groupId>
+            <artifactId>org.osgi.service.composite</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.fileinstall</artifactId>
+            <version>2.0.8</version>
+        </dependency>
+    </dependencies>
+
+</project>