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>.