Added: 
sling/whiteboard/cziegeler/feature-launcher/src/main/java/org/apache/sling/feature/launcher/impl/launchers/FrameworkRunner.java
URL: 
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-launcher/src/main/java/org/apache/sling/feature/launcher/impl/launchers/FrameworkRunner.java?rev=1797026&view=auto
==============================================================================
--- 
sling/whiteboard/cziegeler/feature-launcher/src/main/java/org/apache/sling/feature/launcher/impl/launchers/FrameworkRunner.java
 (added)
+++ 
sling/whiteboard/cziegeler/feature-launcher/src/main/java/org/apache/sling/feature/launcher/impl/launchers/FrameworkRunner.java
 Wed May 31 12:29:12 2017
@@ -0,0 +1,70 @@
+/*
+ * 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.launcher.impl.launchers;
+
+import java.io.File;
+import java.util.List;
+import java.util.Map;
+import java.util.ServiceLoader;
+
+import org.osgi.framework.BundleException;
+import org.osgi.framework.launch.Framework;
+import org.osgi.framework.launch.FrameworkFactory;
+
+/**
+ * Launcher directly using the OSGi launcher API.
+ */
+public class FrameworkRunner extends AbstractRunner {
+
+    public FrameworkRunner(final Map<String, String> frameworkProperties,
+            final Map<Integer, List<File>> bundlesMap,
+            final List<Object[]> configurations,
+            final List<File> installables) throws Exception {
+        super(configurations, installables);
+
+        final ServiceLoader<FrameworkFactory> loader = 
ServiceLoader.load(FrameworkFactory.class);
+        FrameworkFactory factory = null;
+        for(FrameworkFactory f : loader) {
+            factory = f;
+            break;
+        }
+        if ( factory == null ) {
+            throw new Exception("Unable to locate framework factory.");
+        }
+
+        // create the framework
+        final Framework framework = factory.newFramework(frameworkProperties);
+        // initialize the framework
+        framework.init();
+
+        Runtime.getRuntime().addShutdownHook(new Thread() {
+            @Override
+            public void run() {
+                try {
+                    framework.stop();
+                } catch (final BundleException e) {
+                    // ignore
+                }
+            }
+        });
+
+        this.setupFramework(framework, bundlesMap);
+
+        // finally start
+        framework.start();
+    }
+}

Propchange: 
sling/whiteboard/cziegeler/feature-launcher/src/main/java/org/apache/sling/feature/launcher/impl/launchers/FrameworkRunner.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
sling/whiteboard/cziegeler/feature-launcher/src/main/java/org/apache/sling/feature/launcher/impl/launchers/FrameworkRunner.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Added: 
sling/whiteboard/cziegeler/feature-launcher/src/main/java/org/apache/sling/feature/launcher/spi/ArtifactProvider.java
URL: 
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-launcher/src/main/java/org/apache/sling/feature/launcher/spi/ArtifactProvider.java?rev=1797026&view=auto
==============================================================================
--- 
sling/whiteboard/cziegeler/feature-launcher/src/main/java/org/apache/sling/feature/launcher/spi/ArtifactProvider.java
 (added)
+++ 
sling/whiteboard/cziegeler/feature-launcher/src/main/java/org/apache/sling/feature/launcher/spi/ArtifactProvider.java
 Wed May 31 12:29:12 2017
@@ -0,0 +1,55 @@
+/*
+ * 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.launcher.spi;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * The artifact provider is an extension point for providing artifacts
+ * from different sources, like for example s3.
+ */
+public interface ArtifactProvider {
+
+    /**
+     * The protocol name of the provider, e.g. "s3"
+     * @return The protocol name.
+     */
+    String getProtocol();
+
+    /**
+     * Initialize the provider.
+     * @param context The context
+     * @throws IOException If the provider can't be initialized.
+     */
+    void init(ArtifactProviderContext context) throws IOException;
+
+    /**
+     * Shutdown the provider.
+     */
+    void shutdown();
+
+    /**
+     * Get a local file for the artifact URL.
+     *
+     * @param url Artifact url
+     * @param relativeCachePath A relative path that can be used as a cache 
path
+     *                          by the provider. The path does not start with 
a slash.
+     * @return A file if the artifact exists or {@code null}
+     */
+    File getArtifact(String url, String relativeCachePath);
+}

