This is an automated email from the ASF dual-hosted git repository.

pauls pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-whiteboard.git


The following commit(s) were added to refs/heads/master by this push:
     new cbad8993 Add a first version of an atomos launcher
cbad8993 is described below

commit cbad8993f277a4fe6a22a07bc62ed8c5a0fb3508
Author: Karl Pauls <[email protected]>
AuthorDate: Wed Oct 4 13:36:34 2023 +0200

    Add a first version of an atomos launcher
---
 atomosfeaturelauncher/.gitignore                   |   2 +
 atomosfeaturelauncher/pom.xml                      | 130 ++++++++++
 .../src/main/features/feature.json                 | 265 +++++++++++++++++++++
 atomosfeaturelauncher/src/main/features/up.json    |   5 +
 .../launcher/atomos/AtomosArtifactProvider.java    |  60 +++++
 .../launcher/atomos/AtomosFrameworkFactory.java    |  45 ++++
 .../feature/launcher/atomos/AtomosLaucherMain.java |  48 ++++
 .../feature/launcher/atomos/AtomosLauncher.java    |  88 +++++++
 .../feature/launcher/atomos/AtomosRunner.java      | 150 ++++++++++++
 ...sling.feature.io.artifacts.spi.ArtifactProvider |   1 +
 .../org.apache.sling.feature.launcher.spi.Launcher |   1 +
 11 files changed, 795 insertions(+)

