You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by cz...@apache.org on 2017/09/01 15:02:41 UTC

svn commit: r1806972 - in /sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/process: ApplicationBuilder.java BuilderUtil.java FeatureBuilder.java FeatureExtensionHandler.java

Author: cziegeler
Date: Fri Sep  1 15:02:41 2017
New Revision: 1806972

URL: http://svn.apache.org/viewvc?rev=1806972&view=rev
Log:
Add feature extension handler

Added:
    sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/process/FeatureExtensionHandler.java   (with props)
Modified:
    sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/process/ApplicationBuilder.java
    sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/process/BuilderUtil.java
    sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/process/FeatureBuilder.java

Modified: sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/process/ApplicationBuilder.java
URL: http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/process/ApplicationBuilder.java?rev=1806972&r1=1806971&r2=1806972&view=diff
==============================================================================
--- sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/process/ApplicationBuilder.java (original)
+++ sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/process/ApplicationBuilder.java Fri Sep  1 15:02:41 2017
@@ -16,16 +16,16 @@
  */
 package org.apache.sling.feature.process;
 
-import org.apache.sling.feature.Application;
-import org.apache.sling.feature.ArtifactId;
-import org.apache.sling.feature.Feature;
-
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.sling.feature.Application;
+import org.apache.sling.feature.ArtifactId;
+import org.apache.sling.feature.Feature;
+
 /**
  * Build an application based on features.
  */
@@ -156,6 +156,6 @@ public class ApplicationBuilder {
         BuilderUtil.mergeBundles(target.getBundles(), source.getBundles(), BuilderUtil.ArtifactMerge.HIGHEST);
         BuilderUtil.mergeConfigurations(target.getConfigurations(), source.getConfigurations());
         BuilderUtil.mergeFrameworkProperties(target.getFrameworkProperties(), source.getFrameworkProperties());
-        BuilderUtil.mergeExtensions(target.getExtensions(), source.getExtensions(), BuilderUtil.ArtifactMerge.HIGHEST);
+        BuilderUtil.mergeExtensions(target, source, BuilderUtil.ArtifactMerge.HIGHEST);
     }
 }

Modified: sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/process/BuilderUtil.java
URL: http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/process/BuilderUtil.java?rev=1806972&r1=1806971&r2=1806972&view=diff
==============================================================================
--- sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/process/BuilderUtil.java (original)
+++ sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/process/BuilderUtil.java Fri Sep  1 15:02:41 2017
@@ -16,27 +16,29 @@
  */
 package org.apache.sling.feature.process;
 
+import java.io.StringReader;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Map;
+
+import javax.json.Json;
+import javax.json.JsonArray;
+import javax.json.JsonObject;
+import javax.json.JsonStructure;
+import javax.json.JsonValue;
+import javax.json.JsonValue.ValueType;
+
+import org.apache.sling.feature.Application;
 import org.apache.sling.feature.Artifact;
 import org.apache.sling.feature.Bundles;
 import org.apache.sling.feature.Capability;
 import org.apache.sling.feature.Configuration;
 import org.apache.sling.feature.Configurations;
 import org.apache.sling.feature.Extension;
-import org.apache.sling.feature.Extensions;
+import org.apache.sling.feature.Feature;
 import org.apache.sling.feature.KeyValueMap;
 import org.apache.sling.feature.Requirement;
 
-import javax.json.Json;
-import javax.json.JsonArray;
-import javax.json.JsonObject;
-import javax.json.JsonStructure;
-import javax.json.JsonValue;
-import javax.json.JsonValue.ValueType;
-import java.io.StringReader;
-import java.util.Enumeration;
-import java.util.List;
-import java.util.Map;
-
 /**
  * Utility methods for the builders
  */
@@ -114,80 +116,118 @@ class BuilderUtil {
         }
     }
 