Propchange: 
sling/whiteboard/cziegeler/feature-launcher/src/main/java/org/apache/sling/feature/launcher/spi/ArtifactProvider.java
------------------------------------------------------------------------------
    svn:eol-style = native

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

Added: 
sling/whiteboard/cziegeler/feature-launcher/src/main/java/org/apache/sling/feature/launcher/spi/ArtifactProviderContext.java
URL: 
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-launcher/src/main/java/org/apache/sling/feature/launcher/spi/ArtifactProviderContext.java?rev=1797026&view=auto
==============================================================================
--- 
sling/whiteboard/cziegeler/feature-launcher/src/main/java/org/apache/sling/feature/launcher/spi/ArtifactProviderContext.java
 (added)
+++ 
sling/whiteboard/cziegeler/feature-launcher/src/main/java/org/apache/sling/feature/launcher/spi/ArtifactProviderContext.java
 Wed May 31 12:29:12 2017
@@ -0,0 +1,46 @@
+/*
+ * 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.launcher.spi;
+
+import java.io.File;
+
+/**
+ * This is the context for the artifact providers
+ */
+public interface ArtifactProviderContext {
+
+    /**
+     * Get the cache directory
+     * @return The cache directory.
+     */
+    File getCacheDirectory();
+
+    /**
+     * Inform about an artifact found in the cache.
+     */
+    void incCachedArtifacts();
+
+    /**
+     * Inform about an artifact being downloaded
+     */
+    void incDownloadedArtifacts();
+
+    /**
+     * Inform about an artifact found locally.
+     */
+    void incLocalArtifacts();
+}

Propchange: 
sling/whiteboard/cziegeler/feature-launcher/src/main/java/org/apache/sling/feature/launcher/spi/ArtifactProviderContext.java
------------------------------------------------------------------------------
    svn:eol-style = native

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

Added: 
sling/whiteboard/cziegeler/feature-launcher/src/main/java/org/apache/sling/feature/launcher/spi/Launcher.java
URL: 
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-launcher/src/main/java/org/apache/sling/feature/launcher/spi/Launcher.java?rev=1797026&view=auto
==============================================================================
--- 
sling/whiteboard/cziegeler/feature-launcher/src/main/java/org/apache/sling/feature/launcher/spi/Launcher.java
 (added)
+++ 
sling/whiteboard/cziegeler/feature-launcher/src/main/java/org/apache/sling/feature/launcher/spi/Launcher.java
 Wed May 31 12:29:12 2017
@@ -0,0 +1,26 @@
+/*
+ * 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.launcher.spi;
+
+import org.apache.sling.feature.Application;
+
+public interface Launcher {
+
+    void prepare(LauncherPrepareContext context, Application app) throws 
Exception;
+
+    void run(LauncherRunContext context, ClassLoader cl) throws Exception;
+}

Propchange: 
sling/whiteboard/cziegeler/feature-launcher/src/main/java/org/apache/sling/feature/launcher/spi/Launcher.java
------------------------------------------------------------------------------
    svn:eol-style = native

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

Added: 
sling/whiteboard/cziegeler/feature-launcher/src/main/java/org/apache/sling/feature/launcher/spi/LauncherPrepareContext.java
URL: 
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-launcher/src/main/java/org/apache/sling/feature/launcher/spi/LauncherPrepareContext.java?rev=1797026&view=auto
==============================================================================
--- 
sling/whiteboard/cziegeler/feature-launcher/src/main/java/org/apache/sling/feature/launcher/spi/LauncherPrepareContext.java
 (added)
+++ 
sling/whiteboard/cziegeler/feature-launcher/src/main/java/org/apache/sling/feature/launcher/spi/LauncherPrepareContext.java
 Wed May 31 12:29:12 2017
@@ -0,0 +1,32 @@
+/*
+ * 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.launcher.spi;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.sling.feature.ArtifactId;
+
+/**
+ * This is the context for the launcher
+ */
+public interface LauncherPrepareContext {
+
+    void addAppJar(File jar);
+
+    File getArtifactFile(ArtifactId artifact) throws IOException;
+}