diff --git a/atomosfeaturelauncher/.gitignore b/atomosfeaturelauncher/.gitignore
new file mode 100644
index 00000000..c9e18c8e
--- /dev/null
+++ b/atomosfeaturelauncher/.gitignore
@@ -0,0 +1,2 @@
+target
+launcher
diff --git a/atomosfeaturelauncher/pom.xml b/atomosfeaturelauncher/pom.xml
new file mode 100644
index 00000000..48bbdbfb
--- /dev/null
+++ b/atomosfeaturelauncher/pom.xml
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  ~ 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-bundle-parent</artifactId>
+        <version>35</version>
+        <relativePath/>
+    </parent>
+
+    <artifactId>org.apache.sling.feature.launcher.atomos</artifactId>
+    <name>Apache Sling Atomos feature launcher</name>
+    <description></description>
+    <version>0.0.1-SNAPSHOT</version>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.sling</groupId>
+                <artifactId>slingfeature-maven-plugin</artifactId>
+                <version>1.1.6</version>
+                <extensions>true</extensions>
+                <executions>
+                    <execution>
+                        <id>attach</id>
+                        <goals>
+                            <goal>attach-features</goal>
+                        </goals>
+                    </execution>
+                    <execution>
+                        <id>embed</id>
+                        <goals>
+                            <goal>embed-features</goal>
+                        </goals>
+                    </execution>
+                    <execution>
+                        <id>create-repository</id>
+                        <goals>
+                            <goal>repository</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>2.2.5.RELEASE</version>
+                <configuration>
+                    
<mainClass>org.apache.sling.feature.launcher.atomos.AtomosLaucherMain</mainClass>
+                    <classifier>fatjar</classifier>
+                </configuration>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+             <plugin>
+                <groupId>biz.aQute.bnd</groupId>
+                <artifactId>bnd-baseline-maven-plugin</artifactId>
+                <configuration>
+                    <failOnMissing>false</failOnMissing>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.rat</groupId>
+                <artifactId>apache-rat-plugin</artifactId>
+                <configuration>
+                    <excludes>
+                        <exclude>readme.md</exclude>
+                        
<exclude>src/main/resources/META-INF/services/**</exclude>
+                        <exclude>**/*.properties</exclude>
+                        <exclude>launcher/**</exclude>
+                        <exclude>**/*.patch</exclude>
+                    </excludes>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+    <dependencies>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>osgi.core</artifactId>
+            <version>8.0.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.framework</artifactId>
+            <version>7.0.5</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.feature.launcher</artifactId>
+            <version>1.2.4</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.atomos</artifactId>
+            <version>1.0.1-SNAPSHOT</version>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git a/atomosfeaturelauncher/src/main/features/feature.json 
b/atomosfeaturelauncher/src/main/features/feature.json
new file mode 100644
index 00000000..411e2378
--- /dev/null
+++ b/atomosfeaturelauncher/src/main/features/feature.json
@@ -0,0 +1,265 @@
+{
+  "bundles":[
+{
+      "id":"commons-fileupload:commons-fileupload:1.5",
+      "start-order":"1"
+    },
+    {
+      "id":"commons-io:commons-io:2.11.0",
+      "start-order":"1"
+    },
+    {
+      "id":"org.osgi:org.osgi.util.function:1.2.0",
+      "start-order":"1"
+    },
+    {
+      "id":"org.osgi:org.osgi.util.promise:1.2.0",
+      "start-order":"1"
+    },
+    {
+      "id":"org.osgi:org.osgi.service.component:1.5.0",
+      "start-order":"1"
+    },
+    {
+      "id":"org.osgi:org.osgi.util.converter:1.0.9",
+      "start-order":"1"
+    },
+    {
+      "id":"org.apache.sling:org.apache.sling.commons.log:5.4.2",
+      "start-order":"1"
+    },
+    {
+      "id":"org.apache.commons:commons-lang3:3.12.0",
+      "start-order":"1"
+    },
+    {
+      "id":"org.apache.sling:org.apache.sling.commons.logservice:1.1.0",
+      "start-order":"1"
+    },
+    {
+      "id":"org.apache.felix:org.apache.felix.log:1.2.6",
+      "start-order":"1"
+    },
+    {
+      "id":"org.slf4j:jcl-over-slf4j:1.7.36",
+      "start-order":"1"
+    },
+    {
+      "id":"org.slf4j:log4j-over-slf4j:1.7.36",
+      "start-order":"1"
+    },
+    {
+      "id":"org.slf4j:slf4j-api:1.7.36",
+      "start-order":"1"
+    },
+    {
+      "id":"org.apache.logging.log4j:log4j-api:2.20.0",
+      "start-order":1
+    },
+    {
+      "id":"org.apache.logging.log4j:log4j-to-slf4j:2.20.0",
+      "start-order":1
+    },
+    {
+      "id":"org.apache.felix:org.apache.felix.configadmin:1.9.26",
+      "start-order":"1"
+    },
+    {
+      "id":"org.apache.felix:org.apache.felix.eventadmin:1.6.4",
+      "start-order":"2"
+    },
+    {
+      "id":"org.apache.felix:org.apache.felix.metatype:1.2.4",
+      "start-order":"2"
+    },
+    {
+      "id":"org.apache.felix:org.apache.felix.inventory:1.1.0",
+      "start-order":"2"
+    },
+    {
+      "id":"org.apache.felix:org.apache.felix.http.servlet-api:2.0.0",
+      "start-order":"1"
+    },
+    {
+      "id":"org.apache.felix:org.apache.felix.http.jetty:4.2.8",
+      "start-order":"2"
+    },
+    {
+      "id":"org.apache.felix:org.apache.felix.scr:2.2.6",
+      "start-order":"1"
+    },
+    {
+      "id":"io.dropwizard.metrics:metrics-core:3.2.3",
+      "start-order":"1"
+    },
+    {
+      "id":"org.apache.sling:org.apache.sling.commons.metrics:1.2.12",
+      "start-order":"1"
+    },
+    {
+      "id":"org.apache.httpcomponents:httpcore-osgi:4.4.15",
+      "start-order":"20"
+    },
+    {
+      "id":"org.apache.httpcomponents:httpclient-osgi:4.5.13",
+      "start-order":"20"
+    },
+    {
+      "id":"commons-codec:commons-codec:1.15",
+      "start-order":"20"
+    },
+    {
+      "id":"org.apache.commons:commons-collections4:4.4",
+      "start-order":"20"
+    },
+    {
+      "id":"org.apache.commons:commons-text:1.10.0",
+      "start-order":"20"
+    },
+    {
+      "id":"org.apache.sling:org.apache.sling.api:2.27.0",
+      "start-order":"20"
+    },
+    {
+      "id":"org.apache.sling:org.apache.sling.auth.core:1.6.0",
+      "start-order":"20"
+    },
+    {
+      "id":"org.apache.sling:org.apache.sling.commons.classloader:1.4.4",
+      "start-order":"20"
+    },
+    {
+      "id":"org.apache.sling:org.apache.sling.commons.compiler:2.4.0",
+      "start-order":"20"
+    },
+    {
+      "id":"org.apache.sling:org.apache.sling.commons.johnzon:1.2.14",
+      "start-order":"20"
+    },
+    {
+      "id":"org.apache.sling:org.apache.sling.commons.mime:2.2.2",
+      "start-order":"20"
+    },
+    {
+      "id":"org.apache.sling:org.apache.sling.commons.osgi:2.4.2",
+      "start-order":"20"
+    },
+    {
+      
"id":"org.apache.sling:org.apache.sling.sfsresourceprovider:0.0.1-SNAPSHOT",
+      "start-order":"20"
+    },
+    {
+      "id":"org.apache.sling:org.apache.sling.serviceusermapper:1.5.6",
+      "start-order":"20"
+    },
+    {
+      "id":"org.apache.sling:org.apache.sling.servlets.post:2.5.0",
+      "start-order":"20"
+    },
+    {
+      "id":"org.apache.sling:org.apache.sling.settings:1.4.2",
+      "start-order":"20"
+    },
+    {
+      "id":"org.apache.sling:org.apache.sling.xss:2.2.0",
+      "start-order":"20"
+    },
+    {
+      "id":"org.apache.sling:org.apache.sling.scripting.api:2.2.0",
+      "start-order":"20"
+    },
+    {
+      "id":"org.apache.sling:org.apache.sling.scripting.core:2.4.8",
+      "start-order":"20"
+    },
+    {
+      "id":"org.apache.sling:org.apache.sling.scripting.spi:1.0.4",
+      "start-order":"20"
+    },
+    {
+      "id":"org.apache.sling:org.apache.sling.commons.threads:3.2.22",
+      "start-order":"20"
+    },
+    {
+      "id":"org.apache.sling:org.apache.sling.engine:2.14.0",
+      "start-order":"20"
+    },
+    {
+      "id":"org.apache.sling:org.apache.sling.resourceresolver:1.10.0",
+      "start-order":"20"
+    },
+    {
+      "id":"org.apache.sling:org.apache.sling.servlets.get:2.1.44",
+      "start-order":"20"
+    },
+    {
+      "id":"org.apache.sling:org.apache.sling.servlets.resolver:2.9.10",
+      "start-order":"20"
+    },
+    {
+      
"id":"org.apache.felix:org.apache.felix.webconsole.plugins.packageadmin:1.0.4",
+      "start-order":"10"
+    },
+    {
+      "id":"org.apache.felix:org.apache.felix.webconsole.plugins.ds:2.2.0",
+      "start-order":"10"
+    },
+    {
+      "id":"org.apache.felix:org.apache.felix.webconsole:4.8.8",
+      "start-order":"10"
+    },
+    {
+      "id":"org.apache.felix:org.apache.felix.webconsole.plugins.event:1.1.8",
+      "start-order":"10"
+    },
+    {
+      "id":"org.apache.sling:org.apache.sling.commons.log.webconsole:1.0.0",
+      "start-order":"10"
+    },
+    {
+      "id":"org.apache.sling:org.apache.sling.scripting.sightly:1.4.20-1.4.0",
+      "start-order":"10"
+    },
+    {
+      
"id":"org.apache.sling:org.apache.sling.scripting.sightly.runtime:1.2.6-1.4.0",
+      "start-order":"10"
+    },
+    {
+      "id":"org.apache.sling:org.apache.sling.i18n:2.5.18",
+      "start-order":"10"
+    },
+    {
+      "id":"org.apache.sling:org.apache.sling.commons.scheduler:2.7.12",
+      "start-order":"10"
+    },
+    {
+      "id":"org.apache.tika:tika-core:1.20",
+      "start-order":"10"
+    },
+    {
+      "id":"org.apache.tika:tika-parsers:1.20",
+      "start-order":"10"
+    },
+    {
+      "id": "org.apache.sling:org.apache.sling.models.api:1.5.0"
+    },
+    {
+      "id": "org.apache.geronimo.specs:geronimo-atinject_1.0_spec:1.2"
+    }
+  ],
+  "configurations":{
+    "org.apache.sling.jcr.resource.internal.JcrResourceResolverFactoryImpl":{
+      "resource.resolver.required.providernames":""
+    },
+    "org.apache.sling.sfsresource.impl.SFSResourceProvider~pictures":{
+      "provider.root":"/content",
+      "provider.file":"content"
+    },
+    "org.apache.sling.servlets.resolver.SlingServletResolver":{
+      "servletresolver.mountPathProviders":true
+    }
+  },
+  "framework-properties": {
+    "felix.cm.pm": "featurelauncher"
+  }
+}
diff --git a/atomosfeaturelauncher/src/main/features/up.json 
b/atomosfeaturelauncher/src/main/features/up.json
new file mode 100644
index 00000000..b0eac8f0
--- /dev/null
+++ b/atomosfeaturelauncher/src/main/features/up.json
@@ -0,0 +1,5 @@
+{
+  "framework-properties": {
+    "felix.cm.pm": "up"
+  }
+}
\ No newline at end of file
diff --git 
a/atomosfeaturelauncher/src/main/java/org/apache/sling/feature/launcher/atomos/AtomosArtifactProvider.java
 