-    // extensions (add/merge)
-    static void mergeExtensions(final Extensions target,
-            final Extensions source,
+    // default merge for extensions
+    static void mergeExtensions(final Extension target,
+            final Extension source,
             final ArtifactMerge artifactMergeAlg) {
-        for(final Extension ext : source) {
+        switch ( target.getType() ) {
+            case TEXT : // simply append
+                        target.setText(target.getText() + "\n" + source.getText());
+                        break;
+            case JSON : final JsonStructure struct1;
+                        try ( final StringReader reader = new StringReader(target.getJSON()) ) {
+                            struct1 = Json.createReader(reader).read();
+                        }
+                        final JsonStructure struct2;
+                        try ( final StringReader reader = new StringReader(source.getJSON()) ) {
+                            struct2 = Json.createReader(reader).read();
+                        }
+
+                        if ( struct1.getValueType() != struct2.getValueType() ) {
+                            throw new IllegalStateException("Found different JSON types for extension " + target.getName()
+                                + " : " + struct1.getValueType() + " and " + struct2.getValueType());
+                        }
+                        if ( struct1.getValueType() == ValueType.ARRAY ) {
+                            // array is append
+                            final JsonArray a1 = (JsonArray)struct1;
+                            final JsonArray a2 = (JsonArray)struct2;
+                            for(final JsonValue val : a2) {
+                                a1.add(val);
+                            }
+                        } else {
+                            // object is merge
+                            merge((JsonObject)struct1, (JsonObject)struct2);
+                        }
+                        break;
+
+            case ARTIFACTS : for(final Artifact a : source.getArtifacts()) {
+                                 // use artifactMergeAlg
+                                 boolean add = true;
+                                 for(final Artifact targetArtifact : target.getArtifacts()) {
+                                     if ( targetArtifact.getId().isSame(a.getId()) ) {
+                                         if ( artifactMergeAlg == ArtifactMerge.HIGHEST ) {
+                                             if ( targetArtifact.getId().getOSGiVersion().compareTo(a.getId().getOSGiVersion()) > 0 ) {
+                                                 add = false;
+                                             } else {
+                                                 target.getArtifacts().remove(targetArtifact);
+                                             }
+                                         } else { // latest
+
+                                             target.getArtifacts().remove(targetArtifact);
+                                         }
+                                         break;
+                                     }
+                                 }
+
+                                 if ( add ) {
+                                     target.getArtifacts().add(a);
+                                 }
+
+                             }
+                             break;
+        }
+    }
+
+    // extensions (add/merge)
+    static void mergeExtensions(final Feature target,
+            final Feature source,
+            final ArtifactMerge artifactMergeAlg,
+            final FeatureExtensionHandler... extensionMergers) {
+        for(final Extension ext : source.getExtensions()) {
             boolean found = false;
-            for(final Extension current : target) {
+            for(final Extension current : target.getExtensions()) {
                 if ( current.getName().equals(ext.getName()) ) {
                     found = true;
                     if ( current.getType() != ext.getType() ) {
                         throw new IllegalStateException("Found different types for extension " + current.getName()
                         + " : " + current.getType() + " and " + ext.getType());
                     }
-                    switch ( current.getType() ) {
-                        case TEXT : // simply append
-                                    current.setText(current.getText() + "\n" + ext.getText());
-                                    break;
-                        case JSON : final JsonStructure struct1;
-                                    try ( final StringReader reader = new StringReader(current.getJSON()) ) {
-                                        struct1 = Json.createReader(reader).read();
-                                    }
-                                    final JsonStructure struct2;
-                                    try ( final StringReader reader = new StringReader(ext.getJSON()) ) {
-                                        struct2 = Json.createReader(reader).read();
-                                    }
-
-                                    if ( struct1.getValueType() != struct2.getValueType() ) {
-                                        throw new IllegalStateException("Found different JSON types for extension " + current.getName()
-                                        + " : " + struct1.getValueType() + " and " + struct2.getValueType());
-                                    }
-                                    if ( struct1.getValueType() == ValueType.ARRAY ) {
-                                        // array is append
-                                        final JsonArray a1 = (JsonArray)struct1;
-                                        final JsonArray a2 = (JsonArray)struct2;
-                                        for(final JsonValue val : a2) {
-                                            a1.add(val);
-                                        }
-                                    } else {
-                                        // object is merge
-                                        merge((JsonObject)struct1, (JsonObject)struct2);
-                                    }
-                                    break;
-
-                        case ARTIFACTS : for(final Artifact a : ext.getArtifacts()) {
-                                             // use artifactMergeAlg
-                                             boolean add = true;
-                                             for(final Artifact targetArtifact : current.getArtifacts()) {
-                                                 if ( targetArtifact.getId().isSame(a.getId()) ) {
-                                                     if ( artifactMergeAlg == ArtifactMerge.HIGHEST ) {
-                                                         if ( targetArtifact.getId().getOSGiVersion().compareTo(a.getId().getOSGiVersion()) > 0 ) {
-                                                             add = false;
-                                                         } else {
-                                                             current.getArtifacts().remove(targetArtifact);
-                                                         }
-                                                     } else { // latest
-
-                                                         current.getArtifacts().remove(targetArtifact);
-                                                     }
-                                                     break;
-                                                 }
-                                             }
-
-                                             if ( add ) {
-                                                 current.getArtifacts().add(a);
-                                             }
-
-                                         }
-                                         break;
+                    if ( extensionMergers != null ) {
+                        for(final FeatureExtensionHandler fem : extensionMergers) {
+                            if ( fem.canMerge(current.getName()) ) {
+                                fem.merge(target, source, current.getName());
+                            }
+                        }
+                    } else {
+                        // default merge
+                        mergeExtensions(current, ext, artifactMergeAlg);
+                    }
+                }
+            }
+            if ( !found ) {
+                target.getExtensions().add(ext);
+            }
+        }
+    }
 
+    static void mergeExtensions(final Application target,
+            final Feature source,
+            final ArtifactMerge artifactMergeAlg) {
+        for(final Extension ext : source.getExtensions()) {
+            boolean found = false;
+            for(final Extension current : target.getExtensions()) {
+                if ( current.getName().equals(ext.getName()) ) {
+                    found = true;
+                    if ( current.getType() != ext.getType() ) {
+                        throw new IllegalStateException("Found different types for extension " + current.getName()
+                        + " : " + current.getType() + " and " + ext.getType());
                     }
+                    // default merge
+                    mergeExtensions(current, ext, artifactMergeAlg);
                 }
             }
             if ( !found ) {
-                target.add(ext);
+                target.getExtensions().add(ext);
             }
         }
     }

Modified: sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/process/FeatureBuilder.java
URL: http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/process/FeatureBuilder.java?rev=1806972&r1=1806971&r2=1806972&view=diff
==============================================================================
--- sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/process/FeatureBuilder.java (original)
+++ sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/process/FeatureBuilder.java Fri Sep  1 15:02:41 2017
@@ -16,6 +16,12 @@
  */
 package org.apache.sling.feature.process;
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
 import org.apache.sling.feature.Artifact;
 import org.apache.sling.feature.ArtifactId;
 import org.apache.sling.feature.Configuration;
@@ -23,12 +29,6 @@ import org.apache.sling.feature.Extensio
 import org.apache.sling.feature.Feature;
 import org.apache.sling.feature.Include;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
 public class FeatureBuilder {
 
     /**
@@ -36,15 +36,18 @@ public class FeatureBuilder {
      *
      * @param feature The feature to start
      * @param provider A provider providing the included features
+     * @param extensionMergers Optional feature mergers
      * @return The assembled feature.
      * @throws IllegalArgumentException If feature or provider is {@code null}
-     * @throws IllegalStateException If an included feature can't be provided
+     * @throws IllegalStateException If an included feature can't be provided or merged.
      */
-    public static Feature assemble(final Feature feature, final FeatureProvider provider) {
+    public static Feature assemble(final Feature feature,
+            final FeatureProvider provider,
+            final FeatureExtensionHandler... extensionMergers) {
         if ( feature == null || provider == null ) {
             throw new IllegalArgumentException("Feature and/or provider must not be null");
         }
-        return internalAssemble(new ArrayList<>(), feature, provider);
+        return internalAssemble(new ArrayList<>(), feature, provider, extensionMergers);
     }
 
     /**
@@ -64,7 +67,8 @@ public class FeatureBuilder {
      */
     public static Feature assemble(final Feature feature,
             final List<Feature> upgrades,
-            final FeatureProvider provider) {
+            final FeatureProvider provider,
+            final FeatureExtensionHandler... extensionMergers) {
         if ( feature == null || provider == null ) {
             throw new IllegalArgumentException("Feature and/or provider must not be null");
         }
@@ -100,7 +104,7 @@ public class FeatureBuilder {
         }
 
         // assemble feature without upgrades
-        final Feature assembledFeature = internalAssemble(new ArrayList<>(), feature, provider);
+        final Feature assembledFeature = internalAssemble(new ArrayList<>(), feature, provider, extensionMergers);
 
         // handle upgrades
         if ( useUpdates != null ) {
@@ -125,7 +129,7 @@ public class FeatureBuilder {
                 final Feature auf = assemble(uf, provider);
 
                 // merge
-                merge(assembledFeature, auf);
+                merge(assembledFeature, auf, extensionMergers);
             }
         }
 
@@ -134,7 +138,8 @@ public class FeatureBuilder {
 
     private static Feature internalAssemble(final List<String> processedFeatures,
             final Feature feature,
-            final FeatureProvider provider) {
+            final FeatureProvider provider,
+            final FeatureExtensionHandler... extensionMergers) {
         if ( feature.isAssembled() ) {
             return feature;
         }
@@ -187,15 +192,15 @@ public class FeatureBuilder {
                 if ( f == null ) {
                     throw new IllegalStateException("Unable to find included feature " + i.getId());
                 }
-                final Feature af = internalAssemble(processedFeatures, f, provider);
+                final Feature af = internalAssemble(processedFeatures, f, provider, extensionMergers);
 
                 // process include instructions
                 include(af, i);
 
                 // and now merge
-                merge(result, af);
+                merge(result, af, extensionMergers);
             }
-            merge(result, feature);
+            merge(result, feature, extensionMergers);
         }
         processedFeatures.remove(feature.getId().toMvnId());
 
@@ -203,13 +208,17 @@ public class FeatureBuilder {
         return result;
     }
 
-    private static void merge(final Feature target, final Feature source) {
+    private static void merge(final Feature target, final Feature source,
+            final FeatureExtensionHandler... extensionMergers) {
         BuilderUtil.mergeBundles(target.getBundles(), source.getBundles(), BuilderUtil.ArtifactMerge.LATEST);
         BuilderUtil.mergeConfigurations(target.getConfigurations(), source.getConfigurations());
         BuilderUtil.mergeFrameworkProperties(target.getFrameworkProperties(), source.getFrameworkProperties());
         BuilderUtil.mergeRequirements(target.getRequirements(), source.getRequirements());
         BuilderUtil.mergeCapabilities(target.getCapabilities(), source.getCapabilities());
-        BuilderUtil.mergeExtensions(target.getExtensions(), source.getExtensions(), BuilderUtil.ArtifactMerge.LATEST);
+        BuilderUtil.mergeExtensions(target,
+                source,
+                BuilderUtil.ArtifactMerge.LATEST,
+                extensionMergers);
     }
 
     private static void include(final Feature base, final Include i) {

Added: sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/process/FeatureExtensionHandler.java
URL: http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/process/FeatureExtensionHandler.java?rev=1806972&view=auto
==============================================================================
--- sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/process/FeatureExtensionHandler.java (added)
+++ sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/process/FeatureExtensionHandler.java Fri Sep  1 15:02:41 2017
@@ -0,0 +1,51 @@
+/*
+ * 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.process;
+
+import org.apache.sling.feature.Feature;
+
+public interface FeatureExtensionHandler {
+
+    /**
+     * Checks whether this merger can merge extensions with that name
+     * @param extensionName The extension name
+     * @return {@code true} if merger can handle this
+     */
+    boolean canMerge(String extensionName);
+
+    /**
+     * Merge the source extension into the target extension.
+     *
+     * The caller of this method already ensured that both
+     * extensions share the same name and type and that
+     * {@link #canMerge(String)} returned {@code true}.
+     *
+     * @param target The target feature
+     * @param source The source feature
+     * @param extensionName The extension name
+     * @throws IllegalStateException If the extensions can't be merged
+     */
+    void merge(Feature target, Feature source, String extensionName);
+
+    /**
+     * Post process the feature with respect to the extension
+     * @param feature The feature
+     * @param extensionName The extension name
+     * @throws IllegalStateException If post processing failed
+     */
+    void postProcess(Feature feature, String extensionName);
+}

Propchange: sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/process/FeatureExtensionHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/process/FeatureExtensionHandler.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url