Propchange: 
sling/whiteboard/cziegeler/feature-launcher/src/main/java/org/apache/sling/feature/launcher/spi/LauncherPrepareContext.java
------------------------------------------------------------------------------
    svn:eol-style = native

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

Added: 
sling/whiteboard/cziegeler/feature-launcher/src/main/java/org/apache/sling/feature/launcher/spi/LauncherRunContext.java
URL: 
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-launcher/src/main/java/org/apache/sling/feature/launcher/spi/LauncherRunContext.java?rev=1797026&view=auto
==============================================================================
--- 
sling/whiteboard/cziegeler/feature-launcher/src/main/java/org/apache/sling/feature/launcher/spi/LauncherRunContext.java
 (added)
+++ 
sling/whiteboard/cziegeler/feature-launcher/src/main/java/org/apache/sling/feature/launcher/spi/LauncherRunContext.java
 Wed May 31 12:29:12 2017
@@ -0,0 +1,58 @@
+/*
+ * 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.launcher.spi;
+
+import java.io.File;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This is the context for the launcher
+ */
+public interface LauncherRunContext {
+
+    /**
+     * Map of framework properties to be set when the framework is created.
+     * @return The map with the framework properties.
+     */
+    Map<String, String> getFrameworkProperties();
+
+    /**
+     * Bundle map, key is the start level, value is a list of files.
+     * @return The bundle map, might be empty
+     */
+    Map<Integer, List<File>> getBundleMap();
+
+    /**
+     * List of configurations.
+     * The value in each is an object array with three values
+     * <ol>
+     *  <li>The PID
+     *  <li>The factory PID or {@code null}
+     *  <li>The dictionary with the properties
+     * </ol>
+     * We can't use a custom object due to class loading restrictions.
+     * @return The list, might be empty
+     */
+    List<Object[]> getConfigurations();
+
+    /**
+     * List of installable artifacts.
+     * @return The list of files. The list might be empty.
+     */
+    List<File> getInstallableArtifacts();
+}

Propchange: 
sling/whiteboard/cziegeler/feature-launcher/src/main/java/org/apache/sling/feature/launcher/spi/LauncherRunContext.java
------------------------------------------------------------------------------
    svn:eol-style = native

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

Added: 
sling/whiteboard/cziegeler/feature-launcher/src/test/java/org/apache/sling/feature/launcher/impl/artifacts/ArtifactManagerTest.java
URL: 
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-launcher/src/test/java/org/apache/sling/feature/launcher/impl/artifacts/ArtifactManagerTest.java?rev=1797026&view=auto
==============================================================================
--- 
sling/whiteboard/cziegeler/feature-launcher/src/test/java/org/apache/sling/feature/launcher/impl/artifacts/ArtifactManagerTest.java
 (added)
+++ 
sling/whiteboard/cziegeler/feature-launcher/src/test/java/org/apache/sling/feature/launcher/impl/artifacts/ArtifactManagerTest.java
 Wed May 31 12:29:12 2017