b/atomosfeaturelauncher/src/main/java/org/apache/sling/feature/launcher/atomos/AtomosArtifactProvider.java
new file mode 100644
index 00000000..0ed1145b
--- /dev/null
+++ 
b/atomosfeaturelauncher/src/main/java/org/apache/sling/feature/launcher/atomos/AtomosArtifactProvider.java
@@ -0,0 +1,60 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ 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.atomos;
+
+import org.apache.sling.feature.io.artifacts.spi.ArtifactProvider;
+import org.apache.sling.feature.io.artifacts.spi.ArtifactProviderContext;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLStreamHandler;
+
+public class AtomosArtifactProvider implements ArtifactProvider {
+    @Override
+    public String getProtocol() {
+        return "*";
+    }
+
+    @Override
+    public void init(ArtifactProviderContext context) throws IOException {
+
+    }
+
+    @Override
+    public void shutdown() {
+
+    }
+
+    @Override
+    public URL getArtifact(String url, String relativeCachePath) {
+        try {
+            final URLStreamHandler dummy = new URLStreamHandler() {
+                @Override
+                protected URLConnection openConnection(URL u) throws 
IOException {
+                    return new URL(url).openConnection();
+                }
+            };
+            return new URL(new URL(null, "missing:", dummy), 
relativeCachePath, dummy);
+        } catch (MalformedURLException e) {
+            throw new RuntimeException(e);
+        }
+    }
+}
diff --git 
a/atomosfeaturelauncher/src/main/java/org/apache/sling/feature/launcher/atomos/AtomosFrameworkFactory.java
 
