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

timothyjward pushed a commit to branch feature/v1.1
in repository https://gitbox.apache.org/repos/asf/aries-typedevent.git

commit 42dbada0d79660fec2edabcc7fdf3229bb2b0414
Author: Tim Ward <[email protected]>
AuthorDate: Tue Sep 5 16:37:34 2023 +0100

    Initial implementation for Typed Events 1.1
    
    This commit adds in the prototype OSGi API for Typed Events 1.1, which must 
be removed before release. It also implements the new API and fixes up 
dependencies so that the build keeps running.
    
    Signed-off-by: Tim Ward <[email protected]>
---
 org.apache.aries.typedevent.bus/pom.xml            |  35 +-
 .../typedevent/bus/impl/TypedEventBusImpl.java     |  68 +++
 .../osgi/service/typedevent/TopicPermission.java   | 557 +++++++++++++++++++++
 .../org/osgi/service/typedevent/TypedEventBus.java | 114 +++++
 .../service/typedevent/TypedEventConstants.java    |  94 ++++
 .../osgi/service/typedevent/TypedEventHandler.java |  63 +++
 .../service/typedevent/TypedEventPublisher.java    |  94 ++++
 .../service/typedevent/UnhandledEventHandler.java  |  45 ++
 .../service/typedevent/UntypedEventHandler.java    |  59 +++
 .../typedevent/annotations/RequireTypedEvent.java  |  52 ++
 .../typedevent/annotations/package-info.java       |  39 ++
 .../service/typedevent/monitor/MonitorEvent.java   |  45 ++
 .../typedevent/monitor/TypedEventMonitor.java      |  64 +++
 .../service/typedevent/monitor/package-info.java   |  45 ++
 .../org/osgi/service/typedevent/package-info.java  |  46 ++
 .../typedevent/propertytypes/EventFilter.java      |  57 +++
 .../typedevent/propertytypes/EventTopics.java      |  56 +++
 .../typedevent/propertytypes/EventType.java        |  55 ++
 .../typedevent/propertytypes/package-info.java     |  43 ++
 .../typedevent/bus/impl/TypedEventBusImplTest.java | 105 +++-
 .../bus/osgi/EventDeliveryIntegrationTest.java     |  17 +-
 .../typedevent/bus/osgi/FilterIntegrationTest.java |  17 +-
 .../bus/osgi/TypedEventMonitorIntegrationTest.java |  13 +-
 .../osgi/UnhandledEventHandlerIntegrationTest.java |  17 +-
 org.apache.aries.typedevent.bus/test.bndrun        |   8 +-
 .../org.apache.aries.typedevent.remote.api/pom.xml |  10 +-
 .../pom.xml                                        |   9 +-
 .../osgi/RemoteEventBusIntegrationTest.java        |   2 +-
 .../test.bndrun                                    |   9 +-
 .../org.apache.aries.typedevent.remote.spi/pom.xml |   3 +-
 pom.xml                                            |   3 +-
 31 files changed, 1763 insertions(+), 81 deletions(-)

diff --git a/org.apache.aries.typedevent.bus/pom.xml 
b/org.apache.aries.typedevent.bus/pom.xml
index a9fc494..2ee877a 100644
--- a/org.apache.aries.typedevent.bus/pom.xml
+++ b/org.apache.aries.typedevent.bus/pom.xml
@@ -37,10 +37,11 @@
             <groupId>org.osgi</groupId>
             <artifactId>org.osgi.core</artifactId>
         </dependency>
+        <!-- Temporary removal while using the locally built interfaces
         <dependency>
             <groupId>org.osgi</groupId>
             <artifactId>org.osgi.service.typedevent</artifactId>
-        </dependency>
+        </dependency> -->
         <dependency>
             <groupId>org.osgi</groupId>
             <artifactId>osgi.annotation</artifactId>
@@ -89,6 +90,38 @@
             <groupId>ch.qos.logback</groupId>
             <artifactId>logback-core</artifactId>
         </dependency>
+        
+        <!-- Temporary additions to compile the OSGi interfaces -->
+        <dependency>
+                       <groupId>org.osgi</groupId>
+                       <artifactId>org.osgi.annotation.bundle</artifactId>
+               </dependency>
+        <dependency>
+                       <groupId>org.osgi</groupId>
+                       
<artifactId>org.osgi.service.component.annotations</artifactId>
+               </dependency>
+        <dependency>
+                       <groupId>org.osgi</groupId>
+                       
<artifactId>org.osgi.namespace.implementation</artifactId>
+                       <version>1.0.0</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.osgi</groupId>
+                       <artifactId>org.osgi.util.pushstream</artifactId>
+                       <version>1.0.0</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.osgi</groupId>
+                       <artifactId>org.osgi.util.function</artifactId>
+                       <version>1.1.0</version>
+                       <scope>runtime</scope>
+               </dependency>
+               <dependency>
+                       <groupId>org.osgi</groupId>
+                       <artifactId>org.osgi.util.promise</artifactId>
+                       <version>1.1.0</version>
+                       <scope>runtime</scope>
+               </dependency>
     </dependencies>
     
     <build>
diff --git 
a/org.apache.aries.typedevent.bus/src/main/java/org/apache/aries/typedevent/bus/impl/TypedEventBusImpl.java
 
b/org.apache.aries.typedevent.bus/src/main/java/org/apache/aries/typedevent/bus/impl/TypedEventBusImpl.java
index e055443..0c4337b 100644
--- 
a/org.apache.aries.typedevent.bus/src/main/java/org/apache/aries/typedevent/bus/impl/TypedEventBusImpl.java
+++ 
b/org.apache.aries.typedevent.bus/src/main/java/org/apache/aries/typedevent/bus/impl/TypedEventBusImpl.java
@@ -50,6 +50,7 @@ import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.service.typedevent.TypedEventBus;
 import org.osgi.service.typedevent.TypedEventConstants;
 import org.osgi.service.typedevent.TypedEventHandler;
+import org.osgi.service.typedevent.TypedEventPublisher;
 import org.osgi.service.typedevent.UnhandledEventHandler;
 import org.osgi.service.typedevent.UntypedEventHandler;
 import org.osgi.util.converter.TypeReference;
@@ -568,4 +569,71 @@ public class TypedEventBusImpl implements TypedEventBus {
         }
 
     }