@@ -0,0 +1,100 @@
+/*
+ * 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.launcher.impl.artifacts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.sling.feature.launcher.impl.LauncherConfig;
+import org.apache.sling.feature.launcher.spi.ArtifactProvider;
+import org.junit.Test;
+
+public class ArtifactManagerTest {
+
+    private static final String METADATA = "<metadata 
modelVersion=\"1.1.0\">\n" +
+            "<groupId>org.apache.sling.samples</groupId>\n" +
+            "<artifactId>slingshot</artifactId>\n" +
+            "<version>0-DEFAULT-SNAPSHOT</version>\n" +
+            "<versioning>\n" +
+                "<snapshot>\n" +
+                    "<timestamp>20160321.103951</timestamp>\n" +
+                    "<buildNumber>1</buildNumber>\n" +
+                "</snapshot>\n" +
+                "<lastUpdated>20160321103951</lastUpdated>\n" +
+                "<snapshotVersions>\n" +
+                    "<snapshotVersion>\n" +
+                        "<extension>txt</extension>\n" +
+                        "<value>0-DEFAULT-20160321.103951-1</value>\n" +
+                        "<updated>20160321103951</updated>\n" +
+                    "</snapshotVersion>\n" +
+                    "<snapshotVersion>\n" +
+                        "<extension>pom</extension>\n" +
+                        "<value>0-DEFAULT-20160321.103951-1</value>\n" +
+                        "<updated>20160321103951</updated>\n" +
+                    "</snapshotVersion>\n" +
+                "</snapshotVersions>\n" +
+            "</versioning></metadata>";
+
+    @Test public void testMetadataParsing() {
+        final String version = ArtifactManager.getLatestSnapshot(METADATA);
+        assertEquals("20160321.103951-1", version);
+    }
+
+    @Test public void testSnapshotHandling() throws IOException {
+        final String REPO = "http://org.apache.sling";;
+        final LauncherConfig config = mock(LauncherConfig.class);
+        when(config.getRepositoryUrls()).thenReturn(new String[] {REPO});
+
+        final File metadataFile = mock(File.class);
+        when(metadataFile.exists()).thenReturn(true);
+        when(metadataFile.getPath()).thenReturn("/maven-metadata.xml");
+
+        final File artifactFile = mock(File.class);
+        when(artifactFile.exists()).thenReturn(true);
+
+        final ArtifactProvider provider = mock(ArtifactProvider.class);
+        when(provider.getArtifact(REPO + 
"/group/artifact/1.0.0-SNAPSHOT/artifact-1.0.0-SNAPSHOT.txt", 
"group/artifact/1.0.0-SNAPSHOT/artifact-1.0.0-SNAPSHOT.txt")).thenReturn(null);
+        when(provider.getArtifact(REPO + 
"/group/artifact/1.0.0-SNAPSHOT/maven-metadata.xml", 
"org.apache.sling/group/artifact/1.0.0-SNAPSHOT/maven-metadata.xml")).thenReturn(metadataFile);
+        when(provider.getArtifact(REPO + 
"/group/artifact/1.0.0-SNAPSHOT/artifact-1.0.0-20160321.103951-1.txt", 
"group/artifact/1.0.0-SNAPSHOT/artifact-1.0.0-SNAPSHOT.txt")).thenReturn(artifactFile);
+
+        final Map<String, ArtifactProvider> providers = new HashMap<>();
+        providers.put("*", provider);
+
+        final ArtifactManager mgr = new ArtifactManager(config, new String[] 
{REPO}, providers) {
+
+            @Override
+            protected String getFileContents(final ArtifactHandler handler) 
throws IOException {
+                final String path = handler.getArtifact().getPath();
+                if ( "/maven-metadata.xml".equals(path) ) {
+                    return METADATA;
+                }
+                return super.getFileContents(handler);
+            }
+        };
+
+        final ArtifactHandler handler = 
mgr.getArtifactHandler("mvn:group/artifact/1.0.0-SNAPSHOT/txt");
+        assertNotNull(handler);
+        assertEquals(artifactFile, handler.getArtifact());
+    }
+}

Propchange: 
sling/whiteboard/cziegeler/feature-launcher/src/test/java/org/apache/sling/feature/launcher/impl/artifacts/ArtifactManagerTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
sling/whiteboard/cziegeler/feature-launcher/src/test/java/org/apache/sling/feature/launcher/impl/artifacts/ArtifactManagerTest.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Added: 
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/json/ApplicationJSONWriter.java
URL: 
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/json/ApplicationJSONWriter.java?rev=1797026&view=auto
==============================================================================
--- 
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/json/ApplicationJSONWriter.java
 (added)
+++ 
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/json/ApplicationJSONWriter.java
 Wed May 31 12:29:12 2017
@@ -0,0 +1,85 @@
+/*
+ * 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.json;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.json.Json;
+import javax.json.stream.JsonGenerator;
+
+import org.apache.sling.feature.Application;
+import org.apache.sling.feature.ArtifactId;
+import org.apache.sling.feature.Configuration;
+
+
+/**
+ * Simple JSON writer for an application
+ */
+public class ApplicationJSONWriter {
+
+    /**
+     * Writes the application to the writer.
+     * The writer is not closed.
+     * @param writer Writer
+     * @param app The application
+     * @throws IOException
+     */
+    public static void write(final Writer writer, final Application app)
+    throws IOException {
+        final JsonGenerator w = Json.createGenerator(writer);
+        w.writeStartObject();
+
+        // framework
+        if ( app.getFramework() != null ) {
+            w.write("framework", app.getFramework().toMvnId());
+        }
+
+        // features
+        if ( !app.getFeatureIds().isEmpty() ) {
+            w.writeStartArray("features");
+            for(final ArtifactId id : app.getFeatureIds()) {
+                w.write(id.toMvnId());
+            }
+            w.writeEnd();
+        }
+
+        // bundles
+        FeatureJSONWriter.writeBundles(w, app.getBundles(), 
app.getConfigurations());
+
+        // configurations
+        final List<Configuration> cfgs = new ArrayList<>();
+        for(final Configuration cfg : app.getConfigurations()) {
+            final String artifactProp = 
(String)cfg.getProperties().get(Configuration.PROP_ARTIFACT);
+            if (  artifactProp == null ) {
+                cfgs.add(cfg);
+            }
+        }
+        FeatureJSONWriter.writeConfigurations(w, cfgs);
+
+        // framework properties
+        FeatureJSONWriter.writeFrameworkProperties(w, 
app.getFrameworkProperties());
+
+        // extensions
+        FeatureJSONWriter.writeExtensions(w, app.getExtensions(), 
app.getConfigurations());
+
+        w.writeEnd();
+        w.flush();
+    }
+}

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

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