b/atomosfeaturelauncher/src/main/java/org/apache/sling/feature/launcher/atomos/AtomosFrameworkFactory.java
new file mode 100644
index 00000000..96f4a386
--- /dev/null
+++ 
b/atomosfeaturelauncher/src/main/java/org/apache/sling/feature/launcher/atomos/AtomosFrameworkFactory.java
@@ -0,0 +1,45 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ 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.atomos;
+
+import org.apache.felix.atomos.Atomos;
+import org.osgi.framework.connect.ConnectFrameworkFactory;
+import org.osgi.framework.launch.Framework;
+import org.osgi.framework.launch.FrameworkFactory;
+
+import java.util.Map;
+import java.util.ServiceLoader;
+
+public class AtomosFrameworkFactory implements FrameworkFactory {
+    private final Atomos m_atomos;
+
+    public AtomosFrameworkFactory(Atomos atomos) {
+        m_atomos = atomos;
+    }
+
+    @Override
+    public Framework newFramework(Map<String, String> map) {
+        ServiceLoader<ConnectFrameworkFactory> loader = 
ServiceLoader.load(ConnectFrameworkFactory.class);
+        ConnectFrameworkFactory factory = loader.iterator().next();
+        map.put("atomos.content.install", "false");
+        Framework framework = factory.newFramework(map,
+                m_atomos.getModuleConnector());
+        return framework;
+    }
+}
diff --git 
a/atomosfeaturelauncher/src/main/java/org/apache/sling/feature/launcher/atomos/AtomosLaucherMain.java
 
