You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by cs...@apache.org on 2016/03/16 18:35:59 UTC
karaf git commit: [KARAF-4370] EventAdmin commands
Repository: karaf
Updated Branches:
refs/heads/master b8c2617c2 -> 8aabfbd43
[KARAF-4370] EventAdmin commands
Project: http://git-wip-us.apache.org/repos/asf/karaf/repo
Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/8aabfbd4
Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/8aabfbd4
Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/8aabfbd4
Branch: refs/heads/master
Commit: 8aabfbd4368327117eb20dc79e420aa050613c33
Parents: b8c2617
Author: Christian Schneider <ch...@die-schneider.net>
Authored: Wed Mar 16 18:35:37 2016 +0100
Committer: Christian Schneider <ch...@die-schneider.net>
Committed: Wed Mar 16 18:35:37 2016 +0100
----------------------------------------------------------------------
event/.gitignore | 1 +
event/pom.xml | 90 ++++++++++++++++++++
.../apache/karaf/event/EventDisplayCommand.java | 57 +++++++++++++
.../org/apache/karaf/event/EventPrinter.java | 69 +++++++++++++++
.../apache/karaf/event/EventSendCommand.java | 64 ++++++++++++++
.../apache/karaf/event/EventTailCommand.java | 76 +++++++++++++++++
.../karaf/event/service/EventCollector.java | 69 +++++++++++++++
.../karaf/event/service/TopicPredicate.java | 40 +++++++++
.../karaf/event/EventDisplayCommandTest.java | 44 ++++++++++
.../apache/karaf/event/EventPrinterTest.java | 70 +++++++++++++++
.../karaf/event/EventSendCommandTest.java | 55 ++++++++++++
.../karaf/event/EventTailCommandTest.java | 70 +++++++++++++++
.../karaf/event/service/EventCollectorTest.java | 76 +++++++++++++++++
.../karaf/event/service/TopicPredicateTest.java | 57 +++++++++++++
pom.xml | 1 +
15 files changed, 839 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/karaf/blob/8aabfbd4/event/.gitignore
----------------------------------------------------------------------
diff --git a/event/.gitignore b/event/.gitignore
new file mode 100644
index 0000000..b83d222
--- /dev/null
+++ b/event/.gitignore
@@ -0,0 +1 @@
+/target/
http://git-wip-us.apache.org/repos/asf/karaf/blob/8aabfbd4/event/pom.xml
----------------------------------------------------------------------
diff --git a/event/pom.xml b/event/pom.xml
new file mode 100644
index 0000000..748e5e6
--- /dev/null
+++ b/event/pom.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <!--
+
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <artifactId>karaf</artifactId>
+ <groupId>org.apache.karaf</groupId>
+ <version>4.1.0-SNAPSHOT</version>
+ <relativePath>../../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>org.apache.karaf.event</artifactId>
+ <packaging>bundle</packaging>
+ <name>Apache Karaf :: OSGi Services :: Event</name>
+ <description>EventAdmin Commands</description>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.karaf.tooling</groupId>
+ <artifactId>karaf-services-maven-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+ <_dsannotations>*</_dsannotations>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.eventadmin</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.karaf.shell</groupId>
+ <artifactId>org.apache.karaf.shell.core</artifactId>
+ <version>4.0.4</version>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.karaf</groupId>
+ <artifactId>org.apache.karaf.util</artifactId>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.hamcrest</groupId>
+ <artifactId>hamcrest-all</artifactId>
+ <version>1.3</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+</project>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/karaf/blob/8aabfbd4/event/src/main/java/org/apache/karaf/event/EventDisplayCommand.java
----------------------------------------------------------------------
diff --git a/event/src/main/java/org/apache/karaf/event/EventDisplayCommand.java b/event/src/main/java/org/apache/karaf/event/EventDisplayCommand.java
new file mode 100644
index 0000000..37d8f3c
--- /dev/null
+++ b/event/src/main/java/org/apache/karaf/event/EventDisplayCommand.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.event;
+
+import static org.apache.karaf.event.service.TopicPredicate.matchTopic;
+
+import org.apache.karaf.event.service.EventCollector;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.api.console.Session;
+import org.osgi.framework.BundleContext;
+
+@Command(scope = "event", name = "display", description = "Shows events")
+@Service
+public class EventDisplayCommand implements Action {
+
+ @Reference
+ Session session;
+
+ @Reference
+ BundleContext context;
+
+ @Reference
+ EventCollector collector;
+
+ @Argument
+ String topicFilter = "*";
+
+ @Option(name = "-v")
+ boolean verbose = false;
+
+ @Override
+ public Object execute() throws Exception {
+ EventPrinter printer = new EventPrinter(session.getConsole(), verbose);
+ collector.getEvents().filter(matchTopic(topicFilter)).forEach(printer);
+ return null;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/8aabfbd4/event/src/main/java/org/apache/karaf/event/EventPrinter.java
----------------------------------------------------------------------
diff --git a/event/src/main/java/org/apache/karaf/event/EventPrinter.java b/event/src/main/java/org/apache/karaf/event/EventPrinter.java
new file mode 100644
index 0000000..314dc9d
--- /dev/null
+++ b/event/src/main/java/org/apache/karaf/event/EventPrinter.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.event;
+
+import java.io.PrintStream;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.function.Consumer;
+
+import org.osgi.service.event.Event;
+
+public class EventPrinter implements Consumer<Event>{
+ private PrintStream out;
+ private boolean verbose;
+
+ public EventPrinter(PrintStream out, boolean verbose) {
+ this.out = out;
+ this.verbose = verbose;
+ }
+
+
+ @Override
+ public void accept(Event event) {
+ out.println(getTimeStamp(event) + " - " + event.getTopic());
+ if (verbose) {
+ for (String key : event.getPropertyNames()) {
+ if (!key.equals("event.topics") && !key.equals("timestamp")) {
+ out.println(key + ": " + getPrintValue(event, key));
+ }
+ }
+ out.println();
+ out.flush();
+ }
+ }
+
+ private String getTimeStamp(Event event) {
+ Long ts = (Long)event.getProperty("timestamp");
+ if (ts == null) {
+ return "0000-00-00 00:00:00";
+ }
+ DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ return df.format(new Date(ts));
+ }
+
+ private Object getPrintValue(Event event, String key) {
+ Object value = event.getProperty(key);
+ if (value.getClass().isArray()) {
+ return Arrays.toString((Object[])value);
+ }
+ return value.toString();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/8aabfbd4/event/src/main/java/org/apache/karaf/event/EventSendCommand.java
----------------------------------------------------------------------
diff --git a/event/src/main/java/org/apache/karaf/event/EventSendCommand.java b/event/src/main/java/org/apache/karaf/event/EventSendCommand.java
new file mode 100644
index 0000000..ba3ab1b
--- /dev/null
+++ b/event/src/main/java/org/apache/karaf/event/EventSendCommand.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.event;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.api.console.Session;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventAdmin;
+
+@Command(scope = "event", name = "send", description = "Send a simple event to a topic")
+@Service
+public class EventSendCommand implements Action {
+ @Reference
+ Session session;
+
+ @Reference
+ EventAdmin eventAdmin;
+
+ @Argument
+ String topic;
+
+ @Argument(multiValued=true)
+ String propertiesSt;
+
+ @Override
+ public Object execute() throws Exception {
+ eventAdmin.sendEvent(new Event(topic, parse(propertiesSt)));
+ return null;
+ }
+
+ Map<String, String> parse(String propSt) {
+ Map<String, String> properties = new HashMap<>();
+ for (String keyValue : propSt.split(",")) {
+ String[] splitted = keyValue.split("=");
+ if (splitted.length != 2) {
+ throw new IllegalArgumentException("Invalid entry " + keyValue);
+ }
+ properties.put(splitted[0], splitted[1]);
+ };
+ return properties;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/8aabfbd4/event/src/main/java/org/apache/karaf/event/EventTailCommand.java
----------------------------------------------------------------------
diff --git a/event/src/main/java/org/apache/karaf/event/EventTailCommand.java b/event/src/main/java/org/apache/karaf/event/EventTailCommand.java
new file mode 100644
index 0000000..7be8840
--- /dev/null
+++ b/event/src/main/java/org/apache/karaf/event/EventTailCommand.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.event;
+
+import static org.apache.karaf.event.service.TopicPredicate.matchTopic;
+
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+
+import org.apache.karaf.event.service.EventCollector;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.api.console.Session;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.event.Event;
+
+@Command(scope = "event", name = "tail", description = "Shows events and listens for incoming events")
+@Service
+public class EventTailCommand implements Action {
+
+ @Reference
+ Session session;
+
+ @Reference
+ BundleContext context;
+
+ @Reference
+ EventCollector collector;
+
+ @Argument
+ String topicFilter = "*";
+
+ @Option(name = "-v")
+ boolean verbose = false;
+
+ @Override
+ public Object execute() throws Exception {
+ EventPrinter printer = new EventPrinter(session.getConsole(), verbose);
+ Consumer<Event> filteredPrinter = executeIf(matchTopic(topicFilter), printer);
+ collector.addConsumer(filteredPrinter);
+ try {
+ waitTillInterrupted();
+ } catch (InterruptedException e) {
+ collector.removeConsumer(filteredPrinter);
+ }
+ return null;
+ }
+
+ private <T> Consumer<T> executeIf(Predicate<T> pred, Consumer<T> consumer) {
+ return t -> {if (pred.test(t)) consumer.accept(t);};
+ }
+
+ private void waitTillInterrupted() throws InterruptedException {
+ while (true) {
+ Thread.sleep(100);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/8aabfbd4/event/src/main/java/org/apache/karaf/event/service/EventCollector.java
----------------------------------------------------------------------
diff --git a/event/src/main/java/org/apache/karaf/event/service/EventCollector.java b/event/src/main/java/org/apache/karaf/event/service/EventCollector.java
new file mode 100644
index 0000000..0a42d6d
--- /dev/null
+++ b/event/src/main/java/org/apache/karaf/event/service/EventCollector.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.event.service;
+
+import java.util.Deque;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.ConcurrentLinkedDeque;
+import java.util.function.Consumer;
+import java.util.stream.Stream;
+
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventHandler;
+
+@Component(
+ service = {EventHandler.class, EventCollector.class},
+ name = "org.apache.karaf.eventadmin.collector",
+ immediate = true,
+ property = "event.topics=*"
+ )
+public class EventCollector implements EventHandler {
+ private Deque<Event> events;
+ private int maxSize;
+ private Set<Consumer<Event>> consumers;
+
+ public EventCollector() {
+ events = new ConcurrentLinkedDeque<>();
+ maxSize = 100;
+ consumers = new HashSet<>();
+ }
+
+ @Override
+ public synchronized void handleEvent(Event event) {
+ events.addLast(event);
+ if (events.size() > maxSize) {
+ events.removeFirst();
+ }
+ consumers.forEach(c -> c.accept(event));
+ }
+
+ public Stream<Event> getEvents() {
+ return events.stream();
+ }
+
+ public synchronized void addConsumer(Consumer<Event> eventConsumer) {
+ events.forEach(eventConsumer);
+ consumers.add(eventConsumer);
+ }
+
+ public synchronized void removeConsumer(Consumer<Event> eventConsumer) {
+ consumers.remove(eventConsumer);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/8aabfbd4/event/src/main/java/org/apache/karaf/event/service/TopicPredicate.java
----------------------------------------------------------------------
diff --git a/event/src/main/java/org/apache/karaf/event/service/TopicPredicate.java b/event/src/main/java/org/apache/karaf/event/service/TopicPredicate.java
new file mode 100644
index 0000000..974f6e6
--- /dev/null
+++ b/event/src/main/java/org/apache/karaf/event/service/TopicPredicate.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.event.service;
+
+import java.util.function.Predicate;
+import java.util.regex.Pattern;
+
+import org.osgi.service.event.Event;
+
+public class TopicPredicate implements Predicate<Event> {
+ private Pattern pattern;
+
+ private TopicPredicate(String topicFilter) {
+ pattern = Pattern.compile(topicFilter.replace("*", ".*"));
+ }
+
+ @Override
+ public boolean test(Event event) {
+ return pattern.matcher(event.getTopic()).matches();
+ }
+
+ public static Predicate<Event> matchTopic(String topicFilter) {
+ return new TopicPredicate(topicFilter);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/8aabfbd4/event/src/test/java/org/apache/karaf/event/EventDisplayCommandTest.java
----------------------------------------------------------------------
diff --git a/event/src/test/java/org/apache/karaf/event/EventDisplayCommandTest.java b/event/src/test/java/org/apache/karaf/event/EventDisplayCommandTest.java
new file mode 100644
index 0000000..0822f73
--- /dev/null
+++ b/event/src/test/java/org/apache/karaf/event/EventDisplayCommandTest.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.event;
+
+import static org.easymock.EasyMock.createControl;
+import static org.easymock.EasyMock.expect;
+
+import java.util.HashMap;
+
+import org.apache.karaf.event.service.EventCollector;
+import org.apache.karaf.shell.api.console.Session;
+import org.easymock.IMocksControl;
+import org.junit.Test;
+import org.osgi.service.event.Event;
+
+public class EventDisplayCommandTest {
+
+ @Test
+ public void testExecute() throws Exception {
+ IMocksControl c = createControl();
+ EventDisplayCommand display = new EventDisplayCommand();
+ display.session = c.createMock(Session.class);
+ expect(display.session.getConsole()).andReturn(System.out);
+ display.collector = new EventCollector();
+ display.collector.handleEvent(new Event("myTopic", new HashMap<>()));
+ c.replay();
+ display.execute();
+ c.verify();
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/8aabfbd4/event/src/test/java/org/apache/karaf/event/EventPrinterTest.java
----------------------------------------------------------------------
diff --git a/event/src/test/java/org/apache/karaf/event/EventPrinterTest.java b/event/src/test/java/org/apache/karaf/event/EventPrinterTest.java
new file mode 100644
index 0000000..cee5b0f
--- /dev/null
+++ b/event/src/test/java/org/apache/karaf/event/EventPrinterTest.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.event;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.junit.Assert.assertThat;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.io.UnsupportedEncodingException;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+
+import org.junit.Test;
+import org.osgi.service.event.Event;
+
+public class EventPrinterTest {
+ DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm");
+
+ @Test
+ public void testPrint() throws UnsupportedEncodingException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ PrintStream out = new PrintStream(baos);
+ new EventPrinter(out, false).accept(event());
+ String result = baos.toString("utf-8");
+ assertThat(result, equalTo("2016-01-01 12:00:00 - myTopic\n"));
+ }
+
+ @Test
+ public void testPrintVerbose() throws UnsupportedEncodingException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ PrintStream out = new PrintStream(baos);
+ new EventPrinter(out, true).accept(event());
+ String result = baos.toString("utf-8");
+ assertThat(result, equalTo("2016-01-01 12:00:00 - myTopic\n"
+ + "a: b\n"
+ + "c: [d, e]\n\n"));
+ }
+
+ private Event event() {
+ HashMap<String, Object> props = new HashMap<>();
+ props.put("a", "b");
+ props.put("c", new String[]{"d", "e"});
+ Date date;
+ try {
+ date = df.parse("2016-01-01 12:00:00");
+ } catch (ParseException e) {
+ throw new RuntimeException(e);
+ }
+ props.put("timestamp", date.getTime());
+ return new Event("myTopic", props);
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/8aabfbd4/event/src/test/java/org/apache/karaf/event/EventSendCommandTest.java
----------------------------------------------------------------------
diff --git a/event/src/test/java/org/apache/karaf/event/EventSendCommandTest.java b/event/src/test/java/org/apache/karaf/event/EventSendCommandTest.java
new file mode 100644
index 0000000..fb87c4b
--- /dev/null
+++ b/event/src/test/java/org/apache/karaf/event/EventSendCommandTest.java
@@ -0,0 +1,55 @@
+package org.apache.karaf.event;
+
+import static org.easymock.EasyMock.capture;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.mock;
+import static org.easymock.EasyMock.newCapture;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.junit.Assert.assertThat;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.easymock.Capture;
+import org.junit.Test;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventAdmin;
+
+public class EventSendCommandTest {
+ @Test
+ public void testExecute() throws Exception {
+ EventSendCommand send = new EventSendCommand();
+ send.eventAdmin = mock(EventAdmin.class);
+ Capture<Event> eventCapture = newCapture();
+ send.eventAdmin.sendEvent(capture(eventCapture));
+ expectLastCall();
+
+ replay(send.eventAdmin);
+ send.topic = "myTopic";
+ send.propertiesSt = "a=b";
+ send.execute();
+ verify(send.eventAdmin);
+
+ Event event = eventCapture.getValue();
+ assertThat(event.getTopic(), equalTo("myTopic"));
+ assertThat(event.getProperty("a"), equalTo("b"));
+ }
+
+ @Test
+ public void testParse() {
+ String propSt = "a=b,b=c";
+ Map<String, String> expectedMap = new HashMap<>();
+ expectedMap.put("a", "b");
+ expectedMap.put("b", "c");
+ Map<String, String> props = new EventSendCommand().parse(propSt);
+ assertThat(props.entrySet(), equalTo(expectedMap.entrySet()));
+ }
+
+ @Test(expected=IllegalArgumentException.class)
+ public void testParseError() {
+ String propSt = "a=b,c=";
+ new EventSendCommand().parse(propSt);
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/8aabfbd4/event/src/test/java/org/apache/karaf/event/EventTailCommandTest.java
----------------------------------------------------------------------
diff --git a/event/src/test/java/org/apache/karaf/event/EventTailCommandTest.java b/event/src/test/java/org/apache/karaf/event/EventTailCommandTest.java
new file mode 100644
index 0000000..b18f725
--- /dev/null
+++ b/event/src/test/java/org/apache/karaf/event/EventTailCommandTest.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.event;
+
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.mock;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+
+import java.io.PrintStream;
+import java.util.HashMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.karaf.event.service.EventCollector;
+import org.apache.karaf.shell.api.console.Session;
+import org.junit.Test;
+import org.osgi.service.event.Event;
+
+public class EventTailCommandTest {
+
+ private Exception exception;
+
+ @Test
+ public void testTail() throws Exception {
+ EventTailCommand tail = new EventTailCommand();
+ tail.session = mock(Session.class);
+ tail.collector = new EventCollector();
+ PrintStream out = System.out;
+ expect(tail.session.getConsole()).andReturn(out);
+ exception = null;
+ replay(tail.session);
+
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+ executor.execute(() -> {
+ try {
+ tail.execute();
+ } catch (Exception e) {
+ exception = e;
+ }
+ });
+ tail.collector.handleEvent(event());
+ Thread.sleep(200);
+ executor.shutdownNow();
+ executor.awaitTermination(100, TimeUnit.SECONDS);
+ if (exception != null) {
+ throw exception;
+ }
+ verify(tail.session);
+ }
+
+ private Event event() {
+ return new Event("myTopic", new HashMap<>());
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/8aabfbd4/event/src/test/java/org/apache/karaf/event/service/EventCollectorTest.java
----------------------------------------------------------------------
diff --git a/event/src/test/java/org/apache/karaf/event/service/EventCollectorTest.java b/event/src/test/java/org/apache/karaf/event/service/EventCollectorTest.java
new file mode 100644
index 0000000..535ee0d
--- /dev/null
+++ b/event/src/test/java/org/apache/karaf/event/service/EventCollectorTest.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.event.service;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import java.util.HashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Consumer;
+import java.util.stream.IntStream;
+
+import org.junit.Test;
+import org.osgi.service.event.Event;
+
+public class EventCollectorTest {
+
+ @Test
+ public void testHandleEvent() throws Exception {
+ EventCollector collector = new EventCollector();
+ assertThat(collector.getEvents().count(), equalTo(0l));
+ collector.handleEvent(event("myTopic"));
+ assertThat(collector.getEvents().count(), equalTo(1l));
+ assertThat(collector.getEvents().findFirst().get().getTopic(), equalTo("myTopic"));
+
+ }
+
+ @Test
+ public void testLimit() {
+ EventCollector collector = new EventCollector();
+ collector.handleEvent(event("first"));
+ IntStream.rangeClosed(1, 99).forEach(c -> collector.handleEvent(event("myTopic")));
+ assertThat(collector.getEvents().count(), equalTo(100l));
+ collector.handleEvent(event("last"));
+ assertThat(collector.getEvents().count(), equalTo(100l));
+ assertTrue(collector.getEvents().noneMatch(event -> event.getTopic().endsWith("first")));
+ assertTrue(collector.getEvents().anyMatch(event -> event.getTopic().endsWith("last")));
+ }
+
+ @Test
+ public void testAddRemoveConsumer() {
+ final AtomicInteger count = new AtomicInteger();
+ Consumer<Event> countingConsumer = event -> count.incrementAndGet();
+ EventCollector collector = new EventCollector();
+ collector.handleEvent(event("myTopic"));
+ collector.addConsumer(countingConsumer);
+ assertThat(count.get(), equalTo(1));
+
+ collector.handleEvent(event("another"));
+ assertThat(count.get(), equalTo(2));
+
+ collector.removeConsumer(countingConsumer);
+ collector.handleEvent(event("and/another"));
+ assertThat(count.get(), equalTo(2));
+ }
+
+ private Event event(String topic) {
+ return new Event(topic, new HashMap<>());
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/8aabfbd4/event/src/test/java/org/apache/karaf/event/service/TopicPredicateTest.java
----------------------------------------------------------------------
diff --git a/event/src/test/java/org/apache/karaf/event/service/TopicPredicateTest.java b/event/src/test/java/org/apache/karaf/event/service/TopicPredicateTest.java
new file mode 100644
index 0000000..fca6f59
--- /dev/null
+++ b/event/src/test/java/org/apache/karaf/event/service/TopicPredicateTest.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.event.service;
+
+import static org.apache.karaf.event.service.TopicPredicate.matchTopic;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.HashMap;
+import java.util.function.Predicate;
+
+import org.junit.Test;
+import org.osgi.service.event.Event;
+
+public class TopicPredicateTest {
+
+ @Test
+ public void testMatchAll() {
+ Predicate<Event> matcher = matchTopic("*");
+ assertTrue(matcher.test(event("myTopic")));
+ assertTrue(matcher.test(event("my/other")));
+ }
+
+ @Test
+ public void testMatchSpecific() {
+ Predicate<Event> matcher = matchTopic("myTopic");
+ assertTrue(matcher.test(event("myTopic")));
+ assertFalse(matcher.test(event("myTopic/test")));
+ assertFalse(matcher.test(event("my/other")));
+ }
+
+ @Test
+ public void testMatchSubTopics() {
+ Predicate<Event> matcher = matchTopic("myTopic*");
+ assertTrue(matcher.test(event("myTopic")));
+ assertTrue(matcher.test(event("myTopic/test")));
+ assertFalse(matcher.test(event("my/other")));
+ }
+
+ private Event event(String topic) {
+ return new Event(topic, new HashMap<String, String>());
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/8aabfbd4/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 31826b9..4bcf505 100644
--- a/pom.xml
+++ b/pom.xml
@@ -68,6 +68,7 @@
<module>services</module>
<module>subsystem</module>
<module>profile</module>
+ <module>event</module>
<module>tooling</module>
<module>assemblies</module>
<module>demos</module>