Transform api-regions extensions
Into bundle-feature-mapping and feature-region-mapping
diff --git a/src/main/java/org/apache/sling/feature/applicationbuilder/impl/Main.java b/src/main/java/org/apache/sling/feature/applicationbuilder/impl/Main.java
index 9939d64..478b498 100644
--- a/src/main/java/org/apache/sling/feature/applicationbuilder/impl/Main.java
+++ b/src/main/java/org/apache/sling/feature/applicationbuilder/impl/Main.java
@@ -27,16 +27,19 @@
import org.apache.sling.feature.Artifact;
import org.apache.sling.feature.ArtifactId;
import org.apache.sling.feature.Extension;
+import org.apache.sling.feature.ExtensionType;
import org.apache.sling.feature.Feature;
import org.apache.sling.feature.builder.ApplicationBuilder;
import org.apache.sling.feature.builder.BuilderContext;
import org.apache.sling.feature.builder.FeatureProvider;
+import org.apache.sling.feature.io.ArtifactHandler;
import org.apache.sling.feature.io.ArtifactManager;
import org.apache.sling.feature.io.ArtifactManagerConfig;
import org.apache.sling.feature.io.IOUtils;
import org.apache.sling.feature.io.json.ApplicationJSONWriter;
import org.apache.sling.feature.io.json.FeatureJSONReader;
import org.apache.sling.feature.io.json.FeatureJSONReader.SubstituteVariables;
+import org.osgi.framework.Constants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -46,8 +49,14 @@
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Set;
+import java.util.jar.Attributes;
+import java.util.jar.JarFile;
import java.util.stream.Stream;
import javax.json.Json;
@@ -55,6 +64,7 @@
import javax.json.JsonArrayBuilder;
import javax.json.JsonObject;
import javax.json.JsonObjectBuilder;
+import javax.json.JsonString;
import javax.json.JsonValue;
public class Main {
@@ -227,6 +237,9 @@
throw new IOException("No features found.");
}
+ Map<String, String> bundleFeatureMap = new HashMap<>();
+ Map<String, Set<String>> regionPackageMap = new HashMap<>();
+ Map<String, Set<String>> featureRegionMap = new HashMap<>();
List<Feature> features = new ArrayList<>();
for (final String initFile : featureFiles)
@@ -234,7 +247,8 @@
try
{
final Feature f = IOUtils.getFeature(initFile, artifactManager, FeatureJSONReader.SubstituteVariables.RESOLVE);
- addFromFeatureToBundlesAndRegions(f);
+ collectFeatureAndWhitelistMappings(f, artifactManager, bundleFeatureMap,
+ featureRegionMap, regionPackageMap);
features.add(f);
}
catch (Exception ex)
@@ -243,21 +257,6 @@
}
}
- /* */
- // For each bundle in each feature mark where it came from 'from-feature'
- // For each api-region extension in each feature mark it's 'from-feature'
- /*
- for (Feature f : features) {
- System.out.println("*** feature: " + f.getId().toMvnId());
- for (Artifact b : f.getBundles()) {
- b.getMetadata().put("from-feature", f.getId().toMvnId());
- }
- }
- */
-
- // remove the from-feature stuff in the ApplicationBuilder.assemble()
- /* */
-
Collections.sort(features);
app = ApplicationBuilder.assemble(app, new BuilderContext(new FeatureProvider() {
@@ -266,7 +265,8 @@
public Feature provide(final ArtifactId id) {
try {
Feature f = IOUtils.getFeature(id.toMvnUrl(), artifactManager, SubstituteVariables.RESOLVE);
- addFromFeatureToBundlesAndRegions(f);
+ collectFeatureAndWhitelistMappings(f, artifactManager, bundleFeatureMap,
+ featureRegionMap, regionPackageMap);
return f;
} catch (final IOException e) {
// ignore
@@ -275,6 +275,12 @@
}
}), features.toArray(new Feature[0]));
+ Extension bundleFeatureExtension = createBundleFeatureExtension(bundleFeatureMap);
+ app.getExtensions().add(bundleFeatureExtension);
+
+ Extension featureRegionExtension = createFeatureRegionExtension(regionPackageMap, featureRegionMap);
+ app.getExtensions().add(featureRegionExtension);
+
// check framework
if ( app.getFramework() == null ) {
// use hard coded Apache Felix
@@ -284,38 +290,104 @@
return app;
}
- private static void addFromFeatureToBundlesAndRegions(Feature f) {
+ private static Extension createBundleFeatureExtension(Map<String, String> bundleFeatureMap) {
+ Extension bundleFeatureExtension = new Extension(ExtensionType.JSON, "bundle-feature-mapping", true);
+ JsonArrayBuilder ab = Json.createArrayBuilder();
+ JsonObjectBuilder ob = Json.createObjectBuilder();
+ for (Map.Entry<String, String> entry : bundleFeatureMap.entrySet()) {
+ ob.add(entry.getKey(), entry.getValue());
+ }
+ ab.add(ob);
+ bundleFeatureExtension.setJSON(ab.build().toString());
+ return bundleFeatureExtension;
+ }
+
+ private static Extension createFeatureRegionExtension(Map<String, Set<String>> regionPackageMap,
+ Map<String, Set<String>> featureRegionMap) {
+ Extension featureRegionExtension = new Extension(ExtensionType.JSON, "feature-region-mapping", true);
+ JsonArrayBuilder ab = Json.createArrayBuilder();
+
+ JsonObjectBuilder pob = Json.createObjectBuilder();
+ for (Map.Entry<String, Set<String>> entry : regionPackageMap.entrySet()) {
+ JsonArrayBuilder pab = Json.createArrayBuilder();
+ entry.getValue().stream().forEach(pab::add);
+ pob.add(entry.getKey(), pab);
+ }
+ JsonObjectBuilder ob = Json.createObjectBuilder();
+ ob.add("packages", pob);
+
+ JsonObjectBuilder fob = Json.createObjectBuilder();
+ for (Map.Entry<String, Set<String>> entry : featureRegionMap.entrySet()) {
+ JsonArrayBuilder rab = Json.createArrayBuilder();
+ entry.getValue().stream().forEach(rab::add);
+ fob.add(entry.getKey(), rab);
+ }
+ ob.add("regions", fob);
+ ab.add(ob);
+
+ featureRegionExtension.setJSON(ab.build().toString());
+ return featureRegionExtension;
+ }
+
+ private static void collectFeatureAndWhitelistMappings(Feature f,
+ ArtifactManager artifactManager,
+ Map<String, String> bundleFeatureMap,
+ Map<String, Set<String>> featureRegionMap,
+ Map<String, Set<String>> regionPackageMap)
+ throws IOException {
+ String featureID = f.getId().toMvnId();
for (Artifact bundle : f.getBundles()) {
- bundle.getMetadata().put("from-feature", f.getId().toMvnId());
+ ArtifactHandler handler = artifactManager.getArtifactHandler(bundle.getId().toMvnUrl());
+ String bsn = getBsn(handler.getFile());
+ bundleFeatureMap.put(bsn, featureID);
}
- for (Extension e : f.getExtensions()) {
+ for (Iterator<Extension> it = f.getExtensions().iterator(); it.hasNext(); ) {
+ Extension e = it.next();
if ("api-regions".equals(e.getName())) {
+ it.remove(); // api-regions is not needed in the application.json
+
+ Set<String> regions = featureRegionMap.get(featureID);
+ if (regions == null) {
+ regions = new HashSet<>();
+ featureRegionMap.put(featureID, regions);
+ }
+
JsonArray ja = Json.createReader(new StringReader(e.getJSON())).readArray();
- JsonArray newArray = addToJSONMaps(ja, "from-feature", f.getId().toMvnId());
- e.setJSON(newArray.toString());
+ for (JsonValue jv : ja) {
+ if (jv instanceof JsonString) {
+ regions.add(((JsonString) jv).getString());
+ } else if (jv instanceof JsonObject) {
+ JsonObject jo = (JsonObject) jv;
+ String name = jo.getString("name");
+ regions.add(name);
+
+ JsonArray exports = jo.getJsonArray("exports");
+ Set<String> packages = regionPackageMap.get(name);
+ if (packages == null) {
+ packages = new HashSet<>();
+ regionPackageMap.put(name, packages);
+ }
+ for (JsonValue p : exports) {
+ if (p instanceof JsonString) {
+ packages.add(((JsonString) p).getString());
+ }
+ }
+ }
+ }
}
}
}
- private static JsonArray addToJSONMaps(JsonArray ja, String key, String value) {
- JsonArrayBuilder ab = Json.createArrayBuilder();
-
- for (JsonValue jv : ja) {
- if (jv instanceof JsonObject) {
- JsonObject jo = (JsonObject) jv;
- JsonObjectBuilder ob = Json.createObjectBuilder();
- for (Map.Entry<String, JsonValue> entry : jo.entrySet()) {
- ob.add(entry.getKey(), entry.getValue());
- }
- ob.add(key, value);
- ab.add(ob.build());
- } else {
- ab.add(jv);
- }
+ private static String getBsn(File artifactFile) throws IOException {
+ try (JarFile jf = new JarFile(artifactFile)) {
+ Attributes attrs = jf.getManifest().getMainAttributes();
+ String bsn = attrs.getValue(Constants.BUNDLE_SYMBOLICNAME);
+ String version = attrs.getValue(Constants.BUNDLE_VERSION);
+ if (version == null)
+ version = "0.0.0";
+ return bsn + ":" + version;
}
-
- return ab.build();
}
private static Application buildApplication(final Application app) {