+
+       @Override
+       public <T> TypedEventPublisher<T> createPublisher(Class<T> eventType) {
+               Objects.requireNonNull(eventType, "The event type must not be 
null");
+        String topicName = eventType.getName().replace('.', '/');
+        checkTopicSyntax(topicName);
+               return new TypedEventPublisherImpl<>(topicName);
+       }
+
+       @Override
+       public <T> TypedEventPublisher<T> createPublisher(String topic, 
Class<T> eventType) {
+               Objects.requireNonNull(topic, "The event topic must not be 
null");
+               Objects.requireNonNull(eventType, "The event type must not be 
null");
+               checkTopicSyntax(topic);
+               return new TypedEventPublisherImpl<>(topic);
+       }
+
+       @Override
+       public TypedEventPublisher<Object> createPublisher(String topic) {
+               Objects.requireNonNull(topic, "The event topic must not be 
null");
+               checkTopicSyntax(topic);
+               return new TypedEventPublisherImpl<>(topic);
+       }
+       
+       private class TypedEventPublisherImpl<T> implements 
TypedEventPublisher<T> {
+
+               private final String topic;
+               
+               private final AtomicBoolean open = new AtomicBoolean(true);
+               
+               public TypedEventPublisherImpl(String topic) {
+                       this.topic = topic;
+               }
+
+               private void checkOpen() {
+                       if(!open.get()) {
+                               throw new IllegalStateException("The 
TypedEventPublisher for topic " + topic + " is closed.");
+                       }
+               }
+               
+               @Override
+               public void deliver(T event) {
+                       checkOpen();
+                       TypedEventBusImpl.this.deliver(topic, 
EventConverter.forTypedEvent(event));
+               }
+
+               @Override
+               public void deliverUntyped(Map<String, ?> event) {
+                       checkOpen();
+                       TypedEventBusImpl.this.deliver(topic, 
EventConverter.forUntypedEvent(event));
+               }
+
+               @Override
+               public String getTopic() {
+                       return topic;
+               }
+
+               @Override
+               public void close() {
+                       open.set(false);
+               }
+
+               @Override
+               public boolean isOpen() {
+                       return open.get();
+               }
+       }
 }
diff --git 
a/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/TopicPermission.java
 
b/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/TopicPermission.java
new file mode 100644
index 0000000..8bf1b44
--- /dev/null
+++ 
b/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/TopicPermission.java
@@ -0,0 +1,557 @@
+/*******************************************************************************
+ * Copyright (c) Contributors to the Eclipse Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0 
+ 
*******************************************************************************/
+
+package org.osgi.service.typedevent;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamField;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A bundle's authority to publish or subscribe to typed events on a topic.
+ * <p>
+ * A topic is a slash-separated string that defines a topic.
+ * <p>
+ * For example:
+ * 
+ * <pre>
+ * org / osgi / service / foo / FooEvent / ACTION
+ * </pre>
+ * <p>
+ * Topics may also be given a default name based on the event type that is
+ * published to the topic. These use the fully qualified class name of the 
event
+ * object as the name of the topic.
+ * <p>
+ * For example:
+ * 
+ * <pre>
+ * com.acme.foo.event.EventData
+ * </pre>
+ * <p>
+ * {@code TopicPermission} has two actions: {@code publish} and
+ * {@code subscribe}.
+ * 
+ * @ThreadSafe
+ * @author $Id: 35b621041b08d51844397f56fc8c51a682bf7b7b $
+ */
+public final class TopicPermission extends Permission {
+       static final long                                       
serialVersionUID        = -5855563886961618300L;
+       /**
+        * The action string {@code publish}.
+        */
+       public final static String                      PUBLISH                 
        = "publish";
+       /**
+        * The action string {@code subscribe}.
+        */
+       public final static String                      SUBSCRIBE               
        = "subscribe";
+       private final static int                        ACTION_PUBLISH          
= 0x00000001;
+       private final static int                        ACTION_SUBSCRIBE        
= 0x00000002;
+       private final static int                        ACTION_ALL              
        = ACTION_PUBLISH | ACTION_SUBSCRIBE;
+       private final static int                        ACTION_NONE             
        = 0;
+       /**
+        * The actions mask.
+        */
+       private transient int                           action_mask;
+
+       /**
+        * prefix if the name is wildcarded.
+        */
+       private transient volatile String       prefix;
+
+       /**
+        * The actions in canonical form.
+        * 
+        * @serial
+        */
+       private volatile String                         actions                 
        = null;
+
+       /**
+        * Defines the authority to publish and/or subscribe to a topic within 
the
+        * Typed Event service specification.
+        * <p>
+        * The name is specified as a slash-separated string. Wildcards may be 
used.
+        * For example:
+        * 
+        * <pre>
+        *    org/osgi/service/fooFooEvent/ACTION
+        *    com/isv/*
+        *    *
+        * </pre>
+        * <p>
+        * A bundle that needs to publish events on a topic must have the
+        * appropriate {@code TopicPermission} for that topic; similarly, a 
bundle
+        * that needs to subscribe to events on a topic must have the 
appropriate
+        * {@code TopicPermssion} for that topic.
+        * <p>
+        * 
+        * @param name Topic name.
+        * @param actions {@code publish},{@code subscribe} (canonical order).
+        */
+       public TopicPermission(String name, String actions) {
+               this(name, parseActions(actions));
+       }
+
+       /**
+        * Package private constructor used by TopicPermissionCollection.
+        * 
+        * @param name class name
+        * @param mask action mask
+        */
+       TopicPermission(String name, int mask) {
+               super(name);
+               setTransients(mask);
+       }
+
+       /**
+        * Called by constructors and when deserialized.
+        * 
+        * @param name topic name
+        * @param mask action mask
+        */
+       private synchronized void setTransients(final int mask) {
+               final String name = getName();
+               if ((name == null) || name.length() == 0) {
+                       throw new IllegalArgumentException("invalid name");
+               }
+
+               if ((mask == ACTION_NONE) || ((mask & ACTION_ALL) != mask)) {
+                       throw new IllegalArgumentException("invalid action 
string");
+               }
+               action_mask = mask;
+
+               if (name.equals("*")) {
+                       prefix = "";
+               } else {
+                       if (name.endsWith("/*")) {
+                               prefix = name.substring(0, name.length() - 1);
+                       } else {
+                               prefix = null;
+                       }
+               }
+       }
+
+       /**
+        * Returns the current action mask.
+        * <p>
+        * Used by the TopicPermissionCollection class.
+        * 
+        * @return Current action mask.
+        */
+       synchronized int getActionsMask() {
+               return action_mask;
+       }
+
+       /**
+        * Parse action string into action mask.
+        * 
+        * @param actions Action string.
+        * @return action mask.
+        */
+       private static int parseActions(final String actions) {
+               boolean seencomma = false;
+               int mask = ACTION_NONE;
+               if (actions == null) {
+                       return mask;
+               }
+               char[] a = actions.toCharArray();
+               int i = a.length - 1;
+               if (i < 0)
+                       return mask;
+               while (i != -1) {
+                       char c;
+                       // skip whitespace
+                       while ((i != -1) && ((c = a[i]) == ' ' || c == '\r' || 
c == '\n' || c == '\f' || c == '\t'))
+                               i--;
+                       // check for the known strings
+                       int matchlen;
+                       if (i >= 8 && (a[i - 8] == 's' || a[i - 8] == 'S')
+                                       && (a[i - 7] == 'u' || a[i - 7] == 'U')
+                                       && (a[i - 6] == 'b' || a[i - 6] == 'B')
+                                       && (a[i - 5] == 's' || a[i - 5] == 'S')
+                                       && (a[i - 4] == 'c' || a[i - 4] == 'C')
+                                       && (a[i - 3] == 'r' || a[i - 3] == 'R')
+                                       && (a[i - 2] == 'i' || a[i - 2] == 'I')
+                                       && (a[i - 1] == 'b' || a[i - 1] == 'B')
+                                       && (a[i] == 'e' || a[i] == 'E')) {
+                               matchlen = 9;
+                               mask |= ACTION_SUBSCRIBE;
+                       }
+                       else
+                               if (i >= 6 && (a[i - 6] == 'p' || a[i - 6] == 
'P')
+                                               && (a[i - 5] == 'u' || a[i - 5] 
== 'U')
+                                               && (a[i - 4] == 'b' || a[i - 4] 
== 'B')
+                                               && (a[i - 3] == 'l' || a[i - 3] 
== 'L')
+                                               && (a[i - 2] == 'i' || a[i - 2] 
== 'I')
+                                               && (a[i - 1] == 's' || a[i - 1] 
== 'S')
+                                               && (a[i] == 'h' || a[i] == 
'H')) {
+                                       matchlen = 7;
+                                       mask |= ACTION_PUBLISH;
+                               }
+                               else {
+                                       // parse error
+                                       throw new 
IllegalArgumentException("invalid permission: "
+                                                       + actions);
+                               }
+                       // make sure we didn't just match the tail of a word
+                       // like "ackbarfpublish". Also, skip to the comma.
+                       seencomma = false;
+                       while (i >= matchlen && !seencomma) {
+                               switch (a[i - matchlen]) {
+                                       case ',' :
+                                               seencomma = true;
+                                               /* FALLTHROUGH */
+                                       case ' ' :
+                                       case '\r' :
+                                       case '\n' :
+                                       case '\f' :
+                                       case '\t' :
+                                               break;
+                                       default :
+                                               throw new 
IllegalArgumentException("invalid permission: " + actions);
+                               }
+                               i--;
+                       }
+                       // point i at the location of the comma minus one (or 
-1).
+                       i -= matchlen;
+               }
+               if (seencomma) {
+                       throw new IllegalArgumentException("invalid permission: 
" + actions);
+               }
+               return mask;
+       }
+
+       /**
+        * Determines if the specified permission is implied by this object.
+        * 
+        * <p>
+        * This method checks that the topic name of the target is implied by 
the
+        * topic name of this object. The list of {@code TopicPermission} 
actions
+        * must either match or allow for the list of the target object to 
imply the
+        * target {@code TopicPermission} action.
+        * 
+        * <pre>
+        *    x/y/*,&quot;publish&quot; -&gt; x/y/z,&quot;publish&quot; is true
+        *    *,&quot;subscribe&quot; -&gt; x/y,&quot;subscribe&quot;   is true
+        *    *,&quot;publish&quot; -&gt; x/y,&quot;subscribe&quot;     is false
+        *    x/y,&quot;publish&quot; -&gt; x/y/z,&quot;publish&quot;   is false
+        * </pre>
+        * 
+        * @param p The target permission to interrogate.
+        * @return {@code true} if the specified {@code TopicPermission} action 
is
+        *         implied by this object; {@code false} otherwise.
+        */
+       @Override
+       public boolean implies(Permission p) {
+               if (p instanceof TopicPermission) {
+                       TopicPermission requested = (TopicPermission) p;
+                       int requestedMask = requested.getActionsMask();
+                       if ((getActionsMask() & requestedMask) == 
requestedMask) {
+                               String requestedName = requested.getName();
+                               String pre = prefix;
+                               if (pre != null) {
+                                       return requestedName.startsWith(pre);
+                               }
+
+                               return requestedName.equals(getName());
+                       }
+               }
+               return false;
+       }
+
+       /**
+        * Returns the canonical string representation of the
+        * {@code TopicPermission} actions.
+        * 
+        * <p>
+        * Always returns present {@code TopicPermission} actions in the 
following
+        * order: {@code publish},{@code subscribe}.
+        * 
+        * @return Canonical string representation of the {@code 
TopicPermission}
+        *         actions.
+        */
+       @Override
+       public String getActions() {
+               String result = actions;
+               if (result == null) {
+                       StringBuilder sb = new StringBuilder();
+                       boolean comma = false;
+                       int mask = getActionsMask();
+                       if ((mask & ACTION_PUBLISH) == ACTION_PUBLISH) {
+                               sb.append(PUBLISH);
+                               comma = true;
+                       }
+                       if ((mask & ACTION_SUBSCRIBE) == ACTION_SUBSCRIBE) {
+                               if (comma)
+                                       sb.append(',');
+                               sb.append(SUBSCRIBE);
+                       }
+                       actions = result = sb.toString();
+               }
+               return result;
+       }
+
+       /**
+        * Returns a new {@code PermissionCollection} object suitable for 
storing
+        * {@code TopicPermission} objects.
+        * 
+        * @return A new {@code PermissionCollection} object.
+        */
+       @Override
+       public PermissionCollection newPermissionCollection() {
+               return new TopicPermissionCollection();
+       }
+
+       /**
+        * Determines the equality of two {@code TopicPermission} objects.
+        * 
+        * This method checks that specified {@code TopicPermission} has the 
same
+        * topic name and actions as this {@code TopicPermission} object.
+        * 
+        * @param obj The object to test for equality with this
+        *        {@code TopicPermission} object.
+        * @return {@code true} if {@code obj} is a {@code TopicPermission}, 
and has
+        *         the same topic name and actions as this {@code 
TopicPermission}
+        *         object; {@code false} otherwise.
+        */
+       @Override
+       public boolean equals(Object obj) {
+               if (obj == this) {
+                       return true;
+               }
+               if (!(obj instanceof TopicPermission)) {
+                       return false;
+               }
+               TopicPermission tp = (TopicPermission) obj;
+               return (getActionsMask() == tp.getActionsMask()) && 
getName().equals(tp.getName());
+       }
+
+       /**
+        * Returns the hash code value for this object.
+        * 
+        * @return A hash code value for this object.
+        */
+       @Override
+       public int hashCode() {
+               int h = 31 * 17 + getName().hashCode();
+               h = 31 * h + getActions().hashCode();
+               return h;
+       }
+
+       /**
+        * WriteObject is called to save the state of this permission object to 
a
+        * stream. The actions are serialized, and the superclass takes care of 
the
+        * name.
+        */
+       private synchronized void writeObject(java.io.ObjectOutputStream s) 
throws IOException {
+               // Write out the actions. The superclass takes care of the name
+               // call getActions to make sure actions field is initialized
+               if (actions == null)
+                       getActions();
+               s.defaultWriteObject();
+       }
+
+       /**
+        * readObject is called to restore the state of this permission from a
+        * stream.
+        */
+       private synchronized void readObject(java.io.ObjectInputStream s) 
throws IOException, ClassNotFoundException {
+               // Read in the action, then initialize the rest
+               s.defaultReadObject();
+               setTransients(parseActions(actions));
+       }
+}
+
+/**
+ * Stores a set of {@code TopicPermission} permissions.
+ * 
+ * @see java.security.Permission
+ * @see java.security.Permissions
+ * @see java.security.PermissionCollection
+ */
+final class TopicPermissionCollection extends PermissionCollection {
+       static final long                                                       
        serialVersionUID        = -614647783533924048L;
+       /**
+        * Table of permissions.
+        * 
+        * @GuardedBy this
+        */
+       private transient Map<String, TopicPermission>  permissions;
+       /**
+        * Boolean saying if "*" is in the collection.
+        * 
+        * @serial
+        * @GuardedBy this
+        */
+       private boolean                                                         
        all_allowed;
+
+       /**
+        * Create an empty TopicPermissions object.
+        * 
+        */
+       public TopicPermissionCollection() {
+               permissions = new HashMap<String, TopicPermission>();
+               all_allowed = false;
+       }
+
+       /**
+        * Adds a permission to the {@code TopicPermission} objects. The key 
for the
+        * hash is the name.
+        * 
+        * @param permission The {@code TopicPermission} object to add.
+        * 
+        * @throws IllegalArgumentException If the permission is not a
+        *         {@code TopicPermission} instance.
+        * 
+        * @throws SecurityException If this {@code TopicPermissionCollection}
+        *         object has been marked read-only.
+        */
+       @Override
+       public void add(final Permission permission) {
+               if (!(permission instanceof TopicPermission)) {
+                       throw new IllegalArgumentException("invalid permission: 
" + permission);
+               }
+               if (isReadOnly()) {
+                       throw new SecurityException("attempt to add a 
Permission to a " + "readonly PermissionCollection");
+               }
+               final TopicPermission tp = (TopicPermission) permission;
+               final String name = tp.getName();
+               final int newMask = tp.getActionsMask();
+
+               synchronized (this) {
+                       final TopicPermission existing = permissions.get(name);
+                       if (existing != null) {
+                               final int oldMask = existing.getActionsMask();
+                               if (oldMask != newMask) {
+                                       permissions.put(name, new 
TopicPermission(name, oldMask | newMask));
+                               }
+                       } else {
+                               permissions.put(name, tp);
+                       }
+                       if (!all_allowed) {
+                               if (name.equals("*"))
+                                       all_allowed = true;
+                       }
+               }
+       }
+
+       /**
+        * Determines if the specified permissions implies the permissions 
expressed
+        * in {@code permission}.
+        * 
+        * @param permission The Permission object to compare with this
+        *        {@code TopicPermission} object.
+        * 
+        * @return {@code true} if {@code permission} is a proper subset of a
+        *         permission in the set; {@code false} otherwise.
+        */
+       @Override
+       public boolean implies(final Permission permission) {
+               if (!(permission instanceof TopicPermission)) {
+                       return false;
+               }
+               final TopicPermission requested = (TopicPermission) permission;
+               String name = requested.getName();
+               final int desired = requested.getActionsMask();
+               int effective = 0;
+
+               TopicPermission x;
+               // short circuit if the "*" Permission was added
+               synchronized (this) {
+                       if (all_allowed) {
+                               x = permissions.get("*");
+                               if (x != null) {
+                                       effective |= x.getActionsMask();
+                                       if ((effective & desired) == desired) {
+                                               return true;
+                                       }
+                               }
+                       }
+                       x = permissions.get(name);
+               }
+               // strategy:
+               // Check for full match first. Then work our way up the
+               // name looking for matches on a/b/*
+               if (x != null) {
+                       // we have a direct hit!
+                       effective |= x.getActionsMask();
+                       if ((effective & desired) == desired) {
+                               return true;
+                       }
+               }
+               // work our way up the tree...
+               int last;
+               int offset = name.length() - 1;
+               while ((last = name.lastIndexOf('/', offset)) != -1) {
+                       name = name.substring(0, last + 1) + "*";
+                       synchronized (this) {
+                               x = permissions.get(name);
+                       }
+                       if (x != null) {
+                               effective |= x.getActionsMask();
+                               if ((effective & desired) == desired) {
+                                       return true;
+                               }
+                       }
+                       offset = last - 1;
+               }
+               // we don't have to check for "*" as it was already checked
+               // at the top (all_allowed), so we just return false
+               return false;
+       }
+
+       /**
+        * Returns an enumeration of all {@code TopicPermission} objects in the
+        * container.
+        * 
+        * @return Enumeration of all {@code TopicPermission} objects.
+        */
+       @Override
+       public synchronized Enumeration<Permission> elements() {
+               List<Permission> all = new 
ArrayList<Permission>(permissions.values());
+               return Collections.enumeration(all);
+       }
+
+       /* serialization logic */
+       private static final ObjectStreamField[]        serialPersistentFields  
= {new ObjectStreamField("permissions", Hashtable.class), new 
ObjectStreamField("all_allowed", Boolean.TYPE)};
+
+       private synchronized void writeObject(ObjectOutputStream out) throws 
IOException {
+               Hashtable<String, TopicPermission> hashtable = new 
Hashtable<String, TopicPermission>(permissions);
+               ObjectOutputStream.PutField pfields = out.putFields();
+               pfields.put("permissions", hashtable);
+               pfields.put("all_allowed", all_allowed);
+               out.writeFields();
+       }
+
+       private synchronized void readObject(java.io.ObjectInputStream in) 
throws IOException, ClassNotFoundException {
+               ObjectInputStream.GetField gfields = in.readFields();
+               @SuppressWarnings("unchecked")
+               Hashtable<String, TopicPermission> hashtable = 
(Hashtable<String, TopicPermission>) gfields.get("permissions", null);
+               permissions = new HashMap<String, TopicPermission>(hashtable);
+               all_allowed = gfields.get("all_allowed", false);
+       }
+}
diff --git 
a/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/TypedEventBus.java
 
b/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/TypedEventBus.java
new file mode 100644
index 0000000..a73d508
--- /dev/null
+++ 
b/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/TypedEventBus.java
@@ -0,0 +1,114 @@
+/*******************************************************************************
+ * Copyright (c) Contributors to the Eclipse Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0 
+ 
*******************************************************************************/
+
+package org.osgi.service.typedevent;
+
+import java.util.Map;
+
+import org.osgi.annotation.versioning.ProviderType;
+
+/**
+ * The Typed Event service. Bundles wishing to publish events must obtain
+ * this service and call one of the event delivery methods.
+ * 
+ * @ThreadSafe
+ * @author $Id: cace0c5ed2b2e0d6abdf96f4a30e24b9c1610eed $
+ */
+@ProviderType
+public interface TypedEventBus {
+       /**
+        * Initiate asynchronous, ordered delivery of an event. This method 
returns
+        * to the caller before delivery of the event is completed. Events are
+        * delivered in the order that they are received by this method.
+        * <p>
+        * The topic for this event will be automatically set to the fully 
qualified
+        * type name for the supplied event object.
+        * <p>
+        * Logically equivalent to calling
+        * {@code deliver(event.getClass().getName().replace('.', '/'), event)}
+        * 
+        * @param event The event to send to all listeners which subscribe to 
the
+        *            topic of the event.
+        * @throws NullPointerException if the event object is null
+        */
+       void deliver(Object event);
+
+       /**
+        * Initiate asynchronous, ordered delivery of an event. This method 
returns
+        * to the caller before delivery of the event is completed. Events are
+        * delivered in the order that they are received by this method.
+        * 
+        * @param topic The topic to which this event should be sent.
+        * @param event The event to send to all listeners which subscribe to 
the
+        *            topic.
+        * @throws NullPointerException if the event object is null
+        * @throws IllegalArgumentException if the topic name is not valid
+        */
+       void deliver(String topic, Object event);
+
+       /**
+        * Initiate asynchronous, ordered delivery of event data. This method
+        * returns to the caller before delivery of the event is completed. 
Events
+        * are delivered in the order that they are received by this method.
+        * 
+        * @param topic The topic to which this event should be sent.
+        * @param event A Map representation of the event data to send to all
+        *            listeners which subscribe to the topic.
+        * @throws NullPointerException if the event map is null
+        * @throws IllegalArgumentException if the topic name is not valid
+        */
+       void deliverUntyped(String topic, Map<String, ? > event);
+
+       /**
+        * Creates a {@link TypedEventPublisher} for the topic automatically
+        * generated from the passed in event type.
+        * 
+        * @param <T> The type of events to be sent by the
+        *            {@link TypedEventPublisher}
+        * @param eventType The type of events to be sent by the
+        *            {@link TypedEventPublisher}
+        * @return A {@link TypedEventPublisher} that will publish events to the
+        *         topic name automatically generated from {@code eventType}
+        */
+       <T> TypedEventPublisher<T> createPublisher(Class<T> eventType);
+
+       /**
+        * Creates a {@link TypedEventPublisher} for the supplied topic and 
event
+        * type
+        * 
+        * @param <T> The type of events to be sent by the
+        *            {@link TypedEventPublisher}
+        * @param topic The topic to publish events to
+        * @param eventType The type of events to be sent by the
+        *            {@link TypedEventPublisher}
+        * @return A {@link TypedEventPublisher} that will publish events to the
+        *         supplied topic
+        */
+       <T> TypedEventPublisher<T> createPublisher(String topic,
+                       Class<T> eventType);
+
+       /**
+        * Creates a {@link TypedEventPublisher} for the supplied topic
+        * 
+        * @param topic The topic to publish events to
+        * @return A {@link TypedEventPublisher} that will publish events to the
+        *         supplied topic
+        */
+       TypedEventPublisher<Object> createPublisher(String topic);
+
+}
diff --git 
a/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/TypedEventConstants.java
 
b/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/TypedEventConstants.java
new file mode 100644
index 0000000..fcf7fe6
--- /dev/null
+++ 
b/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/TypedEventConstants.java
@@ -0,0 +1,94 @@
+/*******************************************************************************
+ * Copyright (c) Contributors to the Eclipse Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0 
+ 
*******************************************************************************/
+
+package org.osgi.service.typedevent;
+
+import org.osgi.annotation.versioning.ProviderType;
+
+/**
+ * Defines standard names for Typed Event properties.
+ * 
+ * @author $Id: b3c3bb7f79af344b6e1f60f13373feaec5d54bd4 $
+ */
+@ProviderType
+public final class TypedEventConstants {
+
+       /**
+        * The name of the service property used to indicate the type of the 
event
+        * objects received by a {@link TypedEventHandler} service.
+        * <p>
+        * If this service property is not present then the reified type 
parameter
+        * from the TypedEventHandler implementation class will be used.
+        */
+       public static final String      TYPED_EVENT_TYPE                        
                = "event.type";
+
+       /**
+        * The name of the service property used to indicate the topic(s) to 
which
+        * an a {@link TypedEventHandler} or {@link UntypedEventHandler} 
service is
+        * listening.
+        * <p>
+        * If this service property is not present then the reified type 
parameter
+        * from the TypedEventHandler implementation class will be used to 
determine
+        * the topic.
+        */
+       public static final String      TYPED_EVENT_TOPICS                      
                = "event.topics";
+
+       /**
+        * The name of the service property used to indicate a filter that 
should be
+        * applied to events from the {@link #TYPED_EVENT_TOPICS}. Only events 
which
+        * match the filter will be delivered to the Event Handler service.
+        * <p>
+        * If this service property is not present then all events from the 
topic(s)
+        * will be delivered to the Event Handler service.
+        */
+       public static final String      TYPED_EVENT_FILTER                      
                = "event.filter";
+
+       /**
+        * The name of the service property used to indicate that an event 
handler
+        * would like to receive one or more historical events matching its
+        * {@link #TYPED_EVENT_TOPICS} and {@link #TYPED_EVENT_FILTER} before
+        * receiving any new data. The value of this property is an {@link 
Integer}
+        * greater than or equal to zero.
+        * <p>
+        * If this property is set then when the event hander is discovered by 
the
+        * whiteboard the event handler will deliver, in order, up to the 
requested
+        * number of historical events. This will occur before the delivery of 
any
+        * new events. If no history is available then zero events will be
+        * delivered. If insufficient history is available then fewer events 
than
+        * requested will be delivered.
+        */
+       public static final String      TYPED_EVENT_HISTORY                     
                = "event.history";
+
+       /**
+        * The name of the implementation capability for the Typed Event
+        * specification
+        */
+       public static final String      TYPED_EVENT_IMPLEMENTATION              
        = "osgi.typedevent";
+
+       /**
+        * The version of the implementation capability for the Typed Event
+        * specification
+        */
+       public static final String      TYPED_EVENT_SPECIFICATION_VERSION       
= "1.1";
+
+       /**
+        * Private constructor to prevent instantiation
+        */
+       private TypedEventConstants() {
+       }
+}
diff --git 
a/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/TypedEventHandler.java
 
b/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/TypedEventHandler.java
new file mode 100644
index 0000000..63b5e6e
--- /dev/null
+++ 
b/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/TypedEventHandler.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (c) Contributors to the Eclipse Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0 
+ 
*******************************************************************************/
+
+package org.osgi.service.typedevent;
+
+import org.osgi.annotation.versioning.ConsumerType;
+
+/**
+ * Listener for Typed Events.
+ * <p>
+ * {@code TypedEventHandler} objects are registered with the Framework service
+ * registry and are notified with an event object when an event is sent.
+ * <p>
+ * {@code TypedEventHandler} objects are expected to reify the type parameter
+ * {@code T} with the type of object they wish to receive when implementing 
this
+ * interface. This type can be overridden using the
+ * {@link TypedEventConstants#TYPED_EVENT_TOPICS} service property.
+ * <p>
+ * {@code TypedEventHandler} objects may be registered with a service property
+ * {@link TypedEventConstants#TYPED_EVENT_TOPICS} whose value is the list of
+ * topics in which the event handler is interested.
+ * <p>
+ * For example:
+ * 
+ * <pre>
+ * String[] topics = new String[] {
+ *             &quot;com/isv/*&quot;
+ * };
+ * Hashtable ht = new Hashtable();
+ * ht.put(EventConstants.TYPE_SAFE_EVENT_TOPICS, topics);
+ * context.registerService(TypedEventHandler.class, this, ht);
+ * </pre>
+ * 
+ * @ThreadSafe
+ * @author $Id: 1ef1b856280d23975dcb3d2d2c5046eb82cdb6fc $
+ * @param <T> The type of the event to be received
+ */
+@ConsumerType
+public interface TypedEventHandler<T> {
+       /**
+        * Called by the {@link TypedEventBus} service to notify the listener 
of an
+        * event.
+        * 
+        * @param topic The topic to which the event was sent
+        * @param event The event that occurred.
+        */
+       void notify(String topic, T event);
+}
diff --git 
a/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/TypedEventPublisher.java
 
b/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/TypedEventPublisher.java
new file mode 100644
index 0000000..f7c7b90
--- /dev/null
+++ 
b/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/TypedEventPublisher.java
@@ -0,0 +1,94 @@
+/*******************************************************************************
+ * Copyright (c) Contributors to the Eclipse Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0 
+ 
*******************************************************************************/
+
+package org.osgi.service.typedevent;
+
+import java.util.Map;
+
+import org.osgi.annotation.versioning.ProviderType;
+
+/**
+ * A Typed Event publisher for a single topic. Bundles wishing to publish 
events
+ * may obtain this object from the {@link TypedEventBus}.
+ * <p>
+ * All events published by this publisher are sent to the same topic, as
+ * returned by {@link #getTopic()}.
+ * <p>
+ * This object should not be shared as it will not re-validate the caller's
+ * permission to send to the target topic.
+ * 
+ * @ThreadSafe
+ * @author $Id: cace0c5ed2b2e0d6abdf96f4a30e24b9c1610eed $
+ * @param <T> The type of events that may be sent using this publisher
+ */
+@ProviderType
+public interface TypedEventPublisher<T> extends AutoCloseable {
+       /**
+        * Initiate asynchronous, ordered delivery of an event. This method 
returns
+        * to the caller before delivery of the event is completed. Events are
+        * delivered in the order that they are received by this method.
+        * 
+        * @param event The event to send to all listeners which subscribe to 
the
+        *            topic of the event.
+        * @throws NullPointerException if the event object is null
+        * @throws IllegalStateException if the {@link TypedEventPublisher} has 
been
+        *             closed
+        */
+       void deliver(T event);
+
+       /**
+        * Initiate asynchronous, ordered delivery of event data. This method
+        * returns to the caller before delivery of the event is completed. 
Events
+        * are delivered in the order that they are received by this method.
+        * 
+        * @param event A Map representation of the event data to send to all
+        *            listeners which subscribe to the topic.
+        * @throws NullPointerException if the event map is null
+        * @throws IllegalStateException if the {@link TypedEventPublisher} has 
been
+        *             closed
+        */
+       void deliverUntyped(Map<String, ? > event);
+
+       /**
+        * Get the topic for this {@link TypedEventPublisher}. This topic is set
+        * when the {@link TypedEventPublisher} is created and cannot be 
changed.
+        * 
+        * @return The topic for this {@link TypedEventPublisher}
+        */
+       String getTopic();
+
+       /**
+        * Closes this {@link TypedEventPublisher} so that no further events 
can be
+        * sent. After closure all delivery methods throw
+        * {@link IllegalStateException}.
+        * <p>
+        * Calling {@link #close()} on a closed {@link TypedEventPublisher} has 
no
+        * effect.
+        */
+       @Override
+       void close();
+
+       /**
+        * This method allows the caller to check whether the
+        * {@link TypedEventPublisher} has been closed.
+        * 
+        * @return <code>false</code> if the {@link TypedEventPublisher} has 
been
+        *         closed, <code>true</code> otherwise.
+        */
+       boolean isOpen();
+}
diff --git 
a/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/UnhandledEventHandler.java
 
b/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/UnhandledEventHandler.java
new file mode 100644
index 0000000..ddba2ca
--- /dev/null
+++ 
b/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/UnhandledEventHandler.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) Contributors to the Eclipse Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0 
+ 
*******************************************************************************/
+
+package org.osgi.service.typedevent;
+
+import java.util.Map;
+
+import org.osgi.annotation.versioning.ConsumerType;
+
+/**
+ * Listener for Unhandled Events.
+ * <p>
+ * {@code UnhandledEventHandler} objects are registered with the Framework
+ * service registry and are notified with an event object when an event is 
sent,
+ * but no other handler is found to receive the event
+ * 
+ * @ThreadSafe
+ * @author $Id: c6f3ac2430c0caf881b78ffbfdb983331727a9f4 $
+ */
+@ConsumerType
+public interface UnhandledEventHandler {
+       /**
+        * Called by the {@link TypedEventBus} service to notify the listener of
+        * an unhandled event.
+        * 
+        * @param topic The topic to which the event was sent
+        * @param event The event that occurred.
+        */
+       void notifyUnhandled(String topic, Map<String,Object> event);
+}
diff --git 
a/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/UntypedEventHandler.java
 
b/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/UntypedEventHandler.java
new file mode 100644
index 0000000..fbdfac5
--- /dev/null
+++ 
b/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/UntypedEventHandler.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright (c) Contributors to the Eclipse Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0 
+ 
*******************************************************************************/
+
+package org.osgi.service.typedevent;
+
+import java.util.Map;
+
+import org.osgi.annotation.versioning.ConsumerType;
+
+/**
+ * Listener for Untyped Events.
+ * <p>
+ * {@code UntypedEventHandler} objects are registered with the Framework 
service
+ * registry and are notified with an event object when an event is sent.
+ * <p>
+ * {@code UntypedEventHandler} objects must be registered with a service
+ * property {@link TypedEventConstants#TYPED_EVENT_TOPICS} whose value is the
+ * list of topics in which the event handler is interested.
+ * <p>
+ * For example:
+ * 
+ * <pre>
+ * String[] topics = new String[] {
+ *             &quot;com/isv/*&quot;
+ * };
+ * Hashtable ht = new Hashtable();
+ * ht.put(EventConstants.TYPE_SAFE_EVENT_TOPICS, topics);
+ * context.registerService(UntypedEventHandler.class, this, ht);
+ * </pre>
+ * 
+ * @ThreadSafe
+ * @author $Id: 24d2143a364d9f4d7d1b7e17d743d3c1a10b63a9 $
+ */
+@ConsumerType
+public interface UntypedEventHandler {
+       /**
+        * Called by the {@link TypedEventBus} service to notify the listener 
of an
+        * event.
+        * 
+        * @param topic The topic to which the event was sent
+        * @param event The event that occurred.
+        */
+       void notifyUntyped(String topic, Map<String,Object> event);
+}
diff --git 
a/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/annotations/RequireTypedEvent.java
 
b/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/annotations/RequireTypedEvent.java
new file mode 100644
index 0000000..e90e16f
--- /dev/null
+++ 
b/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/annotations/RequireTypedEvent.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) Contributors to the Eclipse Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0 
+ 
*******************************************************************************/
+
+package org.osgi.service.typedevent.annotations;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.osgi.annotation.bundle.Requirement;
+import org.osgi.namespace.implementation.ImplementationNamespace;
+import org.osgi.service.typedevent.TypedEventConstants;
+
+/**
+ * This annotation can be used to require the Typed Event implementation. It 
can
+ * be used directly, or as a meta-annotation.
+ * <p>
+ * This annotation is applied to several of the Typed Event component property
+ * type annotations meaning that it does not normally need to be applied to
+ * Declarative Services components which use the Typed Event specification.
+ * 
+ * @author $Id: 5919b947393ff3b07a0e8cd1dc881dcf4637e6b4 $
+ * @since 1.0
+ */
+@Documented
+@Retention(RetentionPolicy.CLASS)
+@Target({
+               ElementType.TYPE, ElementType.PACKAGE
+})
+@Requirement(namespace = ImplementationNamespace.IMPLEMENTATION_NAMESPACE, //
+               name = TypedEventConstants.TYPED_EVENT_IMPLEMENTATION, //
+               version = TypedEventConstants.TYPED_EVENT_SPECIFICATION_VERSION)
+public @interface RequireTypedEvent {
+       // This is a marker annotation.
+}
diff --git 
a/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/annotations/package-info.java
 
b/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/annotations/package-info.java
new file mode 100644
index 0000000..fa94dbb
--- /dev/null
+++ 
b/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/annotations/package-info.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) Contributors to the Eclipse Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0 
+ 
*******************************************************************************/
+
+/**
+ * Typed Event Annotations Package Version 1.0.
+ * <p>
+ * This package contains annotations that can be used to require the Typed 
Event
+ * implementation.
+ * <p>
+ * Bundles should not normally need to import this package as the annotations
+ * are only used at build-time.
+ * 
+ * @author $Id: 627e9ee98bd7b640ebad077fccfbd6994c9af41e $
+ */
+
+@Export
+@Version(TYPED_EVENT_SPECIFICATION_VERSION)
+package org.osgi.service.typedevent.annotations;
+
+import static 
org.osgi.service.typedevent.TypedEventConstants.TYPED_EVENT_SPECIFICATION_VERSION;
+
+import org.osgi.annotation.bundle.Export;
+import org.osgi.annotation.versioning.Version;
+
diff --git 
a/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/monitor/MonitorEvent.java
 
b/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/monitor/MonitorEvent.java
new file mode 100644
index 0000000..71bea5d
--- /dev/null
+++ 
b/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/monitor/MonitorEvent.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) Contributors to the Eclipse Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0 
+ 
*******************************************************************************/
+package org.osgi.service.typedevent.monitor;
+
+import java.time.Instant;
+import java.util.Map;
+
+import org.osgi.annotation.versioning.ProviderType;
+
+/**
+ * A monitoring event.
+ */
+@ProviderType
+public class MonitorEvent {
+
+       /**
+        * The Event Topic
+        */
+       public String                           topic;
+       
+       /**
+        * The Data from the Event in Map form
+        */
+       public Map<String, Object> eventData;
+
+       /**
+        * The time at which the event was published
+        */
+       public Instant publicationTime;
+}
diff --git 
a/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/monitor/TypedEventMonitor.java
 
b/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/monitor/TypedEventMonitor.java
new file mode 100644
index 0000000..a366b24
--- /dev/null
+++ 
b/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/monitor/TypedEventMonitor.java
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * Copyright (c) Contributors to the Eclipse Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0 
+ 
*******************************************************************************/
+package org.osgi.service.typedevent.monitor;
+
+import java.time.Instant;
+
+import org.osgi.annotation.versioning.ProviderType;
+import org.osgi.util.pushstream.PushStream;
+
+/**
+ * The EventMonitor service can be used to monitor the events that are sent
+ * using the EventBus, and that are received from remote EventBus instances
+ * 
+ * @ThreadSafe
+ * @author $Id: 7f7a493225439de463d0ad550f4b6b206b54277c $
+ */
+@ProviderType
+public interface TypedEventMonitor {
+
+    /**
+        * Get a stream of events, starting now.
+        *
+        * @return A stream of event data
+        */
+       PushStream<MonitorEvent> monitorEvents();
+
+       /**
+        * Get a stream of events, including up to the requested number of
+        * historical data events.
+        *
+        * @param history The requested number of historical events, note that 
fewer
+        *            than this number of events may be returned if history is
+        *            unavailable, or if insufficient events have been sent.
+        * @return A stream of event data
+        */
+       PushStream<MonitorEvent> monitorEvents(int history);
+
+       /**
+        * Get a stream of events, including historical data events prior to the
+        * supplied time
+        *
+        * @param history The requested time after which historical events, 
should
+        *            be included. Note that events may have been discarded, or
+        *            history unavailable.
+        * @return A stream of event data
+        */
+       PushStream<MonitorEvent> monitorEvents(Instant history);
+
+}
diff --git 
a/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/monitor/package-info.java
 
b/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/monitor/package-info.java
new file mode 100644
index 0000000..0a46d1e
--- /dev/null
+++ 
b/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/monitor/package-info.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) Contributors to the Eclipse Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0 
+ 
*******************************************************************************/
+
+/**
+ * Typed Event Monitoring Package Version 1.0.
+ * <p>
+ * Bundles wishing to use this package must list the package in the
+ * Import-Package header of the bundle's manifest. This package has two types 
of
+ * users: the consumers that use the API in this package and the providers that
+ * implement the API in this package.
+ * <p>
+ * Example import for consumers using the API in this package:
+ * <p>
+ * {@code  Import-Package: org.osgi.service.typedevent.monitor; 
version="[1.0,2.0)"}
+ * <p>
+ * Example import for providers implementing the API in this package:
+ * <p>
+ * {@code  Import-Package: org.osgi.service.typedevent.monitor; 
version="[1.0,1.1)"}
+ * 
+ * @author $Id: 9e2a95c6b50c545e6b5148469c6e6c577df042b3 $
+ */
+
+@Export
+@Version(TYPED_EVENT_SPECIFICATION_VERSION)
+package org.osgi.service.typedevent.monitor;
+
+import static 
org.osgi.service.typedevent.TypedEventConstants.TYPED_EVENT_SPECIFICATION_VERSION;
+
+import org.osgi.annotation.bundle.Export;
+import org.osgi.annotation.versioning.Version;
diff --git 
a/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/package-info.java
 
b/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/package-info.java
new file mode 100644
index 0000000..b720bfa
--- /dev/null
+++ 
b/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/package-info.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) Contributors to the Eclipse Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0 
+ 
*******************************************************************************/
+
+/**
+ * Typed Event Package Version 1.0.
+ * <p>
+ * Bundles wishing to use this package must list the package in the
+ * Import-Package header of the bundle's manifest. This package has two types 
of
+ * users: the consumers that use the API in this package and the providers that
+ * implement the API in this package.
+ * <p>
+ * Example import for consumers using the API in this package:
+ * <p>
+ * {@code  Import-Package: org.osgi.service.typedevent; version="[1.0,2.0)"}
+ * <p>
+ * Example import for providers implementing the API in this package:
+ * <p>
+ * {@code  Import-Package: org.osgi.service.typedevent; version="[1.0,1.1)"}
+ * 
+ * @author $Id: 4931ddeaf6f300dbb0ef21877b73d676365e5ae5 $
+ */
+
+@Export
+@Version(TYPED_EVENT_SPECIFICATION_VERSION)
+package org.osgi.service.typedevent;
+
+import static 
org.osgi.service.typedevent.TypedEventConstants.TYPED_EVENT_SPECIFICATION_VERSION;
+
+import org.osgi.annotation.bundle.Export;
+import org.osgi.annotation.versioning.Version;
+
diff --git 
a/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/propertytypes/EventFilter.java
 
b/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/propertytypes/EventFilter.java
new file mode 100644
index 0000000..534e117
--- /dev/null
+++ 
b/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/propertytypes/EventFilter.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) Contributors to the Eclipse Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0 
+ 
*******************************************************************************/
+
+package org.osgi.service.typedevent.propertytypes;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.osgi.service.component.annotations.ComponentPropertyType;
+import org.osgi.service.typedevent.TypedEventConstants;
+import org.osgi.service.typedevent.TypedEventHandler;
+import org.osgi.service.typedevent.UntypedEventHandler;
+import org.osgi.service.typedevent.annotations.RequireTypedEvent;
+
+/**
+ * Component Property Type for the
+ * {@link TypedEventConstants#TYPED_EVENT_FILTER} service property of an Event
+ * Handler service.
+ * <p>
+ * This annotation can be used on an {@link TypedEventHandler} or
+ * {@link UntypedEventHandler} component to declare the value of the
+ * {@link TypedEventConstants#TYPED_EVENT_FILTER} service property.
+ * 
+ * @see "Component Property Types"
+ * @author $Id: 3c99b991160eff4d897ce5040a15a591597d5dce $
+ */
+@ComponentPropertyType
+@Retention(RetentionPolicy.CLASS)
+@Target(ElementType.TYPE)
+@RequireTypedEvent
+public @interface EventFilter {
+       /**
+        * Service property specifying the event filter for a
+        * {@link TypedEventHandler} or {@link UntypedEventHandler} service.
+        * 
+        * @return The event filter.
+        * @see TypedEventConstants#TYPED_EVENT_FILTER
+        */
+       String value();
+}
diff --git 
a/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/propertytypes/EventTopics.java
 
