karlpauls closed pull request #15: SLING-7870 - Proposal for FSRegistry based Content Handler Extension URL: https://github.com/apache/sling-whiteboard/pull/15
This is a PR merged from a forked repository. As GitHub hides the original diff on merge, it is displayed below for the sake of provenance: As this is a foreign pull request (from a fork), the diff is supplied below (as it won't show otherwise due to GitHub magic): diff --git a/featuremodel/feature-content-extension/README.md b/featuremodel/feature-content-extension/README.md new file mode 100644 index 0000000..7a5d244 --- /dev/null +++ b/featuremodel/feature-content-extension/README.md @@ -0,0 +1,6 @@ +# Apache Sling Featuremodel - Content Deployment Exension + +This module is part of the [Apache Sling](https://sling.apache.org) project. + +This project is about creating an Extension to the Sling Featuremodel Launcher to be able to precalculate a FSPackageRegistry and inject precalculated Executionplans to be deployed into the repository during startup. + diff --git a/featuremodel/feature-content-extension/pom.xml b/featuremodel/feature-content-extension/pom.xml new file mode 100644 index 0000000..9c5b284 --- /dev/null +++ b/featuremodel/feature-content-extension/pom.xml @@ -0,0 +1,159 @@ +<?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/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.apache.sling</groupId> + <artifactId>sling</artifactId> + <version>34</version> + <relativePath /> + </parent> + + <artifactId>org.apache.sling.feature.extension.content</artifactId> + <version>0.0.1-SNAPSHOT</version> + <name>Sling Featuremodel - Content Deployment Exension</name> + + <licenses> + <!-- This is also in the Apache parent POM, but adding it here includes + it in dependency-reduced-pom.xml so that it passes the rat check. --> + <license> + <name>The Apache Software License, Version 2.0</name> + <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url> + </license> + </licenses> + + <properties> + <jdk.version>8</jdk.version> + </properties> + + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-shade-plugin</artifactId> + <executions> + <execution> + <phase>package</phase> + <goals> + <goal>shade</goal> + </goals> + <configuration> + <minimizeJar>true</minimizeJar> + <filters> + <filter> + <includes> + <include>org.apache.commons:collections:*</include> + </includes> + </filter> + </filters> + </configuration> + </execution> + </executions> + + </plugin> + <plugin> + <groupId>org.apache.rat</groupId> + <artifactId>apache-rat-plugin</artifactId> + <configuration> + <excludes> + <exclude>src/main/resources/META-INF/services/**</exclude> + </excludes> + </configuration> + </plugin> + </plugins> + </build> + <dependencies> + <dependency> + <groupId>org.apache.jackrabbit.vault</groupId> + <artifactId>org.apache.jackrabbit.vault</artifactId> + <version>3.2.1-SNAPSHOT</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.apache.sling</groupId> + <artifactId>org.apache.sling.feature.launcher</artifactId> + <version>0.1.0-SNAPSHOT</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.apache.sling</groupId> + <artifactId>org.apache.sling.feature.io</artifactId> + <version>0.1.3-SNAPSHOT</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.apache.sling</groupId> + <artifactId>org.apache.sling.feature</artifactId> + <version>0.1.3-SNAPSHOT</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-nop</artifactId> + <version>1.7.25</version> + <scope>compile</scope> + </dependency> <dependency> + <groupId>org.apache.sling</groupId> + <artifactId>org.apache.sling.commons.johnzon</artifactId> + <version>1.0.0</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.apache.felix</groupId> + <artifactId>org.apache.felix.converter</artifactId> + <version>1.0.0</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.apache.sling</groupId> + <artifactId>org.apache.sling.jcr.jcr-wrapper</artifactId> + <version>2.0.0</version> + <scope>compile</scope> + </dependency> + <dependency> + <artifactId>jackrabbit-spi-commons</artifactId> + <version>2.17.3</version> + <groupId>org.apache.jackrabbit</groupId> + <scope>compile</scope> + </dependency> + <dependency> + <artifactId>commons-io</artifactId> + <version>2.6</version> + <groupId>commons-io</groupId> + <scope>compile</scope> + </dependency> + <dependency> + <artifactId>jackrabbit-jcr-commons</artifactId> + <version>2.17.3</version> + <groupId>org.apache.jackrabbit</groupId> + <scope>compile</scope> + </dependency> + <dependency> + <artifactId>jackrabbit-spi</artifactId> + <version>2.17.3</version> + <groupId>org.apache.jackrabbit</groupId> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>commons-cli</groupId> + <artifactId>commons-cli</artifactId> + <version>1.3.1</version> + <scope>compile</scope> + </dependency> + </dependencies> +</project> diff --git a/featuremodel/feature-content-extension/src/main/java/org/apache/sling/feature/extension/content/ContentHandler.java b/featuremodel/feature-content-extension/src/main/java/org/apache/sling/feature/extension/content/ContentHandler.java new file mode 100644 index 0000000..e19ba12 --- /dev/null +++ b/featuremodel/feature-content-extension/src/main/java/org/apache/sling/feature/extension/content/ContentHandler.java @@ -0,0 +1,146 @@ +/* + * 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.feature.extension.content; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.collections.map.MultiValueMap; +import org.apache.jackrabbit.vault.packaging.PackageId; +import org.apache.jackrabbit.vault.packaging.SubPackageHandling; +import org.apache.jackrabbit.vault.packaging.registry.ExecutionPlanBuilder; +import org.apache.jackrabbit.vault.packaging.registry.PackageTask.Type; +import org.apache.jackrabbit.vault.packaging.registry.impl.FSPackageRegistry; +import org.apache.sling.feature.Artifact; +import org.apache.sling.feature.Configuration; +import org.apache.sling.feature.Extension; +import org.apache.sling.feature.ExtensionType; +import org.apache.sling.feature.FeatureConstants; +import org.apache.sling.feature.launcher.spi.LauncherPrepareContext; +import org.apache.sling.feature.launcher.spi.extensions.ExtensionHandler; +import org.apache.sling.feature.launcher.spi.extensions.ExtensionInstallationContext; + +public class ContentHandler implements ExtensionHandler { + + public static final String PACKAGEREGISTRY_HOME = "packageregistry.home"; + + private static final String REPOSITORY_HOME = "repository.home"; + + private static final String REGISTRY_FOLDER = "packageregistry"; + + private static ExecutionPlanBuilder buildExecutionPlan(Collection<Artifact> artifacts, LauncherPrepareContext prepareContext, File registryHome) throws Exception { + + List<File> packageReferences = new ArrayList<File>(); + + for (final Artifact a : artifacts) { + final File file = prepareContext.getArtifactFile(a.getId()); + if (file.exists()) { + packageReferences.add(file); + } + + } + + if(!registryHome.exists()) { + registryHome.mkdirs(); + } + + FSPackageRegistry registry = new FSPackageRegistry(registryHome); + + ExecutionPlanBuilder builder = registry.createExecutionPlan(); + + for (File pkgFile : packageReferences) { + PackageId pid = registry.registerExternal(pkgFile, true); + Map<PackageId, SubPackageHandling.Option> subPkgs = registry.getInstallState(pid).getSubPackages(); + if (!subPkgs.isEmpty()) { + for (PackageId subId : subPkgs.keySet()) { + SubPackageHandling.Option opt = subPkgs.get(subId); + if (opt != SubPackageHandling.Option.IGNORE) { + builder.addTask().with(subId).with(Type.EXTRACT); + } + } + } + + builder.addTask().with(pid).with(Type.EXTRACT); + } + builder.validate(); + return builder; + + } + + @Override + public boolean handle(Extension extension, LauncherPrepareContext prepareContext, + ExtensionInstallationContext installationContext) throws Exception { + File registryHome = getRegistryHomeDir(installationContext); + if (extension.getType() == ExtensionType.ARTIFACTS + && extension.getName().equals(FeatureConstants.EXTENSION_NAME_CONTENT_PACKAGES)) { + MultiValueMap orderedArtifacts = MultiValueMap.decorate(new LinkedHashMap<Integer, Collection<Artifact>>()); + for (final Artifact a : extension.getArtifacts()) { + orderedArtifacts.put(Integer.valueOf(a.getStartOrder()), a); + } + List<String> executionPlans = new ArrayList<String>(); + for (Object key : orderedArtifacts.keySet()) { + @SuppressWarnings("unchecked") + Collection<Artifact> artifacts = orderedArtifacts.getCollection(key); + ExecutionPlanBuilder builder = buildExecutionPlan(artifacts, prepareContext, registryHome); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + builder.save(baos); + executionPlans.add(baos.toString("UTF-8")); + } + final Configuration initcfg = new Configuration("org.apache.sling.jcr.packageinit.impl.ExecutionPlanRepoInitializer"); + initcfg.getProperties().put("executionplans", executionPlans.toArray(new String[executionPlans.size()])); + installationContext.addConfiguration(initcfg.getPid(), initcfg.getFactoryPid(), initcfg.getProperties()); + + final Configuration registrycfg = new Configuration("org.apache.jackrabbit.vault.packaging.registry.impl.FSPackageRegistry"); + registrycfg.getProperties().put("homePath", REGISTRY_FOLDER); + installationContext.addConfiguration(registrycfg.getPid(), registrycfg.getFactoryPid(), registrycfg.getProperties());; + + return true; + } + else { + return false; + } + } + + private File getRegistryHomeDir(ExtensionInstallationContext installationContext) { + //read repository- home from framework properties (throw exception if repo.home not set) + String registryPath = System.getProperty(PACKAGEREGISTRY_HOME); + File registryHome; + if (registryPath != null) { + registryHome = Paths.get(registryPath).toFile(); + + } else { + String repoHome = installationContext.getFrameworkProperties().get(REPOSITORY_HOME); + if (repoHome == null) { + throw new IllegalStateException("Neither registry.home set nor repository.home configured."); + } + registryHome = Paths.get(repoHome, REGISTRY_FOLDER).toFile(); + } + if (!registryHome.exists()) { + registryHome.mkdirs(); + } + if (!registryHome.isDirectory()) { + throw new IllegalStateException("Registry but points to file - must be directory"); + } + return registryHome; + } +} diff --git a/featuremodel/feature-content-extension/src/main/resources/META-INF/services/org.apache.sling.feature.launcher.spi.extensions.ExtensionHandler b/featuremodel/feature-content-extension/src/main/resources/META-INF/services/org.apache.sling.feature.launcher.spi.extensions.ExtensionHandler new file mode 100644 index 0000000..b89c4aa --- /dev/null +++ b/featuremodel/feature-content-extension/src/main/resources/META-INF/services/org.apache.sling.feature.launcher.spi.extensions.ExtensionHandler @@ -0,0 +1 @@ +org.apache.sling.feature.extension.content.ContentHandler ---------------------------------------------------------------- This is an automated message from the Apache Git Service. To respond to the message, please log on GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: [email protected] With regards, Apache Git Services
