You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by tj...@apache.org on 2020/03/06 19:10:45 UTC
[felix-atomos] branch master updated: maven native image builder
This is an automated email from the ASF dual-hosted git repository.
tjwatson pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/felix-atomos.git
The following commit(s) were added to refs/heads/master by this push:
new d6d93ca maven native image builder
new c1a471a Merge pull request #1 from stbischof/maven
d6d93ca is described below
commit d6d93ca145a1e7c69cf765c46ca1115fe1a2db29
Author: Stefan Bischof <st...@bipolis.org>
AuthorDate: Fri Mar 6 15:25:07 2020 +0100
maven native image builder
---
.../additionalResourceConfig.json | 16 +
.../pom.xml | 171 ++++++
.../proxy_config.json | 3 +
.../reflectConfig_felix_atomos.json | 9 +
.../reflectConfig_felix_gogo.json | 40 ++
.../reflectConfig_felix_web.json | 33 ++
.../reflectConfig_jdk.json | 7 +
.../reflectConfig_jetty.json | 13 +
atomos.examples/pom.xml | 1 +
atomos.maven/pom.xml | 193 +++++++
.../felix/atomos/maven/NativeImageBuilder.java | 265 +++++++++
.../apache/felix/atomos/maven/NativeImageMojo.java | 175 ++++++
.../felix/atomos/maven/ReflectConfigUtil.java | 642 +++++++++++++++++++++
.../felix/atomos/maven/ResourceConfigUtil.java | 199 +++++++
.../apache/felix/atomos/maven/SubstrateUtil.java | 244 ++++++++
.../atomos/maven/reflect/ConstructorConfig.java | 40 ++
.../felix/atomos/maven/reflect/MethodConfig.java | 36 ++
.../felix/atomos/maven/reflect/ReflectConfig.java | 89 +++
.../atomos/maven/scrmock/EmptyBundeLogger.java | 468 +++++++++++++++
.../felix/atomos/maven/scrmock/EmptySCRLogger.java | 49 ++
.../felix/atomos/maven/scrmock/PathBundle.java | 206 +++++++
.../org/apache/felix/atomos/maven/MojoTest.java | 49 ++
.../felix/atomos/maven/MojoTestExperiments.java | 46 ++
.../felix/atomos/maven/ReflectConfigTest.java | 248 ++++++++
.../apache/felix/atomos/maven/SubstrateTest.java | 52 ++
.../org/apache/felix/atomos/maven/TestBase.java | 35 ++
.../apache/felix/atomos/maven/TestConstants.java | 118 ++++
.../modulepath/service/ModulepathLaunchTest.java | 25 +-
.../atomos.tests.testbundles.bom/pom.xml | 70 +++
.../pom.xml | 81 +++
.../src/main/java/module-info.java | 18 +
.../tests/testbundles/reflect/command/A.java | 20 +
.../testbundles/reflect/command/AbstractCmd.java | 23 +
.../testbundles/reflect/command/CmdExample.java | 46 ++
.../reflect/command/CommandFunction.java | 35 ++
.../testbundles/reflect/command/CommandScope.java | 34 ++
.../atomos.tests.testbundles.reflect.dto/pom.xml | 76 +++
.../src/main/java/module-info.java | 18 +
.../tests/testbundles/reflect/command/OneDTO.java | 22 +
.../service/impl/activator/Activator.java | 12 +-
.../service/impl/activator/ActivatorEcho.java | 27 +
.../tests/testbundles/service/user/EchoUser.java | 2 +-
.../service/user/{EchoUser.java => EchoUser2.java} | 21 +-
.../pom.xml | 82 +++
.../tests/testbundles/substrate/main/Main.java | 72 +++
atomos.tests/atomos.tests.testbundles/pom.xml | 4 +
pom.xml | 1 +
47 files changed, 4110 insertions(+), 26 deletions(-)
diff --git a/atomos.examples/atomos.examples.substrate.maven.equinox/additionalResourceConfig.json b/atomos.examples/atomos.examples.substrate.maven.equinox/additionalResourceConfig.json
new file mode 100644
index 0000000..2c0fa21
--- /dev/null
+++ b/atomos.examples/atomos.examples.substrate.maven.equinox/additionalResourceConfig.json
@@ -0,0 +1,16 @@
+{
+ "resources": [
+ {
+ "pattern": "META-INF/services/.*$"
+ },
+ {
+ "pattern": "templates/.*$"
+ },
+ {
+ "pattern": "res/.*$"
+ },
+ {
+ "pattern": "/system/console/res/imgs/favicon.ico"
+ }
+ ]
+}
diff --git a/atomos.examples/atomos.examples.substrate.maven.equinox/pom.xml b/atomos.examples/atomos.examples.substrate.maven.equinox/pom.xml
new file mode 100644
index 0000000..d4527c5
--- /dev/null
+++ b/atomos.examples/atomos.examples.substrate.maven.equinox/pom.xml
@@ -0,0 +1,171 @@
+<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.felix.atomos.examples</groupId>
+ <artifactId>org.apache.felix.atomos.examples</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ </parent>
+ <artifactId>org.apache.felix.atomos.examples.substrate.maven.equinox</artifactId>
+ <name>atomos.examples.substrate.maven.equinox</name>
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <java.version>1.8</java.version>
+ <maven.compiler.release combine.self="override"></maven.compiler.release>
+ <maven.compiler.source>${java.version}</maven.compiler.source>
+ <maven.compiler.target>${java.version}</maven.compiler.target>
+ </properties>
+ <repositories>
+ <repository>
+ <id>atomos-temp-m2repo</id>
+ <url>https://github.com/tjwatson/atomos-temp-m2repo/raw/master/repository</url>
+ <snapshots>
+ <enabled>true</enabled>
+ <updatePolicy>interval:60</updatePolicy>
+ </snapshots>
+ </repository>
+ </repositories>
+ <dependencies>
+ <dependency>
+ <groupId>org.eclipse.platform</groupId>
+ <artifactId>org.eclipse.osgi</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.platform</groupId>
+ <artifactId>org.eclipse.osgi</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.atomos.runtime</artifactId>
+ <version>${atomos.version}</version>
+ <exclusions>
+ <exclusion>
+ <groupId>*</groupId>
+ <artifactId>*</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix.atomos.tests</groupId>
+ <artifactId>org.apache.felix.atomos.tests.testbundles.bom</artifactId>
+ <version>${atomos.version}</version>
+ <type>pom</type>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.scr</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>osgi.promise</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.gogo.command</artifactId>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.gogo.runtime</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.gogo.shell</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.http.jetty</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.http.api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.http.whiteboard</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.webconsole</artifactId>
+ <classifier>all</classifier>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.http.servlet-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.service.cm</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.service.event</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>javax.annotation</groupId>
+ <artifactId>javax.annotation-api</artifactId>
+ <version>1.3.2</version>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>copy-dependencies</id>
+ <phase>generate-resources</phase>
+ <goals>
+ <goal>copy-dependencies</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>${project.build.directory}/classpath_lib</outputDirectory>
+ <overWriteReleases>false</overWriteReleases>
+ <overWriteSnapshots>false</overWriteSnapshots>
+ <overWriteIfNewer>true</overWriteIfNewer>
+ <excludeTransitive>false</excludeTransitive>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.atomos.maven</artifactId>
+ <version>${atomos.version}</version>
+ <configuration>
+ <debug>true</debug>
+ <additionalInitializeAtBuildTime>
+ <additionalInitializeAtBuildTime>org.apache.felix.atomos.runtime</additionalInitializeAtBuildTime>
+ <additionalInitializeAtBuildTime>org.apache.felix.atomos.impl</additionalInitializeAtBuildTime>
+ <additionalInitializeAtBuildTime>javax.servlet</additionalInitializeAtBuildTime>
+ <additionalInitializeAtBuildTime>org.apache.felix.service.command.Converter</additionalInitializeAtBuildTime>
+ <!-- <additionalInitializeAtBuildTime>org.apache.felix.atomos.impl.runtime.base</additionalInitializeAtBuildTime> -->
+ </additionalInitializeAtBuildTime>
+
+ <graalResourceConfigFiles>
+ <graalResourceConfigFile>additionalResourceConfig.json</graalResourceConfigFile>
+ </graalResourceConfigFiles>
+ <dynamicProxyConfigurationFiles>
+ <dynamicProxyConfigurationFile>proxy_config.json</dynamicProxyConfigurationFile>
+ </dynamicProxyConfigurationFiles>
+ <reflectConfigFiles>
+ <reflectConfigFile>reflectConfig_felix_atomos.json</reflectConfigFile>
+ <reflectConfigFile>reflectConfig_felix_gogo.json</reflectConfigFile>
+ <reflectConfigFile>reflectConfig_felix_web.json</reflectConfigFile>
+ <reflectConfigFile>reflectConfig_jdk.json</reflectConfigFile>
+ <reflectConfigFile>reflectConfig_jetty.json</reflectConfigFile>
+ </reflectConfigFiles>
+ <mainClass>org.apache.felix.atomos.tests.testbundles.substrate.main.Main</mainClass>
+ </configuration>
+ <executions>
+ <execution>
+ <goals>
+ <goal>atomos-native-image</goal>
+ </goals>
+ <phase>package</phase>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
\ No newline at end of file
diff --git a/atomos.examples/atomos.examples.substrate.maven.equinox/proxy_config.json b/atomos.examples/atomos.examples.substrate.maven.equinox/proxy_config.json
new file mode 100644
index 0000000..f5c672c
--- /dev/null
+++ b/atomos.examples/atomos.examples.substrate.maven.equinox/proxy_config.json
@@ -0,0 +1,3 @@
+[
+ ["org.apache.felix.service.command.Converter"]
+]
diff --git a/atomos.examples/atomos.examples.substrate.maven.equinox/reflectConfig_felix_atomos.json b/atomos.examples/atomos.examples.substrate.maven.equinox/reflectConfig_felix_atomos.json
new file mode 100644
index 0000000..9751c7a
--- /dev/null
+++ b/atomos.examples/atomos.examples.substrate.maven.equinox/reflectConfig_felix_atomos.json
@@ -0,0 +1,9 @@
+[
+ {
+ "name" : "org.apache.felix.atomos.impl.runtime.base.AtomosCommands",
+ "allPublicMethods" : true,
+ "allDeclaredMethods" : true,
+ "allPublicFields" : true,
+ "allDeclaredFields" : true
+ }
+]
diff --git a/atomos.examples/atomos.examples.substrate.maven.equinox/reflectConfig_felix_gogo.json b/atomos.examples/atomos.examples.substrate.maven.equinox/reflectConfig_felix_gogo.json
new file mode 100644
index 0000000..8366da8
--- /dev/null
+++ b/atomos.examples/atomos.examples.substrate.maven.equinox/reflectConfig_felix_gogo.json
@@ -0,0 +1,40 @@
+[
+ {
+ "name":"org.apache.felix.service.command.Converter"
+ },
+ {
+ "name" : "org.apache.felix.gogo.shell.Builtin",
+ "allPublicMethods" : true,
+ "allDeclaredMethods" : true,
+ "allPublicFields" : true,
+ "allDeclaredFields" : true
+ },
+ {
+ "name" : "org.apache.felix.gogo.shell.Shell",
+ "allPublicMethods" : true,
+ "allDeclaredMethods" : true,
+ "allPublicFields" : true,
+ "allDeclaredFields" : true
+ },
+ {
+ "name" : "org.apache.felix.gogo.shell.Procedural",
+ "allPublicMethods" : true,
+ "allDeclaredMethods" : true,
+ "allPublicFields" : true,
+ "allDeclaredFields" : true
+ },
+ {
+ "name" : "org.apache.felix.gogo.shell.Posix",
+ "allPublicMethods" : true,
+ "allDeclaredMethods" : true,
+ "allPublicFields" : true,
+ "allDeclaredFields" : true
+ },
+ {
+ "name" : "org.apache.felix.gogo.shell.Telnet",
+ "allPublicMethods" : true,
+ "allDeclaredMethods" : true,
+ "allPublicFields" : true,
+ "allDeclaredFields" : true
+ }
+]
diff --git a/atomos.examples/atomos.examples.substrate.maven.equinox/reflectConfig_felix_web.json b/atomos.examples/atomos.examples.substrate.maven.equinox/reflectConfig_felix_web.json
new file mode 100644
index 0000000..97e6494
--- /dev/null
+++ b/atomos.examples/atomos.examples.substrate.maven.equinox/reflectConfig_felix_web.json
@@ -0,0 +1,33 @@
+[
+
+ {
+ "name" : "org.apache.felix.webconsole.internal.core.ServicesServlet",
+ "allPublicConstructors" : true,
+ "allPublicMethods" : true
+ },
+ {
+ "name" : "org.apache.felix.webconsole.internal.system.VMStatPlugin",
+ "allPublicConstructors" : true,
+ "allPublicMethods" : true
+ },
+ {
+ "name" : "org.apache.felix.webconsole.internal.configuration.ConfigManager",
+ "allPublicConstructors" : true,
+ "allPublicMethods" : true
+ },
+ {
+ "name" : "org.apache.felix.webconsole.internal.core.BundlesServlet",
+ "allPublicConstructors" : true,
+ "allPublicMethods" : true
+ },
+ {
+ "name" : "org.apache.felix.webconsole.internal.misc.LicenseServlet",
+ "allPublicConstructors" : true,
+ "allPublicMethods" : true
+ },
+ {
+ "name" : "org.apache.felix.webconsole.internal.compendium.LogServlet",
+ "allPublicConstructors" : true,
+ "allPublicMethods" : true
+ }
+]
diff --git a/atomos.examples/atomos.examples.substrate.maven.equinox/reflectConfig_jdk.json b/atomos.examples/atomos.examples.substrate.maven.equinox/reflectConfig_jdk.json
new file mode 100644
index 0000000..281fba6
--- /dev/null
+++ b/atomos.examples/atomos.examples.substrate.maven.equinox/reflectConfig_jdk.json
@@ -0,0 +1,7 @@
+[
+ {
+ "name" : "java.io.File",
+ "allPublicConstructors" : true,
+ "allPublicMethods" : true
+ }
+]
diff --git a/atomos.examples/atomos.examples.substrate.maven.equinox/reflectConfig_jetty.json b/atomos.examples/atomos.examples.substrate.maven.equinox/reflectConfig_jetty.json
new file mode 100644
index 0000000..8f4b6a3
--- /dev/null
+++ b/atomos.examples/atomos.examples.substrate.maven.equinox/reflectConfig_jetty.json
@@ -0,0 +1,13 @@
+[
+ {
+ "name" : "org.eclipse.jetty.servlet.ServletMapping[]",
+ "allPublicConstructors" : true,
+ "allPublicMethods" : true
+ },
+ {
+ "name" : "org.eclipse.jetty.servlet.FilterMapping[]",
+ "allPublicConstructors" : true,
+ "allPublicMethods" : true
+ }
+
+]
diff --git a/atomos.examples/pom.xml b/atomos.examples/pom.xml
index d0f45df..afc2339 100644
--- a/atomos.examples/pom.xml
+++ b/atomos.examples/pom.xml
@@ -20,6 +20,7 @@
<module>atomos.examples.jlink</module>
<module>atomos.examples.substrate.equinox</module>
<module>atomos.examples.substrate.felix</module>
+ <module>atomos.examples.substrate.maven.equinox</module>
</modules>
</profile>
</profiles>
diff --git a/atomos.maven/pom.xml b/atomos.maven/pom.xml
new file mode 100644
index 0000000..a827a46
--- /dev/null
+++ b/atomos.maven/pom.xml
@@ -0,0 +1,193 @@
+<?xml version="1.0"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>atomos-parent</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>org.apache.felix.atomos.maven</artifactId>
+ <packaging>maven-plugin</packaging>
+ <name>atomos.maven</name>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.framework</artifactId>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.scr</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-plugin-api</artifactId>
+ <version>3.6.3</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven.plugin-tools</groupId>
+ <artifactId>maven-plugin-annotations</artifactId>
+ <version>3.6.0</version>
+ <scope>provided</scope>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-core</artifactId>
+ <version>3.6.3</version>
+ </dependency>
+ <dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.assertj</groupId>
+ <artifactId>assertj-core</artifactId>
+ <version>3.15.0</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.javassist</groupId>
+ <artifactId>javassist</artifactId>
+ <version>3.26.0-GA</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix.atomos.tests</groupId>
+ <artifactId>org.apache.felix.atomos.tests.testbundles.bom</artifactId>
+ <type>pom</type>
+ <scope>test</scope>
+ <version>${atomos.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>6.0.0</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.service.http</artifactId>
+ <version>1.2.1</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.gogo.command</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.http.jetty</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.http.api</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.http.whiteboard</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.webconsole</artifactId>
+ <scope>test</scope>
+ <classifier>all</classifier>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.http.servlet-api</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>copy-dependencies</id>
+ <phase>generate-resources</phase>
+ <goals>
+ <goal>copy-dependencies</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>${project.build.directory}/test-dependencies</outputDirectory>
+ <overWriteReleases>false</overWriteReleases>
+ <overWriteSnapshots>false</overWriteSnapshots>
+ <overWriteIfNewer>true</overWriteIfNewer>
+ <excludeTransitive>false</excludeTransitive>
+ <includeGroupIds>org.osgi,org.apache.felix,org.apache.felix.atomos.tests</includeGroupIds>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <!-- <plugin> -->
+ <!-- <artifactId>maven-invoker-plugin</artifactId> -->
+ <!-- <version>3.2.1</version> -->
+ <!-- <configuration> -->
+ <!-- <cloneProjectsTo>${project.build.directory}/it</cloneProjectsTo> -->
+ <!-- <localRepositoryPath>${project.build.directory}/local-repo</localRepositoryPath> -->
+ <!-- <postBuildHookScript>verify</postBuildHookScript> -->
+ <!-- <goals> -->
+ <!-- <goal>install</goal> -->
+ <!-- </goals> -->
+ <!-- </configuration> -->
+ <!-- <executions> -->
+ <!-- <execution> -->
+ <!-- <id>integration-test</id> -->
+ <!-- <goals> -->
+ <!-- <goal>install</goal> -->
+ <!-- <goal>run</goal> -->
+ <!-- </goals> -->
+ <!-- </execution> -->
+ <!-- </executions> -->
+ <!-- </plugin> -->
+ </plugins>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-plugin-plugin</artifactId>
+ <version>3.6.0</version>
+ <executions>
+ <execution>
+ <id>default-descriptor</id>
+ <phase>process-classes</phase>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.eclipse.m2e</groupId>
+ <artifactId>lifecycle-mapping</artifactId>
+ <version>1.0.0</version>
+ <configuration>
+ <lifecycleMappingMetadata>
+ <pluginExecutions>
+ <pluginExecution>
+ <pluginExecutionFilter>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-plugin-plugin</artifactId>
+ <versionRange>[3.6,)</versionRange>
+ <goals>
+ <goal>descriptor</goal>
+ <goal>helpmojo</goal>
+ </goals>
+ </pluginExecutionFilter>
+ <action>
+ <ignore/>
+ </action>
+ </pluginExecution>
+ </pluginExecutions>
+ </lifecycleMappingMetadata>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+</project>
diff --git a/atomos.maven/src/main/java/org/apache/felix/atomos/maven/NativeImageBuilder.java b/atomos.maven/src/main/java/org/apache/felix/atomos/maven/NativeImageBuilder.java
new file mode 100644
index 0000000..cbfd48b
--- /dev/null
+++ b/atomos.maven/src/main/java/org/apache/felix/atomos/maven/NativeImageBuilder.java
@@ -0,0 +1,265 @@
+/*
+ * Licensed 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.felix.atomos.maven;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.apache.felix.atomos.maven.ResourceConfigUtil.ResourceConfigResult;
+
+public class NativeImageBuilder
+{
+
+ private static final String GRAAL_HOME = "GRAAL_HOME";
+
+ private static final String JAVA_HOME = "java.home";
+
+ private static final String NI_DEFAULT_NAME = "Application";
+
+ private static final String NI_PARAM_ALLOW_INCOMPLETE_CLASSPATH = "--allow-incomplete-classpath";
+
+ private static final String NI_PARAM_DEBUG_ATTACH = "--debug-attach";
+
+ private static final String NI_PARAM_H_CLASS = "-H:Class=";
+
+ private static final String NI_PARAM_H_DYNAMIC_PROXY_CONFIGURATION_FILES = "-H:DynamicProxyConfigurationFiles=";
+
+ private static final String NI_PARAM_H_NAME = "-H:Name=";
+
+ private static final String NI_PARAM_H_PRINT_CLASS_INITIALIZATION = "-H:+PrintClassInitialization";
+
+ private static final String NI_PARAM_H_REFLECTION_CONFIGURATION_FILES = "-H:ReflectionConfigurationFiles=";
+
+ private static final String NI_PARAM_H_REPORT_EXCEPTION_STACK_TRACES = "-H:+ReportExceptionStackTraces";
+
+ private static final String NI_PARAM_H_REPORT_UNSUPPORTED_ELEMENTS_AT_RUNTIME = "-H:+ReportUnsupportedElementsAtRuntime";
+
+ private static final String NI_PARAM_H_RESOURCE_CONFIGURATION_FILES = "-H:ResourceConfigurationFiles=";
+
+ private static final String NI_PARAM_H_TRACE_CLASS_INITIALIZATION = "-H:+TraceClassInitialization";
+
+ private static final String NI_PARAM_INITIALIZE_AT_BUILD_TIME = "--initialize-at-build-time=";
+
+ private static final String NI_PARAM_NO_FALLBACK = "--no-fallback";
+
+ public static List<String> createExecutionArgs(
+ List<String> additionalInitializeAtBuildTime, List<Path> reflectConfigFiles,
+ List<Path> resourceConfigs, List<Path> dynamicProxyConfigurationFiles,
+ ResourceConfigResult resourceConfigResult, boolean debug, String mainClass,
+ String imageName) throws IOException
+ {
+ final List<String> args = new ArrayList<>();
+
+ args.add(NI_PARAM_ALLOW_INCOMPLETE_CLASSPATH);
+
+ //initialize-at-build-time
+
+ final List<String> in = new ArrayList<>();
+ if (resourceConfigResult.allResourcePackages != null)
+ {
+ in.addAll(resourceConfigResult.allResourcePackages);
+ }
+ if (additionalInitializeAtBuildTime != null)
+ {
+ in.addAll(additionalInitializeAtBuildTime);
+ }
+
+ final String initBuildTime = in.stream().sorted(
+ (o1, o2) -> o1.compareTo(o2)).collect(Collectors.joining(","));
+
+ if (initBuildTime != null && !initBuildTime.isEmpty())
+ {
+ args.add(NI_PARAM_INITIALIZE_AT_BUILD_TIME + initBuildTime);
+ }
+
+ //H:ReflectionConfigurationFiles
+
+ if (reflectConfigFiles != null && !reflectConfigFiles.isEmpty())
+ {
+ final String reflCfgFiles = reflectConfigFiles.stream().map(
+ p -> p.toAbsolutePath().toString()).collect(Collectors.joining(","));
+
+ args.add(NI_PARAM_H_REFLECTION_CONFIGURATION_FILES + reflCfgFiles);
+
+ }
+ //H:ResourceConfigurationFiles
+
+ if (resourceConfigs != null && !resourceConfigs.isEmpty())
+ {
+ final String files = resourceConfigs.stream().map(
+ p -> p.toAbsolutePath().toString()).collect(Collectors.joining(","));
+ args.add(NI_PARAM_H_RESOURCE_CONFIGURATION_FILES + files);
+ }
+
+ //H:DynamicProxyConfigurationFiles
+ if (dynamicProxyConfigurationFiles != null
+ && !dynamicProxyConfigurationFiles.isEmpty())
+ {
+ args.add(NI_PARAM_H_DYNAMIC_PROXY_CONFIGURATION_FILES
+ + dynamicProxyConfigurationFiles.stream().map(
+ p -> p.toAbsolutePath().toString()).collect(Collectors.joining(",")));
+ }
+ //other
+ args.add(NI_PARAM_H_REPORT_UNSUPPORTED_ELEMENTS_AT_RUNTIME);
+ args.add(NI_PARAM_H_REPORT_EXCEPTION_STACK_TRACES);
+ args.add(NI_PARAM_H_TRACE_CLASS_INITIALIZATION);
+ args.add(NI_PARAM_H_PRINT_CLASS_INITIALIZATION);
+ args.add(NI_PARAM_NO_FALLBACK);
+ if (debug)
+ {
+ args.add(NI_PARAM_DEBUG_ATTACH);
+ }
+ args.add(NI_PARAM_H_CLASS + mainClass);
+ args.add(NI_PARAM_H_NAME + imageName);
+ return args;
+ }
+
+ public static Path execute(Path nativeImageExec, Path outputDir, List<Path> classpath,
+ List<String> args) throws Exception
+ {
+ final Optional<Path> exec = findNativeImageExecutable(nativeImageExec);
+
+ if (exec.isEmpty())
+ {
+ throw new Exception("Missing native image executable. Set '" + GRAAL_HOME
+ + "' with the path as an environment variable");
+ }
+
+ Path resultFile = null;
+
+ Optional<String> imageName = args.stream().filter(
+ s -> s.startsWith(NI_PARAM_H_NAME)).findFirst();
+ if (imageName.isPresent())
+ {
+ final String name = imageName.get().substring(NI_PARAM_H_NAME.length());
+ resultFile = outputDir.resolve(name);
+ }
+ else
+ {
+ args.add(NI_PARAM_H_NAME + NI_DEFAULT_NAME);
+ resultFile = outputDir.resolve(NI_DEFAULT_NAME);
+ }
+
+ final String cp = classpath.stream().map(
+ p -> p.toAbsolutePath().toString()).collect(Collectors.joining(":"));
+
+ final List<String> commands = new ArrayList<>();
+ commands.add(exec.get().toAbsolutePath().toString());
+ commands.add("-cp");
+ commands.add(cp);
+ commands.addAll(args);
+
+ final ProcessBuilder pB = new ProcessBuilder(commands);
+ pB.inheritIO();
+ pB.directory(outputDir.toFile());
+
+ final String cmds = pB.command().stream().collect(Collectors.joining(" "));
+
+ System.out.println(cmds);
+
+ final Process process = pB.start();
+ final int exitValue = process.waitFor();
+ if (exitValue != 0)
+ {
+ throw new Exception("native-image returns exit value: " + exitValue);
+ }
+ if (Files.exists(resultFile))
+ {
+ return resultFile;
+ }
+ throw new Exception(
+ "native-image could not be found: " + resultFile.toAbsolutePath().toString());
+
+ }
+
+ private static Path findNativeImageExec(Path path)
+ {
+
+ Path candidate = null;
+ if (!Files.exists(path))
+ {
+ return candidate;
+ }
+ if (Files.isDirectory(path))
+ {
+ candidate = findNativeImageExec(path.resolve("native-image"));
+
+ if (candidate == null)
+ {
+ candidate = findNativeImageExec(path.resolve("bin"));
+ }
+
+ }
+ else //file o
+ {
+
+ try
+ {
+ final ProcessBuilder processBuilder = new ProcessBuilder(path.toString(),
+ "--version");
+
+ final Process versionProcess = processBuilder.start();
+ final Stream<String> lines = new BufferedReader(
+ new InputStreamReader(versionProcess.getInputStream())).lines();
+ final Optional<String> versionLine = lines.filter(
+ l -> l.contains("GraalVM Version")).findFirst();
+
+ if (!versionLine.isEmpty())
+ {
+ System.out.println(versionLine.get());
+ candidate = path;
+ }
+ }
+ catch (final IOException e)
+ {
+ e.printStackTrace();
+ }
+
+ }
+ return candidate;
+
+ }
+
+ private static Optional<Path> findNativeImageExecutable(Path nativeImageExec)
+ {
+
+ Path exec = null;
+ if (nativeImageExec != null)
+ {
+ exec = findNativeImageExec(nativeImageExec);
+ }
+ if (exec == null)
+ {
+ exec = findNativeImageExec(Paths.get("native-image"));
+ }
+ if (exec == null && System.getenv(GRAAL_HOME) != null)
+ {
+ exec = findNativeImageExec(Paths.get(System.getenv(GRAAL_HOME)));
+ }
+ if (exec == null && System.getProperty(JAVA_HOME) != null)
+ {
+ exec = findNativeImageExec(Paths.get(System.getProperty(JAVA_HOME)));
+ }
+ return Optional.ofNullable(exec);
+ }
+}
diff --git a/atomos.maven/src/main/java/org/apache/felix/atomos/maven/NativeImageMojo.java b/atomos.maven/src/main/java/org/apache/felix/atomos/maven/NativeImageMojo.java
new file mode 100644
index 0000000..ae47886
--- /dev/null
+++ b/atomos.maven/src/main/java/org/apache/felix/atomos/maven/NativeImageMojo.java
@@ -0,0 +1,175 @@
+/*
+ * Licensed 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.felix.atomos.maven;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.jar.JarFile;
+import java.util.stream.Collectors;
+
+import org.apache.felix.atomos.maven.ResourceConfigUtil.ResourceConfigResult;
+import org.apache.felix.atomos.maven.reflect.ReflectConfig;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.project.MavenProject;
+
+@Mojo(name = "atomos-native-image", defaultPhase = LifecyclePhase.GENERATE_RESOURCES)
+public class NativeImageMojo extends AbstractMojo
+{
+
+ private class Config
+ {
+ public List<String> additionalInitializeAtBuildTime = new ArrayList<>();
+
+ public List<Path> dynamicProxyConfigurationFiles = new ArrayList<>();
+ public List<Path> reflectConfigFiles = new ArrayList<>();
+ public List<Path> resourceConfigs = new ArrayList<>();
+ }
+
+ final private static String ATOMOS_PATH = "ATOMOS";
+
+ public static boolean isJarFile(Path path)
+ {
+ try (JarFile j = new JarFile(path.toFile());)
+ {
+
+ return true;
+ }
+ catch (IOException e)
+ {
+
+ }
+
+ return false;
+ }
+
+ @Parameter
+ private List<String> additionalInitializeAtBuildTime;
+
+ @Parameter(defaultValue = "${project.build.directory}/" + "classpath_lib")
+ private File classpath_lib;
+
+ @Parameter(defaultValue = "false") //TODO: CHECK GRAAL EE ONLY
+ private boolean debug;
+
+ @Parameter
+ private List<File> dynamicProxyConfigurationFiles;
+
+ @Parameter
+ private List<File> graalResourceConfigFiles;
+
+ @Parameter
+ private String imageName;
+
+ @Parameter
+ private String mainClass;
+
+ @Parameter(defaultValue = "graal.native.image.build.args")
+ private String nativeImageArgsPropertyName;
+
+ @Parameter
+ private String nativeImageExecutable;
+
+ @Parameter(defaultValue = "${project.build.directory}/" + ATOMOS_PATH)
+ private File outputDirectory;
+
+ @Parameter(defaultValue = "${project}", required = true, readonly = false)
+ private MavenProject project;
+
+ @Parameter
+ private List<File> reflectConfigFiles;
+
+ @Override
+ public void execute() throws MojoExecutionException
+ {
+ getLog().info("outputDirectory" + outputDirectory);
+ try
+ {
+ Files.createDirectories(outputDirectory.toPath());
+
+ Config config = new Config();
+
+ config.additionalInitializeAtBuildTime = additionalInitializeAtBuildTime;
+ if (imageName == null || imageName.isEmpty())
+ {
+ imageName = project.getArtifactId();
+ }
+
+ if (graalResourceConfigFiles != null && !graalResourceConfigFiles.isEmpty())
+ {
+ config.resourceConfigs = graalResourceConfigFiles.stream().map(
+ File::toPath).collect(Collectors.toList());
+ }
+
+ if (reflectConfigFiles != null && !reflectConfigFiles.isEmpty())
+ {
+ config.reflectConfigFiles = reflectConfigFiles.stream().map(
+ File::toPath).collect(Collectors.toList());
+ }
+
+ if (dynamicProxyConfigurationFiles != null
+ && !dynamicProxyConfigurationFiles.isEmpty())
+ {
+ config.dynamicProxyConfigurationFiles = dynamicProxyConfigurationFiles.stream().map(
+ File::toPath).collect(Collectors.toList());
+ }
+
+ List<Path> paths = Files.list(classpath_lib.toPath()).filter(
+ NativeImageMojo::isJarFile).collect(Collectors.toList());
+
+ Path p = SubstrateUtil.substrate(paths, outputDirectory.toPath());
+
+ List<ReflectConfig> reflectConfigs = ReflectConfigUtil.reflectConfig(paths);
+
+ String content = ReflectConfigUtil.json(reflectConfigs);
+
+ if (!content.isEmpty())
+ {
+ Path reflectConfig = outputDirectory.toPath().resolve(
+ "graal_reflect_config.json");
+ Files.write(reflectConfig, content.getBytes());
+
+ config.reflectConfigFiles.add(reflectConfig);
+ }
+
+ ResourceConfigResult resourceConfigResult = ResourceConfigUtil.resourceConfig(
+ paths);
+
+ List<String> argsPath = NativeImageBuilder.createExecutionArgs(
+ config.additionalInitializeAtBuildTime, config.reflectConfigFiles,
+ config.resourceConfigs, config.dynamicProxyConfigurationFiles,
+ resourceConfigResult, false, mainClass, imageName);
+
+ paths.add(p);
+ Path nip = nativeImageExecutable == null ? null
+ : Paths.get(nativeImageExecutable);
+ NativeImageBuilder.execute(nip, outputDirectory.toPath(), paths, argsPath);
+ }
+ catch (
+
+ Exception e)
+ {
+ throw new MojoExecutionException("Error", e);
+ }
+
+ }
+}
diff --git a/atomos.maven/src/main/java/org/apache/felix/atomos/maven/ReflectConfigUtil.java b/atomos.maven/src/main/java/org/apache/felix/atomos/maven/ReflectConfigUtil.java
new file mode 100644
index 0000000..16ac6fd
--- /dev/null
+++ b/atomos.maven/src/main/java/org/apache/felix/atomos/maven/ReflectConfigUtil.java
@@ -0,0 +1,642 @@
+/*
+ * Licensed 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.felix.atomos.maven;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.UncheckedIOException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Dictionary;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.StringTokenizer;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Function;
+import java.util.jar.Attributes;
+import java.util.jar.JarFile;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.apache.felix.atomos.maven.reflect.ConstructorConfig;
+import org.apache.felix.atomos.maven.reflect.MethodConfig;
+import org.apache.felix.atomos.maven.reflect.ReflectConfig;
+import org.apache.felix.atomos.maven.scrmock.EmptyBundeLogger;
+import org.apache.felix.atomos.maven.scrmock.PathBundle;
+import org.apache.felix.scr.impl.logger.BundleLogger;
+import org.apache.felix.scr.impl.metadata.ComponentMetadata;
+import org.apache.felix.scr.impl.metadata.ReferenceMetadata;
+import org.apache.felix.scr.impl.parser.KXml2SAXParser;
+import org.apache.felix.scr.impl.xml.XmlHandler;
+import org.osgi.framework.Constants;
+import org.osgi.service.component.ComponentConstants;
+
+public class ReflectConfigUtil
+{
+ private static final String OSGI_COMMAND_FUNCTION = "osgi.command.function";
+
+ private static String CLASS_START = "{\n";
+ private static String CLASS_END = "}";
+ private static String COMMA_SPACE = ", ";
+ private static String COMMA_ENTER = ",\n";
+ private static String NAME_PATTERN = "\"name\":\"%s\"";
+ private static String CLASS_NAME = NAME_PATTERN;
+ private static String FIELDS_START = "\"fields\" : [\n";
+ private static String FIELD_NAME = NAME_PATTERN;
+ private static String FIELDS_END = "]";
+ private static String METHODS_START = "\"methods\" : [\n";
+ private static String METHOD_NAME = NAME_PATTERN;
+ private static String METHODS_END = FIELDS_END;
+ private static String CONSTRUCTOR_METHOD_NAME = "<init>";
+
+ private static String PARAMETER_TYPE = "\"parameterTypes\":[%s]";
+
+ private static String COMPONENT_CONSTRUCTOR = "\"allPublicConstructors\" : true";
+
+ public static List<ReflectConfig> reflectConfig(List<Path> paths) throws Exception
+ {
+ URL[] urls = paths.stream().map(p -> {
+ try
+ {
+ return p.toUri().toURL();
+ }
+ catch (MalformedURLException e1)
+ {
+ throw new UncheckedIOException(e1);
+ }
+ }).toArray(URL[]::new);
+
+ try (URLClassLoader cl = URLClassLoader.newInstance(urls, null))
+ {
+
+ List<Class<?>> classes = loadClasses(paths, cl);
+
+ List<ReflectConfig> reflectConfigs = new ArrayList<>();
+ for (Path p : paths)
+ {
+ try (JarFile jar = new JarFile(p.toFile()))
+ {
+ discoverBundleActivators(cl, jar, reflectConfigs);
+ discoverSeriviceComponents(cl, jar, reflectConfigs);
+ discoverDTOs(classes, reflectConfigs);
+
+ }
+ }
+ return reflectConfigs;
+ }
+ }
+
+ private static List<Class<?>> loadClasses(List<Path> paths, URLClassLoader cl)
+ {
+ return paths.stream().map(p -> {
+ try
+ {
+ return new JarFile(p.toFile());
+ }
+ catch (IOException e)
+ {
+ throw new UncheckedIOException(e);
+ }
+ }).flatMap(j -> j.stream()).filter(e -> !e.isDirectory()).filter(
+ e -> e.getName().endsWith(".class")).filter(
+ e -> !e.getName().endsWith("module-info.class")).map(e -> {
+ try
+ {
+ String name = e.getName().replace("/", ".").substring(0,
+ e.getName().length() - 6);
+ return cl.loadClass(name);
+ }
+ catch (NoClassDefFoundError | ClassNotFoundException e1)
+ {
+ // happened when incomplete classpath
+ }
+ return null;
+ }).collect(Collectors.toList());
+ }
+
+ private static void discoverDTOs(final List<Class<?>> classes,
+ List<ReflectConfig> reflectConfigs)
+ {
+ classes.stream().filter(c -> c != null).filter(c -> {
+ Class<?> clazz = c;
+ while (clazz != null && clazz != Object.class)
+ {
+
+ if ("org.osgi.dto.DTO".equals(clazz.getName()))
+ {
+ return true;
+ }
+ clazz = clazz.getSuperclass();
+ }
+ return false;
+ }).forEach(clazz -> {
+
+ for (Field field : clazz.getFields())
+ {
+ addField(field.getName(), clazz, reflectConfigs);
+ }
+ });
+
+ }
+
+ public static String json(ReflectConfig reflectConfig)
+ {
+ StringBuilder builder = new StringBuilder();
+ builder.append(ind(1)).append(CLASS_START);
+
+ builder.append(ind(2)).append(String.format(CLASS_NAME, reflectConfig.className));
+
+ AtomicReference<String> comma = new AtomicReference<>("");
+ if (!reflectConfig.fields.isEmpty())
+ {
+ builder.append(COMMA_ENTER).append(ind(2)).append(FIELDS_START);
+ reflectConfig.fields.forEach(
+ f -> builder.append(comma.getAndSet(COMMA_ENTER)).append(ind(3)).append(
+ "{").append(String.format(FIELD_NAME, f)).append("}"));
+ builder.append('\n').append(ind(2)).append(FIELDS_END);
+ }
+
+ comma.set("");
+ if (!reflectConfig.methods.isEmpty() || !reflectConfig.constructor.isEmpty())
+ {
+ builder.append(COMMA_ENTER).append(ind(2)).append(METHODS_START);
+ reflectConfig.constructor.forEach(c -> {
+ builder.append(comma.getAndSet(COMMA_ENTER)).append(ind(3)).append(
+ "{").append(String.format(METHOD_NAME, CONSTRUCTOR_METHOD_NAME));
+
+ if (c.methodParameterTypes != null)
+ {
+ String types = Stream.of(c.methodParameterTypes).sequential().collect(
+ Collectors.joining("\",\""));
+ if (!types.isEmpty())
+ {
+ types = "\"" + types + "\"";
+ }
+ builder.append(COMMA_SPACE).append(
+ String.format(PARAMETER_TYPE, types));
+ }
+ builder.append("}");
+ });
+ reflectConfig.methods.forEach(m -> {
+ builder.append(comma.getAndSet(COMMA_ENTER))//
+ .append(ind(3)).append("{").append(
+ String.format(METHOD_NAME, m.name));
+ if (m.methodParameterTypes != null)
+ {
+ String types = Stream.of(m.methodParameterTypes).sequential().collect(
+ Collectors.joining("\",\""));
+ if (!types.isEmpty())
+ {
+ types = "\"" + types + "\"";
+ }
+ builder.append(COMMA_SPACE).append(
+ String.format(PARAMETER_TYPE, types));
+ }
+ builder.append("}");
+ });
+ builder.append('\n').append(ind(2)).append(METHODS_END);
+ }
+
+ builder.append('\n').append(ind(1)).append(CLASS_END);
+
+ return builder.toString();
+ }
+
+ private static Object ind(int num)
+ {
+ StringBuilder indent = new StringBuilder();
+ for (int i = 0; i < num; i++)
+ {
+ indent.append(" ");
+ }
+ return indent.toString();
+ }
+
+ public static String json(List<ReflectConfig> reflectConfigs)
+ {
+ StringBuilder builder = new StringBuilder();
+ builder.append('[').append('\n');
+ AtomicReference<String> comma = new AtomicReference<>("");
+
+ Collections.sort(reflectConfigs, new Comparator<ReflectConfig>()
+ {
+ @Override
+ public int compare(ReflectConfig o1, ReflectConfig o2)
+ {
+ return o1.className.compareTo(o2.className);
+ }
+ });
+
+ for (ReflectConfig config : reflectConfigs)
+ {
+ builder.append(comma.getAndSet(COMMA_ENTER)).append(json(config));
+ }
+ builder.append('\n').append(']');
+ return builder.toString();
+ }
+
+ private static void discoverBundleActivators(URLClassLoader cl, JarFile jar,
+ List<ReflectConfig> reflectConfigs) throws IOException
+ {
+
+ Attributes attributes = jar.getManifest().getMainAttributes();
+ String bundleActivatorClassName = attributes.getValue(Constants.BUNDLE_ACTIVATOR);
+ if (bundleActivatorClassName == null)
+ {
+ bundleActivatorClassName = attributes.getValue(
+ Constants.EXTENSION_BUNDLE_ACTIVATOR);
+ }
+ if (bundleActivatorClassName != null)
+ {
+ bundleActivatorClassName = bundleActivatorClassName.trim();
+ try
+ {
+ Class<?> bundleActivatorClazz = cl.loadClass(bundleActivatorClassName);
+ Class<?> bundleContextClass = cl.loadClass(
+ "org.osgi.framework.BundleContext");
+ ReflectConfig rc = computeIfAbsent(reflectConfigs,
+ bundleActivatorClassName);
+ rc.constructor.add(new ConstructorConfig(new String[] {}));
+
+ addMethod("start", new Class[] { bundleContextClass },
+ bundleActivatorClazz, reflectConfigs);
+ addMethod("stop", new Class[] { bundleContextClass },
+ bundleActivatorClazz, reflectConfigs);
+ magic(cl, bundleActivatorClazz, reflectConfigs);
+ }
+ catch (ClassNotFoundException e)
+ {
+ // TODO log
+ }
+ }
+ }
+
+ private static ReflectConfig computeIfAbsent(List<ReflectConfig> reflectConfigs,
+ final String activator)
+ {
+ Optional<ReflectConfig> oConfig = reflectConfigs.stream().filter(
+ c -> c.className.equals(activator)).findFirst();
+
+ ReflectConfig rc = null;
+ if (oConfig.isPresent())
+ {
+ rc = oConfig.get();
+ }
+ else
+ {
+ rc = new ReflectConfig(activator);
+ reflectConfigs.add(rc);
+ }
+ return rc;
+ }
+
+ private static void magic(URLClassLoader cl, Class<?> bundleActivatorClass,
+ List<ReflectConfig> reflectConfigs)
+ {
+ try
+ {
+
+ Object o = bundleActivatorClass.newInstance();
+
+ Method startMethod = null;
+ for (Method m : bundleActivatorClass.getMethods())
+ {
+ if (m.getName().equals("start") && m.getReturnType().equals(void.class)
+ && m.getParameterCount() == 1
+ && m.getParameters()[0].getParameterizedType().getTypeName().equals(
+ "org.osgi.framework.BundleContext"))
+ {
+ startMethod = m;
+ break;
+ }
+ }
+
+ if (startMethod != null)
+ {
+ InvocationHandler invocationHandler = new InvocationHandler()
+ {
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args)
+ throws Throwable
+ {
+ try
+ {
+ //System.out.println("----------------------------------");
+ //System.out.println(method);
+ if (method.getName().equals("registerService")
+ && method.getParameterCount() == 3
+ && method.getParameters()[1].getType().getTypeName().equals(
+ "java.lang.Object")
+ && method.getParameters()[2].getType().getTypeName().equals(
+ "java.util.Dictionary"))
+ {
+ Object service = args[1];
+ Dictionary<?, ?> dict = (Dictionary<?, ?>) args[2];
+ //System.out.println("service: "+service.getClass());
+ //System.out.println("cfg: "+dict);
+ if (dict != null)
+ {
+ Map<?, ?> dictCopy = Collections.list(
+ dict.keys()).stream().collect(
+ Collectors.toMap(Function.identity(),
+ dict::get));
+ if (dictCopy.containsKey("osgi.command.function"))
+ {
+ String[] functions = (String[]) dict.get(
+ "osgi.command.function");
+
+ addMethodsFromGogoCommand(reflectConfigs,
+ service.getClass(), functions);
+ }
+ }
+ }
+ if (method.getName().equals("getBundleId"))
+ {
+ return 1L;
+ }
+ if (method.getName().equals("getVersion"))
+ {
+ return cl.loadClass(
+ "org.osgi.framework.Version").getConstructor(
+ int.class, int.class, int.class).newInstance(0, 0,
+ 0);
+ }
+ else if (method.getReturnType().isInterface())
+ {
+ return Proxy.newProxyInstance(cl,
+ new Class[] { method.getReturnType() }, this);
+ }
+ }
+ catch (Exception e)
+ {
+ // expected
+ //e.printStackTrace();
+ }
+ return null;
+ }
+ };
+ Object p = Proxy.newProxyInstance(cl,
+ new Class[] { cl.loadClass("org.osgi.framework.BundleContext") },
+ invocationHandler);
+ startMethod.invoke(o, p);
+ }
+ }
+ catch (Throwable e)
+ { // expected
+ // TODO Log and maybe show cp errors
+ // e.printStackTrace();
+ }
+
+ }
+
+ private static void discoverSeriviceComponents(URLClassLoader cl, JarFile jar,
+ List<ReflectConfig> reflectConfigs) throws Exception
+ {
+
+ List<ComponentMetadata> cDDTOs = readCDDTO(jar);
+
+ for (ComponentMetadata c : cDDTOs)
+ {
+ c.validate();
+ Class<?> clazz = cl.loadClass(c.getImplementationClassName());
+ // Activate Deactivate Modify
+ Optional.ofNullable(c.getActivate()).ifPresent(
+ (m) -> addMethod(m, clazz, reflectConfigs));
+ Optional.ofNullable(c.getModified()).ifPresent(
+ (m) -> addMethod(m, clazz, reflectConfigs));
+ Optional.ofNullable(c.getDeactivate()).ifPresent(
+ (m) -> addMethod(m, clazz, reflectConfigs));
+ if (c.getActivationFields() != null)
+ {
+ for (String fName : c.getActivationFields())
+ {
+ addField(fName, clazz, reflectConfigs);
+ }
+ }
+ //Reference
+ if (c.getDependencies() != null)
+ {
+
+ String[] constrParams = new String[c.getNumberOfConstructorParameters()];
+ for (ReferenceMetadata r : c.getDependencies())
+ {
+ Optional.ofNullable(r.getParameterIndex()).ifPresent(
+ (i) -> constrParams[i] = r.getInterface());
+ Optional.ofNullable(r.getField()).ifPresent(
+ (f) -> addField(f, clazz, reflectConfigs));
+ Optional.ofNullable(r.getBind()).ifPresent(
+ (m) -> addMethod(m, clazz, reflectConfigs));
+ Optional.ofNullable(r.getUpdated()).ifPresent(
+ (m) -> addMethod(m, clazz, reflectConfigs));
+ Optional.ofNullable(r.getUnbind()).ifPresent(
+ (m) -> addMethod(m, clazz, reflectConfigs));
+ Optional.ofNullable(r.getInterface()).ifPresent(
+ (i) -> computeIfAbsent(reflectConfigs, i));
+ }
+ ReflectConfig config = computeIfAbsent(reflectConfigs, clazz.getName());
+
+ boolean foundConstructor = false;
+ if (c.getNumberOfConstructorParameters() == 0)
+ {
+ config.constructor.add(new ConstructorConfig());
+ foundConstructor = true;
+ }
+ else
+ {
+ for (Constructor<?> constructor : clazz.getConstructors())
+ {
+ if (constructor.getParameterCount() != c.getNumberOfConstructorParameters())
+ {
+
+ continue;
+ }
+ boolean match = true;
+ for (int j = 0; j < constructor.getParameterCount(); j++)
+ {
+ String p = constructor.getParameters()[j].getType().getName();
+ String s = constrParams[j];
+ if (s != null && !p.equals(s))
+ {
+ match = false;
+ break;
+ }
+ }
+ if (match)
+ {
+ String[] ps = Stream.of(constructor.getParameters()).map(
+ p -> p.getType().getName()).toArray(String[]::new);
+ config.constructor.add(new ConstructorConfig(ps));
+ foundConstructor = true;
+ break;
+ }
+ }
+ if (!foundConstructor)
+ {
+ config.allPublicConstructors = true;
+ }
+ }
+ }
+ // Gogo osgi.command.function
+ if (c.getProperties().containsKey(OSGI_COMMAND_FUNCTION))
+ {
+ Object oFunctions = c.getProperties().get(OSGI_COMMAND_FUNCTION);
+ String[] functions = null;
+ if (oFunctions instanceof String[])
+ {
+ functions = (String[]) oFunctions;
+ }
+ else
+ {
+ functions = new String[] { oFunctions.toString() };
+ }
+ addMethodsFromGogoCommand(reflectConfigs, clazz, functions);
+ }
+ }
+ }
+
+ private static void addMethodsFromGogoCommand(List<ReflectConfig> classes,
+ Class<?> clazz, String[] functions)
+ {
+ Class<?> tmpClass = clazz;
+
+ for (String function : functions)
+ {
+ addMethod(function, tmpClass, classes);
+ }
+ tmpClass = tmpClass.getSuperclass();
+
+ if (tmpClass != null && !tmpClass.equals(Object.class))
+ {
+ addMethodsFromGogoCommand(classes, tmpClass, functions);
+ }
+ }
+
+ private static List<ComponentMetadata> readCDDTO(JarFile jar) throws Exception
+ {
+
+ BundleLogger logger = new EmptyBundeLogger();
+ List<ComponentMetadata> list = new ArrayList<>();
+ Attributes attributes = jar.getManifest().getMainAttributes();
+ String descriptorLocations = attributes.getValue(
+ ComponentConstants.SERVICE_COMPONENT);
+ if (descriptorLocations == null)
+ {
+ return list;
+ }
+ StringTokenizer st = new StringTokenizer(descriptorLocations, ", ");
+ while (st.hasMoreTokens())
+ {
+ String descriptorLocation = st.nextToken();
+ InputStream stream = jar.getInputStream(jar.getEntry(descriptorLocation));
+ BufferedReader in = new BufferedReader(
+ new InputStreamReader(stream, "UTF-8"));
+ XmlHandler handler = new XmlHandler(new PathBundle(jar), logger, true, true);
+
+
+ KXml2SAXParser parser = new KXml2SAXParser(in);
+ parser.parseXML(handler);
+ list.addAll(handler.getComponentMetadataList());
+ }
+
+ // //Felix SCR Version-> 2.1.17-SNAPSHOT
+ // //https://github.com/apache/felix-dev/commit/2d035e21d69c2bb8892d5d5d3e1027befcc3c50b#diff-dad1c7cc45e5c46bca969c95ac501546
+ // while (st.hasMoreTokens())
+ // {
+ // String descriptorLocation = st.nextToken();
+ // InputStream stream = jar.getInputStream(jar.getEntry(descriptorLocation));
+ // XmlHandler handler = new XmlHandler(new PathBundle(jar), logger, true, true);
+ //
+ // final SAXParserFactory factory = SAXParserFactory.newInstance();
+ // factory.setNamespaceAware(true);
+ // final SAXParser parser = factory.newSAXParser();
+ // parser.parse( stream, handler );
+ // list.addAll(handler.getComponentMetadataList());
+ // }
+
+ return list;
+ }
+
+ private static void addMethod(String mName, Class<?> clazz,
+ List<ReflectConfig> classes)
+ {
+ addMethod(mName, null, clazz, classes);
+ }
+
+ //parameterTypes==null means not Set
+ //parameterTypes=={} means no method parameter
+ private static void addMethod(String mName, Class<?>[] parameterTypes, Class<?> clazz,
+ List<ReflectConfig> reflectConfigs)
+ {
+ for (Method m : clazz.getDeclaredMethods())
+ {
+ if (mName.equals(m.getName()))
+ {
+ if (parameterTypes == null)
+ {
+ ReflectConfig config = computeIfAbsent(reflectConfigs,
+ clazz.getName());
+ config.methods.add(new MethodConfig(mName, null));
+ break;
+ }
+ else if (Arrays.equals(m.getParameterTypes(), parameterTypes))
+ {
+ ReflectConfig config = computeIfAbsent(reflectConfigs,
+ clazz.getName());
+ String[] sParameterTypes = Stream.of(parameterTypes).sequential().map(
+ Class::getName).toArray(String[]::new);
+ config.methods.add(new MethodConfig(mName, sParameterTypes));
+ break;
+ }
+ }
+ }
+ Class<?> superClass = clazz.getSuperclass();
+ if (superClass != null)
+ {
+ addMethod(mName, parameterTypes, superClass, reflectConfigs);
+ }
+ }
+
+ private static void addField(String fName, Class<?> clazz,
+ List<ReflectConfig> reflectConfig)
+ {
+ boolean exists = Stream.of(clazz.getDeclaredFields()).anyMatch(
+ f -> f.getName().equals(fName));
+ if (exists)
+ {
+ ReflectConfig config = computeIfAbsent(reflectConfig, clazz.getName());
+ config.fields.add(fName);
+ }
+
+ Class<?> superClass = clazz.getSuperclass();
+ if (superClass != null)
+ {
+ addField(fName, superClass, reflectConfig);
+ }
+ }
+
+}
diff --git a/atomos.maven/src/main/java/org/apache/felix/atomos/maven/ResourceConfigUtil.java b/atomos.maven/src/main/java/org/apache/felix/atomos/maven/ResourceConfigUtil.java
new file mode 100644
index 0000000..10f8005
--- /dev/null
+++ b/atomos.maven/src/main/java/org/apache/felix/atomos/maven/ResourceConfigUtil.java
@@ -0,0 +1,199 @@
+/*
+ * Licensed 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.felix.atomos.maven;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.stream.Collectors;
+
+public class ResourceConfigUtil
+{
+ //TODO: remove Duplicats with substrateService
+ private static Collection<String> EXCLUDE_DIRS = Collections.unmodifiableList(
+ Arrays.asList("META-INF/", "OSGI-INF/", "OSGI-OPT/"));
+ private static Collection<String> EXCLUDE_NAMES = Collections.unmodifiableList(
+ Arrays.asList("/packageinfo"));
+ private static String SERVICES = "META-INF/services/";
+ private static String CLASS_SUFFIX = ".class";
+ private static String START = "{\n";
+ private static String END = "\n}";
+ private static String COMMA = ",\n";
+ private static char NL = '\n';
+ private static String BUNDLES_START = "\"bundles\" : [\n";
+ private static String BUNDLE_NAME = "{ \"name\" : \"%s\" }";
+ private static String BUNDLES_END = "]";
+ private static String RESOURCES_START = "\"resources\" : [\n";
+ private static String RESOURCE_PATTERN = "{ \"pattern\" : \"%s\" }";
+ private static String RESOURCES_END = BUNDLES_END;
+ private static String FRENCH_BUNDLE_CLASS = "_fr.class";
+ private static String FRENCH_BUNDLE_PROPS = "_fr.properties";
+
+ public static ResourceConfigResult resourceConfig(List<Path> paths) throws IOException
+ {
+
+ Set<String> allResourceBundles = new TreeSet<>();
+ Set<String> allResourcePatterns = new TreeSet<>();
+ Set<String> allResourcePackages = new TreeSet<>();
+ discoverResources(paths, allResourceBundles, allResourcePatterns,
+ allResourcePackages);
+
+ ResourceConfigResult result = new ResourceConfigResult();
+ result.allResourceBundles = allResourceBundles;
+ result.allResourcePackages = allResourcePackages;
+ result.allResourcePatterns = allResourcePatterns;
+
+ return result;
+ }
+
+ public static String createResourceJson(ResourceConfigResult result)
+ {
+ // if (true)
+ // {
+ // return "{\"resources\" : [ {\"pattern\": \"atomos/.*$\"} ] }";
+ // }
+
+ TreeSet<String> allResourceBundles = new TreeSet<>((o1, o2) -> o1.compareTo(o2));
+ allResourceBundles.addAll(result.allResourceBundles);
+ TreeSet<String> allResourcePatterns = new TreeSet<>((o1, o2) -> o1.compareTo(o2));
+ allResourcePatterns.addAll(result.allResourcePatterns);
+
+ AtomicBoolean first = new AtomicBoolean();
+ StringBuilder resourceConfig = new StringBuilder();
+ resourceConfig.append(START);
+ if (!allResourceBundles.isEmpty())
+ {
+ resourceConfig.append(ind(1)).append(BUNDLES_START);
+ allResourceBundles.forEach(b -> {
+ if (!first.compareAndSet(false, true))
+ {
+ resourceConfig.append(COMMA);
+ }
+ resourceConfig.append(ind(2)).append(String.format(BUNDLE_NAME, b));
+ });
+ resourceConfig.append(NL).append(ind(1)).append(BUNDLES_END);
+ }
+ first.set(false);
+ if (!allResourcePatterns.isEmpty())
+ {
+ if (!allResourceBundles.isEmpty())
+ {
+ resourceConfig.append(COMMA);
+ }
+ resourceConfig.append(ind(1)).append(RESOURCES_START);
+ allResourcePatterns.forEach(p -> {
+ if (!first.compareAndSet(false, true))
+ {
+ resourceConfig.append(COMMA);
+ }
+ resourceConfig.append(ind(2)).append(String.format(RESOURCE_PATTERN, p));
+ });
+ resourceConfig.append(NL).append(ind(1)).append(RESOURCES_END);
+ }
+ resourceConfig.append(END);
+ return resourceConfig.toString();
+
+ }
+
+ private static void discoverResources(List<Path> paths,
+ Set<String> allResourceBundles, Set<String> allResourcePatterns,
+ Set<String> allResourcePackages) throws IOException
+ {
+ for (Path path : paths)
+ {
+
+ try (JarFile jar = new JarFile(path.toFile());)
+ {
+ pattern: for (JarEntry entry : jar.stream().collect(Collectors.toList()))
+ {
+ String entryName = entry.getName();
+ if (entry.isDirectory())
+ {
+ continue;
+ }
+ if (entryName.indexOf('/') == -1)
+ {
+ continue;
+ }
+ if (entryName.startsWith(SERVICES))
+ {
+ allResourcePatterns.add(entryName);
+ continue;
+ }
+ for (String excluded : EXCLUDE_NAMES)
+ {
+ if (entryName.endsWith(excluded))
+ {
+ continue pattern;
+ }
+ }
+ for (String excluded : EXCLUDE_DIRS)
+ {
+ if (entryName.startsWith(excluded))
+ {
+ continue pattern;
+ }
+ }
+ if (entryName.endsWith(CLASS_SUFFIX))
+ {
+ // just looking for resource bundle for french as an indicator
+ if (entryName.endsWith(FRENCH_BUNDLE_CLASS))
+ {
+ String bundleName = entryName.substring(0, entryName.length()
+ - FRENCH_BUNDLE_CLASS.length()).replace('/', '.');
+ String bundlePackage = bundleName.substring(0,
+ bundleName.lastIndexOf('.'));
+ allResourceBundles.add(bundleName);
+ allResourcePackages.add(bundlePackage);
+ }
+ continue;
+ }
+ if (entryName.endsWith(FRENCH_BUNDLE_PROPS))
+ {
+ allResourceBundles.add(entryName.substring(0,
+ entryName.length() - FRENCH_BUNDLE_PROPS.length()).replace(
+ '/', '.'));
+ continue;
+ }
+ allResourcePatterns.add(entryName);
+ }
+ }
+ }
+ }
+
+ private static Object ind(int num)
+ {
+ StringBuilder indent = new StringBuilder();
+ for (int i = 0; i < num; i++)
+ {
+ indent.append(" ");
+ }
+ return indent.toString();
+ }
+
+ static class ResourceConfigResult
+ {
+ Set<String> allResourceBundles = new TreeSet<>();
+ Set<String> allResourcePatterns = new TreeSet<>();
+ Set<String> allResourcePackages = new TreeSet<>();
+ }
+}
diff --git a/atomos.maven/src/main/java/org/apache/felix/atomos/maven/SubstrateUtil.java b/atomos.maven/src/main/java/org/apache/felix/atomos/maven/SubstrateUtil.java
new file mode 100644
index 0000000..a946f71
--- /dev/null
+++ b/atomos.maven/src/main/java/org/apache/felix/atomos/maven/SubstrateUtil.java
@@ -0,0 +1,244 @@
+/*
+ * Licensed 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.felix.atomos.maven;
+
+import java.io.BufferedWriter;
+import java.io.ByteArrayOutputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.UncheckedIOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.apache.felix.atomos.maven.ResourceConfigUtil.ResourceConfigResult;
+import org.osgi.framework.Constants;
+
+public class SubstrateUtil
+{
+
+ /**
+ *
+ */
+ private static final String ATOMOS_CATH_ALL = "atomos/.*$";
+ /**
+ *
+ */
+ private static final String ATOMOS_SUBSTRATE_JAR = "atomos.substrate.jar";
+ private static final Collection<String> DEFAULT_EXCLUDE_NAMES = Arrays.asList(
+ "about.html", "DEPENDENCIES", "LICENSE", "NOTICE", "changelog.txt",
+ "LICENSE.txt");
+ private static final Collection<String> DEFAULT_EXCLUDE_PATHS = Arrays.asList(
+ "META-INF/maven/", "OSGI-OPT/");
+ public static final String ATOMOS_BUNDLES_BASE_PATH = "atomos/";
+ public static final String ATOMOS_BUNDLES_INDEX = ATOMOS_BUNDLES_BASE_PATH
+ + "bundles.index";
+ private static final String ATOMOS_BUNDLE_SEPARATOR = "ATOMOS_BUNDLE";
+
+ enum EntryType
+ {
+ PACKAGE, NON_PACKAGE, PACKAGE_CLASS, PACKAGE_RESOURCE, DEFAULT_PACKAGE_CLASS, DEFAULT_PACKAGE_RESOURCE, NON_PACKAGE_RESOURCE
+ }
+
+ private static boolean isClass(String path)
+ {
+ return path.endsWith(".class");
+ }
+
+ private static boolean filter(JarEntry entry)
+ {
+ final String path = entry.getName();
+ if (entry.isDirectory() || isClass(path))
+ {
+ return false;
+ }
+ for (final String excludedPath : DEFAULT_EXCLUDE_PATHS)
+ {
+ if (path.startsWith(excludedPath))
+ {
+ return false;
+ }
+ }
+ for (final String excludedName : DEFAULT_EXCLUDE_NAMES)
+ {
+ if (path.endsWith(excludedName))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static Path substrate(List<Path> files, Path outputDir)
+ throws IOException, NoSuchAlgorithmException
+ {
+ if (!outputDir.toFile().isDirectory())
+ {
+ throw new IllegalArgumentException(
+ "Output file must be a directory." + outputDir);
+ }
+ if (!outputDir.toFile().exists())
+ {
+ Files.createDirectories(outputDir);
+ }
+
+ final Path p = outputDir.resolve(ATOMOS_SUBSTRATE_JAR);
+
+ final Manifest manifest = new Manifest();
+ manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
+ try (final JarOutputStream z = new JarOutputStream(
+ new FileOutputStream(p.toFile()), manifest);)
+ {
+
+ final List<String> bundleIndexLines = new ArrayList<>();
+ final List<String> resources = new ArrayList<>();
+ final AtomicLong counter = new AtomicLong(0);
+ final Stream<SubstrateInfo> bis = files.stream()//
+ .map(path -> create(z, counter.getAndIncrement(), path));
+
+ bis.forEach(s -> {
+ if (s.bsn != null)
+ {
+ bundleIndexLines.add(ATOMOS_BUNDLE_SEPARATOR);
+ bundleIndexLines.add(s.id);
+ bundleIndexLines.add(s.bsn);
+ bundleIndexLines.add(s.version);
+ s.files.forEach(f -> {
+ bundleIndexLines.add(f);
+ resources.add(ATOMOS_BUNDLES_BASE_PATH + s.id + "/" + f);
+ });
+ }
+ });
+ writeBundleIndexFile(z, bundleIndexLines);
+ writeGraalResourceConfig(z, resources);
+ }
+ return p;
+ }
+
+ private static void writeGraalResourceConfig(JarOutputStream jos,
+ List<String> resources) throws IOException
+ {
+ // resources.add(ATOMOS_BUNDLES_INDEX);
+ resources.add(ATOMOS_CATH_ALL); // This alone could be enough,
+
+ final ResourceConfigResult result = new ResourceConfigResult();
+ result.allResourcePatterns.addAll(resources);
+
+ final String graalResConfJson = ResourceConfigUtil.createResourceJson(result);
+
+ final JarEntry graalResConfEntry = new JarEntry(
+ "META-INF/native-image/resource-config.json");
+ jos.putNextEntry(graalResConfEntry);
+ jos.write(graalResConfJson.getBytes());
+
+ }
+
+ private static void writeBundleIndexFile(JarOutputStream jos,
+ final List<String> resources) throws IOException
+ {
+
+ final JarEntry atomosIndexEntry = new JarEntry(ATOMOS_BUNDLES_INDEX);
+ jos.putNextEntry(atomosIndexEntry);
+
+ final ByteArrayOutputStream out = new ByteArrayOutputStream();
+ try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out)))
+ {
+ resources.forEach((l) -> {
+ try
+ {
+ writer.append(l).append('\n');
+ }
+ catch (final IOException ex)
+ {
+ throw new UncheckedIOException(ex);
+ }
+ });
+ }
+ jos.write(out.toByteArray());
+
+ }
+
+ static SubstrateInfo create(JarOutputStream jos, long id, Path path)
+ {
+ final SubstrateInfo info = new SubstrateInfo();
+ info.path = path;
+ try (final JarFile jar = new JarFile(info.path.toFile()))
+ {
+ final Attributes attributes = jar.getManifest().getMainAttributes();
+ info.bsn = attributes.getValue(Constants.BUNDLE_SYMBOLICNAME);
+ info.version = attributes.getValue(Constants.BUNDLE_VERSION);
+ info.id = Long.toString(id);
+
+ if (info.bsn == null)
+ {
+ return info;
+ }
+ if (info.version == null)
+ {
+ info.version = "0.0";
+ }
+ info.files = jar.stream().filter(j -> filter(j)).peek(j -> {
+ try
+ {
+ final JarEntry entry = new JarEntry(
+ ATOMOS_BUNDLES_BASE_PATH + id + "/" + j.getName());
+ if (j.getCreationTime() != null)
+ {
+ entry.setCreationTime(j.getCreationTime());
+ }
+ if (j.getComment() != null)
+ {
+ entry.setComment(j.getComment());
+ }
+ jos.putNextEntry(entry);
+ jos.write(jar.getInputStream(j).readAllBytes());
+ }
+ catch (final IOException e)
+ {
+ throw new UncheckedIOException(e);
+ }
+
+ }).map(JarEntry::getName).collect(Collectors.toList());
+ }
+ catch (final IOException e)
+ {
+ throw new UncheckedIOException(e);
+ }
+ return info;
+ }
+
+ static class SubstrateInfo
+ {
+ Path out;
+ Path path;
+ String id;
+ String bsn;
+ String version;
+ List<String> files = new ArrayList<>();
+
+ }
+}
diff --git a/atomos.maven/src/main/java/org/apache/felix/atomos/maven/reflect/ConstructorConfig.java b/atomos.maven/src/main/java/org/apache/felix/atomos/maven/reflect/ConstructorConfig.java
new file mode 100644
index 0000000..94c2349
--- /dev/null
+++ b/atomos.maven/src/main/java/org/apache/felix/atomos/maven/reflect/ConstructorConfig.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed 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.felix.atomos.maven.reflect;
+
+import java.util.Arrays;
+
+public class ConstructorConfig
+{
+ public String[] methodParameterTypes;
+
+ public ConstructorConfig()
+ {
+ this(new String[] {});
+ }
+
+ public ConstructorConfig(String[] methodParameters)
+ {
+ methodParameterTypes = methodParameters;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "ConstructorConfig [methodParameters=" + Arrays.toString(methodParameterTypes)
+ + "]";
+ }
+}
+
+
diff --git a/atomos.maven/src/main/java/org/apache/felix/atomos/maven/reflect/MethodConfig.java b/atomos.maven/src/main/java/org/apache/felix/atomos/maven/reflect/MethodConfig.java
new file mode 100644
index 0000000..09e5ff0
--- /dev/null
+++ b/atomos.maven/src/main/java/org/apache/felix/atomos/maven/reflect/MethodConfig.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed 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.felix.atomos.maven.reflect;
+
+import java.util.Arrays;
+
+public class MethodConfig extends ConstructorConfig
+{
+ @Override
+ public String toString()
+ {
+ return "MethodConfig [name=" + name + ", methodParameters="
+ + Arrays.toString(methodParameterTypes) + "]";
+ }
+
+ public String name;
+
+ public MethodConfig(String name, String[] methodParameters)
+ {
+ super(methodParameters);
+ this.name = name;
+ }
+
+
+}
\ No newline at end of file
diff --git a/atomos.maven/src/main/java/org/apache/felix/atomos/maven/reflect/ReflectConfig.java b/atomos.maven/src/main/java/org/apache/felix/atomos/maven/reflect/ReflectConfig.java
new file mode 100644
index 0000000..f3dacfe
--- /dev/null
+++ b/atomos.maven/src/main/java/org/apache/felix/atomos/maven/reflect/ReflectConfig.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed 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.felix.atomos.maven.reflect;
+
+import java.util.Comparator;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+public class ReflectConfig
+{
+ static Comparator<MethodConfig> mc = new Comparator<>()
+ {
+
+ @Override
+ public int compare(MethodConfig o1, MethodConfig o2)
+ {
+ int i = o1.name.compareTo(o2.name);
+ if (i == 0)
+ {
+ return cc.compare(o1, o2);
+ }
+ return i;
+ }
+ };
+
+ static Comparator<ConstructorConfig> cc = new Comparator<>()
+ {
+
+ @Override
+ public int compare(ConstructorConfig o1, ConstructorConfig o2)
+ {
+ String s1 = o1.methodParameterTypes == null ? ""
+ : Stream.of(o1.methodParameterTypes).collect(Collectors.joining(","));
+ String s2 = o2.methodParameterTypes == null ? ""
+ : Stream.of(o2.methodParameterTypes).collect(Collectors.joining(","));
+
+ return s1.compareTo(s2);
+ }
+ };
+ public String className;
+
+ public boolean allPublicConstructors = false;
+ public Set<ConstructorConfig> constructor = new TreeSet<>(cc);
+ public Set<String> fields = new TreeSet<>();
+ public Set<MethodConfig> methods = new TreeSet<>(mc);
+
+ public ReflectConfig(String className)
+ {
+ this.className = className;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "ReflectConfig [className=" + className + ", allPublicConstructors="
+ + allPublicConstructors + ", constructor=" + constructor + ", fields="
+ + fields + ", methods=" + methods + "]";
+ }
+
+ @Override
+ public boolean equals(Object other)
+ {
+ if (!(other instanceof ReflectConfig))
+ {
+ return false;
+ }
+ return className == ((ReflectConfig) other).className;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return className.hashCode();
+ }
+
+}
diff --git a/atomos.maven/src/main/java/org/apache/felix/atomos/maven/scrmock/EmptyBundeLogger.java b/atomos.maven/src/main/java/org/apache/felix/atomos/maven/scrmock/EmptyBundeLogger.java
new file mode 100644
index 0000000..1270f34
--- /dev/null
+++ b/atomos.maven/src/main/java/org/apache/felix/atomos/maven/scrmock/EmptyBundeLogger.java
@@ -0,0 +1,468 @@
+/*
+ * Licensed 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.felix.atomos.maven.scrmock;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.security.cert.X509Certificate;
+import java.util.Collection;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.felix.scr.impl.logger.BundleLogger;
+import org.apache.felix.scr.impl.logger.ScrLogger;
+import org.apache.felix.scr.impl.manager.ScrConfiguration;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.BundleListener;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkListener;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceFactory;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceObjects;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.framework.Version;
+
+public class EmptyBundeLogger extends BundleLogger
+{
+ static Bundle b = new Bundle()
+ {
+ @Override
+ public int compareTo(Bundle o)
+ {
+ return 0;
+ }
+
+ @Override
+ public void update(InputStream input) throws BundleException
+ {
+ }
+
+ @Override
+ public void update() throws BundleException
+ {
+ }
+
+ @Override
+ public void uninstall() throws BundleException
+ {
+ }
+
+ @Override
+ public void stop(int options) throws BundleException
+ {
+ }
+
+ @Override
+ public void stop() throws BundleException
+ {
+ }
+
+ @Override
+ public void start(int options) throws BundleException
+ {
+ }
+
+ @Override
+ public void start() throws BundleException
+ {
+ }
+
+ @Override
+ public Class<?> loadClass(String name) throws ClassNotFoundException
+ {
+ return null;
+ }
+
+ @Override
+ public boolean hasPermission(Object permission)
+ {
+ return false;
+ }
+
+ @Override
+ public Version getVersion()
+ {
+ return null;
+ }
+
+ @Override
+ public String getSymbolicName()
+ {
+ return null;
+ }
+
+ @Override
+ public int getState()
+ {
+ return 0;
+ }
+
+ @Override
+ public Map<X509Certificate, List<X509Certificate>> getSignerCertificates(
+ int signersType)
+ {
+ return null;
+ }
+
+ @Override
+ public ServiceReference<?>[] getServicesInUse()
+ {
+ return null;
+ }
+
+ @Override
+ public Enumeration<URL> getResources(String name) throws IOException
+ {
+ return null;
+ }
+
+ @Override
+ public URL getResource(String name)
+ {
+ return null;
+ }
+
+ @Override
+ public ServiceReference<?>[] getRegisteredServices()
+ {
+ return null;
+ }
+
+ @Override
+ public String getLocation()
+ {
+ return null;
+ }
+
+ @Override
+ public long getLastModified()
+ {
+ return 0;
+ }
+
+ @Override
+ public Dictionary<String, String> getHeaders(String locale)
+ {
+ return null;
+ }
+
+ @Override
+ public Dictionary<String, String> getHeaders()
+ {
+ return null;
+ }
+
+ @Override
+ public Enumeration<String> getEntryPaths(String path)
+ {
+ return null;
+ }
+
+ @Override
+ public URL getEntry(String path)
+ {
+ return null;
+ }
+
+ @Override
+ public File getDataFile(String filename)
+ {
+ return null;
+ }
+
+ @Override
+ public long getBundleId()
+ {
+ return 0;
+ }
+
+ @Override
+ public BundleContext getBundleContext()
+ {
+ return null;
+ }
+
+ @Override
+ public Enumeration<URL> findEntries(String path, String filePattern,
+ boolean recurse)
+ {
+ return null;
+ }
+
+ @Override
+ public <A> A adapt(Class<A> type)
+ {
+ return null;
+ }
+ };
+ static BundleContext bc = new BundleContext()
+ {
+ @Override
+ public boolean ungetService(ServiceReference<?> reference)
+ {
+ return false;
+ }
+
+ @Override
+ public void removeServiceListener(ServiceListener listener)
+ {
+ }
+
+ @Override
+ public void removeFrameworkListener(FrameworkListener listener)
+ {
+ }
+
+ @Override
+ public void removeBundleListener(BundleListener listener)
+ {
+ }
+
+ @Override
+ public <S> ServiceRegistration<S> registerService(Class<S> clazz,
+ ServiceFactory<S> factory, Dictionary<String, ?> properties)
+ {
+ return null;
+ }
+
+ @Override
+ public <S> ServiceRegistration<S> registerService(Class<S> clazz, S service,
+ Dictionary<String, ?> properties)
+ {
+ return null;
+ }
+
+ @Override
+ public ServiceRegistration<?> registerService(String clazz, Object service,
+ Dictionary<String, ?> properties)
+ {
+ return null;
+ }
+
+ @Override
+ public ServiceRegistration<?> registerService(String[] clazzes, Object service,
+ Dictionary<String, ?> properties)
+ {
+ return null;
+ }
+
+ @Override
+ public Bundle installBundle(String location, InputStream input)
+ throws BundleException
+ {
+ return null;
+ }
+
+ @Override
+ public Bundle installBundle(String location) throws BundleException
+ {
+ return null;
+ }
+
+ @Override
+ public <S> Collection<ServiceReference<S>> getServiceReferences(Class<S> clazz,
+ String filter) throws InvalidSyntaxException
+ {
+ return null;
+ }
+
+ @Override
+ public ServiceReference<?>[] getServiceReferences(String clazz, String filter)
+ throws InvalidSyntaxException
+ {
+ return null;
+ }
+
+ @Override
+ public <S> ServiceReference<S> getServiceReference(Class<S> clazz)
+ {
+ return null;
+ }
+
+ @Override
+ public ServiceReference<?> getServiceReference(String clazz)
+ {
+ return null;
+ }
+
+ @Override
+ public <S> ServiceObjects<S> getServiceObjects(ServiceReference<S> reference)
+ {
+ return null;
+ }
+
+ @Override
+ public <S> S getService(ServiceReference<S> reference)
+ {
+ return null;
+ }
+
+ @Override
+ public String getProperty(String key)
+ {
+ return null;
+ }
+
+ @Override
+ public File getDataFile(String filename)
+ {
+ return null;
+ }
+
+ @Override
+ public Bundle[] getBundles()
+ {
+ return null;
+ }
+
+ @Override
+ public Bundle getBundle(String location)
+ {
+ return null;
+ }
+
+ @Override
+ public Bundle getBundle(long id)
+ {
+ return null;
+ }
+
+ @Override
+ public Bundle getBundle()
+ {
+ return b;
+ }
+
+ @Override
+ public ServiceReference<?>[] getAllServiceReferences(String clazz, String filter)
+ throws InvalidSyntaxException
+ {
+ return null;
+ }
+
+ @Override
+ public Filter createFilter(String filter) throws InvalidSyntaxException
+ {
+ return null;
+ }
+
+ @Override
+ public void addServiceListener(ServiceListener listener, String filter)
+ throws InvalidSyntaxException
+ {
+ }
+
+ @Override
+ public void addServiceListener(ServiceListener listener)
+ {
+ }
+
+ @Override
+ public void addFrameworkListener(FrameworkListener listener)
+ {
+ }
+
+ @Override
+ public void addBundleListener(BundleListener listener)
+ {
+ }
+ };
+ static ScrConfiguration conf = new ScrConfiguration()
+ {
+ @Override
+ public long stopTimeout()
+ {
+ return 0;
+ }
+
+ @Override
+ public long serviceChangecountTimeout()
+ {
+ return 0;
+ }
+
+ @Override
+ public long lockTimeout()
+ {
+ return 0;
+ }
+
+ @Override
+ public boolean keepInstances()
+ {
+ return false;
+ }
+
+ @Override
+ public boolean isFactoryEnabled()
+ {
+ return false;
+ }
+
+ @Override
+ public boolean infoAsService()
+ {
+ return false;
+ }
+
+ @Override
+ public boolean globalExtender()
+ {
+ return false;
+ }
+
+ @Override
+ public int getLogLevel()
+ {
+ return 0;
+ }
+ };
+ static ScrLogger scrLogger = new EmptySCRLogger(conf, bc);
+
+ public EmptyBundeLogger()
+ {
+ super(bc, scrLogger);
+ }
+
+ @Override
+ public boolean log(int level, String pattern, Throwable ex, Object... arguments)
+ {
+ return true;
+ }
+
+ @Override
+ public boolean log(int level, String message, Throwable ex)
+ {
+ return true;
+ }
+
+ @Override
+ public void close()
+ {
+ }
+
+ @Override
+ public boolean isLogEnabled(int level)
+ {
+ return false;
+ }
+}
diff --git a/atomos.maven/src/main/java/org/apache/felix/atomos/maven/scrmock/EmptySCRLogger.java b/atomos.maven/src/main/java/org/apache/felix/atomos/maven/scrmock/EmptySCRLogger.java
new file mode 100644
index 0000000..8402205
--- /dev/null
+++ b/atomos.maven/src/main/java/org/apache/felix/atomos/maven/scrmock/EmptySCRLogger.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed 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.felix.atomos.maven.scrmock;
+
+import org.apache.felix.scr.impl.logger.ScrLogger;
+import org.apache.felix.scr.impl.manager.ScrConfiguration;
+import org.osgi.framework.BundleContext;
+
+public class EmptySCRLogger extends ScrLogger
+{
+ public EmptySCRLogger(ScrConfiguration config, BundleContext bundleContext)
+ {
+ super(config, bundleContext);
+ }
+
+ @Override
+ public void close()
+ {
+ }
+
+ @Override
+ public boolean isLogEnabled(int level)
+ {
+ return false;
+ }
+
+ @Override
+ public boolean log(int level, String pattern, Throwable ex, Object... arguments)
+ {
+ return true;
+ }
+
+ @Override
+ public boolean log(int level, String message, Throwable ex)
+ {
+ return true;
+ }
+}
diff --git a/atomos.maven/src/main/java/org/apache/felix/atomos/maven/scrmock/PathBundle.java b/atomos.maven/src/main/java/org/apache/felix/atomos/maven/scrmock/PathBundle.java
new file mode 100644
index 0000000..4d43cae
--- /dev/null
+++ b/atomos.maven/src/main/java/org/apache/felix/atomos/maven/scrmock/PathBundle.java
@@ -0,0 +1,206 @@
+/*
+ * Licensed 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.felix.atomos.maven.scrmock;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.security.cert.X509Certificate;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Map;
+import java.util.jar.JarFile;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.Version;
+
+public class PathBundle implements Bundle
+{
+ public PathBundle(JarFile jar)
+ {
+ }
+
+ @Override
+ public int compareTo(Bundle o)
+ {
+ return 0;
+ }
+
+ @Override
+ public int getState()
+ {
+ return 0;
+ }
+
+ @Override
+ public void start(int options) throws BundleException
+ {
+ }
+
+ @Override
+ public void start() throws BundleException
+ {
+ }
+
+ @Override
+ public void stop(int options) throws BundleException
+ {
+ }
+
+ @Override
+ public void stop() throws BundleException
+ {
+ }
+
+ @Override
+ public void update(InputStream input) throws BundleException
+ {
+ }
+
+ @Override
+ public void update() throws BundleException
+ {
+ }
+
+ @Override
+ public void uninstall() throws BundleException
+ {
+ }
+
+ @Override
+ public Dictionary<String, String> getHeaders()
+ {
+ return null;
+ }
+
+ @Override
+ public long getBundleId()
+ {
+ return 0;
+ }
+
+ @Override
+ public String getLocation()
+ {
+ return null;
+ }
+
+ @Override
+ public ServiceReference<?>[] getRegisteredServices()
+ {
+ return null;
+ }
+
+ @Override
+ public ServiceReference<?>[] getServicesInUse()
+ {
+ return null;
+ }
+
+ @Override
+ public boolean hasPermission(Object permission)
+ {
+ return false;
+ }
+
+ @Override
+ public URL getResource(String name)
+ {
+ return null;
+ }
+
+ @Override
+ public Dictionary<String, String> getHeaders(String locale)
+ {
+ return null;
+ }
+
+ @Override
+ public String getSymbolicName()
+ {
+ return null;
+ }
+
+ @Override
+ public Class<?> loadClass(String name) throws ClassNotFoundException
+ {
+ return null;
+ }
+
+ @Override
+ public Enumeration<URL> getResources(String name) throws IOException
+ {
+ return null;
+ }
+
+ @Override
+ public Enumeration<String> getEntryPaths(String path)
+ {
+ return null;
+ }
+
+ @Override
+ public URL getEntry(String path)
+ {
+ return null;
+ }
+
+ @Override
+ public long getLastModified()
+ {
+ return 0;
+ }
+
+ @Override
+ public Enumeration<URL> findEntries(String path, String filePattern, boolean recurse)
+ {
+ return null;
+ }
+
+ @Override
+ public BundleContext getBundleContext()
+ {
+ return null;
+ }
+
+ @Override
+ public Map<X509Certificate, List<X509Certificate>> getSignerCertificates(
+ int signersType)
+ {
+ return null;
+ }
+
+ @Override
+ public Version getVersion()
+ {
+ return null;
+ }
+
+ @Override
+ public <A> A adapt(Class<A> type)
+ {
+ return null;
+ }
+
+ @Override
+ public File getDataFile(String filename)
+ {
+ return null;
+ }
+}
diff --git a/atomos.maven/src/test/java/org/apache/felix/atomos/maven/MojoTest.java b/atomos.maven/src/test/java/org/apache/felix/atomos/maven/MojoTest.java
new file mode 100644
index 0000000..7c8f0b1
--- /dev/null
+++ b/atomos.maven/src/test/java/org/apache/felix/atomos/maven/MojoTest.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed 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.felix.atomos.maven;
+
+import static org.apache.felix.atomos.maven.TestConstants.getAllDependencys;
+
+import java.nio.file.Path;
+import java.util.List;
+
+import org.apache.felix.atomos.maven.ResourceConfigUtil.ResourceConfigResult;
+import org.apache.felix.atomos.maven.reflect.ReflectConfig;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+public class MojoTest extends TestBase
+{
+
+ @Test
+ void testFull(@TempDir Path tempDir) throws Exception
+ {
+
+ List<Path> paths = getAllDependencys();
+
+ SubstrateUtil.substrate(paths, tempDir);
+ List<ReflectConfig> reflectConfigs = ReflectConfigUtil.reflectConfig(paths);
+ ResourceConfigResult resourceConfigResult = ResourceConfigUtil.resourceConfig(
+ paths);
+
+ List<String> args = NativeImageBuilder.createExecutionArgs(List.of(), List.of(),
+ List.of(), List.of(), resourceConfigResult, true, "", "");
+ // for (String arg : args)
+ // {
+ // System.out.println(arg);
+ //
+ // }
+ //
+ }
+}
\ No newline at end of file
diff --git a/atomos.maven/src/test/java/org/apache/felix/atomos/maven/MojoTestExperiments.java b/atomos.maven/src/test/java/org/apache/felix/atomos/maven/MojoTestExperiments.java
new file mode 100644
index 0000000..ace9ce0
--- /dev/null
+++ b/atomos.maven/src/test/java/org/apache/felix/atomos/maven/MojoTestExperiments.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed 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.felix.atomos.maven;
+
+import static org.apache.felix.atomos.maven.TestConstants.DEP_FELIX_HTTP_SERVLET_API;
+import static org.apache.felix.atomos.maven.TestConstants.DEP_FELIX_WEBCONSOLE;
+import static org.apache.felix.atomos.maven.TestConstants.DEP_ORG_OSGI_CORE;
+import static org.apache.felix.atomos.maven.TestConstants.DEP_ORG_OSGI_SERVICE_HTTP;
+import static org.apache.felix.atomos.maven.TestConstants.DEP_ORG_OSGI_SERVICE_LOG;
+import static org.apache.felix.atomos.maven.TestConstants.getDependencys;
+
+import java.nio.file.Path;
+import java.util.List;
+
+import org.apache.felix.atomos.maven.reflect.ReflectConfig;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+public class MojoTestExperiments extends TestBase
+{
+
+ @Test
+ void testReflectBundleActivatorMagicTests(@TempDir Path tempDir) throws Exception
+ {
+ List<Path> paths = getDependencys(DEP_FELIX_WEBCONSOLE, DEP_ORG_OSGI_SERVICE_LOG,
+ // DEP_FELIX_GOGO_RUNTIME, DEP_FELIX_GOGO_COMMAND, DEP_FELIX_SCR,
+ DEP_ORG_OSGI_CORE, DEP_FELIX_HTTP_SERVLET_API, DEP_ORG_OSGI_SERVICE_HTTP);
+
+ List<ReflectConfig> rcs = ReflectConfigUtil.reflectConfig(paths);
+
+ System.out.println(ReflectConfigUtil.json(rcs));
+
+ }
+
+}
\ No newline at end of file
diff --git a/atomos.maven/src/test/java/org/apache/felix/atomos/maven/ReflectConfigTest.java b/atomos.maven/src/test/java/org/apache/felix/atomos/maven/ReflectConfigTest.java
new file mode 100644
index 0000000..a070fb3
--- /dev/null
+++ b/atomos.maven/src/test/java/org/apache/felix/atomos/maven/ReflectConfigTest.java
@@ -0,0 +1,248 @@
+/*
+ * Licensed 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.felix.atomos.maven;
+
+import static org.apache.felix.atomos.maven.TestConstants.DEP_ATOMOS_TESTS_TESTBUNDLES_REFLECT_COMMAND;
+import static org.apache.felix.atomos.maven.TestConstants.DEP_ATOMOS_TESTS_TESTBUNDLES_REFLECT_DTO;
+import static org.apache.felix.atomos.maven.TestConstants.DEP_ATOMOS_TESTS_TESTBUNDLES_SERVICE_CONTRACT;
+import static org.apache.felix.atomos.maven.TestConstants.DEP_ATOMOS_TESTS_TESTBUNDLES_SERVICE_IMPL;
+import static org.apache.felix.atomos.maven.TestConstants.DEP_ATOMOS_TESTS_TESTBUNDLES_SERVICE_IMPL_ACTIVATOR;
+import static org.apache.felix.atomos.maven.TestConstants.DEP_ATOMOS_TESTS_TESTBUNDLES_SERVICE_USER;
+import static org.apache.felix.atomos.maven.TestConstants.DEP_ORG_OSGI_CORE;
+import static org.apache.felix.atomos.maven.TestConstants.DEP_ORG_OSGI_DTO;
+import static org.apache.felix.atomos.maven.TestConstants.filterConstructor;
+import static org.apache.felix.atomos.maven.TestConstants.filterMethod;
+import static org.apache.felix.atomos.maven.TestConstants.filterReflectConfigByClassName;
+import static org.apache.felix.atomos.maven.TestConstants.getDependencys;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+import org.apache.felix.atomos.maven.reflect.ConstructorConfig;
+import org.apache.felix.atomos.maven.reflect.MethodConfig;
+import org.apache.felix.atomos.maven.reflect.ReflectConfig;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+public class ReflectConfigTest extends TestBase
+{
+ @Test
+ void testJsonSimple() throws Exception
+ {
+ ReflectConfig rc = new ReflectConfig("a");
+ String json = ReflectConfigUtil.json(rc);
+ json = shrinkJson(json);
+ assertEquals("{\"name\":\"a\"}", json);
+ }
+
+ @Test
+ void testJson() throws Exception
+ {
+ ReflectConfig rc = new ReflectConfig("a");
+ rc.fields.add("f1");
+ rc.fields.add("f2");
+
+ rc.constructor.add(new ConstructorConfig());
+ rc.constructor.add(new ConstructorConfig(new String[] { "p1" }));
+
+ rc.methods.add(new MethodConfig("m1", null));
+ rc.methods.add(new MethodConfig("m2", new String[] { "m2p1" }));
+ rc.methods.add(new MethodConfig("m3", new String[] { "m3p1", "m3p2" }));
+
+ String json = ReflectConfigUtil.json(rc);
+ json = shrinkJson(json);
+ String exp = "{\"name\":\"a\",\"fields\":[{\"name\":\"f1\"},{\"name\":\"f2\"}],\"methods\":[{\"name\":\"<init>\",\"parameterTypes\":[]},{\"name\":\"<init>\",\"parameterTypes\":[\"p1\"]},{\"name\":\"m1\"},{\"name\":\"m2\",\"parameterTypes\":[\"m2p1\"]},{\"name\":\"m3\",\"parameterTypes\":[\"m3p1\",\"m3p2\"]}]}";
+ assertEquals(exp, json);
+ }
+
+
+ private String shrinkJson(String json)
+ {
+ json = json.replace(" ", "").replace("\n", "");
+ return json;
+ }
+
+ @Test
+ void testJsonFull() throws Exception
+ {
+ List<ReflectConfig> rcs = new ArrayList<>();
+ rcs.add(new ReflectConfig("z"));
+ rcs.add(new ReflectConfig("a"));
+ String json = ReflectConfigUtil.json(rcs);
+ json = shrinkJson(json);
+ assertEquals("[{\"name\":\"a\"},{\"name\":\"z\"}]", json);
+ }
+
+ @Test
+ void testActivateMethod(@TempDir Path tempDir) throws Exception
+ {
+ List<Path> paths = getDependencys(DEP_ATOMOS_TESTS_TESTBUNDLES_SERVICE_CONTRACT,
+ DEP_ATOMOS_TESTS_TESTBUNDLES_SERVICE_IMPL);
+ List<ReflectConfig> rcs = ReflectConfigUtil.reflectConfig(paths);
+ //System.out.println(ReflectConfigUtil.json(rcs));
+
+ ReflectConfig rc = filterReflectConfigByClassName(rcs,
+ "org.apache.felix.atomos.tests.testbundles.service.impl.EchoImpl");
+ assertThat(rc.fields).isEmpty();
+
+ Optional<ConstructorConfig> oc = filterConstructor(rc, new String[] {});
+ assertTrue(oc.isPresent());
+
+ Optional<MethodConfig> omc1 = filterMethod(rc, "activate", null);
+ assertTrue(omc1.isPresent());
+ }
+
+ @Test
+ void testReflectBundleActivator(@TempDir Path tempDir) throws Exception
+ {
+ List<Path> paths = getDependencys(DEP_ORG_OSGI_CORE,
+ DEP_ATOMOS_TESTS_TESTBUNDLES_SERVICE_IMPL_ACTIVATOR);
+
+ List<ReflectConfig> list = ReflectConfigUtil.reflectConfig(paths);
+
+ //System.out.println(ReflectConfigUtil.json(list));
+ ReflectConfig rc = filterReflectConfigByClassName(list,
+ "org.apache.felix.atomos.tests.testbundles.service.impl.activator.Activator");
+ assertThat(rc.fields).isEmpty();
+
+ Optional<ConstructorConfig> oc = filterConstructor(rc, new String[] {});
+ assertTrue(oc.isPresent());
+
+ Optional<MethodConfig> omc1 = filterMethod(rc, "start",
+ new String[] { "org.osgi.framework.BundleContext" });
+ assertTrue(omc1.isPresent());
+ Optional<MethodConfig> omc2 = filterMethod(rc, "stop",
+ new String[] { "org.osgi.framework.BundleContext" });
+ assertTrue(omc2.isPresent());
+ }
+
+ @Test
+ void testBundleActivatorMagic(@TempDir Path tempDir) throws Exception
+ {
+ List<Path> paths = getDependencys(DEP_ORG_OSGI_CORE,
+ DEP_ATOMOS_TESTS_TESTBUNDLES_SERVICE_IMPL_ACTIVATOR,
+ DEP_ATOMOS_TESTS_TESTBUNDLES_SERVICE_CONTRACT);
+
+ List<ReflectConfig> rcs = ReflectConfigUtil.reflectConfig(paths);
+
+ //System.out.println(ReflectConfigUtil.json(rcs));
+
+ ReflectConfig rc = filterReflectConfigByClassName(rcs,
+ "org.apache.felix.atomos.tests.testbundles.service.impl.activator.ActivatorEcho");
+ assertThat(rc.constructor).isEmpty();
+ assertThat(rc.fields).isEmpty();
+
+ Optional<MethodConfig> omc1 = filterMethod(rc, "echo", null);
+ assertTrue(omc1.isPresent());
+ }
+
+ @Test
+ void testDTO(@TempDir Path tempDir) throws Exception
+ {
+
+ List<Path> paths = getDependencys(DEP_ATOMOS_TESTS_TESTBUNDLES_REFLECT_DTO,
+ DEP_ORG_OSGI_DTO);
+
+ List<ReflectConfig> rcs = ReflectConfigUtil.reflectConfig(paths);
+ //System.out.println(ReflectConfigUtil.json(rcs));
+
+ ReflectConfig rc = filterReflectConfigByClassName(rcs,
+ "org.apache.felix.atomos.tests.testbundles.reflect.command.OneDTO");
+ assertThat(rc.constructor).isEmpty();
+ assertThat(rc.methods).isEmpty();
+
+ assertThat(rc.fields).containsExactly("one");
+ }
+
+ @Test
+ void testGOGOCommand(@TempDir Path tempDir) throws Exception
+ {
+ List<Path> paths = getDependencys(DEP_ATOMOS_TESTS_TESTBUNDLES_REFLECT_COMMAND);
+ List<ReflectConfig> rcs = ReflectConfigUtil.reflectConfig(paths);
+ //System.out.println(ReflectConfigUtil.json(rcs));
+
+ ReflectConfig rc1 = filterReflectConfigByClassName(rcs,
+ "org.apache.felix.atomos.tests.testbundles.reflect.command.AbstractCmd");
+ assertThat(rc1.constructor).isEmpty();
+ assertThat(rc1.fields).isEmpty();
+
+ Optional<MethodConfig> rc1mc1 = filterMethod(rc1, "multiple", null);
+ assertNotNull(rc1mc1);
+
+ ReflectConfig rc2 = filterReflectConfigByClassName(rcs,
+ "org.apache.felix.atomos.tests.testbundles.reflect.command.CmdExample");
+
+ assertThat(rc2.fields).isEmpty();
+
+ Optional<ConstructorConfig> rc2cc1 = filterConstructor(rc2, new String[] {});
+ assertTrue(rc2cc1.isPresent());
+
+ Optional<MethodConfig> rc2mc1 = filterMethod(rc2, "a", null);
+ assertTrue(rc2mc1.isPresent());
+
+ Optional<MethodConfig> rc2mc2 = filterMethod(rc2, "multiple", null);
+ assertTrue(rc2mc2.isPresent());
+
+ Optional<MethodConfig> rc2mc3 = filterMethod(rc2, "single", null);
+ assertTrue(rc2mc3.isPresent());
+
+ }
+
+ @Test
+ void testReference(@TempDir Path tempDir) throws Exception
+ {
+ List<Path> paths = getDependencys(DEP_ATOMOS_TESTS_TESTBUNDLES_SERVICE_CONTRACT,
+ DEP_ATOMOS_TESTS_TESTBUNDLES_SERVICE_USER);
+ List<ReflectConfig> rcs = ReflectConfigUtil.reflectConfig(paths);
+ //System.out.println(ReflectConfigUtil.json(rcs));
+
+ ReflectConfig rc1 = filterReflectConfigByClassName(rcs,
+ "org.apache.felix.atomos.tests.testbundles.service.contract.Echo");
+ assertThat(rc1.constructor).isEmpty();
+ assertThat(rc1.fields).isEmpty();
+ assertThat(rc1.methods).isEmpty();
+
+ ReflectConfig rc2 = filterReflectConfigByClassName(rcs,
+ "org.apache.felix.atomos.tests.testbundles.service.user.EchoUser");
+
+ assertThat(rc2.fields).isEmpty();
+
+ Optional<ConstructorConfig> rc2cc1 = filterConstructor(rc2, new String[] {});
+ assertTrue(rc2cc1.isPresent());
+
+ Optional<MethodConfig> rc2mc1 = filterMethod(rc2, "activate", null);
+ assertTrue(rc2mc1.isPresent());
+
+ Optional<MethodConfig> rc2mc2 = filterMethod(rc2, "setEcho", null);
+ assertTrue(rc2mc2.isPresent());
+
+ Optional<MethodConfig> rc2mc3 = filterMethod(rc2, "unsetEcho", null);
+ assertTrue(rc2mc3.isPresent());
+
+ ReflectConfig rc3 = filterReflectConfigByClassName(rcs,
+ "org.apache.felix.atomos.tests.testbundles.service.user.EchoUser2");
+ assertThat(rc3.fields).isEmpty();
+ assertThat(rc3.methods).isEmpty();
+ Optional<ConstructorConfig> rc3cc1 = filterConstructor(rc3,
+ new String[] { "java.util.Map",
+ "org.apache.felix.atomos.tests.testbundles.service.contract.Echo" });
+ assertTrue(rc3cc1.isPresent());
+ }
+}
\ No newline at end of file
diff --git a/atomos.maven/src/test/java/org/apache/felix/atomos/maven/SubstrateTest.java b/atomos.maven/src/test/java/org/apache/felix/atomos/maven/SubstrateTest.java
new file mode 100644
index 0000000..dcb80fa
--- /dev/null
+++ b/atomos.maven/src/test/java/org/apache/felix/atomos/maven/SubstrateTest.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed 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.felix.atomos.maven;
+
+import static org.apache.felix.atomos.maven.TestConstants.DEP_ATOMOS_TESTS_TESTBUNDLES_RESOURCE_A;
+import static org.apache.felix.atomos.maven.TestConstants.getDependency;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.stream.Collectors;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+public class SubstrateTest extends TestBase
+{
+
+ @Test
+ void testSubstrate(@TempDir Path tempDir) throws Exception
+ {
+ Path path = getDependency(DEP_ATOMOS_TESTS_TESTBUNDLES_RESOURCE_A);
+ Path atomosSubstrateJar = SubstrateUtil.substrate(Arrays.asList(path), tempDir);
+ assertThat(atomosSubstrateJar).exists().isRegularFile();
+
+ try (JarFile jarFile = new JarFile(atomosSubstrateJar.toFile());)
+ {
+ assertThat(jarFile.stream().map(JarEntry::getName).collect(
+ Collectors.toList())).containsOnly("META-INF/MANIFEST.MF", //
+ "atomos/0/META-INF/MANIFEST.MF", //
+ "atomos/0/META-TEXT/file.txt", //
+ "atomos/0/org/apache/felix/atomos/tests/testbundles/resource/a/file.txt", //
+ "atomos/0/file.txt", //
+ "atomos/bundles.index", //
+ "META-INF/native-image/resource-config.json");
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/atomos.maven/src/test/java/org/apache/felix/atomos/maven/TestBase.java b/atomos.maven/src/test/java/org/apache/felix/atomos/maven/TestBase.java
new file mode 100644
index 0000000..dff4ddf
--- /dev/null
+++ b/atomos.maven/src/test/java/org/apache/felix/atomos/maven/TestBase.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed 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.felix.atomos.maven;
+
+import static org.apache.felix.atomos.maven.TestConstants.getAllDependencys;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.IOException;
+
+import org.junit.jupiter.api.BeforeAll;
+
+public class TestBase
+{
+
+ @BeforeAll
+ public static void setup() throws IOException
+ {
+
+ assertThat(getAllDependencys()).size().describedAs(
+ "No Dependencys - Please run maven-phase 'generate-resources' first. './mvnw generate-resources -f atomos.maven/pom.xml'").isGreaterThan(
+ 0);
+ }
+
+}
\ No newline at end of file
diff --git a/atomos.maven/src/test/java/org/apache/felix/atomos/maven/TestConstants.java b/atomos.maven/src/test/java/org/apache/felix/atomos/maven/TestConstants.java
new file mode 100644
index 0000000..eaf43f7
--- /dev/null
+++ b/atomos.maven/src/test/java/org/apache/felix/atomos/maven/TestConstants.java
@@ -0,0 +1,118 @@
+/**
+ *
+ */
+package org.apache.felix.atomos.maven;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import org.apache.felix.atomos.maven.reflect.ConstructorConfig;
+import org.apache.felix.atomos.maven.reflect.MethodConfig;
+import org.apache.felix.atomos.maven.reflect.ReflectConfig;
+
+public class TestConstants
+{
+
+ static String ACTIVATOR_CONSTRUCTOR = "\"methods\":[{\"name\":\"<init>\",\"parameterTypes\":[] }]";
+ static String COMPONENT_CONSTRUCTOR = "\"allPublicConstructors\" : true";
+ static String DEP_ATOMOS_TESTS_TESTBUNDLES_REFLECT_COMMAND = "org.apache.felix.atomos.tests.testbundles.reflect.command-";
+ static String DEP_ATOMOS_TESTS_TESTBUNDLES_REFLECT_DTO = "org.apache.felix.atomos.tests.testbundles.reflect.dto-";
+ static String DEP_ATOMOS_TESTS_TESTBUNDLES_RESOURCE_A = "org.apache.felix.atomos.tests.testbundles.resource.a-";
+ static String DEP_ATOMOS_TESTS_TESTBUNDLES_SERVICE_CONTRACT = "org.apache.felix.atomos.tests.testbundles.service.contract-";
+ static String DEP_ATOMOS_TESTS_TESTBUNDLES_SERVICE_IMPL = "org.apache.felix.atomos.tests.testbundles.service.impl-";
+ static String DEP_ATOMOS_TESTS_TESTBUNDLES_SERVICE_IMPL_ACTIVATOR = "org.apache.felix.atomos.tests.testbundles.service.impl.activator-";
+ static String DEP_ATOMOS_TESTS_TESTBUNDLES_SERVICE_USER = "org.apache.felix.atomos.tests.testbundles.service.user-";
+ static String DEP_FELIX_GOGO_COMMAND = "org.apache.felix.gogo.command-";
+ static String DEP_FELIX_GOGO_RUNTIME = "org.apache.felix.gogo.runtime-";
+ static String DEP_FELIX_HTTP_API = "org.apache.felix.http.api-";
+ static String DEP_FELIX_HTTP_SERVLET_API = "org.apache.felix.http.servlet-api-";
+ static String DEP_FELIX_SCR = "org.apache.felix.scr-";
+ static String DEP_FELIX_WEBCONSOLE = "org.apache.felix.webconsole-";
+ static String DEP_ORG_OSGI_CORE = "org.osgi.core-";
+ static String DEP_ORG_OSGI_DTO = "org.osgi.dto-";
+ static String DEP_ORG_OSGI_SERVICE_HTTP = "org.osgi.service.http-";
+ static String DEP_ORG_OSGI_SERVICE_LOG = "org.osgi.service.log-";
+
+ static Optional<ConstructorConfig> filterConstructor(ReflectConfig reflectConfig,
+ String[] parameterTypes)
+ {
+ assertNotNull(reflectConfig);
+ assertNotNull(reflectConfig.constructor);
+
+ return reflectConfig.constructor.stream().filter(
+ c -> Arrays.equals(parameterTypes, c.methodParameterTypes)).findAny();
+
+ }
+
+ static Optional<MethodConfig> filterMethod(ReflectConfig reflectConfig, String name,
+ String[] parameterTypes)
+ {
+ assertNotNull(reflectConfig);
+ assertNotNull(reflectConfig.methods);
+
+ return reflectConfig.methods.stream().filter(c -> c.name.equals(name)
+ && Arrays.equals(parameterTypes, c.methodParameterTypes)).findAny();
+
+ }
+
+ static ReflectConfig filterReflectConfigByClassName(List<ReflectConfig> list,
+ String checkClass)
+ {
+ assertThat(list).isNotNull();
+ Optional<ReflectConfig> optional = list.stream().filter(
+ c -> c.className.equals(checkClass)).findFirst();
+ assertTrue(optional.isPresent());
+ return optional.get();
+ }
+
+ static List<Path> getAllDependencys() throws IOException
+ {
+ return getAllDependencysFrom("target/test-dependencies/");
+ }
+
+ static List<Path> getAllDependencysFrom(String dir) throws IOException
+ {
+ Path dirp = Paths.get(dir);
+
+ if (!Files.exists(dirp))
+ {
+ return new ArrayList<>();
+ }
+ return Files.list(dirp).filter(p -> p.toString().endsWith(".jar")).collect(
+ Collectors.toList());
+ }
+
+ static Path getDependency(String depName) throws IOException
+ {
+ Path testDepsDir = Paths.get("target/test-dependencies/");
+ List<Path> paths = Files.list(testDepsDir).filter(
+ p -> p.getFileName().toString().startsWith(depName)).collect(
+ Collectors.toList());
+ assertEquals(1, paths.size(),
+ String.format("Must be exact one test Dependency with the name %s", depName));
+ return paths.get(0);
+ }
+
+ static List<Path> getDependencys(String... depNames) throws IOException
+ {
+ List<Path> paths = new ArrayList<>();
+ for (String depName : depNames)
+ {
+ paths.add(getDependency(depName));
+ }
+ return paths;
+ }
+
+}
\ No newline at end of file
diff --git a/atomos.tests/atomos.tests.modulepath.service/src/test/java/org/apache/felix/atomos/tests/modulepath/service/ModulepathLaunchTest.java b/atomos.tests/atomos.tests.modulepath.service/src/test/java/org/apache/felix/atomos/tests/modulepath/service/ModulepathLaunchTest.java
index 9186079..bb229e0 100644
--- a/atomos.tests/atomos.tests.modulepath.service/src/test/java/org/apache/felix/atomos/tests/modulepath/service/ModulepathLaunchTest.java
+++ b/atomos.tests/atomos.tests.modulepath.service/src/test/java/org/apache/felix/atomos/tests/modulepath/service/ModulepathLaunchTest.java
@@ -26,7 +26,16 @@ import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.file.Path;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
import java.util.stream.Collectors;
import org.apache.felix.atomos.launch.AtomosLauncher;
@@ -498,7 +507,7 @@ public class ModulepathLaunchTest
{
f = AtomosLauncher.newFramework(
Map.of(Constants.FRAMEWORK_STORAGE, storage2.getAbsolutePath(),
- "felix.cache.locking", "false"),
+ "felix.cache.locking", "false"),
atomosRuntime);
f.start();
fail();
@@ -519,7 +528,7 @@ public class ModulepathLaunchTest
@Test
void testLoaderType(@TempDir Path storage) throws BundleException,
- ClassNotFoundException
+ ClassNotFoundException
{
ModulepathLaunch.main(new String[] {
Constants.FRAMEWORK_STORAGE + '=' + storage.toFile().getAbsolutePath() });
@@ -685,8 +694,8 @@ public class ModulepathLaunchTest
children.iterator().next().getAtomosContents().stream().map(
AtomosContent::getBundle).filter(
Objects::nonNull).filter(
- (b) -> b.getSymbolicName().equals(
- TESTBUNDLES_SERVICE_IMPL_A)).findFirst().orElseThrow().uninstall();
+ (b) -> b.getSymbolicName().equals(
+ TESTBUNDLES_SERVICE_IMPL_A)).findFirst().orElseThrow().uninstall();
checkServices(bc, 7);
testFramework.stop();
@@ -725,9 +734,11 @@ public class ModulepathLaunchTest
final ServiceReference<?>[] refs = b.getRegisteredServices();
assertNotNull(refs, "No services.");
- assertEquals(1, refs.length, "Wrong number of services.");
+ assertEquals(2, refs.length, "Wrong number of services.");
assertEquals(Boolean.TRUE, refs[0].getProperty("echo.reference"),
"Wrong service.");
+ assertEquals(Boolean.TRUE, refs[1].getProperty("echo.reference"),
+ "Wrong service.");
}
@Test
@@ -796,7 +807,7 @@ public class ModulepathLaunchTest
final URL resc = clazz.getResource("/file.txt");
assertNotNull(resc, "Expected URL, got null ");
assertEquals("/file.txt", new BufferedReader(
- new InputStreamReader(resc.openStream())).readLine(),
+ new InputStreamReader(resc.openStream())).readLine(),
"Incorrect contents from URL");
}
catch (final ClassNotFoundException e)
diff --git a/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.bom/pom.xml b/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.bom/pom.xml
new file mode 100644
index 0000000..27dfd39
--- /dev/null
+++ b/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.bom/pom.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.felix.atomos.tests</groupId>
+ <artifactId>org.apache.felix.atomos.tests.testbundles</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>org.apache.felix.atomos.tests.testbundles.bom</artifactId>
+ <packaging>pom</packaging>
+ <name>atomos.tests.testbundles.bom</name>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix.atomos.tests</groupId>
+ <artifactId>org.apache.felix.atomos.tests.testbundles.resource.a</artifactId>
+ <version>${atomos.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix.atomos.tests</groupId>
+ <artifactId>org.apache.felix.atomos.tests.testbundles.service.contract</artifactId>
+ <version>${atomos.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix.atomos.tests</groupId>
+ <artifactId>org.apache.felix.atomos.tests.testbundles.service.impl</artifactId>
+ <version>${atomos.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix.atomos.tests</groupId>
+ <artifactId>org.apache.felix.atomos.tests.testbundles.service.impl.a</artifactId>
+ <version>${atomos.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix.atomos.tests</groupId>
+ <artifactId>org.apache.felix.atomos.tests.testbundles.service.impl.activator</artifactId>
+ <version>${atomos.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix.atomos.tests</groupId>
+ <artifactId>org.apache.felix.atomos.tests.testbundles.service.impl.b</artifactId>
+ <version>${atomos.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix.atomos.tests</groupId>
+ <artifactId>org.apache.felix.atomos.tests.testbundles.service.library</artifactId>
+ <version>${atomos.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix.atomos.tests</groupId>
+ <artifactId>org.apache.felix.atomos.tests.testbundles.service.user</artifactId>
+ <version>${atomos.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix.atomos.tests</groupId>
+ <artifactId>org.apache.felix.atomos.tests.testbundles.substrate.main</artifactId>
+ <version>${atomos.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix.atomos.tests</groupId>
+ <artifactId>org.apache.felix.atomos.tests.testbundles.reflect.command</artifactId>
+ <version>${atomos.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix.atomos.tests</groupId>
+ <artifactId>org.apache.felix.atomos.tests.testbundles.reflect.dto</artifactId>
+ <version>${atomos.version}</version>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.reflect.command/pom.xml b/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.reflect.command/pom.xml
new file mode 100644
index 0000000..ff6c4b4
--- /dev/null
+++ b/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.reflect.command/pom.xml
@@ -0,0 +1,81 @@
+<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.felix.atomos.tests</groupId>
+ <artifactId>org.apache.felix.atomos.tests.testbundles</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ </parent>
+ <artifactId>org.apache.felix.atomos.tests.testbundles.reflect.command</artifactId>
+ <name>atomos.tests.testbundles.reflect.command</name>
+ <dependencies>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>osgi.annotation</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.service.component.annotations</artifactId>
+ <version>1.4.0</version>
+ </dependency>
+ </dependencies>
+ <profiles>
+ <profile>
+ <id>java8</id>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-resources-plugin</artifactId>
+ <version>3.1.0</version>
+ <configuration>
+
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>default-compile</id>
+ <configuration>
+ <!-- compile everything with the default to ensure module-info is correct -->
+ <release>${java.version}</release>
+ </configuration>
+ </execution>
+ <!-- compile the packages that must work with java 8 -->
+ <execution>
+ <id>java8-compile</id>
+ <goals>
+ <goal>compile</goal>
+ </goals>
+ <configuration>
+ <excludes>
+ <exclude>module-info.java</exclude>
+ </excludes>
+ <release>8</release>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>biz.aQute.bnd</groupId>
+ <artifactId>bnd-maven-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <configuration>
+ <archive>
+ <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
+ </archive>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.reflect.command/src/main/java/module-info.java b/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.reflect.command/src/main/java/module-info.java
new file mode 100644
index 0000000..0768315
--- /dev/null
+++ b/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.reflect.command/src/main/java/module-info.java
@@ -0,0 +1,18 @@
+/*
+ * Licensed 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.
+ */
+open module org.apache.felix.atomos.tests.testbundles.reflect.command
+{
+ exports org.apache.felix.atomos.tests.testbundles.reflect.command;
+ requires org.osgi.service.component.annotations;
+}
diff --git a/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.reflect.command/src/main/java/org/apache/felix/atomos/tests/testbundles/reflect/command/A.java b/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.reflect.command/src/main/java/org/apache/felix/atomos/tests/testbundles/reflect/command/A.java
new file mode 100644
index 0000000..30bd0aa
--- /dev/null
+++ b/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.reflect.command/src/main/java/org/apache/felix/atomos/tests/testbundles/reflect/command/A.java
@@ -0,0 +1,20 @@
+/*
+ * Licensed 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.felix.atomos.tests.testbundles.reflect.command;
+
+
+public class A
+{
+ public String a;
+}
diff --git a/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.reflect.command/src/main/java/org/apache/felix/atomos/tests/testbundles/reflect/command/AbstractCmd.java b/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.reflect.command/src/main/java/org/apache/felix/atomos/tests/testbundles/reflect/command/AbstractCmd.java
new file mode 100644
index 0000000..1754f83
--- /dev/null
+++ b/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.reflect.command/src/main/java/org/apache/felix/atomos/tests/testbundles/reflect/command/AbstractCmd.java
@@ -0,0 +1,23 @@
+/*
+ * Licensed 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.felix.atomos.tests.testbundles.reflect.command;
+
+public class AbstractCmd
+{
+ public String multiple()
+ {
+ return "abstractmultiple";
+ }
+
+}
diff --git a/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.reflect.command/src/main/java/org/apache/felix/atomos/tests/testbundles/reflect/command/CmdExample.java b/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.reflect.command/src/main/java/org/apache/felix/atomos/tests/testbundles/reflect/command/CmdExample.java
new file mode 100644
index 0000000..25e0601
--- /dev/null
+++ b/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.reflect.command/src/main/java/org/apache/felix/atomos/tests/testbundles/reflect/command/CmdExample.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed 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.felix.atomos.tests.testbundles.reflect.command;
+
+import org.osgi.service.component.annotations.Component;
+
+@Component(immediate = true, service = CmdExample.class)
+@CommandScope("reflect-test")
+@CommandFunction(value = { "a", "single", "multiple" })
+public class CmdExample extends AbstractCmd
+{
+
+ public String single()
+ {
+ return "single";
+ }
+
+ public String multiple(String s)
+ {
+ return "multiple" + s;
+ }
+
+ public String multiple(String s, boolean b)
+ {
+ return "multiple" + s + b;
+ }
+
+ public A a()
+ {
+ A a = new A();
+ a.a = "a";
+ return a;
+ }
+}
diff --git a/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.reflect.command/src/main/java/org/apache/felix/atomos/tests/testbundles/reflect/command/CommandFunction.java b/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.reflect.command/src/main/java/org/apache/felix/atomos/tests/testbundles/reflect/command/CommandFunction.java
new file mode 100644
index 0000000..87bd505
--- /dev/null
+++ b/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.reflect.command/src/main/java/org/apache/felix/atomos/tests/testbundles/reflect/command/CommandFunction.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed 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.felix.atomos.tests.testbundles.reflect.command;
+
+import org.osgi.service.component.annotations.ComponentPropertyType;
+
+
+/**
+ * The Interface CommandFunction.
+ */
+@ComponentPropertyType
+public @interface CommandFunction {
+
+ /** The Constant PREFIX_. */
+ public static final String PREFIX_ = "osgi.";
+
+ /**
+ * Value.
+ *
+ * @return the string[]
+ */
+ public String[] value();
+}
diff --git a/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.reflect.command/src/main/java/org/apache/felix/atomos/tests/testbundles/reflect/command/CommandScope.java b/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.reflect.command/src/main/java/org/apache/felix/atomos/tests/testbundles/reflect/command/CommandScope.java
new file mode 100644
index 0000000..3d3e916
--- /dev/null
+++ b/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.reflect.command/src/main/java/org/apache/felix/atomos/tests/testbundles/reflect/command/CommandScope.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed 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.felix.atomos.tests.testbundles.reflect.command;
+
+import org.osgi.service.component.annotations.ComponentPropertyType;
+
+
+/**
+ * The Interface CommandScope.
+ */
+@ComponentPropertyType
+public @interface CommandScope {
+
+ /** The Constant PREFIX_. */
+ public static final String PREFIX_ = "osgi.";
+
+ /**
+ * Value.
+ *
+ * @return the string
+ */
+ public String value();
+}
diff --git a/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.reflect.dto/pom.xml b/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.reflect.dto/pom.xml
new file mode 100644
index 0000000..6c0ed63
--- /dev/null
+++ b/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.reflect.dto/pom.xml
@@ -0,0 +1,76 @@
+<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.felix.atomos.tests</groupId>
+ <artifactId>org.apache.felix.atomos.tests.testbundles</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ </parent>
+ <artifactId>org.apache.felix.atomos.tests.testbundles.reflect.dto</artifactId>
+ <name>atomos.tests.testbundles.reflect.dto</name>
+ <dependencies>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.dto</artifactId>
+ <version>1.1.0</version>
+ </dependency>
+ </dependencies>
+ <profiles>
+ <profile>
+ <id>java8</id>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-resources-plugin</artifactId>
+ <version>3.1.0</version>
+ <configuration>
+
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>default-compile</id>
+ <configuration>
+ <!-- compile everything with the default to ensure module-info is correct -->
+ <release>${java.version}</release>
+ </configuration>
+ </execution>
+ <!-- compile the packages that must work with java 8 -->
+ <execution>
+ <id>java8-compile</id>
+ <goals>
+ <goal>compile</goal>
+ </goals>
+ <configuration>
+ <excludes>
+ <exclude>module-info.java</exclude>
+ </excludes>
+ <release>8</release>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>biz.aQute.bnd</groupId>
+ <artifactId>bnd-maven-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <configuration>
+ <archive>
+ <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
+ </archive>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.reflect.dto/src/main/java/module-info.java b/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.reflect.dto/src/main/java/module-info.java
new file mode 100644
index 0000000..b3a461f
--- /dev/null
+++ b/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.reflect.dto/src/main/java/module-info.java
@@ -0,0 +1,18 @@
+/*
+ * Licensed 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.
+ */
+open module org.apache.felix.atomos.tests.testbundles.reflect.command
+{
+ exports org.apache.felix.atomos.tests.testbundles.reflect.command;
+ requires org.osgi.dto;
+}
diff --git a/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.reflect.dto/src/main/java/org/apache/felix/atomos/tests/testbundles/reflect/command/OneDTO.java b/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.reflect.dto/src/main/java/org/apache/felix/atomos/tests/testbundles/reflect/command/OneDTO.java
new file mode 100644
index 0000000..d3037eb
--- /dev/null
+++ b/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.reflect.dto/src/main/java/org/apache/felix/atomos/tests/testbundles/reflect/command/OneDTO.java
@@ -0,0 +1,22 @@
+/*
+ * Licensed 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.felix.atomos.tests.testbundles.reflect.command;
+
+import org.osgi.dto.DTO;
+
+public class OneDTO extends DTO
+{
+ public String one;
+
+}
diff --git a/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.service.impl.activator/src/main/java/org/apache/felix/atomos/tests/testbundles/service/impl/activator/Activator.java b/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.service.impl.activator/src/main/java/org/apache/felix/atomos/tests/testbundles/service/impl/activator/Activator.java
index 43f5536..58ecc4a 100644
--- a/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.service.impl.activator/src/main/java/org/apache/felix/atomos/tests/testbundles/service/impl/activator/Activator.java
+++ b/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.service.impl.activator/src/main/java/org/apache/felix/atomos/tests/testbundles/service/impl/activator/Activator.java
@@ -13,7 +13,6 @@
*/
package org.apache.felix.atomos.tests.testbundles.service.impl.activator;
-import java.util.Collections;
import java.util.Hashtable;
import org.apache.felix.atomos.tests.testbundles.service.contract.Echo;
@@ -29,9 +28,14 @@ public class Activator implements BundleActivator
@Override
public void start(BundleContext context) throws Exception
{
- Echo impl = (m) -> "impl.activator " + m;
- context.registerService(Echo.class, impl, new Hashtable<String, String>(
- Collections.singletonMap("type", "impl.activator")));
+ Echo impl = new ActivatorEcho();
+
+ Hashtable<String, Object> ht = new Hashtable<>();
+ ht.put("type", "impl.activator");
+ ht.put("osgi.command.scope", "echo");
+ ht.put("osgi.command.function", new String[] { "echo" });
+
+ context.registerService(Echo.class, impl, ht);
System.out.println("Registered Echo service from activator.");
}
diff --git a/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.service.impl.activator/src/main/java/org/apache/felix/atomos/tests/testbundles/service/impl/activator/ActivatorEcho.java b/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.service.impl.activator/src/main/java/org/apache/felix/atomos/tests/testbundles/service/impl/activator/ActivatorEcho.java
new file mode 100644
index 0000000..047b453
--- /dev/null
+++ b/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.service.impl.activator/src/main/java/org/apache/felix/atomos/tests/testbundles/service/impl/activator/ActivatorEcho.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed 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.felix.atomos.tests.testbundles.service.impl.activator;
+
+import org.apache.felix.atomos.tests.testbundles.service.contract.Echo;
+
+public class ActivatorEcho implements Echo
+{
+
+ @Override
+ public String echo(String msg)
+ {
+ return "impl.activator " + msg;
+ }
+
+}
diff --git a/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.service.user/src/main/java/org/apache/felix/atomos/tests/testbundles/service/user/EchoUser.java b/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.service.user/src/main/java/org/apache/felix/atomos/tests/testbundles/service/user/EchoUser.java
index 723d3df..357ed25 100644
--- a/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.service.user/src/main/java/org/apache/felix/atomos/tests/testbundles/service/user/EchoUser.java
+++ b/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.service.user/src/main/java/org/apache/felix/atomos/tests/testbundles/service/user/EchoUser.java
@@ -19,7 +19,7 @@ import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
@Component(service = EchoUser.class, property = {
- "echo.reference:Boolean=true" }, immediate = true)
+"echo.reference:Boolean=true" }, immediate = true)
@org.osgi.annotation.bundle.Requirement(namespace = "osgi.ee", filter = "(&(osgi.ee=JavaSE)(version=1.8))")
public class EchoUser
{
diff --git a/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.service.user/src/main/java/org/apache/felix/atomos/tests/testbundles/service/user/EchoUser.java b/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.service.user/src/main/java/org/apache/felix/atomos/tests/testbundles/service/user/EchoUser2.java
similarity index 67%
copy from atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.service.user/src/main/java/org/apache/felix/atomos/tests/testbundles/service/user/EchoUser.java
copy to atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.service.user/src/main/java/org/apache/felix/atomos/tests/testbundles/service/user/EchoUser2.java
index 723d3df..0cc2863 100644
--- a/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.service.user/src/main/java/org/apache/felix/atomos/tests/testbundles/service/user/EchoUser.java
+++ b/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.service.user/src/main/java/org/apache/felix/atomos/tests/testbundles/service/user/EchoUser2.java
@@ -13,30 +13,23 @@
*/
package org.apache.felix.atomos.tests.testbundles.service.user;
+import java.util.Map;
+
import org.apache.felix.atomos.tests.testbundles.service.contract.Echo;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
-@Component(service = EchoUser.class, property = {
- "echo.reference:Boolean=true" }, immediate = true)
+@Component(service = EchoUser2.class, property = {
+"echo.reference:Boolean=true" }, immediate = true)
@org.osgi.annotation.bundle.Requirement(namespace = "osgi.ee", filter = "(&(osgi.ee=JavaSE)(version=1.8))")
-public class EchoUser
+public class EchoUser2
{
@Activate
- public void activate()
+ public EchoUser2(Map<String, Object> componentProps, @Reference Echo echo)
{
- System.out.println("Activated: " + getClass().getName());
+ System.out.println("Activated via constructor: " + getClass().getName());
}
- @Reference
- protected void setEcho(Echo echo)
- {
- System.out.println("Echo service found: " + echo.echo("hello"));
- }
- protected void unsetEcho(Echo echo)
- {
- System.out.println("Echo service unset: " + echo.echo("goodbye"));
- }
}
diff --git a/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.substrate.main/pom.xml b/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.substrate.main/pom.xml
new file mode 100644
index 0000000..cd6a57b
--- /dev/null
+++ b/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.substrate.main/pom.xml
@@ -0,0 +1,82 @@
+<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.felix.atomos.tests</groupId>
+ <artifactId>org.apache.felix.atomos.tests.testbundles</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ </parent>
+ <artifactId>org.apache.felix.atomos.tests.testbundles.substrate.main</artifactId>
+ <name>atomos.tests.testbundles.substrate.main</name>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.atomos.runtime</artifactId>
+ <version>${atomos.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.service.log</artifactId>
+ <version>1.4.0</version>
+ <scope>compile</scope>
+ </dependency>
+ </dependencies>
+ <profiles>
+ <profile>
+ <id>java8</id>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-resources-plugin</artifactId>
+ <version>3.1.0</version>
+ <configuration>
+
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>default-compile</id>
+ <configuration>
+ <!-- compile everything with the default to ensure module-info is correct -->
+ <release>${java.version}</release>
+ </configuration>
+ </execution>
+ <!-- compile the packages that must work with java 8 -->
+ <execution>
+ <id>java8-compile</id>
+ <goals>
+ <goal>compile</goal>
+ </goals>
+ <configuration>
+ <excludes>
+ <exclude>module-info.java</exclude>
+ </excludes>
+ <release>8</release>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>biz.aQute.bnd</groupId>
+ <artifactId>bnd-maven-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <configuration>
+ <archive>
+ <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
+ </archive>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.substrate.main/src/main/java/org/apache/felix/atomos/tests/testbundles/substrate/main/Main.java b/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.substrate.main/src/main/java/org/apache/felix/atomos/tests/testbundles/substrate/main/Main.java
new file mode 100644
index 0000000..dea2e67
--- /dev/null
+++ b/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.substrate.main/src/main/java/org/apache/felix/atomos/tests/testbundles/substrate/main/Main.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed 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.felix.atomos.tests.testbundles.substrate.main;
+
+import java.util.Arrays;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.felix.atomos.launch.AtomosLauncher;
+import org.apache.felix.atomos.runtime.AtomosRuntime;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.launch.Framework;
+import org.osgi.service.log.LogEntry;
+import org.osgi.service.log.LogLevel;
+import org.osgi.service.log.LogReaderService;
+import org.osgi.service.log.admin.LoggerContext;
+
+public class Main
+{
+ public static void main(String[] args) throws BundleException, ClassNotFoundException
+ {
+ final long start = System.nanoTime();
+
+ final AtomosRuntime atomosRuntime = AtomosRuntime.newAtomosRuntime();
+ final Map<String, String> config = AtomosLauncher.getConfiguration(args);
+ config.putIfAbsent(LoggerContext.LOGGER_CONTEXT_DEFAULT_LOGLEVEL,
+ LogLevel.AUDIT.name());
+ final Framework framework = AtomosLauncher.newFramework(config, atomosRuntime);
+ framework.init();
+ final BundleContext bc = framework.getBundleContext();
+ final LogReaderService logReader = bc.getService(
+ bc.getServiceReference(LogReaderService.class));
+ logReader.addLogListener((e) -> {
+ System.out.println(getLogMessage(e));
+ });
+ framework.start();
+
+ final long total = System.nanoTime() - start;
+ System.out.println("Total time: " + TimeUnit.NANOSECONDS.toMillis(total));
+
+ if (Arrays.asList(args).contains("-exit"))
+ {
+ System.exit(0);
+ }
+ }
+
+ private static String getLogMessage(LogEntry e)
+ {
+ final StringBuilder builder = new StringBuilder(e.getMessage());
+ if (e.getBundle() != null)
+ {
+ builder.append(" - bundle: " + e.getBundle());
+ }
+ if (e.getServiceReference() != null)
+ {
+ builder.append(" - service: " + e.getServiceReference());
+ }
+ return builder.toString();
+ }
+}
diff --git a/atomos.tests/atomos.tests.testbundles/pom.xml b/atomos.tests/atomos.tests.testbundles/pom.xml
index 3544d21..73ef4c2 100644
--- a/atomos.tests/atomos.tests.testbundles/pom.xml
+++ b/atomos.tests/atomos.tests.testbundles/pom.xml
@@ -18,5 +18,9 @@
<module>atomos.tests.testbundles.service.user</module>
<module>atomos.tests.testbundles.service.library</module>
<module>atomos.tests.testbundles.resources.a</module>
+ <module>atomos.tests.testbundles.substrate.main</module>
+ <module>atomos.tests.testbundles.bom</module>
+ <module>atomos.tests.testbundles.reflect.command</module>
+ <module>atomos.tests.testbundles.reflect.dto</module>
</modules>
</project>
diff --git a/pom.xml b/pom.xml
index 4eed20c..b9d3b64 100644
--- a/pom.xml
+++ b/pom.xml
@@ -22,6 +22,7 @@
<module>atomos.tests</module>
<module>atomos.substrate.config</module>
<module>atomos.examples</module>
+ <module>atomos.maven</module>
</modules>
<build>