b/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/propertytypes/EventTopics.java
new file mode 100644
index 0000000..857e1d0
--- /dev/null
+++ 
b/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/propertytypes/EventTopics.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (c) Contributors to the Eclipse Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0 
+ 
*******************************************************************************/
+
+package org.osgi.service.typedevent.propertytypes;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.osgi.service.component.annotations.ComponentPropertyType;
+import org.osgi.service.typedevent.TypedEventConstants;
+import org.osgi.service.typedevent.TypedEventHandler;
+import org.osgi.service.typedevent.UntypedEventHandler;
+import org.osgi.service.typedevent.annotations.RequireTypedEvent;
+
+/**
+ * Component Property Type for the {@link 
TypedEventConstants#TYPED_EVENT_TOPICS}
+ * service property of a {@link TypedEventHandler} or
+ * {@link UntypedEventHandler} service.
+ * <p>
+ * This annotation can be used on a component to declare the values of the
+ * {@link TypedEventConstants#TYPED_EVENT_TOPICS} service property.
+ * 
+ * @see "Component Property Types"
+ * @author $Id: a82d95f6131235a5f94b7a778ea8e19ef968df41 $
+ */
+@ComponentPropertyType
+@Retention(RetentionPolicy.CLASS)
+@Target(ElementType.TYPE)
+@RequireTypedEvent
+public @interface EventTopics {
+       /**
+        * Service property specifying the {@code Event} topics of interest to 
an
+        * {@link TypedEventHandler} or {@link UntypedEventHandler} service.
+        * 
+        * @return The event topics.
+        * @see TypedEventConstants#TYPED_EVENT_TOPICS
+        */
+       String[] value();
+}
diff --git 
a/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/propertytypes/EventType.java
 