b/atomosfeaturelauncher/src/main/java/org/apache/sling/feature/launcher/atomos/AtomosLaucherMain.java
new file mode 100644
index 00000000..956f84fe
--- /dev/null
+++ 
b/atomosfeaturelauncher/src/main/java/org/apache/sling/feature/launcher/atomos/AtomosLaucherMain.java
@@ -0,0 +1,48 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ 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.atomos;
+
+
+import org.apache.sling.feature.launcher.impl.Main;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class AtomosLaucherMain {
+    public static void main(String[] args) {
+        List<String> launcherArgs = new ArrayList<>(Arrays.asList(args));
+
+        if (args.length > 0) {
+            URL feature = 
AtomosLaucherMain.class.getResource("/META-INF/features/feature-" + args[0] + 
".json");
+            if (feature != null) {
+                launcherArgs.remove(0);
+                launcherArgs.add(0, feature.toString());
+                launcherArgs.add(0, "-f");
+            }
+        } else {
+            URL feature = 
AtomosLaucherMain.class.getResource("/META-INF/features/feature.json");
+            if (feature != null) {
+                launcherArgs.addAll(Arrays.asList("-f", feature.toString()));
+            }
+        }
+        Main.main(launcherArgs.toArray(new String[0]));
+    }
+}
diff --git 
a/atomosfeaturelauncher/src/main/java/org/apache/sling/feature/launcher/atomos/AtomosLauncher.java
 
b/atomosfeaturelauncher/src/main/java/org/apache/sling/feature/launcher/atomos/AtomosLauncher.java
new file mode 100644
index 00000000..4ee7097e
--- /dev/null
+++ 
b/atomosfeaturelauncher/src/main/java/org/apache/sling/feature/launcher/atomos/AtomosLauncher.java
@@ -0,0 +1,88 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ 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.atomos;
+
+import org.apache.sling.feature.ArtifactId;
+import org.apache.sling.feature.Feature;
+import org.apache.sling.feature.launcher.impl.launchers.FrameworkLauncher;
+import org.apache.sling.feature.launcher.spi.LauncherPrepareContext;
+import org.slf4j.Logger;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Enumeration;
+
+public class AtomosLauncher extends FrameworkLauncher {
+    @Override
+    public void prepare(LauncherPrepareContext launcherPrepareContext, 
ArtifactId artifactId, Feature feature) throws Exception {
+        super.prepare(new LauncherPrepareContext() {
+            @Override
+            public Logger getLogger() {
+                return launcherPrepareContext.getLogger();
+            }
+
+            @Override
+            public void addAppJar(URL url) {
+
+            }
+
+            @Override
+            public URL getArtifactFile(ArtifactId artifactId) throws 
IOException {
+                return null;
+            }
+        }, artifactId, feature);
+    }
+
+    @Override
+    protected String getFrameworkRunnerClass() {
+        return AtomosRunner.class.getName();
+    }
+
+    @Override
+    public LauncherClassLoader createClassLoader() {
+        return new AtomosLauncherClassLoader();
+    }
+
+    private static final class AtomosLauncherClassLoader extends 
LauncherClassLoader {
+        static {
+            ClassLoader.registerAsParallelCapable();
+        }
+
+        private final ClassLoader parent;
+
+        private AtomosLauncherClassLoader() {
+            parent = getClass().getClassLoader();
+        }
+
+        @Override
+        protected Class<?> findClass(String name) throws 
ClassNotFoundException {
+            return parent.loadClass(name);
+        }
+
+        @Override
+        public URL findResource(String name) {
+            return parent.getResource(name);
+        }
+
+        @Override
+        public Enumeration<URL> findResources(String name) throws IOException {
+            return parent.getResources(name);
+        }
+    }
+}
diff --git 
a/atomosfeaturelauncher/src/main/java/org/apache/sling/feature/launcher/atomos/AtomosRunner.java
 
