/* * Copyright 2015 Open Networking Laboratory * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.onosproject.ui; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; import org.onlab.osgi.ServiceDirectory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Set; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; /** * Abstraction of an entity capable of processing JSON messages from the user * interface client. *

* The message structure is: *

*
 * {
 *     "type": "event-type",
 *     "payload": {
 *         arbitrary JSON object structure
 *     }
 * }
 * 
* On {@link #init initialization} the handler will create and cache * {@link RequestHandler} instances, each of which are bound to a particular * event-type. On {@link #process arrival} of a new message, * the event-type is determined, and the message dispatched to the * corresponding RequestHandler's * {@link RequestHandler#process process} method. */ public abstract class UiMessageHandler { private final Logger log = LoggerFactory.getLogger(getClass()); private final Map handlerMap = new HashMap<>(); private final ObjectMapper mapper = new ObjectMapper(); private UiConnection connection; private ServiceDirectory directory; /** * Subclasses must create and return the collection of request handlers * for the message types they handle. *

* Note that request handlers should be stateless. When we are * {@link #destroy destroyed}, we will simply drop our references to them * and allow them to be garbage collected. * * @return the message handler instances */ protected abstract Collection createRequestHandlers(); /** * Returns the set of message types which this handler is capable of * processing. * * @return set of message types */ public Set messageTypes() { return Collections.unmodifiableSet(handlerMap.keySet()); } /** * Processes a JSON message from the user interface client. * * @param message JSON message */ public void process(ObjectNode message) { String type = JsonUtils.eventType(message); ObjectNode payload = JsonUtils.payload(message); // TODO: remove sid exec(type, 0, payload); } /** * Finds the appropriate handler and executes the process method. * * @param eventType event type * @param sid sequence identifier * @param payload message payload */ // TODO: remove sid from signature void exec(String eventType, long sid, ObjectNode payload) { RequestHandler requestHandler = handlerMap.get(eventType); if (requestHandler != null) { requestHandler.process(sid, payload); } else { log.warn("no request handler for event type {}", eventType); } } /** * Initializes the handler with the user interface connection and * service directory context. * * @param connection user interface connection * @param directory service directory */ public void init(UiConnection connection, ServiceDirectory directory) { this.connection = connection; this.directory = directory; Collection handlers = createRequestHandlers(); checkNotNull(handlers, "Handlers cannot be null"); checkArgument(!handlers.isEmpty(), "Handlers cannot be empty"); for (RequestHandler h : handlers) { h.setParent(this); handlerMap.put(h.eventType(), h); } } /** * Destroys the message handler context. */ public void destroy() { this.connection = null; this.directory = null; handlerMap.clear(); } /** * Returns the user interface connection with which this handler was primed. * * @return user interface connection */ public UiConnection connection() { return connection; } /** * Returns the user interface connection with which this handler was primed. * * @return user interface connection */ public ServiceDirectory directory() { return directory; } /** * Returns implementation of the specified service class. * * @param serviceClass service class * @param type of service * @return implementation class * @throws org.onlab.osgi.ServiceNotFoundException if no implementation found */ protected T get(Class serviceClass) { return directory.get(serviceClass); } /** * Returns a freshly minted object node. * * @return new object node */ protected ObjectNode objectNode() { return mapper.createObjectNode(); } /** * Returns a freshly minted array node. * * @return new array node */ protected ArrayNode arrayNode() { return mapper.createArrayNode(); } /** * Sends the specified data to the client. * It is expected that the data is in the prescribed JSON format for * events to the client. * * @param data data to be sent */ protected synchronized void sendMessage(ObjectNode data) { UiConnection connection = connection(); if (connection != null) { connection.sendMessage(data); } } }