Ensure OSGi CDI works
diff --git a/pom.xml b/pom.xml
index 0995c29..bd038c1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -37,10 +37,11 @@
<name>Apache Winegrower</name>
<properties>
- <junit.version>5.6.2</junit.version>
+ <junit.version>5.7.0</junit.version>
<osgi.version>7.0.0</osgi.version>
<slf4j.version>1.7.30</slf4j.version>
- <xbean.version>4.17</xbean.version>
+ <xbean.version>4.18</xbean.version>
+ <aries-cdi.version>1.1.0</aries-cdi.version>
<surefire.log.level>INFO</surefire.log.level>
@@ -137,8 +138,9 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
- <version>3.0.0-M3</version>
+ <version>3.0.0-M5</version>
<configuration>
+ <trimStackTrace>false</trimStackTrace>
<systemPropertyVariables>
<org.slf4j.simpleLogger.defaultLogLevel>${surefire.log.level}</org.slf4j.simpleLogger.defaultLogLevel>
<org.slf4j.simpleLogger.logFile>System.out</org.slf4j.simpleLogger.logFile>
diff --git a/winegrower-cepages/winegrower-cepage-osgi-cdi/pom.xml b/winegrower-cepages/winegrower-cepage-osgi-cdi/pom.xml
index 4f948a3..7bb9278 100644
--- a/winegrower-cepages/winegrower-cepage-osgi-cdi/pom.xml
+++ b/winegrower-cepages/winegrower-cepage-osgi-cdi/pom.xml
@@ -33,8 +33,7 @@
<name>Apache Winegrower :: Cepages :: OSGi CDI</name>
<properties>
- <aries-cdi.version>1.1.0</aries-cdi.version>
- <owb.version>2.0.14</owb.version>
+ <owb.version>2.0.17</owb.version>
</properties>
<dependencies>
diff --git a/winegrower-cepages/winegrower-cepage-osgi-cdi/src/main/java/org/apache/winegrower/scanner/manifest/OSGiCDIManifestContributor.java b/winegrower-cepages/winegrower-cepage-osgi-cdi/src/main/java/org/apache/winegrower/scanner/manifest/OSGiCDIManifestContributor.java
deleted file mode 100644
index 0e5501a..0000000
--- a/winegrower-cepages/winegrower-cepage-osgi-cdi/src/main/java/org/apache/winegrower/scanner/manifest/OSGiCDIManifestContributor.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/**
- * 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
- * <p>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p>
- * 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.winegrower.scanner.manifest;
-
-import static java.util.Optional.ofNullable;
-import static java.util.stream.Collectors.joining;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.nio.file.Files;
-import java.util.Objects;
-import java.util.function.Supplier;
-import java.util.jar.Attributes;
-import java.util.jar.Manifest;
-import java.util.stream.Stream;
-
-import org.apache.xbean.finder.AnnotationFinder;
-import org.apache.xbean.finder.archive.Archive;
-import org.apache.xbean.finder.archive.FileArchive;
-import org.osgi.framework.Constants;
-
-public class OSGiCDIManifestContributor implements ManifestContributor {
- @Override
- public void contribute(final AnnotationFinder finder, final Supplier<Manifest> manifest) {
- final Archive archive = finder.getArchive();
- if (!FileArchive.class.isInstance(archive) || !hasBeansXml(FileArchive.class.cast(archive))) {
- return; // already a jar, its manifest is likely already good
- }
-
- final Attributes attributes = manifest.get().getMainAttributes();
- final String newRequireCapability = toCapability(finder);
- final String existing = attributes.getValue(Constants.REQUIRE_CAPABILITY);
- final String ariesCdiExtensions = findCdiExtensions(finder);
- attributes.putValue(Constants.REQUIRE_CAPABILITY, Stream.of(existing, newRequireCapability, ariesCdiExtensions)
- .filter(Objects::nonNull)
- .filter(it -> !it.isEmpty())
- .collect(joining(",")));
- }
-
- // todo: drop and handle @Requirement transitively in core
- private String findCdiExtensions(final AnnotationFinder finder) {
- try {
- final ClassLoader loader = ofNullable(Thread.currentThread().getContextClassLoader())
- .orElseGet(ClassLoader::getSystemClassLoader);
- final Class<? extends Annotation> singular = (Class<? extends Annotation>)
- loader.loadClass("org.apache.aries.cdi.extra.RequireCDIExtension");
- final Class<? extends Annotation> plural = (Class<? extends Annotation>)
- loader.loadClass("org.apache.aries.cdi.extra.RequireCDIExtensions");
- final Method value = singular.getMethod("value");
- return Stream.concat(
- finder.findAnnotatedClasses(plural).stream(),
- finder.findAnnotatedClasses(singular).stream())
- .distinct()
- .flatMap(c -> Stream.of(c.getAnnotationsByType(singular)))
- .map(rce -> {
- try {
- final Object extension = value.invoke(rce);
- return "osgi.cdi.extension;filter:=\"(osgi.cdi.extension=" + extension + ")\"";
- } catch (final IllegalAccessException e) {
- throw new IllegalStateException(e);
- } catch (final InvocationTargetException e) {
- throw new IllegalStateException(e.getTargetException());
- }
- })
- .collect(joining(","));
- } catch (final Exception cnfe) {
- return null;
- }
- }
-
- private String toCapability(final AnnotationFinder finder) {
- return "osgi.extender;filter:=\"(osgi.extender=osgi.cdi)\";beans:List<String>=\"" +
- String.join(",", finder.getAnnotatedClassNames()) + "\"";
- }
-
- private boolean hasBeansXml(final FileArchive archive) {
- return Files.exists(archive.getDir().toPath().resolve("META-INF/beans.xml"));
- }
-}
diff --git a/winegrower-cepages/winegrower-cepage-osgi-cdi/src/main/resources/META-INF/openwebbeans/openwebbeans.properties b/winegrower-cepages/winegrower-cepage-osgi-cdi/src/main/resources/META-INF/openwebbeans/openwebbeans.properties
new file mode 100644
index 0000000..ed22ada
--- /dev/null
+++ b/winegrower-cepages/winegrower-cepage-osgi-cdi/src/main/resources/META-INF/openwebbeans/openwebbeans.properties
@@ -0,0 +1,24 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# workaround due to the lack of isolation, we override owb-web config with se one
+#
+
+configuration.ordinal=12
+org.apache.webbeans.spi.ContainerLifecycle=org.apache.webbeans.lifecycle.StandaloneLifeCycle
+org.apache.webbeans.spi.ContextsService=org.apache.webbeans.corespi.se.StandaloneContextsService
+org.apache.webbeans.spi.ConversationService=org.apache.webbeans.conversation.DefaultConversationService
+org.apache.webbeans.application.jsp=false
diff --git a/winegrower-cepages/winegrower-cepage-osgi-cdi/src/main/resources/META-INF/services/org.apache.winegrower.scanner.manifest.ManifestContributor b/winegrower-cepages/winegrower-cepage-osgi-cdi/src/main/resources/META-INF/services/org.apache.winegrower.scanner.manifest.ManifestContributor
deleted file mode 100644
index 434c653..0000000
--- a/winegrower-cepages/winegrower-cepage-osgi-cdi/src/main/resources/META-INF/services/org.apache.winegrower.scanner.manifest.ManifestContributor
+++ /dev/null
@@ -1 +0,0 @@
-org.apache.winegrower.scanner.manifest.OSGiCDIManifestContributor
diff --git a/winegrower-cepages/winegrower-cepage-osgi-cdi/src/test/java/org/apache/winegrower/cepage/osgicdi/OSGiCDITest.java b/winegrower-cepages/winegrower-cepage-osgi-cdi/src/test/java/org/apache/winegrower/cepage/osgicdi/OSGiCDITest.java
deleted file mode 100644
index 017efa5..0000000
--- a/winegrower-cepages/winegrower-cepage-osgi-cdi/src/test/java/org/apache/winegrower/cepage/osgicdi/OSGiCDITest.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/**
- * 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
- * <p>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p>
- * 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.winegrower.cepage.osgicdi;
-
-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 static org.junit.jupiter.api.Assertions.fail;
-
-import java.util.Collection;
-import java.util.Map;
-
-import org.apache.winegrower.Ripener;
-import org.apache.winegrower.api.InjectedService;
-import org.apache.winegrower.deployer.OSGiBundleLifecycle;
-import org.apache.winegrower.extension.testing.junit5.Winegrower;
-import org.junit.jupiter.api.Test;
-import org.osgi.service.cdi.runtime.CDIComponentRuntime;
-import org.osgi.service.cdi.runtime.dto.ContainerDTO;
-
-@Winegrower
-class OSGiCDITest {
- @InjectedService
- private Ripener ripener;
-
- @InjectedService
- private CDIComponentRuntime ccr;
-
- @Test
- void test() {
- assertNotNull(ccr);
-
- final Map<Long, OSGiBundleLifecycle> bundles = ripener.getRegistry().getBundles();
- final long id = bundles.entrySet().stream()
- .filter(e -> e.getValue().getBundle().getLocation().endsWith("test-classes"))
- .findFirst()
- .map(Map.Entry::getKey)
- .orElseGet(() -> fail("no test-classes bundle"));
-
- final Collection<ContainerDTO> containerDTOs = ccr.getContainerDTOs(bundles.get(id).getBundle());
- assertNotNull(containerDTOs);
- assertEquals(1, containerDTOs.size());
-
- final ContainerDTO dto = containerDTOs.iterator().next();
- assertNotNull(dto);
- assertTrue(dto.errors.isEmpty(), () -> dto.errors.toString());
- }
-}
diff --git a/winegrower-core/pom.xml b/winegrower-core/pom.xml
index ae2120e..310f988 100644
--- a/winegrower-core/pom.xml
+++ b/winegrower-core/pom.xml
@@ -65,5 +65,12 @@
<artifactId>slf4j-simple</artifactId>
<scope>test</scope>
</dependency>
+
+ <dependency>
+ <groupId>org.apache.aries.cdi</groupId>
+ <artifactId>org.apache.aries.cdi.extra</artifactId>
+ <version>${aries-cdi.version}</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</project>
diff --git a/winegrower-core/src/main/java/org/apache/winegrower/Ripener.java b/winegrower-core/src/main/java/org/apache/winegrower/Ripener.java
index 4cbd37e..70768c4 100644
--- a/winegrower-core/src/main/java/org/apache/winegrower/Ripener.java
+++ b/winegrower-core/src/main/java/org/apache/winegrower/Ripener.java
@@ -13,13 +13,25 @@
*/
package org.apache.winegrower;
-import static java.util.Arrays.asList;
-import static java.util.Collections.emptyList;
-import static java.util.Locale.ROOT;
-import static java.util.Optional.ofNullable;
-import static java.util.function.Function.identity;
-import static java.util.stream.Collectors.toList;
-import static java.util.stream.Collectors.toMap;
+import org.apache.winegrower.deployer.OSGiBundleLifecycle;
+import org.apache.winegrower.scanner.StandaloneScanner;
+import org.apache.winegrower.scanner.manifest.HeaderManifestContributor;
+import org.apache.winegrower.scanner.manifest.KarafCommandManifestContributor;
+import org.apache.winegrower.scanner.manifest.ManifestContributor;
+import org.apache.winegrower.scanner.manifest.OSGIInfContributor;
+import org.apache.winegrower.scanner.manifest.OSGiCDIManifestContributor;
+import org.apache.winegrower.scanner.manifest.RequirementManifestContributor;
+import org.apache.winegrower.service.BundleRegistry;
+import org.apache.winegrower.service.DefaultConfigurationAdmin;
+import org.apache.winegrower.service.DefaultEventAdmin;
+import org.apache.winegrower.service.OSGiServices;
+import org.apache.winegrower.service.Slf4jOSGiLoggerFactory;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.cm.ConfigurationListener;
+import org.osgi.service.event.EventAdmin;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
@@ -52,22 +64,13 @@
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
-import org.apache.winegrower.deployer.OSGiBundleLifecycle;
-import org.apache.winegrower.scanner.StandaloneScanner;
-import org.apache.winegrower.scanner.manifest.HeaderManifestContributor;
-import org.apache.winegrower.scanner.manifest.KarafCommandManifestContributor;
-import org.apache.winegrower.scanner.manifest.ManifestContributor;
-import org.apache.winegrower.scanner.manifest.OSGIInfContributor;
-import org.apache.winegrower.service.BundleRegistry;
-import org.apache.winegrower.service.DefaultConfigurationAdmin;
-import org.apache.winegrower.service.DefaultEventAdmin;
-import org.apache.winegrower.service.OSGiServices;
-import org.osgi.framework.ServiceReference;
-import org.osgi.service.cm.ConfigurationAdmin;
-import org.osgi.service.cm.ConfigurationListener;
-import org.osgi.service.event.EventAdmin;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import static java.util.Arrays.asList;
+import static java.util.Collections.emptyList;
+import static java.util.Locale.ROOT;
+import static java.util.Optional.ofNullable;
+import static java.util.function.Function.identity;
+import static java.util.stream.Collectors.toList;
+import static java.util.stream.Collectors.toMap;
public interface Ripener extends AutoCloseable {
Configuration getConfiguration();
@@ -90,11 +93,15 @@
void close();
class Configuration {
- private static final Collection<String> DEFAULT_EXCLUSIONS = asList( // todo: make it configurable
+ private static final Collection<String> DEFAULT_EXCLUSIONS = asList(
"slf4j-",
"xbean-",
"org.osgi.",
- "opentest4j-"
+ "opentest4j-",
+ "junit-platform-",
+ "junit-jupiter-",
+ "debugger-agent",
+ "asm-"
);
private File workDir = new File(System.getProperty("java.io.tmpdir"), "karaf-boot_" + UUID.randomUUID().toString());
@@ -104,7 +111,11 @@
private Collection<String> ignoredBundles = emptyList();
private Collection<ManifestContributor> manifestContributors = Stream.concat(
// built-in
- Stream.of(new KarafCommandManifestContributor(), new HeaderManifestContributor(), new OSGIInfContributor()),
+ Stream.of(
+ new HeaderManifestContributor(), new RequirementManifestContributor(),
+ new OSGIInfContributor(),
+ new KarafCommandManifestContributor(),
+ new OSGiCDIManifestContributor()),
// extensions
StreamSupport.stream(ServiceLoader.load(ManifestContributor.class).spliterator(), false)
).collect(toList());
@@ -114,7 +125,8 @@
"org.apache.aries.blueprint.cm",
"pax-web-extender-whiteboard",
"org.apache.aries.jax.rs.whiteboard",
- "pax-web-runtime");
+ "pax-web-runtime",
+ "org.apache.aries.cdi");
public Collection<String> getIgnoredBundles() {
return ignoredBundles;
@@ -198,6 +210,7 @@
this.eventAdmin = loadEventAdmin(eventListeners);
registerBuiltInService(ConfigurationAdmin.class, this.configurationAdmin, new Hashtable<>());
registerBuiltInService(EventAdmin.class, this.eventAdmin, new Hashtable<>());
+ registerBuiltInService(org.osgi.service.log.LoggerFactory.class, loadLoggerFactory(), new Hashtable<>());
try (final InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream("winegrower.properties")) {
loadConfiguration(stream);
@@ -226,6 +239,14 @@
};
}
+ private org.osgi.service.log.LoggerFactory loadLoggerFactory() {
+ final Iterator<org.osgi.service.log.LoggerFactory> eventAdminIterator = ServiceLoader.load(org.osgi.service.log.LoggerFactory.class).iterator();
+ if (eventAdminIterator.hasNext()) {
+ return eventAdminIterator.next();
+ }
+ return new Slf4jOSGiLoggerFactory();
+ }
+
private EventAdmin loadEventAdmin(final Collection<DefaultEventAdmin.EventHandlerInstance> listeners) {
final Iterator<EventAdmin> eventAdminIterator = ServiceLoader.load(EventAdmin.class).iterator();
if (eventAdminIterator.hasNext()) {
@@ -249,10 +270,10 @@
// case insensitive
public void loadConfiguration(final Properties embedConfig) {
final Map<Object, Method> setters = Stream.of(this.configuration.getClass().getMethods())
- .filter(it -> it.getName().startsWith("set") && it.getParameterCount() == 1)
- .collect(toMap(it ->
- (Character.toLowerCase(it.getName().charAt(3)) + it.getName().substring(4)).toLowerCase(ROOT),
- identity()));
+ .filter(it -> it.getName().startsWith("set") && it.getParameterCount() == 1)
+ .collect(toMap(it ->
+ (Character.toLowerCase(it.getName().charAt(3)) + it.getName().substring(4)).toLowerCase(ROOT),
+ identity()));
final Collection<String> matched = new ArrayList<>();
embedConfig.stringPropertyNames().stream().filter(it -> setters.containsKey(it.toLowerCase(ROOT))).forEach(key -> {
final String value = embedConfig.getProperty(key);
@@ -274,9 +295,9 @@
// from here all parameters are lists
final Collection<String> asList = Stream.of(value.split(","))
- .map(String::trim)
- .filter(it -> !it.isEmpty())
- .collect(toList());
+ .map(String::trim)
+ .filter(it -> !it.isEmpty())
+ .collect(toList());
if (type == Predicate.class) { // Predicate<String> + startsWith logic
final Predicate<String> predicate =
val -> val != null && asList.stream().anyMatch(val::startsWith);
@@ -285,18 +306,18 @@
setter.invoke(this.configuration, asList);
} else if (type == Collection.class
&& ManifestContributor.class == ParameterizedType.class.cast(
- setter.getParameters()[0].getParameterizedType()).getActualTypeArguments()[0]) {
+ setter.getParameters()[0].getParameterizedType()).getActualTypeArguments()[0]) {
final ClassLoader loader = Thread.currentThread().getContextClassLoader();
setter.invoke(this.configuration, asList.stream()
- .map(it -> {
- try {
- return loader.loadClass(it);
- } catch (final ClassNotFoundException e) {
- throw new IllegalArgumentException(e);
- }
- })
- .collect(toList()));
- } else if (type == Collection.class ) { // Collection<String>
+ .map(it -> {
+ try {
+ return loader.loadClass(it);
+ } catch (final ClassNotFoundException e) {
+ throw new IllegalArgumentException(e);
+ }
+ })
+ .collect(toList()));
+ } else if (type == Collection.class) { // Collection<String>
setter.invoke(this.configuration, asList);
} else {
throw new IllegalArgumentException("Unsupported: " + setter);
@@ -311,14 +332,14 @@
if (DefaultConfigurationAdmin.class.isInstance(configurationAdmin)) {
final DefaultConfigurationAdmin dca = DefaultConfigurationAdmin.class.cast(configurationAdmin);
embedConfig.stringPropertyNames()
- .stream()
- .filter(it -> it.startsWith("winegrower.service."))
- .peek(matched::add)
- .forEach(key -> dca.getProvidedConfiguration().put(key, embedConfig.getProperty(key)));
+ .stream()
+ .filter(it -> it.startsWith("winegrower.service."))
+ .peek(matched::add)
+ .forEach(key -> dca.getProvidedConfiguration().put(key, embedConfig.getProperty(key)));
}
embedConfig.stringPropertyNames().stream().filter(it -> !matched.contains(it.toLowerCase(ROOT)))
- .forEach(it -> LOGGER.warn("Didn't match configuration {}, did you mispell it?", it));
+ .forEach(it -> LOGGER.warn("Didn't match configuration {}, did you mispell it?", it));
}
@Override
@@ -339,9 +360,9 @@
final StandaloneScanner scanner = new StandaloneScanner(configuration, registry.getFramework());
final AtomicLong bundleIdGenerator = new AtomicLong(1);
Stream.concat(Stream.concat(
- scanner.findOSGiBundles().stream(),
- scanner.findPotentialOSGiBundles().stream()),
- scanner.findEmbeddedClasses().stream())
+ scanner.findOSGiBundles().stream(),
+ scanner.findPotentialOSGiBundles().stream()),
+ scanner.findEmbeddedClasses().stream())
.sorted(this::compareBundles)
.map(it -> new OSGiBundleLifecycle(
it.getManifest(), it.getJar(),
@@ -359,8 +380,8 @@
LOGGER.info("Stopping Apache Winegrower application on {}", LocalDateTime.now());
final Map<Long, OSGiBundleLifecycle> bundles = registry.getBundles();
bundles.values().stream()
- .sorted((o1, o2) -> (int) (o2.getBundle().getBundleId() - o1.getBundle().getBundleId()))
- .forEach(OSGiBundleLifecycle::stop);
+ .sorted((o1, o2) -> (int) (o2.getBundle().getBundleId() - o1.getBundle().getBundleId()))
+ .forEach(OSGiBundleLifecycle::stop);
bundles.clear();
if (configuration.getWorkDir().exists()) {
try {
diff --git a/winegrower-core/src/main/java/org/apache/winegrower/deployer/BundleWiringImpl.java b/winegrower-core/src/main/java/org/apache/winegrower/deployer/BundleWiringImpl.java
index 598efa8..4e277bd 100644
--- a/winegrower-core/src/main/java/org/apache/winegrower/deployer/BundleWiringImpl.java
+++ b/winegrower-core/src/main/java/org/apache/winegrower/deployer/BundleWiringImpl.java
@@ -82,6 +82,7 @@
@Override
public List<BundleWire> getRequiredWires(final String namespace) {
return bundle.getRequirements().stream()
+ .filter(it -> Objects.equals(it.getNamespace(), namespace))
.map(requirement -> toWire(requirement, registry.getBundles()))
.filter(Objects::nonNull)
.collect(toList());
diff --git a/winegrower-core/src/main/java/org/apache/winegrower/scanner/manifest/HeaderManifestContributor.java b/winegrower-core/src/main/java/org/apache/winegrower/scanner/manifest/HeaderManifestContributor.java
index ef1ef5d..6a020ef 100644
--- a/winegrower-core/src/main/java/org/apache/winegrower/scanner/manifest/HeaderManifestContributor.java
+++ b/winegrower-core/src/main/java/org/apache/winegrower/scanner/manifest/HeaderManifestContributor.java
@@ -13,9 +13,9 @@
*/
package org.apache.winegrower.scanner.manifest;
-import org.apache.xbean.asm8.AnnotationVisitor;
-import org.apache.xbean.asm8.ClassReader;
-import org.apache.xbean.asm8.ClassVisitor;
+import org.apache.xbean.asm9.AnnotationVisitor;
+import org.apache.xbean.asm9.ClassReader;
+import org.apache.xbean.asm9.ClassVisitor;
import org.apache.xbean.finder.AnnotationFinder;
import java.io.InputStream;
@@ -30,10 +30,10 @@
import java.util.stream.Stream;
import static java.util.stream.Collectors.toMap;
-import static org.apache.xbean.asm8.ClassReader.SKIP_CODE;
-import static org.apache.xbean.asm8.ClassReader.SKIP_DEBUG;
-import static org.apache.xbean.asm8.ClassReader.SKIP_FRAMES;
-import static org.apache.xbean.asm8.Opcodes.ASM8;
+import static org.apache.xbean.asm9.ClassReader.SKIP_CODE;
+import static org.apache.xbean.asm9.ClassReader.SKIP_DEBUG;
+import static org.apache.xbean.asm9.ClassReader.SKIP_FRAMES;
+import static org.apache.xbean.asm9.Opcodes.ASM9;
public class HeaderManifestContributor implements ManifestContributor {
@@ -75,7 +75,7 @@
try (final InputStream stream = loader.getResourceAsStream(clazz.getName().replace('.', '/') + ".class")) {
final ClassReader reader = new ClassReader(stream);
final Collection<KeyValue> headers = new ArrayList<>();
- final Supplier<AnnotationVisitor> newHeaderVisitor = () -> new AnnotationVisitor(ASM8) {
+ final Supplier<AnnotationVisitor> newHeaderVisitor = () -> new AnnotationVisitor(ASM9) {
private final KeyValue header = new KeyValue();
@Override
@@ -98,7 +98,7 @@
}
};
- reader.accept(new ClassVisitor(ASM8) {
+ reader.accept(new ClassVisitor(ASM9) {
@Override
public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
switch (descriptor) {
@@ -135,7 +135,7 @@
private final Supplier<AnnotationVisitor> visitor;
private PluralAnnotationVisitor(final String singular, final Supplier<AnnotationVisitor> nestedVisitor) {
- super(ASM8);
+ super(ASM9);
this.visitor = nestedVisitor;
this.singular = singular;
}
@@ -144,7 +144,7 @@
public AnnotationVisitor visitArray(final String name) {
switch (name) {
case "value":
- return new AnnotationVisitor(ASM8) {
+ return new AnnotationVisitor(ASM9) {
@Override
public AnnotationVisitor visitAnnotation(final String name, final String descriptor) {
if (singular.equals(descriptor)) {
diff --git a/winegrower-core/src/main/java/org/apache/winegrower/scanner/manifest/OSGiCDIManifestContributor.java b/winegrower-core/src/main/java/org/apache/winegrower/scanner/manifest/OSGiCDIManifestContributor.java
new file mode 100644
index 0000000..b1dd0cb
--- /dev/null
+++ b/winegrower-core/src/main/java/org/apache/winegrower/scanner/manifest/OSGiCDIManifestContributor.java
@@ -0,0 +1,168 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.winegrower.scanner.manifest;
+
+import org.apache.xbean.asm9.AnnotationVisitor;
+import org.apache.xbean.asm9.ClassReader;
+import org.apache.xbean.asm9.shade.commons.EmptyVisitor;
+import org.apache.xbean.finder.AnnotationFinder;
+import org.apache.xbean.finder.archive.Archive;
+import org.apache.xbean.finder.archive.FileArchive;
+import org.apache.xbean.finder.archive.JarArchive;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Objects;
+import java.util.function.Supplier;
+import java.util.jar.Attributes;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+import java.util.stream.Stream;
+
+import static java.util.Optional.ofNullable;
+import static java.util.stream.Collectors.joining;
+import static org.apache.xbean.asm9.ClassReader.SKIP_CODE;
+import static org.apache.xbean.asm9.ClassReader.SKIP_DEBUG;
+import static org.apache.xbean.asm9.ClassReader.SKIP_FRAMES;
+import static org.apache.xbean.asm9.Opcodes.ASM9;
+import static org.osgi.framework.Constants.REQUIRE_CAPABILITY;
+
+// simplified flavor of the scanner requiring to have a META-INF/beans.xml (as in CDI 1.1)
+public class OSGiCDIManifestContributor implements ManifestContributor {
+ @Override
+ public void contribute(final AnnotationFinder finder, final Supplier<Manifest> manifest) {
+ final Manifest mf = manifest.get();
+ if (hasCdiExtender(mf)) {
+ return;
+ }
+
+ final Archive archive = finder.getArchive();
+ final WinegrowerAnnotationFinder waf = WinegrowerAnnotationFinder.class.cast(finder);
+ if (JarArchive.class.isInstance(archive)) {
+ try (final JarFile jar = new JarFile(org.apache.xbean.finder.util.Files.toFile(JarArchive.class.cast(archive).getUrl()))) {
+ if (jar.getEntry("META-INF/beans/xml") == null) {
+ return;
+ }
+ appendOsgiCDIExtender(mf, waf);
+ } catch (final IOException e) {
+ // no-op
+ }
+ } else if (FileArchive.class.isInstance(archive)) {
+ final Path base = FileArchive.class.cast(archive).getDir().toPath();
+ if (!Files.exists(base.resolve("META-INF/beans.xml"))) {
+ return;
+ }
+ appendOsgiCDIExtender(mf, waf);
+ }
+ }
+
+ private void appendOsgiCDIExtender(final Manifest mf, final WinegrowerAnnotationFinder af) {
+ if (af.getAnnotatedClassNames().isEmpty()) { // aries-cdi will skip bundles with no bean classes anyway
+ return;
+ }
+ final Attributes attributes = mf.getMainAttributes();
+ attributes.putValue(
+ REQUIRE_CAPABILITY,
+ Stream.of(attributes.getValue(REQUIRE_CAPABILITY), toCapability(af), findCdiExtensions(af))
+ .filter(Objects::nonNull)
+ .filter(it -> !it.isEmpty())
+ .collect(joining(",")));
+ }
+
+ private boolean hasCdiExtender(final Manifest manifest) {
+ return ofNullable(manifest.getMainAttributes().getValue(REQUIRE_CAPABILITY))
+ .map(a -> a.contains("(osgi.extender=osgi.cdi)"))
+ .orElse(false);
+ }
+
+ // todo: drop and handle @Requirement transitively in core
+ private String findCdiExtensions(final WinegrowerAnnotationFinder finder) {
+ try {
+ return Stream.concat(
+ finder.findAnnotatedClasses("org.apache.aries.cdi.extra.RequireCDIExtensions").stream(),
+ finder.findAnnotatedClasses("org.apache.aries.cdi.extra.RequireCDIExtension").stream())
+ .distinct()
+ .flatMap(c -> extractAriesCdiExtensions(c, finder))
+ .filter(it -> !it.isEmpty())
+ .map(it -> "osgi.cdi.extension;filter:=\"(osgi.cdi.extension=" + it + ")\"")
+ .distinct()
+ .sorted()
+ .collect(joining(","));
+ } catch (final Exception cnfe) {
+ return null;
+ }
+ }
+
+ private Stream<String> extractAriesCdiExtensions(final Class<?> aClass, final WinegrowerAnnotationFinder finder) {
+ try (final InputStream bytecode = finder.getArchive().getBytecode(aClass.getName())) {
+ final Collection<String> extensions = new ArrayList<>();
+ final ClassReader reader = new ClassReader(bytecode);
+ reader.accept(new EmptyVisitor() {
+ @Override
+ public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+ switch (desc) {
+ case "Lorg/apache/aries/cdi/extra/RequireCDIExtension;":
+ return new AnnotationVisitor(ASM9) {
+ @Override
+ public void visit(final String name, final Object value) {
+ if ("value".equals(name)) {
+ extensions.add(String.valueOf(value));
+ }
+ }
+ };
+ case "Lorg/apache/aries/cdi/extra/RequireCDIExtensions;":
+ return new AnnotationVisitor(ASM9) {
+ @Override
+ public AnnotationVisitor visitAnnotation(final String name, final String descriptor) {
+ if ("Lorg/apache/aries/cdi/extra/RequireCDIExtension;".equals(descriptor)) {
+ return new AnnotationVisitor(ASM9) {
+ @Override
+ public void visit(final String name, final Object value) {
+ if ("value".equals(name)) {
+ extensions.add(String.valueOf(value));
+ }
+ }
+ };
+ }
+ return super.visitAnnotation(desc, descriptor);
+ }
+
+ @Override
+ public AnnotationVisitor visitArray(final String name) {
+ if ("value".equals(name)) {
+ return this;
+ }
+ return super.visitArray(name);
+ }
+ };
+ default:
+ return super.visitAnnotation(desc, visible);
+ }
+ }
+ }, SKIP_FRAMES | SKIP_CODE | SKIP_DEBUG);
+ return extensions.stream();
+ } catch (final IOException | ClassNotFoundException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ private String toCapability(final WinegrowerAnnotationFinder finder) {
+ return "osgi.extender;filter:=\"(osgi.extender=osgi.cdi)\";beans:List<String>=\"" +
+ finder.getAnnotatedClassNames().stream().sorted().collect(joining(",")) + "\"";
+ }
+}
diff --git a/winegrower-core/src/main/java/org/apache/winegrower/scanner/manifest/RequirementManifestContributor.java b/winegrower-core/src/main/java/org/apache/winegrower/scanner/manifest/RequirementManifestContributor.java
new file mode 100644
index 0000000..65194bc
--- /dev/null
+++ b/winegrower-core/src/main/java/org/apache/winegrower/scanner/manifest/RequirementManifestContributor.java
@@ -0,0 +1,147 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.winegrower.scanner.manifest;
+
+import org.apache.xbean.asm9.AnnotationVisitor;
+import org.apache.xbean.asm9.ClassReader;
+import org.apache.xbean.asm9.shade.commons.EmptyVisitor;
+import org.apache.xbean.finder.AnnotationFinder;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Objects;
+import java.util.function.Supplier;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+import java.util.stream.Stream;
+
+import static java.util.Collections.emptyList;
+import static java.util.stream.Collectors.joining;
+import static java.util.stream.Collectors.toList;
+import static org.apache.xbean.asm9.ClassReader.SKIP_CODE;
+import static org.apache.xbean.asm9.ClassReader.SKIP_DEBUG;
+import static org.apache.xbean.asm9.ClassReader.SKIP_FRAMES;
+import static org.apache.xbean.asm9.Opcodes.ASM9;
+import static org.osgi.framework.Constants.REQUIRE_CAPABILITY;
+
+public class RequirementManifestContributor implements ManifestContributor {
+ @Override
+ public void contribute(final AnnotationFinder finder, final Supplier<Manifest> manifest) {
+ final Attributes attributes = manifest.get().getMainAttributes();
+ final String existing = attributes.getValue(REQUIRE_CAPABILITY);
+ final Collection<String> requirements = findRequirements(WinegrowerAnnotationFinder.class.cast(finder));
+ if (requirements == null || requirements.isEmpty()) {
+ return;
+ }
+ attributes.putValue(
+ REQUIRE_CAPABILITY,
+ Stream.concat(
+ Stream.of(existing),
+ requirements.stream()
+ .filter(it -> existing == null || !existing.contains(it)))
+ .filter(Objects::nonNull)
+ .filter(it -> !it.isEmpty())
+ .collect(joining(",")));
+ }
+
+ private Collection<String> findRequirements(final WinegrowerAnnotationFinder finder) {
+ try {
+ return Stream.concat(
+ finder.findAnnotatedClasses("org.osgi.annotation.bundle.Requirement").stream(),
+ finder.findAnnotatedClasses("org.osgi.annotation.bundle.Requirements").stream())
+ .distinct()
+ .flatMap(c -> findRequirements(c, finder))
+ .filter(it -> !it.isEmpty())
+ .distinct()
+ .sorted()
+ .collect(toList());
+ } catch (final Exception cnfe) {
+ return emptyList();
+ }
+ }
+
+ private Stream<String> findRequirements(final Class<?> aClass, final WinegrowerAnnotationFinder finder) {
+ try (final InputStream bytecode = finder.getArchive().getBytecode(aClass.getName())) {
+ final Collection<String> requirements = new ArrayList<>();
+ final ClassReader reader = new ClassReader(bytecode);
+ reader.accept(new EmptyVisitor() {
+ @Override
+ public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+ switch (desc) {
+ case "Lorg/osgi/annotation/bundle/Requirement;":
+ return new RequirementAnnotationVisitor(requirements);
+ case "Lorg/osgi/annotation/bundle/Requirements;":
+ return new AnnotationVisitor(ASM9) {
+ @Override
+ public AnnotationVisitor visitAnnotation(final String name, final String descriptor) {
+ if ("Lorg/osgi/annotation/bundle/Requirement;".equals(descriptor)) {
+ return new RequirementAnnotationVisitor(requirements);
+ }
+ return super.visitAnnotation(desc, descriptor);
+ }
+
+ @Override
+ public AnnotationVisitor visitArray(final String name) {
+ if ("value".equals(name)) {
+ return this;
+ }
+ return super.visitArray(name);
+ }
+ };
+ default:
+ return super.visitAnnotation(desc, visible);
+ }
+ }
+ }, SKIP_FRAMES | SKIP_CODE | SKIP_DEBUG);
+ return requirements.stream();
+ } catch (final IOException | ClassNotFoundException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ private static class RequirementAnnotationVisitor extends AnnotationVisitor {
+ private final Collection<String> requirements;
+
+ private String namespace;
+ private String name;
+
+ private RequirementAnnotationVisitor(final Collection<String> requirements) {
+ super(ASM9);
+ this.requirements = requirements;
+ }
+
+ @Override
+ public void visit(final String name, final Object value) {
+ switch (name) {
+ case "name":
+ this.name = String.valueOf(value);
+ break;
+ case "namespace":
+ this.namespace = String.valueOf(value);
+ break;
+ default:
+ }
+ }
+
+ @Override
+ public void visitEnd() {
+ super.visitEnd();
+ if (name != null && namespace != null) {
+ requirements.add(namespace + ";filter:=\"(" + namespace + '=' + name + ")\"");
+ }
+ }
+ }
+}
diff --git a/winegrower-core/src/main/java/org/apache/winegrower/service/Slf4jOSGiLoggerFactory.java b/winegrower-core/src/main/java/org/apache/winegrower/service/Slf4jOSGiLoggerFactory.java
new file mode 100644
index 0000000..fafebad
--- /dev/null
+++ b/winegrower-core/src/main/java/org/apache/winegrower/service/Slf4jOSGiLoggerFactory.java
@@ -0,0 +1,240 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.winegrower.service;
+
+import org.osgi.framework.Bundle;
+import org.osgi.service.log.FormatterLogger;
+import org.osgi.service.log.Logger;
+import org.osgi.service.log.LoggerConsumer;
+import org.osgi.service.log.LoggerFactory;
+
+public class Slf4jOSGiLoggerFactory implements LoggerFactory {
+ @Override
+ public Logger getLogger(final String s) {
+ return new Slf4jLogger(org.slf4j.LoggerFactory.getLogger(s));
+ }
+
+ @Override
+ public Logger getLogger(final Class<?> aClass) {
+ return getLogger(aClass.getName());
+ }
+
+ @Override
+ public <L extends Logger> L getLogger(final String s, final Class<L> aClass) {
+ return aClass.cast(getLogger(s));
+ }
+
+ @Override
+ public <L extends Logger> L getLogger(final Class<?> aClass, final Class<L> aClass1) {
+ return aClass1.cast(getLogger(aClass.getName()));
+ }
+
+ @Override
+ public <L extends Logger> L getLogger(final Bundle bundle, final String s, final Class<L> aClass) {
+ return aClass.cast(getLogger(s));
+ }
+
+ private static class Slf4jLogger implements FormatterLogger {
+ private final org.slf4j.Logger delegate;
+
+ private Slf4jLogger(final org.slf4j.Logger logger) {
+ this.delegate = logger;
+ }
+
+ @Override
+ public String getName() {
+ return delegate.getName();
+ }
+
+ @Override
+ public boolean isTraceEnabled() {
+ return delegate.isTraceEnabled();
+ }
+
+ @Override
+ public void trace(final String message) {
+ delegate.trace(message);
+ }
+
+ @Override
+ public void trace(final String format, final Object arg) {
+ delegate.trace(format, arg);
+ }
+
+ @Override
+ public void trace(final String format, final Object arg1, final Object arg2) {
+ delegate.trace(format, arg1, arg2);
+ }
+
+ @Override
+ public void trace(final String format, final Object... arguments) {
+ delegate.trace(format, arguments);
+ }
+
+ @Override
+ public <E extends Exception> void trace(final LoggerConsumer<E> consumer) throws E {
+ if (delegate.isTraceEnabled()) {
+ consumer.accept(this);
+ }
+ }
+
+ @Override
+ public boolean isDebugEnabled() {
+ return delegate.isDebugEnabled();
+ }
+
+ @Override
+ public void debug(final String message) {
+ delegate.debug(message);
+ }
+
+ @Override
+ public void debug(final String format, final Object arg) {
+ delegate.debug(format, arg);
+ }
+
+ @Override
+ public void debug(final String format, final Object arg1, final Object arg2) {
+ delegate.debug(format, arg1, arg2);
+ }
+
+ @Override
+ public void debug(final String format, final Object... arguments) {
+ delegate.debug(format, arguments);
+ }
+
+ @Override
+ public <E extends Exception> void debug(final LoggerConsumer<E> consumer) throws E {
+ if (isDebugEnabled()) {
+ consumer.accept(this);
+ }
+ }
+
+ @Override
+ public boolean isInfoEnabled() {
+ return delegate.isInfoEnabled();
+ }
+
+ @Override
+ public void info(final String message) {
+ delegate.info(message);
+ }
+
+ @Override
+ public void info(final String format, final Object arg) {
+ delegate.info(format, arg);
+ }
+
+ @Override
+ public void info(final String format, final Object arg1, final Object arg2) {
+ delegate.info(format, arg1, arg2);
+ }
+
+ @Override
+ public void info(final String format, final Object... arguments) {
+ delegate.info(format, arguments);
+ }
+
+ @Override
+ public <E extends Exception> void info(final LoggerConsumer<E> consumer) throws E {
+ if (isInfoEnabled()) {
+ consumer.accept(this);
+ }
+ }
+
+ @Override
+ public boolean isWarnEnabled() {
+ return delegate.isWarnEnabled();
+ }
+
+ @Override
+ public void warn(final String message) {
+ delegate.warn(message);
+ }
+
+ @Override
+ public void warn(final String format, final Object arg) {
+ delegate.warn(format, arg);
+ }
+
+ @Override
+ public void warn(final String format, final Object arg1, final Object arg2) {
+ delegate.warn(format, arg1, arg2);
+ }
+
+ @Override
+ public void warn(final String format, final Object... arguments) {
+ delegate.warn(format, arguments);
+ }
+
+ @Override
+ public <E extends Exception> void warn(final LoggerConsumer<E> consumer) throws E {
+ if (isWarnEnabled()) {
+ consumer.accept(this);
+ }
+ }
+
+ @Override
+ public boolean isErrorEnabled() {
+ return delegate.isErrorEnabled();
+ }
+
+ @Override
+ public void error(final String message) {
+ delegate.error(message);
+ }
+
+ @Override
+ public void error(final String format, final Object arg) {
+ delegate.error(format, arg);
+ }
+
+ @Override
+ public void error(final String format, final Object arg1, final Object arg2) {
+ delegate.error(format, arg1, arg2);
+ }
+
+ @Override
+ public void error(final String format, final Object... arguments) {
+ delegate.error(format, arguments);
+ }
+
+ @Override
+ public <E extends Exception> void error(final LoggerConsumer<E> consumer) throws E {
+ if (isErrorEnabled()) {
+ consumer.accept(this);
+ }
+ }
+
+ @Override
+ public void audit(final String message) {
+ delegate.info(message);
+ }
+
+ @Override
+ public void audit(final String format, final Object arg) {
+ delegate.info(format, arg);
+ }
+
+ @Override
+ public void audit(final String format, final Object arg1, final Object arg2) {
+ delegate.info(format, arg1, arg2);
+ }
+
+ @Override
+ public void audit(final String format, final Object... arguments) {
+ delegate.info(format, arguments);
+ }
+ }
+}
diff --git a/winegrower-core/src/test/java/org/apache/winegrower/RipenerTest.java b/winegrower-core/src/test/java/org/apache/winegrower/RipenerTest.java
index 623b537..e1ec641 100644
--- a/winegrower-core/src/test/java/org/apache/winegrower/RipenerTest.java
+++ b/winegrower-core/src/test/java/org/apache/winegrower/RipenerTest.java
@@ -86,13 +86,13 @@
@Test
@WithRipener
void ensureFrameworkBundle(@Service final Ripener ripener) {
- assertEquals(10, ripener.getRegistry().getBundles().size());
+ assertEquals(5, ripener.getRegistry().getBundles().size(), () -> ripener.getRegistry().getBundles().toString());
}
@Test
@WithRipener(includeResources = @Entry(path = "org.apache.winegrower.test.implicitactivator"))
void implicitActivator(@Service final Ripener ripener) {
- assertEquals(11, ripener.getRegistry().getBundles().size());
+ assertEquals(6, ripener.getRegistry().getBundles().size());
final BundleActivatorHandler activatorHandler = ripener.getRegistry().getBundles().values().stream()
.filter(it -> it.getActivator() != null)
@@ -111,7 +111,7 @@
@WithRipener(includeResources = @Entry(path = "org.apache.winegrower.test.simpleactivator"))
void simpleActivator(@Service final Ripener ripener) {
final Map<Long, OSGiBundleLifecycle> bundles = ripener.getRegistry().getBundles();
- assertEquals(11 /*includes junit5 with v >= 5.6*/, bundles.size());
+ assertEquals(6, bundles.size());
final BundleActivatorHandler activatorHandler = ripener.getRegistry().getBundles().values().stream()
.filter(it -> it.getActivator() != null)
@@ -134,8 +134,8 @@
@Test
@WithRipener(includeResources = @Entry(path = "org.apache.winegrower.test.simpleservice"))
void simpleServiceRegistration(@Service final Ripener ripener) {
- // config admin + event admin + myservice
- assertEquals(3, ripener.getServices().getServices().size());
+ // config admin + event admin + loggerfactory + myservice
+ assertEquals(4, ripener.getServices().getServices().size());
}
@Test
@@ -153,7 +153,7 @@
}
private void validateTracker(final Ripener ripener) {
- assertEquals(3, ripener.getServices().getServices().size());
+ assertEquals(4, ripener.getServices().getServices().size());
final Map<String, BundleActivatorHandler> activatorHandler = ripener.getRegistry().getBundles().values().stream()
.filter(it -> it.getActivator() != null)
diff --git a/winegrower-core/src/test/java/org/apache/winegrower/scanner/manifest/OSGiCDIManifestContributorTest.java b/winegrower-core/src/test/java/org/apache/winegrower/scanner/manifest/OSGiCDIManifestContributorTest.java
new file mode 100644
index 0000000..fbe63fe
--- /dev/null
+++ b/winegrower-core/src/test/java/org/apache/winegrower/scanner/manifest/OSGiCDIManifestContributorTest.java
@@ -0,0 +1,76 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.winegrower.scanner.manifest;
+
+import org.apache.winegrower.scanner.manifest.cdi.AriesPluralRequirement;
+import org.apache.winegrower.scanner.manifest.cdi.AriesSingularRequirement;
+import org.apache.winegrower.scanner.manifest.cdi.StandardRequirement;
+import org.apache.xbean.finder.archive.FileArchive;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.jar.Manifest;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.osgi.framework.Constants.REQUIRE_CAPABILITY;
+
+class OSGiCDIManifestContributorTest {
+ @Test
+ void scanSingularAriesRequireExtension(@TempDir final Path temp) throws IOException {
+ prepare(AriesSingularRequirement.class, temp);
+ assertEquals("osgi.extender;filter:=\"(osgi.extender=osgi.cdi)\";" +
+ "beans:List<String>=\"org.apache.winegrower.scanner.manifest.cdi.AriesSingularRequirement\"," +
+ "osgi.cdi.extension;filter:=\"(osgi.cdi.extension=the-extension)\"", execute(temp));
+ }
+
+ @Test
+ void scanPluralAriesRequireExtension(@TempDir final Path temp) throws IOException {
+ prepare(AriesPluralRequirement.class, temp);
+ assertEquals("osgi.extender;filter:=\"(osgi.extender=osgi.cdi)\";" +
+ "beans:List<String>=\"org.apache.winegrower.scanner.manifest.cdi.AriesPluralRequirement\"," +
+ "osgi.cdi.extension;filter:=\"(osgi.cdi.extension=the-extension-1)\"," +
+ "osgi.cdi.extension;filter:=\"(osgi.cdi.extension=the-extension-2)\"", execute(temp));
+ }
+
+ @Test
+ void scanDefaultRequirement(@TempDir final Path temp) throws IOException {
+ prepare(StandardRequirement.class, temp);
+ // here we don't scan an aries-cdi extension - but std requirement work, see requirement manifest contributor test
+ assertEquals("osgi.extender;filter:=\"(osgi.extender=osgi.cdi)\";beans:List<String>=\"org.apache.winegrower.scanner.manifest.cdi.StandardRequirement\"", execute(temp));
+ }
+
+ private String execute(final Path temp) {
+ final Manifest manifest = new Manifest();
+ final ManifestContributor.WinegrowerAnnotationFinder finder = new ManifestContributor.WinegrowerAnnotationFinder(
+ new FileArchive(Thread.currentThread().getContextClassLoader(), temp.toFile()), false);
+ new OSGiCDIManifestContributor().contribute(finder, () -> manifest);
+ return manifest.getMainAttributes().getValue(REQUIRE_CAPABILITY);
+ }
+
+ private void prepare(final Class<?> toScan, final Path temp) throws IOException {
+ final String path = toScan.getName().replace('.', '/') + ".class";
+ final Path to = temp.resolve(path);
+ Files.createDirectories(to.getParent());
+ final Path base = Paths.get("target/test-classes");
+ Files.copy(base.resolve(path), to);
+ final Path metaInf = temp.resolve("META-INF");
+ Files.createDirectories(metaInf);
+ Files.write(metaInf.resolve("beans.xml"), "<beans/>".getBytes(StandardCharsets.UTF_8));
+ }
+}
diff --git a/winegrower-core/src/test/java/org/apache/winegrower/scanner/manifest/RequirementManifestContributorTest.java b/winegrower-core/src/test/java/org/apache/winegrower/scanner/manifest/RequirementManifestContributorTest.java
new file mode 100644
index 0000000..2929eff
--- /dev/null
+++ b/winegrower-core/src/test/java/org/apache/winegrower/scanner/manifest/RequirementManifestContributorTest.java
@@ -0,0 +1,43 @@
+package org.apache.winegrower.scanner.manifest;
+
+import org.apache.winegrower.scanner.manifest.cdi.StandardRequirement;
+import org.apache.xbean.finder.archive.FileArchive;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.jar.Manifest;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.osgi.framework.Constants.REQUIRE_CAPABILITY;
+
+class RequirementManifestContributorTest {
+ @Test
+ void scanDefaultRequirement(@TempDir final Path temp) throws IOException {
+ prepare(StandardRequirement.class, temp);
+ assertEquals("osgi.cdi.extension;filter:=\"(osgi.cdi.extension=the-direct-extension)\"", execute(temp));
+ }
+
+ private String execute(final Path temp) {
+ final Manifest manifest = new Manifest();
+ final ManifestContributor.WinegrowerAnnotationFinder finder = new ManifestContributor.WinegrowerAnnotationFinder(
+ new FileArchive(Thread.currentThread().getContextClassLoader(), temp.toFile()), false);
+ new RequirementManifestContributor().contribute(finder, () -> manifest);
+ return manifest.getMainAttributes().getValue(REQUIRE_CAPABILITY);
+ }
+
+ private void prepare(final Class<?> toScan, final Path temp) throws IOException {
+ final String path = toScan.getName().replace('.', '/') + ".class";
+ final Path to = temp.resolve(path);
+ Files.createDirectories(to.getParent());
+ final Path base = Paths.get("target/test-classes");
+ Files.copy(base.resolve(path), to);
+ final Path metaInf = temp.resolve("META-INF");
+ Files.createDirectories(metaInf);
+ Files.write(metaInf.resolve("beans.xml"), "<beans/>".getBytes(StandardCharsets.UTF_8));
+ }
+}
diff --git a/winegrower-core/src/test/java/org/apache/winegrower/scanner/manifest/cdi/AriesPluralRequirement.java b/winegrower-core/src/test/java/org/apache/winegrower/scanner/manifest/cdi/AriesPluralRequirement.java
new file mode 100644
index 0000000..12f9413
--- /dev/null
+++ b/winegrower-core/src/test/java/org/apache/winegrower/scanner/manifest/cdi/AriesPluralRequirement.java
@@ -0,0 +1,24 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.winegrower.scanner.manifest.cdi;
+
+import org.apache.aries.cdi.extra.RequireCDIExtension;
+import org.apache.aries.cdi.extra.RequireCDIExtensions;
+
+@RequireCDIExtensions({
+ @RequireCDIExtension("the-extension-1"),
+ @RequireCDIExtension("the-extension-2")
+})
+public class AriesPluralRequirement {
+}
diff --git a/winegrower-core/src/test/java/org/apache/winegrower/scanner/manifest/cdi/AriesSingularRequirement.java b/winegrower-core/src/test/java/org/apache/winegrower/scanner/manifest/cdi/AriesSingularRequirement.java
new file mode 100644
index 0000000..2012bb7
--- /dev/null
+++ b/winegrower-core/src/test/java/org/apache/winegrower/scanner/manifest/cdi/AriesSingularRequirement.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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.winegrower.scanner.manifest.cdi;
+
+import org.apache.aries.cdi.extra.RequireCDIExtension;
+
+@RequireCDIExtension("the-extension")
+public class AriesSingularRequirement {
+}
diff --git a/winegrower-core/src/test/java/org/apache/winegrower/scanner/manifest/cdi/StandardRequirement.java b/winegrower-core/src/test/java/org/apache/winegrower/scanner/manifest/cdi/StandardRequirement.java
new file mode 100644
index 0000000..2e2f8cc
--- /dev/null
+++ b/winegrower-core/src/test/java/org/apache/winegrower/scanner/manifest/cdi/StandardRequirement.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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.winegrower.scanner.manifest.cdi;
+
+import org.osgi.annotation.bundle.Requirement;
+
+@Requirement(
+ namespace = "osgi.cdi.extension",
+ name = "the-direct-extension"
+)
+public class StandardRequirement {
+}
diff --git a/winegrower-core/src/test/java/org/apache/winegrower/test/WithRipener.java b/winegrower-core/src/test/java/org/apache/winegrower/test/WithRipener.java
index d8dc144..51046ea 100644
--- a/winegrower-core/src/test/java/org/apache/winegrower/test/WithRipener.java
+++ b/winegrower-core/src/test/java/org/apache/winegrower/test/WithRipener.java
@@ -102,7 +102,7 @@
thread.setContextClassLoader(loader);
final Ripener.Configuration configuration = new Ripener.Configuration();
- configuration.setScanningExcludes(singletonList("test-classes"));
+ configuration.setScanningExcludes(asList("common-java5-" /* surefire, yes... */, "test-classes"));
setConfiguration(configuration, config);
final Ripener ripener = new Ripener.Impl(configuration).start();
diff --git a/winegrower-examples/osgi-cdi/pom.xml b/winegrower-examples/osgi-cdi/pom.xml
index 0711bd2..6b05fa6 100644
--- a/winegrower-examples/osgi-cdi/pom.xml
+++ b/winegrower-examples/osgi-cdi/pom.xml
@@ -43,13 +43,6 @@
<groupId>org.apache.winegrower.cepages</groupId>
<artifactId>winegrower-cepage-osgi-cdi</artifactId>
<version>${project.version}</version>
- <type>pom</type>
- </dependency>
- <dependency>
- <groupId>org.apache.winegrower.cepages</groupId>
- <artifactId>winegrower-cepage-http</artifactId>
- <version>${project.version}</version>
- <type>pom</type>
</dependency>
</dependencies>
diff --git a/winegrower-cepages/winegrower-cepage-osgi-cdi/src/test/resources/META-INF/beans.xml b/winegrower-examples/osgi-cdi/src/main/resources/META-INF/beans.xml
similarity index 69%
rename from winegrower-cepages/winegrower-cepage-osgi-cdi/src/test/resources/META-INF/beans.xml
rename to winegrower-examples/osgi-cdi/src/main/resources/META-INF/beans.xml
index 1d9dae2..55f1b68 100644
--- a/winegrower-cepages/winegrower-cepage-osgi-cdi/src/test/resources/META-INF/beans.xml
+++ b/winegrower-examples/osgi-cdi/src/main/resources/META-INF/beans.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<?xml version="1.0"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@@ -15,11 +15,4 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<beans bean-discovery-mode="all" version="2.0"
- xmlns="http://xmlns.jcp.org/xml/ns/javaee"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="
- http://xmlns.jcp.org/xml/ns/javaee
- http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd">
- <trim/>
-</beans>
+<beans />
diff --git a/winegrower-extension/winegrower-build/winegrower-build-common/pom.xml b/winegrower-extension/winegrower-build/winegrower-build-common/pom.xml
index a8ffb43..4d40745 100644
--- a/winegrower-extension/winegrower-build/winegrower-build-common/pom.xml
+++ b/winegrower-extension/winegrower-build/winegrower-build-common/pom.xml
@@ -57,8 +57,14 @@
</dependency>
<dependency>
<groupId>org.apache.xbean</groupId>
- <artifactId>xbean-asm8-shaded</artifactId>
+ <artifactId>xbean-asm9-shaded</artifactId>
<version>${xbean.version}</version>
+ <exclusions>
+ <exclusion>
+ <groupId>*</groupId>
+ <artifactId>*</artifactId>
+ </exclusion>
+ </exclusions>
</dependency>
<dependency>
<groupId>org.apache.winegrower</groupId>
diff --git a/winegrower-extension/winegrower-build/winegrower-maven-plugin/src/main/java/org/apache/winegrower/extension/build/maven/PourMojo.java b/winegrower-extension/winegrower-build/winegrower-maven-plugin/src/main/java/org/apache/winegrower/extension/build/maven/PourMojo.java
index 4760fe1..43b5b1e 100644
--- a/winegrower-extension/winegrower-build/winegrower-maven-plugin/src/main/java/org/apache/winegrower/extension/build/maven/PourMojo.java
+++ b/winegrower-extension/winegrower-build/winegrower-maven-plugin/src/main/java/org/apache/winegrower/extension/build/maven/PourMojo.java
@@ -13,9 +13,13 @@
*/
package org.apache.winegrower.extension.build.maven;
-import static java.util.Optional.ofNullable;
-import static java.util.stream.Collectors.toList;
-import static org.apache.maven.plugins.annotations.ResolutionScope.RUNTIME_PLUS_SYSTEM;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.project.MavenProject;
+import org.apache.xbean.finder.util.Files;
import java.io.File;
import java.io.IOException;
@@ -31,13 +35,9 @@
import java.util.function.Predicate;
import java.util.stream.Stream;
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.plugin.AbstractMojo;
-import org.apache.maven.plugin.MojoExecutionException;
-import org.apache.maven.plugins.annotations.Mojo;
-import org.apache.maven.plugins.annotations.Parameter;
-import org.apache.maven.project.MavenProject;
-import org.apache.xbean.finder.util.Files;
+import static java.util.Optional.ofNullable;
+import static java.util.stream.Collectors.toList;
+import static org.apache.maven.plugins.annotations.ResolutionScope.RUNTIME_PLUS_SYSTEM;
@Mojo(name = "pour", requiresDependencyResolution = RUNTIME_PLUS_SYSTEM)
public class PourMojo extends AbstractMojo {
@@ -140,29 +140,9 @@
throw new IllegalArgumentException(e);
}
}
- return urls.isEmpty() ? parent : new URLClassLoader(
- urls.toArray(new URL[0]),
- !excludeOsgi || !hasWinegrower ? parent : new ClassLoader(parent) {
- @Override
- protected Class<?> loadClass(final String name, final boolean resolve) throws ClassNotFoundException {
- if (name.startsWith("org.")) {
- final String sub = name.substring("org.".length());
- if (sub.startsWith("osgi.")) {
- throw new ClassNotFoundException(name);
- } else if (sub.startsWith("apache.")) {
- final String apache = sub.substring("apache.".length());
- if (apache.startsWith("winegrower.")) {
- throw new ClassNotFoundException(name);
- }
- if (apache.startsWith("xbean.")) {
- throw new ClassNotFoundException(name);
- }
- }
- }
- return super.loadClass(name, resolve);
- }
- }) {
-
+ final ClassLoader workaroundMaven = new WorkAroundMavenClassLoader(parent);
+ final ClassLoader parentLoader = !excludeOsgi || !hasWinegrower ? workaroundMaven : new IgnoreWinegrowerckClassLoader(workaroundMaven);
+ return urls.isEmpty() ? workaroundMaven : new URLClassLoader(urls.toArray(new URL[0]), parentLoader) {
@Override
public boolean equals(final Object obj) {
return super.equals(obj) || parent.equals(obj);
@@ -247,4 +227,46 @@
throw new IllegalStateException(ex);
}
}
+
+ private static class WorkAroundMavenClassLoader extends ClassLoader {
+ private WorkAroundMavenClassLoader(final ClassLoader parent) {
+ super(parent);
+ }
+
+ @Override
+ public Class<?> loadClass(final String name, final boolean resolve) throws ClassNotFoundException {
+ if (name.startsWith("javax.")) {
+ final String sub = name.substring("javax.".length());
+ if (sub.startsWith("enterprise.") || sub.startsWith("decorator.")) { // maven has an outdated cdi-api
+ throw new ClassNotFoundException(name);
+ }
+ }
+ return getParent().loadClass(name);
+ }
+ }
+
+ private static class IgnoreWinegrowerckClassLoader extends ClassLoader {
+ private IgnoreWinegrowerckClassLoader(final ClassLoader workaroundMaven) {
+ super(workaroundMaven);
+ }
+
+ @Override
+ protected Class<?> loadClass(final String name, final boolean resolve) throws ClassNotFoundException {
+ if (name.startsWith("org.")) {
+ final String sub = name.substring("org.".length());
+ if (sub.startsWith("osgi.")) {
+ throw new ClassNotFoundException(name);
+ } else if (sub.startsWith("apache.")) {
+ final String apache = sub.substring("apache.".length());
+ if (apache.startsWith("winegrower.")) {
+ throw new ClassNotFoundException(name);
+ }
+ if (apache.startsWith("xbean.")) {
+ throw new ClassNotFoundException(name);
+ }
+ }
+ }
+ return super.loadClass(name, resolve);
+ }
+ }
}