b/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/propertytypes/EventType.java
new file mode 100644
index 0000000..5be6da4
--- /dev/null
+++ 
b/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/propertytypes/EventType.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) Contributors to the Eclipse Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0 
+ 
*******************************************************************************/
+
+package org.osgi.service.typedevent.propertytypes;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.osgi.service.component.annotations.ComponentPropertyType;
+import org.osgi.service.typedevent.TypedEventConstants;
+import org.osgi.service.typedevent.TypedEventHandler;
+import org.osgi.service.typedevent.annotations.RequireTypedEvent;
+
+/**
+ * Component Property Type for the {@link TypedEventConstants#TYPED_EVENT_TYPE}
+ * service property of an {@link TypedEventHandler} service.
+ * <p>
+ * This annotation can be used on an {@link TypedEventHandler} component to
+ * declare the value of the {@link TypedEventConstants#TYPED_EVENT_TYPE} 
service
+ * property.
+ * 
+ * @see "Component Property Types"
+ * @author $Id: 3799448fcf60ec8a125bf857b2b7da23d9f45570 $
+ */
+@ComponentPropertyType
+@Retention(RetentionPolicy.CLASS)
+@Target(ElementType.TYPE)
+@RequireTypedEvent
+public @interface EventType {
+       /**
+        * Service property specifying the {@code EventType} for a
+        * {@link TypedEventHandler} service.
+        * 
+        * @return The event filter.
+        * @see TypedEventConstants#TYPED_EVENT_TYPE
+        */
+       Class<?> value();
+}
diff --git 
a/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/propertytypes/package-info.java
 
