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);
+        }
+    }
 }