You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2017/11/07 09:42:58 UTC

[sling-org-apache-sling-installer-factory-subsystems] 01/10: Initial subsystem support for the OSGi installer

This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.installer.factory.subsystems-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-installer-factory-subsystems.git

commit aabcbfb8a829a64bdaed163f655a0a658fb8d244
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Wed Aug 6 16:20:32 2014 +0000

    Initial subsystem support for the OSGi installer
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/installer/factories/subsystems@1616266 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml                                            |  86 ++++++
 .../factories/subsystems/impl/Activator.java       | 100 +++++++
 .../subsystems/impl/InstallSubsystemTask.java      |  60 ++++
 .../subsystems/impl/SubsystemInstaller.java        | 304 +++++++++++++++++++++
 .../subsystems/impl/UninstallSubsystemTask.java    |  73 +++++
 .../subsystems/impl/UpdateSubsystemTask.java       |  77 ++++++
 6 files changed, 700 insertions(+)

diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..d3f0918
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,86 @@
+<!--
+ 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.sling</groupId>
+        <artifactId>sling</artifactId>
+        <version>18</version>
+        <relativePath>../../../parent/pom.xml</relativePath>
+    </parent>
+
+    <artifactId>org.apache.sling.installer.factory.subsystems</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <packaging>bundle</packaging>
+
+    <name>Apache Sling Subsystems Installer</name>
+    <description> 
+        Provides support for subsystems to the Apache Sling OSGi installer
+    </description>
+
+    <scm>
+        <connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/installer/factories/subsystems</connection>
+        <developerConnection> scm:svn:https://svn.apache.org/repos/asf/sling/trunk/installer/factories/subsystems</developerConnection>
+        <url>http://svn.apache.org/viewvc/sling/trunk/installer/factories/subsystems/</url>
+    </scm>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Bundle-Activator>
+                            org.apache.sling.installer.factories.subsystems.impl.Activator
+                        </Bundle-Activator>
+                        <Private-Package>
+                            org.apache.sling.installer.factories.subsystems.impl.*
+                        </Private-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <version>5.0.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+            <version>5.0.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.installer.api</artifactId>
+            <version>1.0.0</version>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/src/main/java/org/apache/sling/installer/factories/subsystems/impl/Activator.java b/src/main/java/org/apache/sling/installer/factories/subsystems/impl/Activator.java
new file mode 100644
index 0000000..2a4e173
--- /dev/null
+++ b/src/main/java/org/apache/sling/installer/factories/subsystems/impl/Activator.java
@@ -0,0 +1,100 @@
+/*
+ * 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.sling.installer.factories.subsystems.impl;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.apache.sling.installer.api.tasks.InstallTaskFactory;
+import org.apache.sling.installer.api.tasks.ResourceTransformer;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.subsystem.Subsystem;
+import org.osgi.service.subsystem.SubsystemConstants;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
+
+public class Activator implements BundleActivator {
+
+    /** The service tracker for the root subsystem */
+    private ServiceTracker<Subsystem, Subsystem> rootSubsystemTracker;
+
+    /** The service registration for the installer service. */
+    private ServiceRegistration<?> serviceReg;
+
+    /**
+     * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
+     */
+    public void start(final BundleContext context) throws Exception {
+        this.rootSubsystemTracker = new ServiceTracker<Subsystem, Subsystem>(context,
+            "&(" + Constants.OBJECTCLASS + "=" + Subsystem.class.getName() + ")" +
+             "(" + SubsystemConstants.SUBSYSTEM_ID_PROPERTY + "=0)",
+
+             new ServiceTrackerCustomizer<Subsystem, Subsystem>() {
+
+                public Subsystem addingService(final ServiceReference<Subsystem> reference) {
+                    final Subsystem service = context.getService(reference);
+                    if ( service != null ) {
+                        registerInstaller(context, service);
+                    }
+                    return service;
+                }
+
+                public void modifiedService(final ServiceReference<Subsystem> reference, final Subsystem service) {
+                    // nothing to do
+                }
+
+                public void removedService(final ServiceReference<Subsystem> reference, final Subsystem service) {
+                    unregisterInstaller();
+                }
+
+        });
+        this.rootSubsystemTracker.open();
+    }
+
+    /**
+     * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
+     */
+    public void stop(final BundleContext context) throws Exception {
+        if ( this.rootSubsystemTracker != null ) {
+            this.rootSubsystemTracker.close();
+            this.rootSubsystemTracker = null;
+        }
+        this.unregisterInstaller();
+    }
+
+    private void registerInstaller(final BundleContext context, final Subsystem rootSubsystem) {
+        final Dictionary<String, Object> props = new Hashtable<String, Object>();
+        props.put(Constants.SERVICE_DESCRIPTION, "Apache Sling Installer Support for Subsystems");
+        props.put(Constants.SERVICE_VENDOR, "The Apache Software Foundation");
+        this.serviceReg = context.registerService(
+                new String[] {ResourceTransformer.class.getName(), InstallTaskFactory.class.getName()},
+                new SubsystemInstaller(rootSubsystem, context), props);
+    }
+
+    private void unregisterInstaller() {
+        if ( serviceReg != null ) {
+            serviceReg.unregister();
+            serviceReg = null;
+        }
+    }
+}
diff --git a/src/main/java/org/apache/sling/installer/factories/subsystems/impl/InstallSubsystemTask.java b/src/main/java/org/apache/sling/installer/factories/subsystems/impl/InstallSubsystemTask.java
new file mode 100644
index 0000000..3f1e10f
--- /dev/null
+++ b/src/main/java/org/apache/sling/installer/factories/subsystems/impl/InstallSubsystemTask.java
@@ -0,0 +1,60 @@
+/*
+ * 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.sling.installer.factories.subsystems.impl;
+
+import java.io.IOException;
+
+import org.apache.sling.installer.api.tasks.ChangeStateTask;
+import org.apache.sling.installer.api.tasks.InstallTask;
+import org.apache.sling.installer.api.tasks.InstallationContext;
+import org.apache.sling.installer.api.tasks.ResourceState;
+import org.apache.sling.installer.api.tasks.TaskResource;
+import org.apache.sling.installer.api.tasks.TaskResourceGroup;
+import org.osgi.service.subsystem.Subsystem;
+
+public class InstallSubsystemTask extends InstallTask {
+
+    private static final String INSTALL_ORDER = "53-";
+
+    private final Subsystem rootSubsystem;
+
+    public InstallSubsystemTask(final TaskResourceGroup grp, final Subsystem rootSubsystem) {
+        super(grp);
+        this.rootSubsystem = rootSubsystem;
+    }
+
+    @Override
+    public void execute(final InstallationContext ctx) {
+        final TaskResource tr = this.getResource();
+        ctx.log("Installing new subsystem from {}", tr);
+
+        try {
+            this.rootSubsystem.install(tr.getURL(), tr.getInputStream());
+            ctx.addTaskToCurrentCycle(new ChangeStateTask(this.getResourceGroup(), ResourceState.INSTALLED));
+        } catch (final IOException e) {
+            ctx.log("Unable to install subsystem {} : {}", tr, e);
+            ctx.addTaskToCurrentCycle(new ChangeStateTask(this.getResourceGroup(), ResourceState.IGNORED));
+        }
+    }
+
+    @Override
+    public String getSortKey() {
+        return INSTALL_ORDER + getResource().getURL();
+    }
+}
diff --git a/src/main/java/org/apache/sling/installer/factories/subsystems/impl/SubsystemInstaller.java b/src/main/java/org/apache/sling/installer/factories/subsystems/impl/SubsystemInstaller.java
new file mode 100644
index 0000000..2b4b3c5
--- /dev/null
+++ b/src/main/java/org/apache/sling/installer/factories/subsystems/impl/SubsystemInstaller.java
@@ -0,0 +1,304 @@
+/*
+ * 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.sling.installer.factories.subsystems.impl;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.jar.JarInputStream;
+import java.util.jar.Manifest;
+
+import org.apache.sling.installer.api.InstallableResource;
+import org.apache.sling.installer.api.tasks.ChangeStateTask;
+import org.apache.sling.installer.api.tasks.InstallTask;
+import org.apache.sling.installer.api.tasks.InstallTaskFactory;
+import org.apache.sling.installer.api.tasks.RegisteredResource;
+import org.apache.sling.installer.api.tasks.ResourceState;
+import org.apache.sling.installer.api.tasks.ResourceTransformer;
+import org.apache.sling.installer.api.tasks.TaskResource;
+import org.apache.sling.installer.api.tasks.TaskResourceGroup;
+import org.apache.sling.installer.api.tasks.TransformationResult;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.Version;
+import org.osgi.service.subsystem.Subsystem;
+import org.osgi.service.subsystem.SubsystemConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This is an extension for the OSGi installer
+ * It listens for files ending with ".esa" and a proper manifest. Though subsystems does
+ * not require a complete manifest, the installer supports only subsystems with the
+ * basic info.
+ */
+public class SubsystemInstaller
+    implements ResourceTransformer, InstallTaskFactory {
+
+    private static final String TYPE_SUBSYSTEM = "esa";
+
+    private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+    private final Subsystem rootSubsystem;
+
+    private final BundleContext bundleContext;
+
+    public SubsystemInstaller(final Subsystem root, final BundleContext bundleContext) {
+        this.rootSubsystem = root;
+        this.bundleContext = bundleContext;
+    }
+
+    /**
+     * @see org.apache.sling.installer.api.tasks.ResourceTransformer#transform(org.apache.sling.installer.api.tasks.RegisteredResource)
+     */
+    public TransformationResult[] transform(final RegisteredResource resource) {
+        if ( resource.getType().equals(InstallableResource.TYPE_FILE) ) {
+            if ( resource.getURL().endsWith("." + TYPE_SUBSYSTEM) ) {
+                logger.info("Found potential subsystem resource {}", resource);
+                final SubsystemInfo headers = readSubsystemHeaders(resource);
+                if ( headers != null ) {
+                    // check the version for validity
+                    boolean validVersion = true;
+                    try {
+                        new Version(headers.version);
+                    } catch (final IllegalArgumentException iae) {
+                        logger.info("Rejecting subsystem {} from {} due to invalid version information: {}.",
+                                new Object[] {headers.symbolicName, resource, headers.version});
+                        validVersion = false;
+                    }
+                    if ( validVersion ) {
+                        final Map<String, Object> attr = new HashMap<String, Object>();
+                        attr.put(SubsystemConstants.SUBSYSTEM_SYMBOLICNAME, headers.symbolicName);
+                        attr.put(SubsystemConstants.SUBSYSTEM_VERSION, headers.version);
+
+                        final TransformationResult tr = new TransformationResult();
+                        tr.setId(headers.symbolicName);
+                        tr.setResourceType(TYPE_SUBSYSTEM);
+                        tr.setAttributes(attr);
+                        tr.setVersion(new Version(headers.version));
+
+                        return new TransformationResult[] {tr};
+                    }
+
+                } else {
+                    logger.info("Subsystem resource does not have required headers.");
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Check that the required attributes are available.
+     * This is just a sanity check
+     */
+    private SubsystemInfo checkResource(final TaskResourceGroup toActivate) {
+        final TaskResource rsrc = toActivate.getActiveResource();
+
+        SubsystemInfo result = null;
+        final String symbolicName = (String) rsrc.getAttribute(SubsystemConstants.SUBSYSTEM_SYMBOLICNAME);
+        if ( symbolicName == null ) {
+            logger.error("Subsystem resource is missing symbolic name {}", rsrc);
+        } else {
+            final String version = (String)rsrc.getAttribute(SubsystemConstants.SUBSYSTEM_VERSION);
+            if ( version == null ) {
+                logger.error("Subsystem resource is missing version {}", rsrc);
+            } else {
+                // check the version for validity
+                boolean validVersion = true;
+                try {
+                    new Version(version);
+                } catch (final IllegalArgumentException iae) {
+                    logger.info("Rejecting subsystem {} from {} due to invalid version information: {}.",
+                            new Object[] {symbolicName, rsrc, version});
+                    validVersion = false;
+                }
+                if ( validVersion ) {
+                    result = new SubsystemInfo();
+                    result.symbolicName = symbolicName;
+                    result.version = version;
+                }
+            }
+        }
+        return result;
+    }
+
+    private ServiceReference<Subsystem> getSubsystemReference(final String symbolicName) {
+        // search a subsystem with the symbolic name
+        ServiceReference<Subsystem> ref = null;
+        try {
+            final Collection<ServiceReference<Subsystem>> refs = this.bundleContext.getServiceReferences(Subsystem.class, "(subsystem.symbolicName=" + symbolicName + ")");
+            if ( refs.size() > 0 ) {
+                ref = refs.iterator().next();
+            }
+        } catch (final InvalidSyntaxException e) {
+            logger.error("Problem searching for subsystem with symbolic name " + symbolicName, e);
+        }
+        return ref;
+    }
+
+    /**
+     * @see org.apache.sling.installer.api.tasks.InstallTaskFactory#createTask(org.apache.sling.installer.api.tasks.TaskResourceGroup)
+     */
+    public InstallTask createTask(final TaskResourceGroup toActivate) {
+        final InstallTask result;
+
+        final TaskResource rsrc = toActivate.getActiveResource();
+        if ( rsrc.getType().equals(TYPE_SUBSYSTEM) ) {
+
+            // check if the required info is available
+            final SubsystemInfo info = checkResource(toActivate);
+            if ( info == null ) {
+                // ignore as info is missing
+                result = new ChangeStateTask(toActivate, ResourceState.IGNORED);
+            } else {
+                // search a subsystem with the symbolic name
+                final ServiceReference<Subsystem> ref = this.getSubsystemReference(info.symbolicName);
+
+                final Version newVersion = new Version(info.version);
+                final Version oldVersion = (ref == null ? null : (Version)ref.getProperty("subsystem.version"));
+
+                // Install
+                if ( rsrc.getState() == ResourceState.INSTALL ) {
+                    if ( oldVersion != null ) {
+
+                        final int compare = oldVersion.compareTo(newVersion);
+                        if (compare < 0) {
+                            // installed version is lower -> update
+                            result = new UpdateSubsystemTask(toActivate, this.bundleContext, ref, this.rootSubsystem);
+                        } else {
+                            // TODO - support SNAPSHOT?
+                            logger.debug("{} is not installed, subsystem with same or higher version is already installed: {}", info, newVersion);
+                            result = new ChangeStateTask(toActivate, ResourceState.IGNORED);
+                        }
+                    } else {
+                        result = new InstallSubsystemTask(toActivate, this.rootSubsystem);
+                    }
+
+                // Uninstall
+                } else if ( rsrc.getState() == ResourceState.UNINSTALL ) {
+                    if ( oldVersion == null ) {
+                        logger.error("Nothing to uninstall. {} is currently not installed.", info);
+                        result = new ChangeStateTask(toActivate, ResourceState.IGNORED);
+                    } else {
+
+                        final int compare = oldVersion.compareTo(newVersion);
+                        if ( compare == 0 ) {
+                            result = new UninstallSubsystemTask(toActivate, this.bundleContext, ref);
+                        } else {
+                            logger.error("Nothing to uninstall. {} is currently not installed, different version is installed {}", info, oldVersion);
+                            result = new ChangeStateTask(toActivate, ResourceState.IGNORED);
+                        }
+                    }
+                } else {
+                    result = null;
+                }
+            }
+        } else {
+            result = null;
+        }
+        return result;
+    }
+
+    /**
+     * Read the manifest from supplied input stream, which is closed before return.
+     */
+    private static Manifest getManifest(final RegisteredResource rsrc, final Logger logger)
+    throws IOException {
+        final InputStream ins = rsrc.getInputStream();
+
+        Manifest result = null;
+
+        if ( ins != null ) {
+            JarInputStream jis = null;
+            try {
+                jis = new JarInputStream(ins);
+                result = jis.getManifest();
+
+                // SLING-2288 : if this is a jar file, but the manifest is not the first entry
+                //              log a warning
+                if ( rsrc.getURL().endsWith(".jar") && result == null ) {
+                    logger.warn("Resource {} does not have the manifest as its first entry in the archive. If this is " +
+                                "a subsystem, make sure to put the manifest first in the jar file.", rsrc.getURL());
+                }
+            } finally {
+
+                // close the jar stream or the input stream, if the jar
+                // stream is set, we don't need to close the input stream
+                // since closing the jar stream closes the input stream
+                if (jis != null) {
+                    try {
+                        jis.close();
+                    } catch (IOException ignore) {
+                    }
+                } else {
+                    try {
+                        ins.close();
+                    } catch (IOException ignore) {
+                    }
+                }
+            }
+        }
+        return result;
+    }
+
+    final static public class SubsystemInfo {
+        public String symbolicName;
+        public String version;
+        @Override
+
+        public String toString() {
+            return "Subsystem[symbolicName=" + symbolicName + ", version="
+                    + version + "]";
+        }
+
+    }
+
+    /**
+     * Read the subsystem info from the manifest (if available)
+     */
+    private SubsystemInfo readSubsystemHeaders(final RegisteredResource resource) {
+        try {
+            final Manifest m = SubsystemInstaller.getManifest(resource, logger);
+            if (m != null) {
+                final String sn = m.getMainAttributes().getValue(SubsystemConstants.SUBSYSTEM_SYMBOLICNAME);
+                if (sn != null) {
+                    final String v = m.getMainAttributes().getValue(SubsystemConstants.SUBSYSTEM_VERSION);
+                    final int paramPos = sn.indexOf(';');
+                    final String symbolicName = (paramPos == -1 ? sn : sn.substring(0, paramPos));
+                    final SubsystemInfo headers = new SubsystemInfo();
+                    headers.symbolicName = symbolicName;
+                    headers.version = v;
+
+                    // if no version is specified, use default version
+                    if ( headers.version == null ) {
+                        headers.version = "0.0.0.0";
+                    }
+                    return headers;
+                }
+            }
+        } catch (final IOException ignore) {
+            // ignore
+        }
+        return null;
+    }
+}
diff --git a/src/main/java/org/apache/sling/installer/factories/subsystems/impl/UninstallSubsystemTask.java b/src/main/java/org/apache/sling/installer/factories/subsystems/impl/UninstallSubsystemTask.java
new file mode 100644
index 0000000..4ae0dab
--- /dev/null
+++ b/src/main/java/org/apache/sling/installer/factories/subsystems/impl/UninstallSubsystemTask.java
@@ -0,0 +1,73 @@
+/*
+ * 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.sling.installer.factories.subsystems.impl;
+
+import org.apache.sling.installer.api.tasks.ChangeStateTask;
+import org.apache.sling.installer.api.tasks.InstallTask;
+import org.apache.sling.installer.api.tasks.InstallationContext;
+import org.apache.sling.installer.api.tasks.ResourceState;
+import org.apache.sling.installer.api.tasks.TaskResource;
+import org.apache.sling.installer.api.tasks.TaskResourceGroup;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.subsystem.Subsystem;
+
+public class UninstallSubsystemTask extends InstallTask {
+
+    private static final String INSTALL_ORDER = "52-";
+
+    private final ServiceReference<Subsystem> subsystemReference;
+
+    private final BundleContext bundleContext;
+
+    public UninstallSubsystemTask(final TaskResourceGroup grp,
+            final BundleContext bundleContext,
+            final ServiceReference<Subsystem> ref) {
+        super(grp);
+        this.bundleContext = bundleContext;
+        this.subsystemReference = ref;
+    }
+
+    @Override
+    public void execute(final InstallationContext ctx) {
+        final TaskResource tr = this.getResource();
+        ctx.log("Uninstalling subsystem from {}", tr);
+
+        Subsystem subsystem = null;
+        try {
+            subsystem = this.bundleContext.getService(this.subsystemReference);
+            if ( subsystem != null ) {
+                subsystem.uninstall();
+                ctx.addTaskToCurrentCycle(new ChangeStateTask(this.getResourceGroup(), ResourceState.UNINSTALLED));
+            } else {
+                ctx.log("Unable to uninstall subsystem {}.", tr);
+                ctx.addTaskToCurrentCycle(new ChangeStateTask(this.getResourceGroup(), ResourceState.IGNORED));
+            }
+        } finally {
+            if ( subsystem != null ) {
+                this.bundleContext.ungetService(this.subsystemReference);
+            }
+        }
+    }
+
+    @Override
+    public String getSortKey() {
+        return INSTALL_ORDER + getResource().getURL();
+    }
+}
diff --git a/src/main/java/org/apache/sling/installer/factories/subsystems/impl/UpdateSubsystemTask.java b/src/main/java/org/apache/sling/installer/factories/subsystems/impl/UpdateSubsystemTask.java
new file mode 100644
index 0000000..3da254b
--- /dev/null
+++ b/src/main/java/org/apache/sling/installer/factories/subsystems/impl/UpdateSubsystemTask.java
@@ -0,0 +1,77 @@
+/*
+ * 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.sling.installer.factories.subsystems.impl;
+
+import org.apache.sling.installer.api.tasks.ChangeStateTask;
+import org.apache.sling.installer.api.tasks.InstallTask;
+import org.apache.sling.installer.api.tasks.InstallationContext;
+import org.apache.sling.installer.api.tasks.ResourceState;
+import org.apache.sling.installer.api.tasks.TaskResource;
+import org.apache.sling.installer.api.tasks.TaskResourceGroup;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.subsystem.Subsystem;
+
+public class UpdateSubsystemTask extends InstallTask {
+
+    private static final String INSTALL_ORDER = "54-";
+
+    private final Subsystem rootSubsystem;
+
+    private final ServiceReference<Subsystem> subsystemReference;
+
+    private final BundleContext bundleContext;
+
+    public UpdateSubsystemTask(final TaskResourceGroup grp,
+            final BundleContext bundleContext,
+            final ServiceReference<Subsystem> ref,
+            final Subsystem rootSubsystem) {
+        super(grp);
+        this.bundleContext = bundleContext;
+        this.subsystemReference = ref;
+        this.rootSubsystem = rootSubsystem;
+    }
+
+    @Override
+    public void execute(final InstallationContext ctx) {
+        final TaskResource tr = this.getResource();
+        ctx.log("Updating subsystem from {}", tr);
+
+        Subsystem subsystem = null;
+        try {
+            subsystem = this.bundleContext.getService(this.subsystemReference);
+            if ( subsystem != null ) {
+                subsystem.uninstall();
+                ctx.addTaskToCurrentCycle(new InstallSubsystemTask(this.getResourceGroup(), this.rootSubsystem));
+            } else {
+                ctx.log("Unable to update subsystem {}.", tr);
+                ctx.addTaskToCurrentCycle(new ChangeStateTask(this.getResourceGroup(), ResourceState.IGNORED));
+            }
+        } finally {
+            if ( subsystem != null ) {
+                this.bundleContext.ungetService(this.subsystemReference);
+            }
+        }
+    }
+
+    @Override
+    public String getSortKey() {
+        return INSTALL_ORDER + getResource().getURL();
+    }
+}

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.