b/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/propertytypes/package-info.java
new file mode 100644
index 0000000..e937468
--- /dev/null
+++ 
b/org.apache.aries.typedevent.bus/src/main/java/org/osgi/service/typedevent/propertytypes/package-info.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) Contributors to the Eclipse Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0 
+ 
*******************************************************************************/
+
+/**
+ * Typed Event Component Property Types Package Version 1.0.
+ * <p>
+ * When used as annotations, component property types are processed by tools to
+ * generate Component Descriptions which are used at runtime.
+ * <p>
+ * Bundles wishing to use this package at runtime must list the package in the
+ * Import-Package header of the bundle's manifest.
+ * <p>
+ * Example import for consumers using the API in this package:
+ * <p>
+ * {@code  Import-Package: org.osgi.service.typedevent.propertytypes; 
version="[1.0,2.0)"}
+ * 
+ * @author $Id: 75ea41c54d3a9602dfaf4e2d31e0019cef207c0f $
+ */
+
+@Export
+@Version(TYPED_EVENT_SPECIFICATION_VERSION)
+package org.osgi.service.typedevent.propertytypes;
+
+import static 
org.osgi.service.typedevent.TypedEventConstants.TYPED_EVENT_SPECIFICATION_VERSION;
+
+import org.osgi.annotation.bundle.Export;
+import org.osgi.annotation.versioning.Version;
+
diff --git 
a/org.apache.aries.typedevent.bus/src/test/java/org/apache/aries/typedevent/bus/impl/TypedEventBusImplTest.java
 
