2 * ============LICENSE_START========================================================================
3 * ONAP : ccsdk feature sdnr wt
4 * =================================================================================================
5 * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
6 * =================================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
8 * in compliance with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software distributed under the License
13 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14 * or implied. See the License for the specific language governing permissions and limitations under
16 * ============LICENSE_END==========================================================================
18 package org.onap.ccsdk.features.sdnr.wt.websocketmanager;
20 import com.fasterxml.jackson.core.JsonProcessingException;
21 import java.util.ArrayList;
22 import java.util.HashMap;
23 import java.util.List;
25 import java.util.Map.Entry;
26 import java.util.Random;
28 import java.util.regex.Matcher;
29 import java.util.regex.Pattern;
30 import org.eclipse.jetty.websocket.api.Session;
31 import org.eclipse.jetty.websocket.api.WebSocketAdapter;
32 import org.onap.ccsdk.features.sdnr.wt.websocketmanager.model.data.NotificationOutput;
33 import org.onap.ccsdk.features.sdnr.wt.websocketmanager.model.data.ReducedSchemaInfo;
34 import org.onap.ccsdk.features.sdnr.wt.websocketmanager.model.data.ScopeRegistration;
35 import org.onap.ccsdk.features.sdnr.wt.websocketmanager.model.data.ScopeRegistration.DataType;
36 import org.onap.ccsdk.features.sdnr.wt.websocketmanager.model.data.ScopeRegistrationResponse;
37 import org.onap.ccsdk.features.sdnr.wt.websocketmanager.utils.UserScopes;
38 import org.onap.ccsdk.features.sdnr.wt.yang.mapper.YangToolsMapper;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
42 public class WebSocketManagerSocket extends WebSocketAdapter {
44 private static final Logger LOG = LoggerFactory.getLogger(WebSocketManagerSocket.class.getName());
45 public static final String MSG_KEY_DATA = "data";
46 public static final DataType MSG_KEY_SCOPES = DataType.scopes;
47 public static final String MSG_KEY_PARAM = "param";
48 public static final String MSG_KEY_VALUE = "value";
49 public static final String MSG_KEY_SCOPE = "scope";
51 public static final String KEY_NODEID = "nodeId";
52 public static final String KEY_EVENTTYPE = "eventType";
53 private static final String REGEX_SCOPEREGISTRATION = "\"data\"[\\s]*:[\\s]*\"scopes\"";
54 private static final Pattern PATTERN_SCOPEREGISTRATION =
55 Pattern.compile(REGEX_SCOPEREGISTRATION, Pattern.MULTILINE);
56 private static final Random RND = new Random();
60 * list of all sessionids
62 private static final List<String> sessionIds = new ArrayList<>();
64 * map of sessionid <=> UserScopes
66 private static final HashMap<String, UserScopes> userScopesList = new HashMap<>();
68 * map of class.hashCode <=> class
70 private static final HashMap<String, WebSocketManagerSocket> clientList = new HashMap<>();
72 private static final YangToolsMapper mapper = new YangToolsMapper();
73 private final String myUniqueSessionId;
75 private Session session = null;
77 public interface EventInputCallback {
78 void onMessagePushed(final String message) throws Exception;
81 public WebSocketManagerSocket() {
82 this.myUniqueSessionId = _genSessionId();
86 protected void finalize() throws Throwable {
87 sessionIds.remove(this.myUniqueSessionId);
90 private static String _genSessionId() {
91 String sid = String.valueOf(RND.nextLong());
92 while (sessionIds.contains(sid)) {
93 sid = String.valueOf(RND.nextLong());
100 public void onWebSocketText(String message) {
101 LOG.info("{} has sent {}", this.getRemoteAdr(), message);
102 if (!this.manageClientRequest(message)) {
103 this.manageClientRequest2(message);
108 public void onWebSocketBinary(byte[] payload, int offset, int len) {
109 LOG.debug("Binary not supported");
113 public void onWebSocketConnect(Session sess) {
115 clientList.put(String.valueOf(this.hashCode()), this);
116 LOG.debug("client connected from " + this.getRemoteAdr());
120 public void onWebSocketClose(int statusCode, String reason) {
121 clientList.remove(String.valueOf(this.hashCode()));
122 LOG.debug("client disconnected from " + this.getRemoteAdr());
126 public void onWebSocketError(Throwable cause) {
127 LOG.debug("error caused on " + this.getRemoteAdr() + " :" + cause.getMessage());
128 // super.onWebSocketError(cause);
131 private String getRemoteAdr() {
132 String adr = "unknown";
134 adr = this.session.getRemoteAddress().toString();
135 } catch (Exception e) {
136 LOG.debug("error resolving adr: {}", e.getMessage());
143 * @param request is a json object {"data":"scopes","scopes":["scope1","scope2",...]}
146 private boolean manageClientRequest(String request) {
148 final Matcher matcher = PATTERN_SCOPEREGISTRATION.matcher(request);
149 if(!matcher.find()) {
153 ScopeRegistration registration = mapper.readValue(request, ScopeRegistration.class);
154 if (registration!=null && registration.validate() && registration.isType(MSG_KEY_SCOPES)) {
156 String sessionId = this.getSessionId();
157 UserScopes clientDto = new UserScopes();
158 clientDto.setScopes(registration.getScopes());
159 userScopesList.put(sessionId, clientDto);
160 this.send(mapper.writeValueAsString(ScopeRegistrationResponse.success(registration.getScopes())));
163 } catch (JsonProcessingException e) {
164 LOG.warn("problem set scope: " + e.getMessage());
166 this.send(mapper.writeValueAsString(ScopeRegistrationResponse.error(e.getMessage())));
167 } catch (JsonProcessingException e1) {
168 LOG.warn("problem sending error response via ws: " + e1);
175 * broadcast message to all your clients
177 private void manageClientRequest2(String request) {
179 NotificationOutput notification = mapper.readValue(request, NotificationOutput.class);
180 if (notification.getNodeId() != null && notification.getType() != null) {
181 this.sendToAll(notification.getNodeId(), notification.getType(), request);
183 } catch (Exception e) {
184 LOG.warn("handle ws request failed:" + e.getMessage());
188 public void send(String msg) {
190 LOG.trace("sending {}", msg);
191 this.session.getRemote().sendString(msg);
192 } catch (Exception e) {
193 LOG.warn("problem sending message: " + e.getMessage());
197 public String getSessionId() {
198 return this.myUniqueSessionId;
201 private void sendToAll(NotificationOutput output) {
203 this.sendToAll(output.getNodeId(), output.getType(), mapper.writeValueAsString(output));
204 } catch (JsonProcessingException e) {
205 LOG.warn("problem serializing noitifcation: ", e);
209 private void sendToAll(String nodeId, ReducedSchemaInfo reducedSchemaInfo, String notification) {
210 if (clientList.size() > 0) {
211 for (Map.Entry<String, WebSocketManagerSocket> entry : clientList.entrySet()) {
212 WebSocketManagerSocket socket = entry.getValue();
213 if (socket != null) {
215 UserScopes clientScopes = userScopesList.get(socket.getSessionId());
216 if (clientScopes != null) {
217 if (clientScopes.hasScope(nodeId, reducedSchemaInfo)) {
218 socket.send(notification);
220 LOG.debug("client has not scope {}", reducedSchemaInfo);
223 LOG.debug("no scopes for notifications registered");
225 } catch (Exception ioe) {
226 LOG.warn(ioe.getMessage());
229 LOG.debug("cannot broadcast. socket is null");
235 public static void broadCast(NotificationOutput output) {
236 if (clientList.size() > 0) {
237 Set<Entry<String, WebSocketManagerSocket>> e = clientList.entrySet();
238 WebSocketManagerSocket s = e.iterator().next().getValue();