Committed by
Gerrit Code Review
ONOS-1235 Enhanced UI extension mechanism to provide message handler factory and…
… took a first cut at the core UiWebSocket mechanism. Change-Id: Iaad080c5371c3aa5e24a23489b1679d373ec0720
Showing
10 changed files
with
465 additions
and
10 deletions
... | @@ -55,6 +55,10 @@ | ... | @@ -55,6 +55,10 @@ |
55 | <artifactId>easymock</artifactId> | 55 | <artifactId>easymock</artifactId> |
56 | <scope>test</scope> | 56 | <scope>test</scope> |
57 | </dependency> | 57 | </dependency> |
58 | + <dependency> | ||
59 | + <groupId>org.onosproject</groupId> | ||
60 | + <artifactId>onlab-osgi</artifactId> | ||
61 | + </dependency> | ||
58 | </dependencies> | 62 | </dependencies> |
59 | 63 | ||
60 | </project> | 64 | </project> | ... | ... |
1 | +/* | ||
2 | + * Copyright 2015 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.ui; | ||
17 | + | ||
18 | +import com.fasterxml.jackson.databind.node.ObjectNode; | ||
19 | + | ||
20 | +/** | ||
21 | + * Abstraction of a user interface session connection. | ||
22 | + */ | ||
23 | +public interface UiConnection { | ||
24 | + | ||
25 | + /** | ||
26 | + * Sends the specified JSON message to the user interface client. | ||
27 | + * | ||
28 | + * @param message message to send | ||
29 | + */ | ||
30 | + void sendMessage(ObjectNode message); | ||
31 | + | ||
32 | +} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
... | @@ -32,16 +32,20 @@ public class UiExtension { | ... | @@ -32,16 +32,20 @@ public class UiExtension { |
32 | private final String prefix; | 32 | private final String prefix; |
33 | private final ClassLoader classLoader; | 33 | private final ClassLoader classLoader; |
34 | private final List<UiView> views; | 34 | private final List<UiView> views; |
35 | + private final UiMessageHandlerFactory messageHandlerFactory; | ||
35 | 36 | ||
36 | /** | 37 | /** |
37 | * Creates a user interface extension for loading CSS and JS injections | 38 | * Creates a user interface extension for loading CSS and JS injections |
38 | * from {@code css.html} and {@code js.html} resources, respectively. | 39 | * from {@code css.html} and {@code js.html} resources, respectively. |
39 | * | 40 | * |
40 | * @param views list of contributed views | 41 | * @param views list of contributed views |
42 | + * @param messageHandlerFactory optional message handler factory | ||
41 | * @param classLoader class-loader for user interface resources | 43 | * @param classLoader class-loader for user interface resources |
42 | */ | 44 | */ |
43 | - public UiExtension(List<UiView> views, ClassLoader classLoader) { | 45 | + public UiExtension(List<UiView> views, |
44 | - this(views, null, classLoader); | 46 | + UiMessageHandlerFactory messageHandlerFactory, |
47 | + ClassLoader classLoader) { | ||
48 | + this(views, messageHandlerFactory, null, classLoader); | ||
45 | } | 49 | } |
46 | 50 | ||
47 | /** | 51 | /** |
... | @@ -50,11 +54,15 @@ public class UiExtension { | ... | @@ -50,11 +54,15 @@ public class UiExtension { |
50 | * {@code prefix/js.html} resources, respectively. | 54 | * {@code prefix/js.html} resources, respectively. |
51 | * | 55 | * |
52 | * @param views list of user interface views | 56 | * @param views list of user interface views |
57 | + * @param messageHandlerFactory optional message handler factory | ||
53 | * @param path resource path prefix | 58 | * @param path resource path prefix |
54 | * @param classLoader class-loader for user interface resources | 59 | * @param classLoader class-loader for user interface resources |
55 | */ | 60 | */ |
56 | - public UiExtension(List<UiView> views, String path, ClassLoader classLoader) { | 61 | + public UiExtension(List<UiView> views, |
62 | + UiMessageHandlerFactory messageHandlerFactory, | ||
63 | + String path, ClassLoader classLoader) { | ||
57 | this.views = checkNotNull(ImmutableList.copyOf(views), "Views cannot be null"); | 64 | this.views = checkNotNull(ImmutableList.copyOf(views), "Views cannot be null"); |
65 | + this.messageHandlerFactory = messageHandlerFactory; | ||
58 | this.prefix = path != null ? (path + "/") : ""; | 66 | this.prefix = path != null ? (path + "/") : ""; |
59 | this.classLoader = checkNotNull(classLoader, "Class loader must be specified"); | 67 | this.classLoader = checkNotNull(classLoader, "Class loader must be specified"); |
60 | } | 68 | } |
... | @@ -98,4 +106,12 @@ public class UiExtension { | ... | @@ -98,4 +106,12 @@ public class UiExtension { |
98 | return is; | 106 | return is; |
99 | } | 107 | } |
100 | 108 | ||
109 | + /** | ||
110 | + * Returns message handler factory. | ||
111 | + * | ||
112 | + * @return message handlers | ||
113 | + */ | ||
114 | + public UiMessageHandlerFactory messageHandlerFactory() { | ||
115 | + return messageHandlerFactory; | ||
116 | + } | ||
101 | } | 117 | } | ... | ... |
1 | +/* | ||
2 | + * Copyright 2015 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.ui; | ||
17 | + | ||
18 | +import com.fasterxml.jackson.databind.node.ObjectNode; | ||
19 | +import org.onlab.osgi.ServiceDirectory; | ||
20 | + | ||
21 | +import java.util.Set; | ||
22 | + | ||
23 | +import static com.google.common.base.Preconditions.checkArgument; | ||
24 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
25 | + | ||
26 | +/** | ||
27 | + * Abstraction of an entity capable of processing a JSON message from the user | ||
28 | + * interface client. | ||
29 | + * <p> | ||
30 | + * The message is a JSON object with the following structure: | ||
31 | + * <pre> | ||
32 | + * { | ||
33 | + * "type": "<em>event-type</em>", | ||
34 | + * "sid": "<em>sequence-number</em>", | ||
35 | + * "payload": { | ||
36 | + * <em>arbitrary JSON object structure</em> | ||
37 | + * } | ||
38 | + * } | ||
39 | + * </pre> | ||
40 | + */ | ||
41 | +public abstract class UiMessageHandler { | ||
42 | + | ||
43 | + private final Set<String> messageTypes; | ||
44 | + private UiConnection connection; | ||
45 | + private ServiceDirectory directory; | ||
46 | + | ||
47 | + /** | ||
48 | + * Creates a new message handler for the specified set of message types. | ||
49 | + * | ||
50 | + * @param messageTypes set of message types | ||
51 | + */ | ||
52 | + protected UiMessageHandler(Set<String> messageTypes) { | ||
53 | + this.messageTypes = checkNotNull(messageTypes, "Message types cannot be null"); | ||
54 | + checkArgument(!messageTypes.isEmpty(), "Message types cannot be empty"); | ||
55 | + } | ||
56 | + | ||
57 | + /** | ||
58 | + * Returns the set of message types which this handler is capable of | ||
59 | + * processing. | ||
60 | + * | ||
61 | + * @return set of message types | ||
62 | + */ | ||
63 | + public Set<String> messageTypes() { | ||
64 | + return messageTypes; | ||
65 | + } | ||
66 | + | ||
67 | + /** | ||
68 | + * Processes a JSON message from the user interface client. | ||
69 | + * | ||
70 | + * @param message JSON message | ||
71 | + */ | ||
72 | + public abstract void process(ObjectNode message); | ||
73 | + | ||
74 | + /** | ||
75 | + * Initializes the handler with the user interface connection and | ||
76 | + * service directory context. | ||
77 | + * | ||
78 | + * @param connection user interface connection | ||
79 | + * @param directory service directory | ||
80 | + */ | ||
81 | + public void init(UiConnection connection, ServiceDirectory directory) { | ||
82 | + this.connection = connection; | ||
83 | + this.directory = directory; | ||
84 | + } | ||
85 | + | ||
86 | + /** | ||
87 | + * Destroys the message handler context. | ||
88 | + */ | ||
89 | + public void destroy() { | ||
90 | + this.connection = null; | ||
91 | + this.directory = null; | ||
92 | + } | ||
93 | + | ||
94 | + /** | ||
95 | + * Returns the user interface connection with which this handler was primed. | ||
96 | + * | ||
97 | + * @return user interface connection | ||
98 | + */ | ||
99 | + public UiConnection connection() { | ||
100 | + return connection; | ||
101 | + } | ||
102 | + | ||
103 | + /** | ||
104 | + * Returns the user interface connection with which this handler was primed. | ||
105 | + * | ||
106 | + * @return user interface connection | ||
107 | + */ | ||
108 | + public ServiceDirectory directory() { | ||
109 | + return directory; | ||
110 | + } | ||
111 | + | ||
112 | + /** | ||
113 | + * Returns implementation of the specified service class. | ||
114 | + * | ||
115 | + * @param serviceClass service class | ||
116 | + * @param <T> type of service | ||
117 | + * @return implementation class | ||
118 | + * @throws org.onlab.osgi.ServiceNotFoundException if no implementation found | ||
119 | + */ | ||
120 | + protected <T> T get(Class<T> serviceClass) { | ||
121 | + return directory.get(serviceClass); | ||
122 | + } | ||
123 | + | ||
124 | +} |
1 | +/* | ||
2 | + * Copyright 2015 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.ui; | ||
17 | + | ||
18 | +import java.util.Collection; | ||
19 | + | ||
20 | +/** | ||
21 | + * Abstraction of an entity capable of producing a set of message handlers | ||
22 | + * specific to the given user interface connection. | ||
23 | + */ | ||
24 | +public interface UiMessageHandlerFactory { | ||
25 | + | ||
26 | + /** | ||
27 | + * Produces a collection of new message handlers. | ||
28 | + * | ||
29 | + * @return collection of new handlers | ||
30 | + */ | ||
31 | + Collection<UiMessageHandler> newHandlers(); | ||
32 | + | ||
33 | +} |
... | @@ -21,8 +21,7 @@ import org.junit.Test; | ... | @@ -21,8 +21,7 @@ import org.junit.Test; |
21 | import java.io.IOException; | 21 | import java.io.IOException; |
22 | 22 | ||
23 | import static com.google.common.io.ByteStreams.toByteArray; | 23 | import static com.google.common.io.ByteStreams.toByteArray; |
24 | -import static org.junit.Assert.assertEquals; | 24 | +import static org.junit.Assert.*; |
25 | -import static org.junit.Assert.assertTrue; | ||
26 | 25 | ||
27 | /** | 26 | /** |
28 | * Tests the default user interface extension descriptor. | 27 | * Tests the default user interface extension descriptor. |
... | @@ -32,22 +31,25 @@ public class UiExtensionTest { | ... | @@ -32,22 +31,25 @@ public class UiExtensionTest { |
32 | @Test | 31 | @Test |
33 | public void basics() throws IOException { | 32 | public void basics() throws IOException { |
34 | UiExtension ext = new UiExtension(ImmutableList.of(new UiView("foo", "Foo View")), | 33 | UiExtension ext = new UiExtension(ImmutableList.of(new UiView("foo", "Foo View")), |
34 | + null, | ||
35 | getClass().getClassLoader()); | 35 | getClass().getClassLoader()); |
36 | String css = new String(toByteArray(ext.css())); | 36 | String css = new String(toByteArray(ext.css())); |
37 | assertTrue("incorrect css stream", css.contains("foo-css")); | 37 | assertTrue("incorrect css stream", css.contains("foo-css")); |
38 | String js = new String(toByteArray(ext.js())); | 38 | String js = new String(toByteArray(ext.js())); |
39 | assertTrue("incorrect js stream", js.contains("foo-js")); | 39 | assertTrue("incorrect js stream", js.contains("foo-js")); |
40 | assertEquals("incorrect views stream", "foo", ext.views().get(0).id()); | 40 | assertEquals("incorrect views stream", "foo", ext.views().get(0).id()); |
41 | + assertNull("incorrect handler factory", ext.messageHandlerFactory()); | ||
41 | } | 42 | } |
42 | 43 | ||
43 | @Test | 44 | @Test |
44 | public void withPath() throws IOException { | 45 | public void withPath() throws IOException { |
45 | UiExtension ext = new UiExtension(ImmutableList.of(new UiView("foo", "Foo View")), | 46 | UiExtension ext = new UiExtension(ImmutableList.of(new UiView("foo", "Foo View")), |
46 | - "custom", getClass().getClassLoader()); | 47 | + null, "custom", getClass().getClassLoader()); |
47 | String css = new String(toByteArray(ext.css())); | 48 | String css = new String(toByteArray(ext.css())); |
48 | assertTrue("incorrect css stream", css.contains("custom-css")); | 49 | assertTrue("incorrect css stream", css.contains("custom-css")); |
49 | String js = new String(toByteArray(ext.js())); | 50 | String js = new String(toByteArray(ext.js())); |
50 | assertTrue("incorrect js stream", js.contains("custom-js")); | 51 | assertTrue("incorrect js stream", js.contains("custom-js")); |
51 | assertEquals("incorrect views stream", "foo", ext.views().get(0).id()); | 52 | assertEquals("incorrect views stream", "foo", ext.views().get(0).id()); |
53 | + assertNull("incorrect handler factory", ext.messageHandlerFactory()); | ||
52 | } | 54 | } |
53 | } | 55 | } |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
... | @@ -23,6 +23,7 @@ public interface ServiceDirectory { | ... | @@ -23,6 +23,7 @@ public interface ServiceDirectory { |
23 | 23 | ||
24 | /** | 24 | /** |
25 | * Returns implementation of the specified service class. | 25 | * Returns implementation of the specified service class. |
26 | + * | ||
26 | * @param serviceClass service class | 27 | * @param serviceClass service class |
27 | * @param <T> type of service | 28 | * @param <T> type of service |
28 | * @return implementation class | 29 | * @return implementation class | ... | ... |
... | @@ -24,6 +24,7 @@ import org.apache.felix.scr.annotations.Deactivate; | ... | @@ -24,6 +24,7 @@ import org.apache.felix.scr.annotations.Deactivate; |
24 | import org.apache.felix.scr.annotations.Service; | 24 | import org.apache.felix.scr.annotations.Service; |
25 | import org.onosproject.ui.UiExtension; | 25 | import org.onosproject.ui.UiExtension; |
26 | import org.onosproject.ui.UiExtensionService; | 26 | import org.onosproject.ui.UiExtensionService; |
27 | +import org.onosproject.ui.UiMessageHandlerFactory; | ||
27 | import org.onosproject.ui.UiView; | 28 | import org.onosproject.ui.UiView; |
28 | import org.slf4j.Logger; | 29 | import org.slf4j.Logger; |
29 | import org.slf4j.LoggerFactory; | 30 | import org.slf4j.LoggerFactory; |
... | @@ -50,12 +51,18 @@ public class UiExtensionManager implements UiExtensionService { | ... | @@ -50,12 +51,18 @@ public class UiExtensionManager implements UiExtensionService { |
50 | private final Map<String, UiExtension> views = Maps.newHashMap(); | 51 | private final Map<String, UiExtension> views = Maps.newHashMap(); |
51 | 52 | ||
52 | // Core views & core extension | 53 | // Core views & core extension |
53 | - private final List<UiView> coreViews = of(new UiView("sample", "Sample"), | 54 | + private final UiExtension core = createCoreExtension(); |
55 | + | ||
56 | + | ||
57 | + // Creates core UI extension | ||
58 | + private static UiExtension createCoreExtension() { | ||
59 | + List<UiView> coreViews = of(new UiView("sample", "Sample"), | ||
54 | new UiView("topo", "Topology View"), | 60 | new UiView("topo", "Topology View"), |
55 | new UiView("device", "Devices")); | 61 | new UiView("device", "Devices")); |
56 | - | 62 | + UiMessageHandlerFactory messageHandlerFactory = null; |
57 | - private final UiExtension core = new UiExtension(coreViews, "core", | 63 | + return new UiExtension(coreViews, messageHandlerFactory, "core", |
58 | - getClass().getClassLoader()); | 64 | + UiExtensionManager.class.getClassLoader()); |
65 | + } | ||
59 | 66 | ||
60 | @Activate | 67 | @Activate |
61 | public void activate() { | 68 | public void activate() { | ... | ... |
1 | +/* | ||
2 | + * Copyright 2015 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.ui.impl; | ||
17 | + | ||
18 | +import com.fasterxml.jackson.databind.ObjectMapper; | ||
19 | +import com.fasterxml.jackson.databind.node.ObjectNode; | ||
20 | +import org.eclipse.jetty.websocket.WebSocket; | ||
21 | +import org.onlab.osgi.ServiceDirectory; | ||
22 | +import org.onosproject.ui.UiConnection; | ||
23 | +import org.onosproject.ui.UiExtensionService; | ||
24 | +import org.onosproject.ui.UiMessageHandler; | ||
25 | +import org.slf4j.Logger; | ||
26 | +import org.slf4j.LoggerFactory; | ||
27 | + | ||
28 | +import java.io.IOException; | ||
29 | +import java.util.HashMap; | ||
30 | +import java.util.Map; | ||
31 | + | ||
32 | +/** | ||
33 | + * Web socket capable of interacting with the GUI. | ||
34 | + */ | ||
35 | +public class UiWebSocket | ||
36 | + implements UiConnection, WebSocket.OnTextMessage, WebSocket.OnControl { | ||
37 | + | ||
38 | + private static final Logger log = LoggerFactory.getLogger(UiWebSocket.class); | ||
39 | + | ||
40 | + private static final long MAX_AGE_MS = 15000; | ||
41 | + | ||
42 | + private static final byte PING = 0x9; | ||
43 | + private static final byte PONG = 0xA; | ||
44 | + private static final byte[] PING_DATA = new byte[]{(byte) 0xde, (byte) 0xad}; | ||
45 | + | ||
46 | + private final ServiceDirectory directory; | ||
47 | + | ||
48 | + private Connection connection; | ||
49 | + private FrameConnection control; | ||
50 | + | ||
51 | + private final ObjectMapper mapper = new ObjectMapper(); | ||
52 | + | ||
53 | + private long lastActive = System.currentTimeMillis(); | ||
54 | + | ||
55 | + private Map<String, UiMessageHandler> handlers; | ||
56 | + | ||
57 | + /** | ||
58 | + * Creates a new web-socket for serving data to GUI. | ||
59 | + * | ||
60 | + * @param directory service directory | ||
61 | + */ | ||
62 | + public UiWebSocket(ServiceDirectory directory) { | ||
63 | + this.directory = directory; | ||
64 | + } | ||
65 | + | ||
66 | + /** | ||
67 | + * Issues a close on the connection. | ||
68 | + */ | ||
69 | + synchronized void close() { | ||
70 | + destroyHandlers(); | ||
71 | + if (connection.isOpen()) { | ||
72 | + connection.close(); | ||
73 | + } | ||
74 | + } | ||
75 | + | ||
76 | + /** | ||
77 | + * Indicates if this connection is idle. | ||
78 | + * | ||
79 | + * @return true if idle or closed | ||
80 | + */ | ||
81 | + synchronized boolean isIdle() { | ||
82 | + boolean idle = (System.currentTimeMillis() - lastActive) > MAX_AGE_MS; | ||
83 | + if (idle || (connection != null && !connection.isOpen())) { | ||
84 | + return true; | ||
85 | + } else if (connection != null) { | ||
86 | + try { | ||
87 | + control.sendControl(PING, PING_DATA, 0, PING_DATA.length); | ||
88 | + } catch (IOException e) { | ||
89 | + log.warn("Unable to send ping message due to: ", e); | ||
90 | + } | ||
91 | + } | ||
92 | + return false; | ||
93 | + } | ||
94 | + | ||
95 | + @Override | ||
96 | + public void onOpen(Connection connection) { | ||
97 | + log.info("GUI client connected"); | ||
98 | + this.connection = connection; | ||
99 | + this.control = (FrameConnection) connection; | ||
100 | + createHandlers(); | ||
101 | + } | ||
102 | + | ||
103 | + @Override | ||
104 | + public synchronized void onClose(int closeCode, String message) { | ||
105 | + destroyHandlers(); | ||
106 | + log.info("GUI client disconnected"); | ||
107 | + } | ||
108 | + | ||
109 | + @Override | ||
110 | + public boolean onControl(byte controlCode, byte[] data, int offset, int length) { | ||
111 | + lastActive = System.currentTimeMillis(); | ||
112 | + return true; | ||
113 | + } | ||
114 | + | ||
115 | + @Override | ||
116 | + public void onMessage(String data) { | ||
117 | + lastActive = System.currentTimeMillis(); | ||
118 | + try { | ||
119 | + ObjectNode message = (ObjectNode) mapper.reader().readTree(data); | ||
120 | + String type = message.path("type").asText("unknown"); | ||
121 | + UiMessageHandler handler = handlers.get(type); | ||
122 | + if (handler != null) { | ||
123 | + handler.process(message); | ||
124 | + } else { | ||
125 | + log.warn("No GUI message handler for type {}", type); | ||
126 | + } | ||
127 | + } catch (Exception e) { | ||
128 | + log.warn("Unable to parse GUI message {} due to {}", data, e); | ||
129 | + log.debug("Boom!!!", e); | ||
130 | + } | ||
131 | + } | ||
132 | + | ||
133 | + @Override | ||
134 | + public void sendMessage(ObjectNode message) { | ||
135 | + try { | ||
136 | + if (connection.isOpen()) { | ||
137 | + connection.sendMessage(message.toString()); | ||
138 | + } | ||
139 | + } catch (IOException e) { | ||
140 | + log.warn("Unable to send message {} to GUI due to {}", message, e); | ||
141 | + log.debug("Boom!!!", e); | ||
142 | + } | ||
143 | + } | ||
144 | + | ||
145 | + // Creates new message handlers. | ||
146 | + private void createHandlers() { | ||
147 | + handlers = new HashMap<>(); | ||
148 | + UiExtensionService service = directory.get(UiExtensionService.class); | ||
149 | + service.getExtensions().forEach(ext -> ext.messageHandlerFactory().newHandlers().forEach(handler -> { | ||
150 | + handler.init(this, directory); | ||
151 | + handler.messageTypes().forEach(type -> handlers.put(type, handler)); | ||
152 | + })); | ||
153 | + } | ||
154 | + | ||
155 | + // Destroys message handlers. | ||
156 | + private synchronized void destroyHandlers() { | ||
157 | + handlers.forEach((type, handler) -> handler.destroy()); | ||
158 | + handlers.clear(); | ||
159 | + } | ||
160 | +} | ||
161 | + |
1 | +/* | ||
2 | + * Copyright 2015 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.ui.impl; | ||
17 | + | ||
18 | +import org.eclipse.jetty.websocket.WebSocket; | ||
19 | +import org.eclipse.jetty.websocket.WebSocketServlet; | ||
20 | +import org.onlab.osgi.DefaultServiceDirectory; | ||
21 | +import org.onlab.osgi.ServiceDirectory; | ||
22 | + | ||
23 | +import javax.servlet.ServletException; | ||
24 | +import javax.servlet.http.HttpServletRequest; | ||
25 | +import java.util.HashSet; | ||
26 | +import java.util.Iterator; | ||
27 | +import java.util.Set; | ||
28 | +import java.util.Timer; | ||
29 | +import java.util.TimerTask; | ||
30 | + | ||
31 | +/** | ||
32 | + * Web socket servlet capable of creating web sockets for the user interface. | ||
33 | + */ | ||
34 | +public class UiWebSocketServlet extends WebSocketServlet { | ||
35 | + | ||
36 | + private static final long PING_DELAY_MS = 5000; | ||
37 | + | ||
38 | + private ServiceDirectory directory = new DefaultServiceDirectory(); | ||
39 | + | ||
40 | + private final Set<UiWebSocket> sockets = new HashSet<>(); | ||
41 | + private final Timer timer = new Timer(); | ||
42 | + private final TimerTask pruner = new Pruner(); | ||
43 | + | ||
44 | + @Override | ||
45 | + public void init() throws ServletException { | ||
46 | + super.init(); | ||
47 | + timer.schedule(pruner, PING_DELAY_MS, PING_DELAY_MS); | ||
48 | + } | ||
49 | + | ||
50 | + @Override | ||
51 | + public WebSocket doWebSocketConnect(HttpServletRequest request, String protocol) { | ||
52 | + UiWebSocket socket = new UiWebSocket(directory); | ||
53 | + synchronized (sockets) { | ||
54 | + sockets.add(socket); | ||
55 | + } | ||
56 | + return socket; | ||
57 | + } | ||
58 | + | ||
59 | + // Task for pruning web-sockets that are idle. | ||
60 | + private class Pruner extends TimerTask { | ||
61 | + @Override | ||
62 | + public void run() { | ||
63 | + synchronized (sockets) { | ||
64 | + Iterator<UiWebSocket> it = sockets.iterator(); | ||
65 | + while (it.hasNext()) { | ||
66 | + UiWebSocket socket = it.next(); | ||
67 | + if (socket.isIdle()) { | ||
68 | + it.remove(); | ||
69 | + socket.close(); | ||
70 | + } | ||
71 | + } | ||
72 | + } | ||
73 | + } | ||
74 | + } | ||
75 | +} |
-
Please register or login to post a comment