b/org.apache.aries.typedevent.bus/src/test/java/org/apache/aries/typedevent/bus/impl/TypedEventBusImplTest.java
index 017e1be..749a149 100644
--- 
a/org.apache.aries.typedevent.bus/src/test/java/org/apache/aries/typedevent/bus/impl/TypedEventBusImplTest.java
+++ 
b/org.apache.aries.typedevent.bus/src/test/java/org/apache/aries/typedevent/bus/impl/TypedEventBusImplTest.java
@@ -18,9 +18,11 @@
 package org.apache.aries.typedevent.bus.impl;
 
 import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mock.Strictness.LENIENT;
 import static org.osgi.framework.Constants.SERVICE_ID;
 import static 
org.osgi.service.typedevent.TypedEventConstants.TYPED_EVENT_FILTER;
 import static 
org.osgi.service.typedevent.TypedEventConstants.TYPED_EVENT_TOPICS;
@@ -35,16 +37,19 @@ import java.util.concurrent.TimeUnit;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.ArgumentMatcher;
 import org.mockito.Mock;
 import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
+import org.mockito.junit.jupiter.MockitoExtension;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.Constants;
 import org.osgi.service.typedevent.TypedEventHandler;
+import org.osgi.service.typedevent.TypedEventPublisher;
 import org.osgi.service.typedevent.UnhandledEventHandler;
 import org.osgi.service.typedevent.UntypedEventHandler;
 
