HIGUCHI Yuta
Committed by Gerrit Code Review

Event history service and CLI

- Tool created while debugging ONOS-3509

  Usage Example: (See recent Mastership and Device events)
   onos> events -m -d

Change-Id: I87aceaf8fe61732a61c2d1e39399d0f10a729b54
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<!--
3 + ~ Copyright 2016 Open Networking Laboratory
4 + ~
5 + ~ Licensed under the Apache License, Version 2.0 (the "License");
6 + ~ you may not use this file except in compliance with the License.
7 + ~ You may obtain a copy of the License at
8 + ~
9 + ~ http://www.apache.org/licenses/LICENSE-2.0
10 + ~
11 + ~ Unless required by applicable law or agreed to in writing, software
12 + ~ distributed under the License is distributed on an "AS IS" BASIS,
13 + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + ~ See the License for the specific language governing permissions and
15 + ~ limitations under the License.
16 + -->
17 +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
18 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
19 + <modelVersion>4.0.0</modelVersion>
20 + <parent>
21 + <artifactId>onos-apps</artifactId>
22 + <groupId>org.onosproject</groupId>
23 + <version>1.5.0-SNAPSHOT</version>
24 + <relativePath>../pom.xml</relativePath>
25 + </parent>
26 +
27 + <groupId>org.onosproject</groupId>
28 + <artifactId>onos-events</artifactId>
29 + <packaging>bundle</packaging>
30 +
31 + <description>App to display ONOS event history</description>
32 + <url>http://onosproject.org</url>
33 +
34 + <properties>
35 + <onos.version>1.5.0-SNAPSHOT</onos.version>
36 + <onos.app.name>org.onosproject.events</onos.app.name>
37 + </properties>
38 +
39 + <dependencies>
40 + <dependency>
41 + <groupId>org.onosproject</groupId>
42 + <artifactId>onos-api</artifactId>
43 + </dependency>
44 +
45 + <dependency>
46 + <groupId>org.onosproject</groupId>
47 + <artifactId>onlab-osgi</artifactId>
48 + </dependency>
49 +
50 + <dependency>
51 + <groupId>junit</groupId>
52 + <artifactId>junit</artifactId>
53 + <scope>test</scope>
54 + </dependency>
55 +
56 + <dependency>
57 + <groupId>org.onosproject</groupId>
58 + <artifactId>onos-api</artifactId>
59 + <scope>test</scope>
60 + <classifier>tests</classifier>
61 + </dependency>
62 +
63 + <dependency>
64 + <groupId>org.apache.felix</groupId>
65 + <artifactId>org.apache.felix.scr.annotations</artifactId>
66 + <scope>provided</scope>
67 + </dependency>
68 +
69 + <dependency>
70 + <groupId>org.onosproject</groupId>
71 + <artifactId>onos-cli</artifactId>
72 + <version>${project.version}</version>
73 + </dependency>
74 +
75 + <dependency>
76 + <groupId>org.osgi</groupId>
77 + <artifactId>org.osgi.core</artifactId>
78 + <scope>provided</scope>
79 + </dependency>
80 +
81 + <dependency>
82 + <groupId>org.apache.karaf.shell</groupId>
83 + <artifactId>org.apache.karaf.shell.console</artifactId>
84 + <scope>provided</scope>
85 + </dependency>
86 + <dependency>
87 + <groupId>org.onosproject</groupId>
88 + <artifactId>onlab-junit</artifactId>
89 + <scope>test</scope>
90 + </dependency>
91 + <dependency>
92 + <groupId>org.onosproject</groupId>
93 + <artifactId>onlab-misc</artifactId>
94 + </dependency>
95 + </dependencies>
96 +
97 + <build>
98 + <plugins>
99 + <plugin>
100 + <groupId>org.apache.felix</groupId>
101 + <artifactId>maven-bundle-plugin</artifactId>
102 + <extensions>true</extensions>
103 + </plugin>
104 + <plugin>
105 + <groupId>org.apache.maven.plugins</groupId>
106 + <artifactId>maven-compiler-plugin</artifactId>
107 + </plugin>
108 + <plugin>
109 + <groupId>org.apache.felix</groupId>
110 + <artifactId>maven-scr-plugin</artifactId>
111 + <executions>
112 + <execution>
113 + <id>generate-scr-srcdescriptor</id>
114 + <goals>
115 + <goal>scr</goal>
116 + </goals>
117 + </execution>
118 + </executions>
119 + <configuration>
120 + <supportedProjectTypes>
121 + <supportedProjectType>bundle</supportedProjectType>
122 + <supportedProjectType>war</supportedProjectType>
123 + </supportedProjectTypes>
124 + </configuration>
125 + </plugin>
126 + <plugin>
127 + <groupId>org.onosproject</groupId>
128 + <artifactId>onos-maven-plugin</artifactId>
129 + <executions>
130 + <execution>
131 + <id>cfg</id>
132 + <phase>generate-resources</phase>
133 + <goals>
134 + <goal>cfg</goal>
135 + </goals>
136 + </execution>
137 + <execution>
138 + <id>swagger</id>
139 + <phase>generate-sources</phase>
140 + <goals>
141 + <goal>swagger</goal>
142 + </goals>
143 + </execution>
144 + <execution>
145 + <id>app</id>
146 + <phase>package</phase>
147 + <goals>
148 + <goal>app</goal>
149 + </goals>
150 + </execution>
151 + </executions>
152 + </plugin>
153 + </plugins>
154 + </build>
155 +
156 +</project>
1 +/*
2 + * Copyright 2016 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.events;
17 +
18 +import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
19 +import static org.onlab.util.Tools.groupedThreads;
20 +import static org.onlab.util.Tools.minPriority;
21 +
22 +import java.util.Deque;
23 +import java.util.concurrent.ConcurrentLinkedDeque;
24 +import java.util.concurrent.ScheduledExecutorService;
25 +import java.util.concurrent.TimeUnit;
26 +
27 +import org.apache.felix.scr.annotations.Activate;
28 +import org.apache.felix.scr.annotations.Component;
29 +import org.apache.felix.scr.annotations.Deactivate;
30 +import org.apache.felix.scr.annotations.Property;
31 +import org.apache.felix.scr.annotations.Reference;
32 +import org.apache.felix.scr.annotations.ReferenceCardinality;
33 +import org.apache.felix.scr.annotations.Service;
34 +import org.onlab.util.UnmodifiableDeque;
35 +import org.onosproject.cluster.ClusterEvent;
36 +import org.onosproject.cluster.ClusterEventListener;
37 +import org.onosproject.cluster.ClusterService;
38 +import org.onosproject.core.ApplicationId;
39 +import org.onosproject.core.CoreService;
40 +import org.onosproject.event.Event;
41 +import org.onosproject.event.ListenerTracker;
42 +import org.onosproject.mastership.MastershipEvent;
43 +import org.onosproject.mastership.MastershipListener;
44 +import org.onosproject.mastership.MastershipService;
45 +import org.onosproject.net.device.DeviceEvent;
46 +import org.onosproject.net.device.DeviceListener;
47 +import org.onosproject.net.device.DeviceService;
48 +import org.onosproject.net.host.HostEvent;
49 +import org.onosproject.net.host.HostListener;
50 +import org.onosproject.net.host.HostService;
51 +import org.onosproject.net.link.LinkEvent;
52 +import org.onosproject.net.link.LinkListener;
53 +import org.onosproject.net.link.LinkService;
54 +import org.onosproject.net.topology.TopologyEvent;
55 +import org.onosproject.net.topology.TopologyListener;
56 +import org.onosproject.net.topology.TopologyService;
57 +import org.slf4j.Logger;
58 +import org.slf4j.LoggerFactory;
59 +
60 +/**
61 + * Application to store history of instance local ONOS Events.
62 + */
63 +@Component(immediate = true)
64 +@Service
65 +public class EventHistoryManager
66 + implements EventHistoryService {
67 +
68 + private final Logger log = LoggerFactory.getLogger(getClass());
69 +
70 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
71 + protected CoreService coreService;
72 +
73 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
74 + protected MastershipService mastershipService;
75 +
76 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
77 + protected DeviceService deviceService;
78 +
79 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
80 + protected LinkService linkService;
81 +
82 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
83 + protected TopologyService topologyService;
84 +
85 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
86 + protected HostService hostService;
87 +
88 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
89 + protected ClusterService clusterService;
90 +
91 + @Property(name = "excludeStatsEvent", boolValue = true,
92 + label = "Exclude stats related events")
93 + private boolean excludeStatsEvent = true;
94 +
95 + @Property(name = "sizeLimit", intValue = 10_000,
96 + label = "Number of event history to store")
97 + private int sizeLimit = 10_000;
98 +
99 + private ApplicationId appId;
100 +
101 + private ListenerTracker listeners;
102 +
103 + // Using Deque so that it'll be possible to iterate from both ends
104 + // (Tail-end is the most recent event)
105 + private final Deque<Event<?, ?>> history = new ConcurrentLinkedDeque<>();
106 +
107 + private ScheduledExecutorService pruner;
108 +
109 + // pruneEventHistoryTask() execution interval in seconds
110 + private long pruneInterval = 5;
111 +
112 +
113 + @Activate
114 + protected void activate() {
115 + appId = coreService.registerApplication("org.onosproject.events");
116 + log.debug("Registered as {}", appId);
117 +
118 + pruner = newSingleThreadScheduledExecutor(minPriority(groupedThreads("onos/events", "history-pruner")));
119 +
120 + pruner.scheduleWithFixedDelay(this::pruneEventHistoryTask,
121 + pruneInterval , pruneInterval, TimeUnit.SECONDS);
122 +
123 + listeners = new ListenerTracker();
124 + listeners.addListener(mastershipService, new InternalMastershipListener())
125 + .addListener(deviceService, new InternalDeviceListener())
126 + .addListener(linkService, new InternalLinkListener())
127 + .addListener(topologyService, new InternalTopologyListener())
128 + .addListener(hostService, new InternalHostListener())
129 + .addListener(clusterService, new InternalClusterListener());
130 +
131 + log.info("Started");
132 + }
133 +
134 + @Deactivate
135 + protected void deactivate() {
136 + listeners.removeListeners();
137 +
138 + pruner.shutdownNow();
139 + history.clear();
140 +
141 + log.info("Stopped");
142 + }
143 +
144 + @Override
145 + public Deque<Event<?, ?>> history() {
146 + return UnmodifiableDeque.unmodifiableDeque(history);
147 + }
148 +
149 + @Override
150 + public void clear() {
151 + history.clear();
152 + }
153 +
154 + // This method assumes only 1 call is in flight at the same time.
155 + private void pruneEventHistoryTask() {
156 + int size = history.size();
157 + int overflows = size - sizeLimit;
158 + if (overflows > 0) {
159 + for (int i = 0; i < overflows; ++i) {
160 + history.poll();
161 + }
162 + }
163 + }
164 +
165 + private void addEvent(Event<?, ?> event) {
166 + history.offer(event);
167 + }
168 +
169 + class InternalMastershipListener
170 + implements MastershipListener {
171 +
172 + @Override
173 + public void event(MastershipEvent event) {
174 + addEvent(event);
175 + }
176 + }
177 +
178 + class InternalDeviceListener
179 + implements DeviceListener {
180 +
181 + @Override
182 + public boolean isRelevant(DeviceEvent event) {
183 + if (excludeStatsEvent) {
184 + return event.type() != DeviceEvent.Type.PORT_STATS_UPDATED;
185 + } else {
186 + return true;
187 + }
188 + }
189 +
190 + @Override
191 + public void event(DeviceEvent event) {
192 + addEvent(event);
193 + }
194 + }
195 +
196 + class InternalLinkListener
197 + implements LinkListener {
198 +
199 + @Override
200 + public void event(LinkEvent event) {
201 + addEvent(event);
202 + }
203 + }
204 +
205 + class InternalTopologyListener
206 + implements TopologyListener {
207 +
208 + @Override
209 + public void event(TopologyEvent event) {
210 + addEvent(event);
211 + }
212 + }
213 +
214 + class InternalHostListener
215 + implements HostListener {
216 +
217 + @Override
218 + public void event(HostEvent event) {
219 + addEvent(event);
220 + }
221 + }
222 +
223 + class InternalClusterListener
224 + implements ClusterEventListener {
225 +
226 + @Override
227 + public void event(ClusterEvent event) {
228 + addEvent(event);
229 + }
230 + }
231 +
232 +}
1 +/*
2 + * Copyright 2016 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.events;
17 +
18 +import java.util.Deque;
19 +
20 +import org.onosproject.event.Event;
21 +
22 +import com.google.common.annotations.Beta;
23 +
24 +/**
25 + * Provides history of instance local ONOS Events.
26 + */
27 +@Beta
28 +public interface EventHistoryService {
29 +
30 + /**
31 + * Returns unmodifiable view of ONOS events history.
32 + *
33 + * @return ONOS events (First element is the oldest event stored)
34 + */
35 + Deque<Event<?, ?>> history();
36 +
37 + /**
38 + * Clears all stored history.
39 + */
40 + void clear();
41 +}
1 +/*
2 + * Copyright 2016 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.events;
17 +
18 +import static java.util.stream.Collectors.toList;
19 +
20 +import java.io.PrintWriter;
21 +import java.io.StringWriter;
22 +import java.util.List;
23 +import java.util.function.Predicate;
24 +import java.util.stream.Collector;
25 +import java.util.stream.Stream;
26 +
27 +import org.apache.karaf.shell.commands.Command;
28 +import org.apache.karaf.shell.commands.Option;
29 +import org.joda.time.LocalDateTime;
30 +import org.onosproject.cli.AbstractShellCommand;
31 +import org.onosproject.cluster.ClusterEvent;
32 +import org.onosproject.event.Event;
33 +import org.onosproject.mastership.MastershipEvent;
34 +import org.onosproject.net.Link;
35 +import org.onosproject.net.device.DeviceEvent;
36 +import org.onosproject.net.host.HostEvent;
37 +import org.onosproject.net.link.LinkEvent;
38 +import org.onosproject.net.topology.Topology;
39 +import org.onosproject.net.topology.TopologyEvent;
40 +
41 +import com.fasterxml.jackson.core.JsonProcessingException;
42 +import com.fasterxml.jackson.databind.JsonNode;
43 +import com.fasterxml.jackson.databind.node.ArrayNode;
44 +import com.fasterxml.jackson.databind.node.ObjectNode;
45 +import com.google.common.base.MoreObjects;
46 +import com.google.common.collect.ImmutableList;
47 +
48 +/**
49 + * Command to print history of instance local ONOS Events.
50 + */
51 +@Command(scope = "onos", name = "events",
52 + description = "Command to print history of instance local ONOS Events")
53 +public class EventsCommand
54 + extends AbstractShellCommand {
55 +
56 + @Option(name = "--all", aliases = "-a",
57 + description = "Include all Events (default behavior)",
58 + required = false)
59 + private boolean all = false;
60 +
61 + @Option(name = "--mastership", aliases = "-m",
62 + description = "Include MastershipEvent",
63 + required = false)
64 + private boolean mastership = false;
65 +
66 + @Option(name = "--device", aliases = "-d",
67 + description = "Include DeviceEvent",
68 + required = false)
69 + private boolean device = false;
70 +
71 + @Option(name = "--link", aliases = "-l",
72 + description = "Include LinkEvent",
73 + required = false)
74 + private boolean link = false;
75 +
76 + @Option(name = "--topology", aliases = "-t",
77 + description = "Include TopologyEvent",
78 + required = false)
79 + private boolean topology = false;
80 +
81 + @Option(name = "--host", aliases = "-t",
82 + description = "Include HostEvent",
83 + required = false)
84 + private boolean host = false;
85 +
86 + @Option(name = "--cluster", aliases = "-c",
87 + description = "Include ClusterEvent",
88 + required = false)
89 + private boolean cluster = false;
90 +
91 + @Option(name = "--max-events", aliases = "-n",
92 + description = "Maximum number of events to print",
93 + required = false,
94 + valueToShowInHelp = "-1 [no limit]")
95 + private long maxSize = -1;
96 +
97 + @Override
98 + protected void execute() {
99 + EventHistoryService eventHistoryService = get(EventHistoryService.class);
100 +
101 + Stream<Event<?, ?>> events = eventHistoryService.history().stream();
102 +
103 + boolean dumpAll = all || !(mastership || device || link || topology || host);
104 +
105 + if (!dumpAll) {
106 + Predicate<Event<?, ?>> filter = (defaultIs) -> false;
107 +
108 + if (mastership) {
109 + filter = filter.or(evt -> evt instanceof MastershipEvent);
110 + }
111 + if (device) {
112 + filter = filter.or(evt -> evt instanceof DeviceEvent);
113 + }
114 + if (link) {
115 + filter = filter.or(evt -> evt instanceof LinkEvent);
116 + }
117 + if (topology) {
118 + filter = filter.or(evt -> evt instanceof TopologyEvent);
119 + }
120 + if (host) {
121 + filter = filter.or(evt -> evt instanceof HostEvent);
122 + }
123 + if (cluster) {
124 + filter = filter.or(evt -> evt instanceof ClusterEvent);
125 + }
126 +
127 + events = events.filter(filter);
128 + }
129 +
130 + if (maxSize > 0) {
131 + events = events.limit(maxSize);
132 + }
133 +
134 + if (outputJson()) {
135 + ArrayNode jsonEvents = events.map(this::json).collect(toArrayNode());
136 + printJson(jsonEvents);
137 + } else {
138 + events.forEach(this::printEvent);
139 + }
140 +
141 + }
142 +
143 + private Collector<JsonNode, ArrayNode, ArrayNode> toArrayNode() {
144 + return Collector.of(() -> mapper().createArrayNode(),
145 + ArrayNode::add,
146 + ArrayNode::addAll);
147 + }
148 +
149 + private ObjectNode json(Event<?, ?> event) {
150 + ObjectNode result = mapper().createObjectNode();
151 +
152 + result.put("time", event.time())
153 + .put("type", event.type().toString())
154 + .put("event", event.toString());
155 +
156 + return result;
157 + }
158 +
159 + /**
160 + * Print JsonNode using default pretty printer.
161 + *
162 + * @param json JSON node to print
163 + */
164 + private void printJson(JsonNode json) {
165 + try {
166 + print("%s", mapper().writerWithDefaultPrettyPrinter().writeValueAsString(json));
167 + } catch (JsonProcessingException e) {
168 + StringWriter sw = new StringWriter();
169 + e.printStackTrace(new PrintWriter(sw));
170 + print("[ERROR] %s\n%s", e.getMessage(), sw.toString());
171 + }
172 + }
173 +
174 + private void printEvent(Event<?, ?> event) {
175 + if (event instanceof DeviceEvent) {
176 + DeviceEvent deviceEvent = (DeviceEvent) event;
177 + if (event.type().toString().startsWith("PORT")) {
178 + // Port event
179 + print("%s %s\t%s/%s [%s]",
180 + new LocalDateTime(event.time()),
181 + event.type(),
182 + deviceEvent.subject().id(), deviceEvent.port().number(),
183 + deviceEvent.port()
184 + );
185 + } else {
186 + // Device event
187 + print("%s %s\t%s [%s]",
188 + new LocalDateTime(event.time()),
189 + event.type(),
190 + deviceEvent.subject().id(),
191 + deviceEvent.subject()
192 + );
193 + }
194 +
195 + } else if (event instanceof MastershipEvent) {
196 + print("%s %s\t%s [%s]",
197 + new LocalDateTime(event.time()),
198 + event.type(),
199 + event.subject(),
200 + ((MastershipEvent) event).roleInfo());
201 +
202 + } else if (event instanceof LinkEvent) {
203 + LinkEvent linkEvent = (LinkEvent) event;
204 + Link link = linkEvent.subject();
205 + print("%s %s\t%s/%s-%s/%s [%s]",
206 + new LocalDateTime(event.time()),
207 + event.type(),
208 + link.src().deviceId(), link.src().port(), link.dst().deviceId(), link.dst().port(),
209 + link);
210 +
211 + } else if (event instanceof HostEvent) {
212 + HostEvent hostEvent = (HostEvent) event;
213 + print("%s %s\t%s [%s->%s]",
214 + new LocalDateTime(event.time()),
215 + event.type(),
216 + hostEvent.subject().id(),
217 + hostEvent.prevSubject(), hostEvent.subject());
218 +
219 + } else if (event instanceof TopologyEvent) {
220 + TopologyEvent topoEvent = (TopologyEvent) event;
221 + List<Event> reasons = MoreObjects.firstNonNull(topoEvent.reasons(), ImmutableList.of());
222 + Topology topo = topoEvent.subject();
223 + String summary = String.format("(d=%d,l=%d,c=%d)",
224 + topo.deviceCount(),
225 + topo.linkCount(),
226 + topo.clusterCount());
227 + print("%s %s%s [%s]",
228 + new LocalDateTime(event.time()),
229 + event.type(),
230 + summary,
231 + reasons.stream().map(e -> e.type()).collect(toList()));
232 +
233 + } else if (event instanceof ClusterEvent) {
234 + print("%s %s\t%s [%s]",
235 + new LocalDateTime(event.time()),
236 + event.type(),
237 + ((ClusterEvent) event).subject().id(),
238 + event.subject());
239 +
240 + } else {
241 + // Unknown Event?
242 + print("%s %s\t%s [%s]",
243 + new LocalDateTime(event.time()),
244 + event.type(),
245 + event.subject(),
246 + event);
247 + }
248 + }
249 +
250 +}
1 +/*
2 + * Copyright 2016 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +/**
18 + * Application to store history of instance local ONOS Events.
19 + */
20 +package org.onosproject.events;
1 +<!--
2 + ~ Copyright 2016 Open Networking Laboratory
3 + ~
4 + ~ Licensed under the Apache License, Version 2.0 (the "License");
5 + ~ you may not use this file except in compliance with the License.
6 + ~ You may obtain a copy of the License at
7 + ~
8 + ~ http://www.apache.org/licenses/LICENSE-2.0
9 + ~
10 + ~ Unless required by applicable law or agreed to in writing, software
11 + ~ distributed under the License is distributed on an "AS IS" BASIS,
12 + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + ~ See the License for the specific language governing permissions and
14 + ~ limitations under the License.
15 + -->
16 +<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
17 +
18 + <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0">
19 + <command>
20 + <action class="org.onosproject.events.EventsCommand"/>
21 + </command>
22 + </command-bundle>
23 +
24 +</blueprint>
...@@ -63,6 +63,7 @@ ...@@ -63,6 +63,7 @@
63 <module>pathpainter</module> 63 <module>pathpainter</module>
64 <module>drivermatrix</module> 64 <module>drivermatrix</module>
65 <module>cpman</module> 65 <module>cpman</module>
66 + <module>events</module>
66 </modules> 67 </modules>
67 68
68 <properties> 69 <properties>
...@@ -107,3 +108,4 @@ ...@@ -107,3 +108,4 @@
107 </build> 108 </build>
108 109
109 </project> 110 </project>
111 +
......
1 +/*
2 + * Copyright 2016 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.event;
17 +
18 +import java.util.ArrayList;
19 +import java.util.List;
20 +
21 +import javax.annotation.concurrent.NotThreadSafe;
22 +
23 +import org.apache.commons.lang3.tuple.Pair;
24 +
25 +import com.google.common.annotations.Beta;
26 +import com.google.common.collect.Lists;
27 +
28 +/**
29 + * Utility to keeps track of registered Listeners.
30 + * <p>
31 + * Usage Example:
32 + * <pre>
33 + * <code>
34 + private ListenerTracker listeners;
35 +
36 + {@code @Activate}
37 + protected void activate() {
38 + listeners = new ListenerTracker();
39 + listeners.addListener(mastershipService, new InternalMastershipListener())
40 + .addListener(deviceService, new InternalDeviceListener())
41 + .addListener(linkService, new InternalLinkListener())
42 + .addListener(topologyService, new InternalTopologyListener())
43 + .addListener(hostService, new InternalHostListener());
44 + }
45 +
46 + {@code @Deactivate}
47 + protected void deactivate() {
48 + listeners.removeListeners();
49 + }
50 + * </code>
51 + * </pre>
52 + */
53 +@Beta
54 +@NotThreadSafe
55 +public class ListenerTracker {
56 +
57 + @SuppressWarnings("rawtypes")
58 + private List<Pair<ListenerService, EventListener>> listeners = new ArrayList<>();
59 +
60 + /**
61 + * Adds {@link EventListener} to specified {@link ListenerService}.
62 + *
63 + * @param service {@link ListenerService}
64 + * @param listener {@link EventListener}
65 + * @return self
66 + */
67 + public <E extends Event<?, ?>, L extends EventListener<E>>
68 + ListenerTracker addListener(ListenerService<E, L> service, L listener) {
69 + service.addListener(listener);
70 + listeners.add(Pair.of(service, listener));
71 + return this;
72 + }
73 +
74 + /**
75 + * Removes all listeners in reverse order they have been registered.
76 + */
77 + public void removeListeners() {
78 + Lists.reverse(listeners)
79 + .forEach(r -> r.getLeft().removeListener(r.getRight()));
80 + listeners.clear();
81 + }
82 +}
1 +/*
2 + * Copyright 2016 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onlab.util;
17 +
18 +import static com.google.common.base.Preconditions.checkNotNull;
19 +
20 +import java.util.Collection;
21 +import java.util.Deque;
22 +import java.util.Iterator;
23 +import java.util.Spliterator;
24 +import java.util.function.Consumer;
25 +import java.util.function.Predicate;
26 +import java.util.stream.Stream;
27 +import com.google.common.collect.Iterators;
28 +
29 +/**
30 + * Unmodifiable view of the specified Deque.
31 + */
32 +public class UnmodifiableDeque<E> implements Deque<E> {
33 +
34 + private final Deque<E> deque;
35 +
36 + UnmodifiableDeque(Deque<E> deque) {
37 + this.deque = checkNotNull(deque);
38 + }
39 +
40 + /**
41 + * Returns an unmodifiable view of the specified Deque.
42 + *
43 + * @param deque underlying {@link Deque} to use.
44 + * @return unmodifiable view of {@code deque}
45 + */
46 + public static <T> Deque<T> unmodifiableDeque(Deque<T> deque) {
47 + return new UnmodifiableDeque<T>(deque);
48 + }
49 +
50 + @Override
51 + public void forEach(Consumer<? super E> action) {
52 + deque.forEach(action);
53 + }
54 +
55 + @Override
56 + public void addFirst(E e) {
57 + throw new UnsupportedOperationException();
58 + }
59 +
60 + @Override
61 + public boolean isEmpty() {
62 + return deque.isEmpty();
63 + }
64 +
65 + @Override
66 + public void addLast(E e) {
67 + throw new UnsupportedOperationException();
68 + }
69 +
70 + @Override
71 + public Object[] toArray() {
72 + return deque.toArray();
73 + }
74 +
75 + @Override
76 + public boolean offerFirst(E e) {
77 + throw new UnsupportedOperationException();
78 + }
79 +
80 + @Override
81 + public <T> T[] toArray(T[] a) {
82 + return deque.toArray(a);
83 + }
84 +
85 + @Override
86 + public boolean offerLast(E e) {
87 + throw new UnsupportedOperationException();
88 + }
89 +
90 + @Override
91 + public E removeFirst() {
92 + throw new UnsupportedOperationException();
93 + }
94 +
95 + @Override
96 + public E removeLast() {
97 + throw new UnsupportedOperationException();
98 + }
99 +
100 + @Override
101 + public E pollFirst() {
102 + throw new UnsupportedOperationException();
103 + }
104 +
105 + @Override
106 + public E pollLast() {
107 + throw new UnsupportedOperationException();
108 + }
109 +
110 + @Override
111 + public E getFirst() {
112 + return deque.getFirst();
113 + }
114 +
115 + @Override
116 + public E getLast() {
117 + return deque.getLast();
118 + }
119 +
120 + @Override
121 + public E peekFirst() {
122 + return deque.peekFirst();
123 + }
124 +
125 + @Override
126 + public E peekLast() {
127 + return deque.peekLast();
128 + }
129 +
130 + @Override
131 + public boolean removeFirstOccurrence(Object o) {
132 + throw new UnsupportedOperationException();
133 + }
134 +
135 + @Override
136 + public boolean removeLastOccurrence(Object o) {
137 + throw new UnsupportedOperationException();
138 + }
139 +
140 + @Override
141 + public boolean containsAll(Collection<?> c) {
142 + return deque.containsAll(c);
143 + }
144 +
145 + @Override
146 + public boolean add(E e) {
147 + throw new UnsupportedOperationException();
148 + }
149 +
150 + @Override
151 + public boolean addAll(Collection<? extends E> c) {
152 + throw new UnsupportedOperationException();
153 + }
154 +
155 + @Override
156 + public boolean offer(E e) {
157 + throw new UnsupportedOperationException();
158 + }
159 +
160 + @Override
161 + public boolean removeAll(Collection<?> c) {
162 + throw new UnsupportedOperationException();
163 + }
164 +
165 + @Override
166 + public E remove() {
167 + throw new UnsupportedOperationException();
168 + }
169 +
170 + @Override
171 + public E poll() {
172 + throw new UnsupportedOperationException();
173 + }
174 +
175 + @Override
176 + public E element() {
177 + return deque.element();
178 + }
179 +
180 + @Override
181 + public boolean removeIf(Predicate<? super E> filter) {
182 + throw new UnsupportedOperationException();
183 + }
184 +
185 + @Override
186 + public E peek() {
187 + return deque.peek();
188 + }
189 +
190 + @Override
191 + public void push(E e) {
192 + throw new UnsupportedOperationException();
193 + }
194 +
195 + @Override
196 + public boolean retainAll(Collection<?> c) {
197 + throw new UnsupportedOperationException();
198 + }
199 +
200 + @Override
201 + public E pop() {
202 + throw new UnsupportedOperationException();
203 + }
204 +
205 + @Override
206 + public boolean remove(Object o) {
207 + throw new UnsupportedOperationException();
208 + }
209 +
210 + @Override
211 + public void clear() {
212 + throw new UnsupportedOperationException();
213 + }
214 +
215 + @Override
216 + public boolean equals(Object o) {
217 + return deque.equals(o);
218 + }
219 +
220 + @Override
221 + public boolean contains(Object o) {
222 + return deque.contains(o);
223 + }
224 +
225 + @Override
226 + public int size() {
227 + return deque.size();
228 + }
229 +
230 + @Override
231 + public Iterator<E> iterator() {
232 + return Iterators.unmodifiableIterator(deque.iterator());
233 + }
234 +
235 + @Override
236 + public Iterator<E> descendingIterator() {
237 + return Iterators.unmodifiableIterator(deque.descendingIterator());
238 + }
239 +
240 + @Override
241 + public int hashCode() {
242 + return deque.hashCode();
243 + }
244 +
245 + @Override
246 + public Spliterator<E> spliterator() {
247 + return deque.spliterator();
248 + }
249 +
250 + @Override
251 + public Stream<E> stream() {
252 + return deque.stream();
253 + }
254 +
255 + @Override
256 + public Stream<E> parallelStream() {
257 + return deque.parallelStream();
258 + }
259 +
260 + @Override
261 + public String toString() {
262 + return deque.toString();
263 + }
264 +}