b/atomosfeaturelauncher/src/main/java/org/apache/sling/feature/launcher/atomos/AtomosRunner.java
new file mode 100644
index 00000000..3a3f9386
--- /dev/null
+++ 
b/atomosfeaturelauncher/src/main/java/org/apache/sling/feature/launcher/atomos/AtomosRunner.java
@@ -0,0 +1,150 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ 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.atomos;
+
+import org.apache.felix.atomos.Atomos;
+import org.apache.felix.atomos.AtomosContent;
+import org.apache.sling.feature.launcher.impl.launchers.FrameworkRunner;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+import org.osgi.framework.launch.Framework;
+import org.osgi.framework.launch.FrameworkFactory;
+import org.osgi.framework.startlevel.BundleStartLevel;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLStreamHandler;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.BiConsumer;
+
+public class AtomosRunner extends FrameworkRunner {
+    private final Atomos m_atomos = Atomos.newAtomos();
+    private BiConsumer<URL, Map<String, String>> bundleReporter;
+
+    public AtomosRunner(Map<String, String> frameworkProperties, Map<Integer, 
List<URL>> bundlesMap, List<Object[]> configurations, List<URL> installables) 
throws Exception {
+        super(frameworkProperties, bundlesMap, configurations, installables);
+    }
+
+    private static Iterable<Integer> sortStartLevels(final Collection<Integer> 
startLevels, final int defaultStartLevel) {
+        final List<Integer> result = new ArrayList<>(startLevels);
+        Collections.sort(result, (o1, o2) -> {
+            int i1 = o1 == 0 ? defaultStartLevel : o1;
+            int i2 = o2 == 0 ? defaultStartLevel : o2;
+            return Integer.compare(i1, i2);
+        });
+        return result;
+    }
+
+    private static int getProperty(BundleContext bc, String propName, int 
defaultValue) {
+        String val = bc.getProperty(propName);
+        if (val == null) {
+            return defaultValue;
+        } else {
+            return Integer.parseInt(val);
+        }
+    }
+
+    @Override
+    protected FrameworkFactory getFrameworkFactory() throws Exception {
+        return new AtomosFrameworkFactory(m_atomos);
+    }
+
+    @Override
+    protected void setupFramework(Framework framework, Map<Integer, List<URL>> 
bundlesMap) throws BundleException {
+        super.setupFramework(framework, Collections.emptyMap());
+        this.install(framework, bundlesMap);
+    }
+
+    @Override
+    public void setBundleReporter(final BiConsumer<URL, Map<String, String>> 
reporter) {
+        this.bundleReporter = reporter;
+        super.setBundleReporter(reporter);
+    }
+
+    private boolean isSystemBundleFragment(final Bundle installedBundle) {
+        final String fragmentHeader = getFragmentHostHeader(installedBundle);
+        return fragmentHeader != null
+                && fragmentHeader.indexOf(Constants.EXTENSION_DIRECTIVE) > 0;
+    }
+
+    /**
+     * Gets the bundle's Fragment-Host header.
+     */
+    private String getFragmentHostHeader(final Bundle b) {
+        return b.getHeaders().get(Constants.FRAGMENT_HOST);
+    }
+
+    private void install(final Framework framework, final Map<Integer, 
List<URL>> bundleMap) throws BundleException {
+        final BundleContext bc = framework.getBundleContext();
+        int defaultStartLevel = getProperty(bc, "felix.startlevel.bundle", 1);
+        for (final Integer startLevel : sortStartLevels(bundleMap.keySet(), 
defaultStartLevel)) {
+            logger.debug("Installing bundles with start level {}", startLevel);
+
+            for (final URL file : bundleMap.get(startLevel)) {
+                logger.debug("- {}", file);
+
+                final URLStreamHandler dummyHandler = new URLStreamHandler() {
+                    @Override
+                    protected URLConnection openConnection(URL u) throws 
IOException {
+                        return null;
+                    }
+                };
+                AtomosContent content = m_atomos
+                        .getBootLayer()
+                        .getAtomosContents().stream()
+                        .filter(atomosContent -> {
+                            try {
+                                return new URL(new URL(null, "missing:", 
dummyHandler), atomosContent.getAtomosLocation(), 
dummyHandler).getPath().endsWith(file.getPath().substring(file.getPath().lastIndexOf('/')));
+                            } catch (MalformedURLException e) {
+                                throw new RuntimeException(e);
+                            }
+                        })
+                        .findFirst().orElseThrow(() -> new 
IllegalStateException("Unable to find " + file.getPath() + " on the 
classpath!"));
+
+                final Bundle bundle = content.install();
+
+                // fragment?
+                if (!isSystemBundleFragment(bundle) && 
getFragmentHostHeader(bundle) == null) {
+                    if (startLevel > 0) {
+                        
bundle.adapt(BundleStartLevel.class).setStartLevel(startLevel);
+                    }
+                    bundle.start();
+                }
+
+                if (this.bundleReporter != null) {
+                    final Map<String, String> params = new HashMap<>();
+                    params.put(Constants.BUNDLE_SYMBOLICNAME, 
bundle.getSymbolicName());
+                    params.put(Constants.BUNDLE_VERSION, 
bundle.getVersion().toString());
+                    params.put("Bundle-Id", 
String.valueOf(bundle.getBundleId()));
+
+                    this.bundleReporter.accept(file, params);
+                }
+            }
+        }
+    }
+}
diff --git 
a/atomosfeaturelauncher/src/main/resources/META-INF/services/org.apache.sling.feature.io.artifacts.spi.ArtifactProvider
 
b/atomosfeaturelauncher/src/main/resources/META-INF/services/org.apache.sling.feature.io.artifacts.spi.ArtifactProvider
new file mode 100644
index 00000000..4e897b11
--- /dev/null
+++ 
b/atomosfeaturelauncher/src/main/resources/META-INF/services/org.apache.sling.feature.io.artifacts.spi.ArtifactProvider
@@ -0,0 +1 @@
+org.apache.sling.feature.launcher.atomos.AtomosArtifactProvider
\ No newline at end of file
diff --git 
a/atomosfeaturelauncher/src/main/resources/META-INF/services/org.apache.sling.feature.launcher.spi.Launcher
 
b/atomosfeaturelauncher/src/main/resources/META-INF/services/org.apache.sling.feature.launcher.spi.Launcher
new file mode 100644
index 00000000..6c66d9df
--- /dev/null
+++ 
b/atomosfeaturelauncher/src/main/resources/META-INF/services/org.apache.sling.feature.launcher.spi.Launcher
@@ -0,0 +1 @@
+org.apache.sling.feature.launcher.atomos.AtomosLauncher
\ No newline at end of file

Reply via email to