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/10/18 23:26:55 UTC

[sling-org-apache-sling-installer-factory-packages] 01/11: SLING-6082 : Add installer factory for content packages

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

rombert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-installer-factory-packages.git

commit ebf980aaa8c0a04a3205a4b52da639bb9488cc8a
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Fri Oct 7 08:40:29 2016 +0000

    SLING-6082 : Add installer factory for content packages
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@1763696 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml                                            |  87 +++++
 .../factory/packages/impl/PackageTransformer.java  | 367 +++++++++++++++++++++
 2 files changed, 454 insertions(+)

diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..5fb25fd
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0"?>
+<!--
+ 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>28</version>
+        <relativePath/>
+    </parent>
+
+    <artifactId>org.apache.sling.installer.factory.packages</artifactId>
+    <version>0.1.0-SNAPSHOT</version>
+    <packaging>bundle</packaging>
+
+    <name>Apache Sling Installer Content Package Support</name>
+    <description> 
+        Provides support for content packages to the Apache Sling OSGi installer
+    </description>
+
+    <scm>
+        <connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/installer/factories/packages</connection>
+        <developerConnection> scm:svn:https://svn.apache.org/repos/asf/sling/trunk/installer/factories/packages</developerConnection>
+        <url>http://svn.apache.org/viewvc/sling/trunk/installer/factories/packages</url>
+    </scm>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+            </plugin>
+        </plugins>
+    </build>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>osgi.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>javax.jcr</groupId>
+            <artifactId>jcr</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.jcr.api</artifactId>
+            <version>2.1.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.installer.core</artifactId>
+            <version>3.5.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.jackrabbit.vault</groupId>
+            <artifactId>org.apache.jackrabbit.vault</artifactId>
+            <version>3.1.30</version>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git a/src/main/java/org/apache/sling/installer/factory/packages/impl/PackageTransformer.java b/src/main/java/org/apache/sling/installer/factory/packages/impl/PackageTransformer.java
new file mode 100644
index 0000000..d46c905
--- /dev/null
+++ b/src/main/java/org/apache/sling/installer/factory/packages/impl/PackageTransformer.java
@@ -0,0 +1,367 @@
+/*
+ * 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.factory.packages.impl;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.zip.ZipInputStream;
+
+import javax.jcr.Session;
+
+import org.apache.jackrabbit.vault.fs.io.ImportOptions;
+import org.apache.jackrabbit.vault.packaging.Dependency;
+import org.apache.jackrabbit.vault.packaging.JcrPackage;
+import org.apache.jackrabbit.vault.packaging.JcrPackageManager;
+import org.apache.jackrabbit.vault.packaging.PackageId;
+import org.apache.jackrabbit.vault.packaging.Packaging;
+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.InstallationContext;
+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.RetryHandler;
+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.apache.sling.jcr.api.SlingRepository;
+import org.osgi.framework.Version;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The package transformer:
+ * <ul>
+ *   <li>detects content packages (ResourceTransformer)
+ *   <li>and creates tasks for installing / removing of content packages
+ * </ul>
+ */
+@Component( service = {ResourceTransformer.class, InstallTaskFactory.class})
+public class PackageTransformer implements ResourceTransformer, InstallTaskFactory {
+
+    /** The attribute holding the package id. */
+    private static final String ATTR_PCK_ID = "package-id";
+
+    /** The resource type for packages. */
+    private static final String RESOURCE_TYPE = "content-package";
+
+    /**
+     * The logger.
+     */
+    private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+    @Reference
+    private SlingRepository repository;
+
+    @Reference
+    private Packaging pkgSvc;
+
+    @Reference
+    private RetryHandler retryHandler;
+
+    /**
+     * @see org.apache.sling.installer.api.tasks.ResourceTransformer#transform(org.apache.sling.installer.api.tasks.RegisteredResource)
+     */
+    @Override
+    public TransformationResult[] transform(final RegisteredResource resource) {
+        if (resource.getType().equals(InstallableResource.TYPE_FILE)) {
+            return checkForPackage(resource);
+        }
+        return null;
+    }
+
+    /**
+     * Check if the resource is a content package
+     * @param resource The resource
+     * @return {@code null} if not a content package, a result otherwise
+     */
+    private TransformationResult[] checkForPackage(final RegisteredResource resource) {
+        // first check if this is a zip archive
+        try (final ZipInputStream zin = new ZipInputStream(new BufferedInputStream(resource.getInputStream()))) {
+            if (zin.getNextEntry() == null) {
+                return null;
+            }
+        } catch (final IOException ioe) {
+            logger.debug("Unable to read resource.", ioe);
+            return null;
+        }
+
+        Session session = null;
+        JcrPackage pck = null;
+        try {
+            // create an admin session
+            session = repository.loginAdministrative(null);
+
+            final JcrPackageManager pckMgr = pkgSvc.getPackageManager(session);
+            pck = pckMgr.upload(resource.getInputStream(), true, true);
+            if (pck.isValid()) {
+                final PackageId pid = pck.getDefinition().getId();
+                final Map<String, Object> attrs = new HashMap<String, Object>();
+                attrs.put(ATTR_PCK_ID, pid.toString());
+
+                final TransformationResult tr = new TransformationResult();
+                tr.setId(pid.getGroup() + ':' + pid.getName());
+                tr.setResourceType(RESOURCE_TYPE);
+                tr.setAttributes(attrs);
+
+                // version
+                final String version = pid.getVersionString();
+                if ( version.length() > 0 ) {
+                    tr.setVersion(new Version(cleanupVersion(version)));
+                }
+
+                return new TransformationResult[] {tr};
+            }
+        } catch (final Exception ioe) {
+            logger.debug("Unable to check content package " + resource.getURL(), ioe);
+        } finally {
+            if (pck != null) {
+                pck.close();
+            }
+            if (session != null) {
+                session.logout();
+            }
+        }
+        return null;
+    }
+
+    /**
+     * @see org.apache.sling.installer.api.tasks.InstallTaskFactory#createTask(org.apache.sling.installer.api.tasks.TaskResourceGroup)
+     */
+    @Override
+    public InstallTask createTask(final TaskResourceGroup toActivate) {
+        final TaskResource resource = toActivate.getActiveResource();
+        if (resource == null || !resource.getType().equals(RESOURCE_TYPE)) {
+            return null;
+        }
+
+        // extract the package id
+        final String id = (String)resource.getAttribute(ATTR_PCK_ID);
+        final PackageId pkgId = PackageId.fromString(id);
+        if (pkgId == null) {
+            logger.error("Error during processing of {}: Package id is wrong/null.", resource);
+            return new ChangeStateTask(toActivate, ResourceState.IGNORED);
+        }
+
+        if (resource.getState() == ResourceState.INSTALL) {
+            return new InstallPackageTask(pkgId, toActivate);
+        }
+        return new UninstallPackageTask(pkgId, toActivate);
+    }
+
+    /**
+     * Task for installing a package.
+     */
+    private class InstallPackageTask extends InstallTask {
+
+        private final PackageId pkgId;
+
+        public InstallPackageTask(final PackageId pkgId, final TaskResourceGroup erl) {
+            super(erl);
+            this.pkgId = pkgId;
+        }
+
+        @Override
+        public void execute(final InstallationContext ctx) {
+            final TaskResource resource = this.getResource();
+
+            // now check the dependencies
+            Session session = null;
+            JcrPackage pkg = null;
+            try {
+                session = repository.loginAdministrative(null);
+                final JcrPackageManager pkgMgr = pkgSvc.getPackageManager(session);
+
+                // open package
+                pkg = pkgMgr.open(pkgId);
+                if (pkg == null) {
+                    logger.error("Error during installation of {}: Package {} missing.", resource, pkgId);
+                    this.setFinishedState(ResourceState.IGNORED);
+                    return;
+                }
+
+                // check if package was installed in the meantime
+                if (pkg.isInstalled()) {
+                    logger.info("Package {} was installed externally. Marking as installed.", pkgId);
+                    this.setFinishedState(ResourceState.INSTALLED);
+                    return;
+                }
+
+                // check if dependencies are installed
+                for (final Dependency d : pkg.getDefinition().getDependencies()) {
+                    if (pkgMgr.resolve(d, true) == null) {
+                        logger.info("Delaying installation of {} due to missing dependency {}.", pkgId, d);
+                        return;
+                    }
+                }
+
+                // finally, install package
+                final ImportOptions opts = new ImportOptions();
+
+                pkg.install(opts);
+
+                ctx.log("Content package installed: {}", resource);
+                setFinishedState(ResourceState.INSTALLED);
+
+                // notify retry handler to install dependend packages.
+                retryHandler.scheduleRetry();
+
+            } catch (final Exception e) {
+                logger.error("Error while processing install task of {}.", resource, e);
+                this.setFinishedState(ResourceState.IGNORED);
+            } finally {
+                if (pkg != null) {
+                    pkg.close();
+                }
+                if (session != null) {
+                    session.logout();
+                }
+            }
+        }
+
+        @Override
+        public String getSortKey() {
+            return "25-" + getResource().getEntityId();
+        }
+    }
+
+    /**
+     * Task for uninstalling a package.
+     */
+    private final class UninstallPackageTask extends InstallTask {
+
+        private final PackageId pkgId;
+
+        public UninstallPackageTask(final PackageId pkgId, final TaskResourceGroup erl) {
+            super(erl);
+            this.pkgId = pkgId;
+        }
+
+        @Override
+        public void execute(final InstallationContext ctx) {
+            Session session = null;
+            JcrPackage pkg = null;
+            try {
+                session = repository.loginAdministrative(null);
+                final JcrPackageManager pkgMgr = pkgSvc.getPackageManager(session);
+
+                pkg = pkgMgr.open(this.pkgId);
+                if ( pkg != null ) {
+                    final ImportOptions opts = new ImportOptions();
+                    pkg.uninstall(opts);
+                }
+
+            } catch (final Exception e) {
+                logger.error("Error while processing uninstall task of {}.", pkgId, e);
+            } finally {
+                if (pkg != null) {
+                    pkg.close();
+                }
+                if (session != null) {
+                    session.logout();
+                }
+            }
+            ctx.log("Uninstalled content package {}", getResource());
+            setFinishedState(ResourceState.UNINSTALLED);
+            retryHandler.scheduleRetry();
+        }
+
+        @Override
+        public String getSortKey() {
+            return "55-" + getResource().getEntityId();
+        }
+    }
+
+    private static final Pattern FUZZY_VERSION = Pattern.compile( "(\\d+)(\\.(\\d+)(\\.(\\d+))?)?([^a-zA-Z0-9](.*))?",
+            Pattern.DOTALL );
+
+    /**
+     * Clean up version parameters. Other builders use more fuzzy definitions of
+     * the version syntax. This method cleans up such a version to match an OSGi
+     * version.
+     *
+     * @param version The version string to clean up
+     * @return the clean version
+     */
+    private static String cleanupVersion(final String version) {
+        final StringBuilder result = new StringBuilder();
+        final Matcher m = FUZZY_VERSION.matcher( version );
+        if ( m.matches() ) {
+            final String major = m.group( 1 );
+            final String minor = m.group( 3 );
+            final String micro = m.group( 5 );
+            final String qualifier = m.group( 7 );
+
+            if ( major != null ) {
+                result.append( major );
+                if ( minor != null ) {
+                    result.append( "." );
+                    result.append( minor );
+                    if ( micro != null ) {
+                        result.append( "." );
+                        result.append( micro );
+                        if ( qualifier != null ) {
+                            result.append( "." );
+                            cleanupModifier( result, qualifier );
+                        }
+                    } else if ( qualifier != null ) {
+                        result.append( ".0." );
+                        cleanupModifier( result, qualifier );
+                    } else {
+                        result.append( ".0" );
+                    }
+                } else if ( qualifier != null ) {
+                    result.append( ".0.0." );
+                    cleanupModifier( result, qualifier );
+                } else {
+                    result.append( ".0.0" );
+                }
+            }
+        } else {
+            result.append( "0.0.0." );
+            cleanupModifier( result, version );
+        }
+        return result.toString();
+    }
+
+
+    private static void cleanupModifier( final StringBuilder result, final String modifier ) {
+        for ( int i = 0; i < modifier.length(); i++ ) {
+            char c = modifier.charAt( i );
+            if ( ( c >= '0' && c <= '9' )
+              || ( c >= 'a' && c <= 'z' )
+              || ( c >= 'A' && c <= 'Z' )
+              || c == '_'
+              || c == '-' ) {
+                result.append( c );
+            } else {
+                result.append( '_' );
+            }
+        }
+    }
+}

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