Modified: 
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/json/FeatureJSONReader.java
URL: 
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/json/FeatureJSONReader.java?rev=1797026&r1=1797025&r2=1797026&view=diff
==============================================================================
--- 
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/json/FeatureJSONReader.java
 (original)
+++ 
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/json/FeatureJSONReader.java
 Wed May 31 12:29:12 2017
@@ -23,6 +23,7 @@ import java.io.StringWriter;
 import java.io.Writer;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Enumeration;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
@@ -532,6 +533,15 @@ public class FeatureJSONReader {
             } else {
                 config = new Configuration(c.getPid());
             }
+            final Enumeration<String> keyEnum = c.getProperties().keys();
+            while ( keyEnum.hasMoreElements() ) {
+                final String key = keyEnum.nextElement();
+                if ( key.startsWith(":configurator:") ) {
+                    throw new IOException(this.exceptionPrefix + 
"Configuration must not define configurator property " + key);
+                }
+                final Object val = c.getProperties().get(key);
+                config.getProperties().put(key, val);
+            }
             if ( config.getProperties().get(Configuration.PROP_ARTIFACT) != 
null ) {
                 throw new IOException(this.exceptionPrefix + "Configuration 
must not define property " + Configuration.PROP_ARTIFACT);
             }

Modified: 
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/json/FeatureJSONWriter.java
URL: 
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/json/FeatureJSONWriter.java?rev=1797026&r1=1797025&r2=1797026&view=diff
==============================================================================
--- 
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/json/FeatureJSONWriter.java
 (original)
+++ 
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/json/FeatureJSONWriter.java
 Wed May 31 12:29:12 2017
@@ -30,12 +30,14 @@ import javax.json.stream.JsonGenerator;
 
 import org.apache.sling.feature.Artifact;
 import org.apache.sling.feature.ArtifactId;
+import org.apache.sling.feature.Bundles;
 import org.apache.sling.feature.Capability;
 import org.apache.sling.feature.Configuration;
 import org.apache.sling.feature.Extension;
 import org.apache.sling.feature.ExtensionType;
 import org.apache.sling.feature.Feature;
 import org.apache.sling.feature.Include;
+import org.apache.sling.feature.KeyValueMap;
 import org.apache.sling.feature.Requirement;
 
 
@@ -48,7 +50,7 @@ public class FeatureJSONWriter {
      * Writes the feature to the writer.
      * The writer is not closed.
      * @param writer Writer
-     * @param model Model
+     * @param feature Feature
      * @throws IOException
      */
     public static void write(final Writer writer, final Feature feature)
@@ -170,14 +172,40 @@ public class FeatureJSONWriter {
         }
 
         // bundles
-        if ( !feature.getBundles().getBundlesByStartLevel().isEmpty() ) {
+        writeBundles(w, feature.getBundles(), feature.getConfigurations());
+
+        // configurations
+        final List<Configuration> cfgs = new ArrayList<>();
+        for(final Configuration cfg : feature.getConfigurations()) {
+            final String artifactProp = 
(String)cfg.getProperties().get(Configuration.PROP_ARTIFACT);
+            if (  artifactProp == null ) {
+                cfgs.add(cfg);
+            }
+        }
+        writeConfigurations(w, cfgs);
+
+        // framework properties
+        writeFrameworkProperties(w, feature.getFrameworkProperties());
+
+        // extensions
+        writeExtensions(w, feature.getExtensions(), 
feature.getConfigurations());
+
+        w.writeEnd();
+        w.flush();
+    }
+
+    static void writeBundles(final JsonGenerator w,
+            final Bundles bundles,
+            final List<Configuration> allConfigs) {
+        // bundles
+        if ( !bundles.getBundlesByStartLevel().isEmpty() ) {
             w.writeStartObject(JSONConstants.FEATURE_BUNDLES);
-            for(final Map.Entry<Integer, List<Artifact>> entry : 
feature.getBundles().getBundlesByStartLevel().entrySet()) {
+            for(final Map.Entry<Integer, List<Artifact>> entry : 
bundles.getBundlesByStartLevel().entrySet()) {
                 w.writeStartArray(String.valueOf(entry.getKey()));
 
                 for(final Artifact artifact : entry.getValue()) {
                     final List<Configuration> cfgs = new ArrayList<>();
-                    for(final Configuration cfg : feature.getConfigurations()) 
{
+                    for(final Configuration cfg : allConfigs) {
                         final String artifactProp = 
(String)cfg.getProperties().get(Configuration.PROP_ARTIFACT);
                         if (  artifact.getId().toMvnId().equals(artifactProp) 
) {
                             cfgs.add(cfg);
@@ -202,29 +230,65 @@ public class FeatureJSONWriter {
 
             w.writeEnd();
         }
+    }
 
-        // configurations
-        final List<Configuration> cfgs = new ArrayList<>();
-        for(final Configuration cfg : feature.getConfigurations()) {
-            final String artifactProp = 
(String)cfg.getProperties().get(Configuration.PROP_ARTIFACT);
-            if (  artifactProp == null ) {
-                cfgs.add(cfg);
+    /**
+     * Write the list of configurations into a "configurations" element
+     * @param w The json generator
+     * @param cfgs The list of configurations
+     */
+    static void writeConfigurations(final JsonGenerator w, final 
List<Configuration> cfgs) {
+        if ( !cfgs.isEmpty() ) {
+            w.writeStartObject(JSONConstants.FEATURE_CONFIGURATIONS);
+            for(final Configuration cfg : cfgs) {
+                final String key;
+                if ( cfg.isFactoryConfiguration() ) {
+                    key = cfg.getFactoryPid() + "~" + cfg.getName();
+                } else {
+                    key = cfg.getPid();
+                }
+                w.writeStartObject(key);
+
+                final Enumeration<String> e = cfg.getProperties().keys();
+                while ( e.hasMoreElements() ) {
+                    final String name = e.nextElement();
+                    if ( Configuration.PROP_ARTIFACT.equals(name) ) {
+                        continue;
+                    }
+
+                    final Object val = cfg.getProperties().get(name);
+                    if ( val instanceof String ) {
+                        w.write(key, (String)val);
+                    } else if ( val instanceof Boolean ) {
+                        w.write(key, (Boolean)val);
+                    } else {
+                        //  TODO - full type conversion, we have to reverse 
all types supported by the configurator
+                        w.write(key, val.toString());
+                    }
+                }
+
+                w.writeEnd();
             }
+            w.writeEnd();
         }
-        writeConfigurations(w, cfgs);
+    }
 
+    static void writeFrameworkProperties(final JsonGenerator w, final 
KeyValueMap<String> props) {
         // framework properties
-        if ( !feature.getFrameworkProperties().isEmpty() ) {
+        if ( !props.isEmpty() ) {
             w.writeStartObject(JSONConstants.FEATURE_FRAMEWORK_PROPERTIES);
 
-            for(final Map.Entry<String, String> entry : 
feature.getFrameworkProperties()) {
+            for(final Map.Entry<String, String> entry : props) {
                 w.write(entry.getKey(), entry.getValue());
             }
             w.writeEnd();
         }
+    }
 
-        // extensions
-        for(final Extension ext : feature.getExtensions()) {
+    static void writeExtensions(final JsonGenerator w,
+            final List<Extension> extensions,
+            final List<Configuration> allConfigs) {
+        for(final Extension ext : extensions) {
             final String key = ext.getName() + ":" + ext.getType().name() + 
"|" + ext.isOptional();
             if ( ext.getType() == ExtensionType.JSON ) {
                 final JsonStructure struct;
@@ -238,7 +302,7 @@ public class FeatureJSONWriter {
                 w.writeStartArray(key);
                 for(final Artifact artifact : ext.getArtifacts()) {
                     final List<Configuration> artifactCfgs = new ArrayList<>();
-                    for(final Configuration cfg : feature.getConfigurations()) 
{
+                    for(final Configuration cfg : allConfigs) {
                         final String artifactProp = 
(String)cfg.getProperties().get(Configuration.PROP_ARTIFACT);
                         if (  artifact.getId().toMvnId().equals(artifactProp) 
) {
                             artifactCfgs.add(cfg);
@@ -261,49 +325,5 @@ public class FeatureJSONWriter {
                 w.writeEnd();
             }
         }
-
-        w.writeEnd();
-        w.flush();
-    }
-
-    /**
-     * Write the list of configurations into a "configurations" element
-     * @param w The json generator
-     * @param cfgs The list of configurations
-     */
-    private static void writeConfigurations(final JsonGenerator w, final 
List<Configuration> cfgs) {
-        if ( !cfgs.isEmpty() ) {
-            w.writeStartObject(JSONConstants.FEATURE_CONFIGURATIONS);
-            for(final Configuration cfg : cfgs) {
-                final String key;
-                if ( cfg.isFactoryConfiguration() ) {
-                    key = cfg.getFactoryPid() + "~" + cfg.getName();
-                } else {
-                    key = cfg.getPid();
-                }
-                w.writeStartObject(key);
-
-                final Enumeration<String> e = cfg.getProperties().keys();
-                while ( e.hasMoreElements() ) {
-                    final String name = e.nextElement();
-                    if ( Configuration.PROP_ARTIFACT.equals(name) ) {
-                        continue;
-                    }
-
-                    final Object val = cfg.getProperties().get(name);
-                    if ( val instanceof String ) {
-                        w.write(key, (String)val);
-                    } else if ( val instanceof Boolean ) {
-                        w.write(key, (Boolean)val);
-                    } else {
-                        //  TODO - full type conversion
-                        w.write(key, val.toString());
-                    }
-                }
-
-                w.writeEnd();
-            }
-            w.writeEnd();
-        }
     }
 }


Reply via email to