SLING-9262 : Add prototype feature to feature archive
diff --git a/src/main/java/org/apache/sling/feature/io/archive/ArchiveWriter.java b/src/main/java/org/apache/sling/feature/io/archive/ArchiveWriter.java
index a4d6e29..3207e56 100644
--- a/src/main/java/org/apache/sling/feature/io/archive/ArchiveWriter.java
+++ b/src/main/java/org/apache/sling/feature/io/archive/ArchiveWriter.java
@@ -16,12 +16,16 @@
*/
package org.apache.sling.feature.io.archive;
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.StringReader;
import java.io.Writer;
import java.net.URL;
+import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
@@ -37,6 +41,7 @@
import org.apache.sling.feature.ExtensionType;
import org.apache.sling.feature.Feature;
import org.apache.sling.feature.builder.ArtifactProvider;
+import org.apache.sling.feature.io.json.FeatureJSONReader;
import org.apache.sling.feature.io.json.FeatureJSONWriter;
/**
@@ -87,23 +92,19 @@
manifest.getMainAttributes().putValue(CONTENTS_HEADER, String.join(",", Arrays.asList(features).stream()
.map(feature -> feature.getId().toMvnId()).collect(Collectors.toList())));
+ final Set<ArtifactId> artifacts = new HashSet<>();
+ final byte[] buffer = new byte[1024*1024*256];
+
// create archive
final JarOutputStream jos = new JarOutputStream(out, manifest);
// write everything without compression
jos.setLevel(Deflater.NO_COMPRESSION);
for (final Feature feature : features) {
- final JarEntry entry = new JarEntry(feature.getId().toMvnPath());
- jos.putNextEntry(entry);
- final Writer writer = new OutputStreamWriter(jos, "UTF-8");
- FeatureJSONWriter.write(writer, feature);
- writer.flush();
- jos.closeEntry();
+ writeFeature(artifacts, feature, provider, jos, buffer);
}
- final byte[] buffer = new byte[1024*1024*256];
- final Set<ArtifactId> artifacts = new HashSet<>();
for (final Feature feature : features) {
for (final Artifact a : feature.getBundles()) {
@@ -112,8 +113,13 @@
for (final Extension e : feature.getExtensions()) {
if (e.getType() == ExtensionType.ARTIFACTS) {
+ final boolean isFeature = Extension.EXTENSION_NAME_ASSEMBLED_FEATURES.equals(e.getName());
for (final Artifact a : e.getArtifacts()) {
- writeArtifact(artifacts, provider, a, jos, buffer);
+ if ( isFeature ) {
+ writeFeature(artifacts, provider, a.getId(), jos, buffer);
+ } else {
+ writeArtifact(artifacts, provider, a, jos, buffer);
+ }
}
}
}
@@ -121,6 +127,45 @@
return jos;
}
+ private static void writeFeature(final Set<ArtifactId> artifacts,
+ final Feature feature,
+ final ArtifactProvider provider,
+ final JarOutputStream jos, final byte[] buffer) throws IOException {
+ if ( artifacts.add(feature.getId())) {
+ final JarEntry entry = new JarEntry(feature.getId().toMvnPath());
+ jos.putNextEntry(entry);
+ final Writer writer = new OutputStreamWriter(jos, StandardCharsets.UTF_8);
+ FeatureJSONWriter.write(writer, feature);
+ writer.flush();
+ jos.closeEntry();
+
+ if ( feature.getPrototype() != null ) {
+ writeFeature(artifacts, provider, feature.getPrototype().getId(), jos, buffer);
+ }
+ }
+ }
+
+ private static void writeFeature(final Set<ArtifactId> artifacts,
+ final ArtifactProvider provider,
+ final ArtifactId featureId,
+ final JarOutputStream jos, final byte[] buffer) throws IOException {
+ if ( !artifacts.contains(featureId)) {
+ final URL url = provider.provide(featureId);
+ try ( final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ final InputStream is = url.openStream()) {
+ int l = 0;
+ while ( (l = is.read(buffer)) > 0 ) {
+ baos.write(buffer, 0, l);
+ }
+ final String contents = new String(baos.toByteArray(), StandardCharsets.UTF_8);
+ try ( final Reader reader = new StringReader(contents)) {
+ final Feature feature = FeatureJSONReader.read(reader, featureId.toMvnId());
+ writeFeature(artifacts, feature, provider, jos, buffer);
+ }
+ }
+ }
+ }
+
private static void writeArtifact(final Set<ArtifactId> artifacts,
final ArtifactProvider provider,
final Artifact artifact,