+@ExtendWith(MockitoExtension.class)
 public class TypedEventBusImplTest {
 
     private static final String SPECIAL_TEST_EVENT_TOPIC = 
SpecialTestEvent.class.getName().replace(".", "/");
@@ -65,16 +70,16 @@ public class TypedEventBusImplTest {
         
     }
 
-    @Mock(lenient = true)
+    @Mock(strictness = LENIENT)
     Bundle registeringBundle;
 
-    @Mock(lenient = true)
+    @Mock(strictness = LENIENT)
     TypedEventHandler<Object> handlerA, handlerB;
 
-    @Mock(lenient = true)
+    @Mock(strictness = LENIENT)
     UntypedEventHandler untypedHandlerA, untypedHandlerB;
 
-    @Mock(lenient = true)
+    @Mock(strictness = LENIENT)
     UnhandledEventHandler unhandledHandler;
 
     Semaphore semA = new Semaphore(0), semB = new Semaphore(0), untypedSemA = 
new Semaphore(0),
@@ -83,13 +88,9 @@ public class TypedEventBusImplTest {
     TypedEventBusImpl impl;
     TypedEventMonitorImpl monitorImpl;
 
-    private AutoCloseable mocks;
-
     @BeforeEach
     public void start() throws ClassNotFoundException {
 
-        mocks = MockitoAnnotations.openMocks(this);
-        
         Mockito.doAnswer(i -> 
TestEvent.class.getClassLoader().loadClass(i.getArgument(0, String.class)))
                .when(registeringBundle).loadClass(Mockito.anyString());
         
@@ -128,7 +129,6 @@ public class TypedEventBusImplTest {
     public void stop() throws Exception {
         impl.stop();
         monitorImpl.destroy();
-        mocks.close();
     }
 
     /**
@@ -550,6 +550,91 @@ public class TypedEventBusImplTest {
         assertFalse(semA.tryAcquire(1, TimeUnit.SECONDS));
 
     }
+    
+    /**
+     * Tests that events are delivered correctly using a publisher
+     * 
+     * @throws InterruptedException
+     */
+    @Test
+    public void testEventPublisher() throws InterruptedException {
+
+        TestEvent event = new TestEvent();
+        event.message = "boo";
+
+        Map<String, Object> serviceProperties = new HashMap<>();
+
+        serviceProperties.put(TYPED_EVENT_TOPICS, TEST_EVENT_TOPIC);
+        serviceProperties.put(TYPED_EVENT_TYPE, TestEvent.class.getName());
+        serviceProperties.put(SERVICE_ID, 42L);
+
+        impl.addTypedEventHandler(registeringBundle, handlerA, 
serviceProperties);
+
+        serviceProperties = new HashMap<>();
+
+        serviceProperties.put(TYPED_EVENT_TOPICS, 
TestEvent2.class.getName().replace(".", "/"));
+        serviceProperties.put(TYPED_EVENT_TYPE, TestEvent2.class.getName());
+        serviceProperties.put(SERVICE_ID, 43L);
+
+        impl.addTypedEventHandler(registeringBundle, handlerB, 
serviceProperties);
+
+        serviceProperties = new HashMap<>();
+
+        serviceProperties.put(TYPED_EVENT_TOPICS, TEST_EVENT_TOPIC);
+        serviceProperties.put(SERVICE_ID, 44L);
+
+        impl.addUntypedEventHandler(untypedHandlerA, serviceProperties);
+
+        serviceProperties = new HashMap<>();
+
+        serviceProperties.put(TYPED_EVENT_TOPICS, 
TestEvent2.class.getName().replace(".", "/"));
+        serviceProperties.put(SERVICE_ID, 45L);
+
+        impl.addUntypedEventHandler(untypedHandlerB, serviceProperties);
+
+        TypedEventPublisher<TestEvent> publisher = 
impl.createPublisher(TestEvent.class);
+        
+        publisher.deliver(event);
+
+        assertTrue(semA.tryAcquire(1, TimeUnit.SECONDS));
+
+        
Mockito.verify(handlerA).notify(Mockito.eq(TestEvent.class.getName().replace('.',
 '/')),
+                Mockito.argThat(isTestEventWithMessage("boo")));
+
+        assertFalse(semB.tryAcquire(1, TimeUnit.SECONDS));
+
+        assertTrue(untypedSemA.tryAcquire(1, TimeUnit.SECONDS));
+
+        
Mockito.verify(untypedHandlerA).notifyUntyped(Mockito.eq(TestEvent.class.getName().replace('.',
 '/')),
+                Mockito.argThat(isUntypedTestEventWithMessage("boo")));
+
+        assertFalse(untypedSemB.tryAcquire(1, TimeUnit.SECONDS));
+        
+        
+        Map<String, Object> eventMap = Map.of("message", "far");
+        publisher.deliverUntyped(eventMap);
+
+        assertTrue(semA.tryAcquire(1, TimeUnit.SECONDS));
+
+        
Mockito.verify(handlerA).notify(Mockito.eq(TestEvent.class.getName().replace('.',
 '/')),
+                Mockito.argThat(isTestEventWithMessage("far")));
+
+        assertFalse(semB.tryAcquire(1, TimeUnit.SECONDS));
+
+        assertTrue(untypedSemA.tryAcquire(1, TimeUnit.SECONDS));
+
+        
Mockito.verify(untypedHandlerA).notifyUntyped(Mockito.eq(TestEvent.class.getName().replace('.',
 '/')),
+                Mockito.argThat(isUntypedTestEventWithMessage("far")));
+
+        assertFalse(untypedSemB.tryAcquire(1, TimeUnit.SECONDS));        
+        
+        assertTrue(publisher.isOpen());
+        publisher.close();
+        assertFalse(publisher.isOpen());
+        
+        assertThrows(IllegalStateException.class, () -> 
publisher.deliver(event));
+        assertThrows(IllegalStateException.class, () -> 
publisher.deliverUntyped(eventMap));
+    }
 
     ArgumentMatcher<TestEvent> isTestEventWithMessage(String message) {
         return new ArgumentMatcher<TestEvent>() {
diff --git 
a/org.apache.aries.typedevent.bus/src/test/java/org/apache/aries/typedevent/bus/osgi/EventDeliveryIntegrationTest.java
 
b/org.apache.aries.typedevent.bus/src/test/java/org/apache/aries/typedevent/bus/osgi/EventDeliveryIntegrationTest.java
index 40543fa..d435b7a 100644
--- 
a/org.apache.aries.typedevent.bus/src/test/java/org/apache/aries/typedevent/bus/osgi/EventDeliveryIntegrationTest.java
+++ 
b/org.apache.aries.typedevent.bus/src/test/java/org/apache/aries/typedevent/bus/osgi/EventDeliveryIntegrationTest.java
@@ -29,14 +29,12 @@ import org.apache.aries.typedevent.bus.common.TestEvent2;
 import org.apache.aries.typedevent.bus.common.TestEvent2.EventType;
 import org.apache.aries.typedevent.bus.common.TestEvent2Consumer;
 import org.apache.aries.typedevent.bus.common.TestEventConsumer;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
+import org.mockito.junit.jupiter.MockitoExtension;
 import org.osgi.framework.BundleContext;
 import org.osgi.service.typedevent.TypedEventBus;
 import org.osgi.service.typedevent.TypedEventConstants;
@@ -56,6 +54,7 @@ import org.osgi.test.junit5.service.ServiceExtension;
  */
 @ExtendWith(BundleContextExtension.class)
 @ExtendWith(ServiceExtension.class)
+@ExtendWith(MockitoExtension.class)
 public class EventDeliveryIntegrationTest extends AbstractIntegrationTest {
     
     @InjectBundleContext
@@ -72,18 +71,6 @@ public class EventDeliveryIntegrationTest extends 
AbstractIntegrationTest {
 
     @Mock
     UntypedEventHandler untypedEventHandler, untypedEventHandler2;
-
-    private AutoCloseable mocks;
-    
-    @BeforeEach
-    public void setupMocks() {
-        mocks = MockitoAnnotations.openMocks(this);
-    }
-    
-    @AfterEach
-    public void stop() throws Exception {
-        mocks.close();
-    }
     
     /**
      * Tests that events are delivered to untyped Event Handlers
diff --git 
a/org.apache.aries.typedevent.bus/src/test/java/org/apache/aries/typedevent/bus/osgi/FilterIntegrationTest.java
 
b/org.apache.aries.typedevent.bus/src/test/java/org/apache/aries/typedevent/bus/osgi/FilterIntegrationTest.java
index 2d17847..67e5066 100644
--- 
a/org.apache.aries.typedevent.bus/src/test/java/org/apache/aries/typedevent/bus/osgi/FilterIntegrationTest.java
+++ 
b/org.apache.aries.typedevent.bus/src/test/java/org/apache/aries/typedevent/bus/osgi/FilterIntegrationTest.java
@@ -23,13 +23,11 @@ import java.util.Hashtable;
 
 import org.apache.aries.typedevent.bus.common.TestEvent;
 import org.apache.aries.typedevent.bus.common.TestEventConsumer;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.Mock;
 import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
+import org.mockito.junit.jupiter.MockitoExtension;
 import org.osgi.framework.BundleContext;
 import org.osgi.service.typedevent.TypedEventBus;
 import org.osgi.service.typedevent.TypedEventHandler;
@@ -47,6 +45,7 @@ import org.osgi.test.junit5.service.ServiceExtension;
  */
 @ExtendWith(BundleContextExtension.class)
 @ExtendWith(ServiceExtension.class)
+@ExtendWith(MockitoExtension.class)
 public class FilterIntegrationTest extends AbstractIntegrationTest {
     
     @InjectBundleContext
@@ -58,18 +57,6 @@ public class FilterIntegrationTest extends 
AbstractIntegrationTest {
     @Mock
     TestEventConsumer typedEventHandler, typedEventHandlerB;
 
-    private AutoCloseable mocks;
-    
-    @BeforeEach
-    public void setupMocks() {
-        mocks = MockitoAnnotations.openMocks(this);
-    }
-    
-    @AfterEach
-    public void stop() throws Exception {
-        mocks.close();
-    }
-    
     @Test
     public void testFilteredListener() throws Exception {
         Dictionary<String, Object> props = new Hashtable<>();
diff --git 
a/org.apache.aries.typedevent.bus/src/test/java/org/apache/aries/typedevent/bus/osgi/TypedEventMonitorIntegrationTest.java
 
b/org.apache.aries.typedevent.bus/src/test/java/org/apache/aries/typedevent/bus/osgi/TypedEventMonitorIntegrationTest.java
index 9c3729d..ee630df 100644
--- 
a/org.apache.aries.typedevent.bus/src/test/java/org/apache/aries/typedevent/bus/osgi/TypedEventMonitorIntegrationTest.java
+++ 
b/org.apache.aries.typedevent.bus/src/test/java/org/apache/aries/typedevent/bus/osgi/TypedEventMonitorIntegrationTest.java
@@ -32,12 +32,11 @@ import org.apache.aries.typedevent.bus.common.TestEvent;
 import org.apache.aries.typedevent.bus.common.TestEventConsumer;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.Mock;
 import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
+import org.mockito.junit.jupiter.MockitoExtension;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.service.typedevent.TypedEventBus;
@@ -53,13 +52,12 @@ import org.osgi.util.promise.Promise;
 
 @ExtendWith(BundleContextExtension.class)
 @ExtendWith(ServiceExtension.class)
+@ExtendWith(MockitoExtension.class)
 public class TypedEventMonitorIntegrationTest extends AbstractIntegrationTest {
 
     @Mock
     TestEventConsumer typedEventHandler;
 
-    private AutoCloseable mocks;
-
     private static Bundle eventBusBundle;
     
     @BeforeAll
@@ -76,15 +74,8 @@ public class TypedEventMonitorIntegrationTest extends 
AbstractIntegrationTest {
                 .findAny().orElse(null);
     }
 
-    @BeforeEach
-    public void setupMocks() {
-        mocks = MockitoAnnotations.openMocks(this);
-    }
-
     @AfterEach
     public void stop() throws Exception {
-        mocks.close();
-
         // Needed to clear history from previous tests
         eventBusBundle.stop();
         eventBusBundle.start();
diff --git 
a/org.apache.aries.typedevent.bus/src/test/java/org/apache/aries/typedevent/bus/osgi/UnhandledEventHandlerIntegrationTest.java
 
b/org.apache.aries.typedevent.bus/src/test/java/org/apache/aries/typedevent/bus/osgi/UnhandledEventHandlerIntegrationTest.java
index 084a92a..5a8675e 100644
--- 
a/org.apache.aries.typedevent.bus/src/test/java/org/apache/aries/typedevent/bus/osgi/UnhandledEventHandlerIntegrationTest.java
+++ 
b/org.apache.aries.typedevent.bus/src/test/java/org/apache/aries/typedevent/bus/osgi/UnhandledEventHandlerIntegrationTest.java
@@ -31,12 +31,10 @@ import java.util.Hashtable;
 
 import org.apache.aries.typedevent.bus.common.TestEvent;
 import org.apache.aries.typedevent.bus.common.TestEventConsumer;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
+import org.mockito.junit.jupiter.MockitoExtension;
 import org.osgi.framework.BundleContext;
 import org.osgi.service.typedevent.TypedEventBus;
 import org.osgi.service.typedevent.TypedEventHandler;
@@ -56,6 +54,7 @@ import org.osgi.test.junit5.service.ServiceExtension;
  */
 @ExtendWith(BundleContextExtension.class)
 @ExtendWith(ServiceExtension.class)
+@ExtendWith(MockitoExtension.class)
 public class UnhandledEventHandlerIntegrationTest extends 
AbstractIntegrationTest {
     
     @InjectBundleContext
@@ -73,18 +72,6 @@ public class UnhandledEventHandlerIntegrationTest extends 
AbstractIntegrationTes
     @Mock
     UnhandledEventHandler unhandledEventHandler;
 
-    private AutoCloseable mocks;
-    
-    @BeforeEach
-    public void setupMocks() {
-        mocks = MockitoAnnotations.openMocks(this);
-    }
-    
-    @AfterEach
-    public void stop() throws Exception {
-        mocks.close();
-    }
-    
     /**
      * Tests that the unhandledEventHandler gets called appropriately
      * @throws InterruptedException
diff --git a/org.apache.aries.typedevent.bus/test.bndrun 
b/org.apache.aries.typedevent.bus/test.bndrun
index fe7f98b..b8cbb94 100644
--- a/org.apache.aries.typedevent.bus/test.bndrun
+++ b/org.apache.aries.typedevent.bus/test.bndrun
@@ -31,11 +31,8 @@
 
 -resolve.effective: active
 -runbundles: \
-       org.osgi.service.typedevent;version='[1.0.0,1.0.1)',\
        org.osgi.util.converter;version='[1.0.9,1.0.10)',\
        org.osgi.util.function;version='[1.1.0,1.1.1)',\
-       org.osgi.util.promise;version='[1.1.1,1.1.2)',\
-       org.osgi.util.pushstream;version='[1.0.1,1.0.2)',\
        junit-jupiter-api;version='[5.10.0,5.10.1)',\
        junit-platform-commons;version='[1.10.0,1.10.1)',\
        junit-jupiter-engine;version='[5.10.0,5.10.1)',\
@@ -55,4 +52,7 @@
        ch.qos.logback.core;version='[1.2.3,1.2.4)',\
        org.apache.aries.component-dsl.component-dsl;version='[1.2.2,1.2.3)',\
        org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\
-       slf4j.api;version='[1.7.30,1.7.31)'
\ No newline at end of file
+       slf4j.api;version='[1.7.30,1.7.31)',\
+       org.mockito.junit-jupiter;version='[5.5.0,5.5.1)',\
+       org.osgi.util.promise;version='[1.1.0,1.1.1)',\
+       org.osgi.util.pushstream;version='[1.0.0,1.0.1)'
\ No newline at end of file
diff --git 
a/org.apache.aries.typedevent.remote/org.apache.aries.typedevent.remote.api/pom.xml
 
b/org.apache.aries.typedevent.remote/org.apache.aries.typedevent.remote.api/pom.xml
index 7c43d9f..2d3fba9 100644
--- 
a/org.apache.aries.typedevent.remote/org.apache.aries.typedevent.remote.api/pom.xml
+++ 
b/org.apache.aries.typedevent.remote/org.apache.aries.typedevent.remote.api/pom.xml
@@ -30,10 +30,11 @@
             <groupId>org.osgi</groupId>
             <artifactId>org.osgi.core</artifactId>
         </dependency>
+        <!-- Temporary removal while using the locally built interfaces
         <dependency>
             <groupId>org.osgi</groupId>
             <artifactId>org.osgi.service.typedevent</artifactId>
-        </dependency>
+        </dependency> -->
         <dependency>
             <groupId>org.osgi</groupId>
             <artifactId>osgi.annotation</artifactId>
@@ -46,6 +47,13 @@
             <groupId>org.osgi</groupId>
             <artifactId>org.osgi.annotation.bundle</artifactId>
         </dependency>
+        
+        <!-- Temporary additions to compile with the new OSGi interfaces -->
+        <dependency>
+                       <groupId>org.apache.aries.typedevent</groupId>
+                       <artifactId>org.apache.aries.typedevent.bus</artifactId>
+                       <version>1.1.0-SNAPSHOT</version>
+               </dependency>
     </dependencies>
     
     <build>
diff --git 
a/org.apache.aries.typedevent.remote/org.apache.aries.typedevent.remote.remoteservices/pom.xml
 
b/org.apache.aries.typedevent.remote/org.apache.aries.typedevent.remote.remoteservices/pom.xml
index 46fcd8b..887fe55 100644
--- 
a/org.apache.aries.typedevent.remote/org.apache.aries.typedevent.remote.remoteservices/pom.xml
+++ 
b/org.apache.aries.typedevent.remote/org.apache.aries.typedevent.remote.remoteservices/pom.xml
@@ -37,10 +37,11 @@
             <groupId>org.osgi</groupId>
             <artifactId>org.osgi.core</artifactId>
         </dependency>
+        <!-- Temporary removal while using the locally built interfaces
         <dependency>
             <groupId>org.osgi</groupId>
             <artifactId>org.osgi.service.typedevent</artifactId>
-        </dependency>
+        </dependency> -->
         <dependency>
             <groupId>org.osgi</groupId>
             <artifactId>osgi.annotation</artifactId>
@@ -65,6 +66,12 @@
         <dependency>
             <groupId>org.osgi</groupId>
             <artifactId>org.osgi.util.converter</artifactId>
+            <exclusions>
+                               <exclusion>
+                                       <groupId>org.osgi</groupId>
+                                       
<artifactId>org.osgi.util.function</artifactId>
+                               </exclusion>
+                       </exclusions>
         </dependency>
         <dependency>
             <groupId>org.slf4j</groupId>
diff --git 
a/org.apache.aries.typedevent.remote/org.apache.aries.typedevent.remote.remoteservices/src/test/java/org/apache/aries/typedevent/remote/remoteservices/osgi/RemoteEventBusIntegrationTest.java
 
b/org.apache.aries.typedevent.remote/org.apache.aries.typedevent.remote.remoteservices/src/test/java/org/apache/aries/typedevent/remote/remoteservices/osgi/RemoteEventBusIntegrationTest.java
index 5b12943..cbb461b 100644
--- 
a/org.apache.aries.typedevent.remote/org.apache.aries.typedevent.remote.remoteservices/src/test/java/org/apache/aries/typedevent/remote/remoteservices/osgi/RemoteEventBusIntegrationTest.java
+++ 
b/org.apache.aries.typedevent.remote/org.apache.aries.typedevent.remote.remoteservices/src/test/java/org/apache/aries/typedevent/remote/remoteservices/osgi/RemoteEventBusIntegrationTest.java
@@ -324,7 +324,7 @@ public class RemoteEventBusIntegrationTest extends 
AbstractIntegrationTest {
         BundleContext remoteContext = frameworks.values().stream()
                 .filter(fw -> !getUUID(fw).equals(getMasterFrameworkUUID()))
                 .flatMap(fw -> 
Arrays.stream(fw.getBundleContext().getBundles()))
-                .filter(b -> 
b.getSymbolicName().equals("org.osgi.service.typedevent"))
+                .filter(b -> 
b.getSymbolicName().equals("org.apache.aries.typedevent.bus"))
                 .map(Bundle::getBundleContext)
                 .findFirst()
                 .get();
diff --git 
a/org.apache.aries.typedevent.remote/org.apache.aries.typedevent.remote.remoteservices/test.bndrun
 
b/org.apache.aries.typedevent.remote/org.apache.aries.typedevent.remote.remoteservices/test.bndrun
index ecc0976..2cf83af 100644
--- 
a/org.apache.aries.typedevent.remote/org.apache.aries.typedevent.remote.remoteservices/test.bndrun
+++ 
b/org.apache.aries.typedevent.remote/org.apache.aries.typedevent.remote.remoteservices/test.bndrun
@@ -32,14 +32,10 @@
        ch.qos.logback.classic;version='[1.2.3,1.2.4)',\
        ch.qos.logback.core;version='[1.2.3,1.2.4)',\
        org.apache.aries.component-dsl.component-dsl;version='[1.2.2,1.2.3)',\
-       org.osgi.service.typedevent;version='[1.0.0,1.0.1)',\
        org.osgi.util.converter;version='[1.0.9,1.0.10)',\
        org.osgi.util.function;version='[1.1.0,1.1.1)',\
-       org.osgi.util.promise;version='[1.1.1,1.1.2)',\
-       org.osgi.util.pushstream;version='[1.0.1,1.0.2)',\
        slf4j.api;version='[1.7.30,1.7.31)',\
        org.apache.aries.typedevent.bus;version='[1.1.0,1.1.1)',\
-       org.apache.aries.typedevent.remote.api;version='[1.1.0,1.1.1)',\
        
org.apache.aries.typedevent.remote.remoteservices;version='[1.1.0,1.1.1)',\
        
org.apache.aries.typedevent.remote.remoteservices-tests;version='[1.1.0,1.1.1)',\
        org.apache.aries.typedevent.remote.spi;version='[1.1.0,1.1.1)',\
@@ -56,4 +52,7 @@
        org.objenesis;version='[3.3.0,3.3.1)',\
        org.opentest4j;version='[1.3.0,1.3.1)',\
        org.osgi.test.common;version='[1.2.1,1.2.2)',\
-       org.osgi.test.junit5;version='[1.2.1,1.2.2)'
+       org.osgi.test.junit5;version='[1.2.1,1.2.2)',\
+       org.apache.aries.typedevent.remote.api;version='[0.0.2,0.0.3)',\
+       org.osgi.util.promise;version='[1.1.0,1.1.1)',\
+       org.osgi.util.pushstream;version='[1.0.0,1.0.1)'
diff --git 
a/org.apache.aries.typedevent.remote/org.apache.aries.typedevent.remote.spi/pom.xml
 
b/org.apache.aries.typedevent.remote/org.apache.aries.typedevent.remote.spi/pom.xml
index f9ad1e8..680caa8 100644
--- 
a/org.apache.aries.typedevent.remote/org.apache.aries.typedevent.remote.spi/pom.xml
+++ 
b/org.apache.aries.typedevent.remote/org.apache.aries.typedevent.remote.spi/pom.xml
@@ -30,10 +30,11 @@
             <groupId>org.osgi</groupId>
             <artifactId>org.osgi.core</artifactId>
         </dependency>
+        <!-- Temporary removal while using the locally built interfaces
         <dependency>
             <groupId>org.osgi</groupId>
             <artifactId>org.osgi.service.typedevent</artifactId>
-        </dependency>
+        </dependency> -->
         <dependency>
             <groupId>org.osgi</groupId>
             <artifactId>osgi.annotation</artifactId>
diff --git a/pom.xml b/pom.xml
index 00f1f66..6884091 100644
--- a/pom.xml
+++ b/pom.xml
@@ -97,12 +97,13 @@
                 <version>1.5.0</version>
                 <scope>compile</scope>
             </dependency>
+            <!-- Temporary removal while using the locally built interfaces
             <dependency>
                 <groupId>org.osgi</groupId>
                 <artifactId>org.osgi.service.typedevent</artifactId>
                 <version>1.0.0-RC1</version>
                 <scope>compile</scope>
-            </dependency>
+            </dependency> -->
             <dependency>
                 <groupId>org.osgi</groupId>
                 <artifactId>org.osgi.service.component.annotations</artifactId>


Reply via email to