summaryrefslogtreecommitdiffstats
path: root/sdnr/wt/websocketmanager2/provider/src
diff options
context:
space:
mode:
Diffstat (limited to 'sdnr/wt/websocketmanager2/provider/src')
-rw-r--r--sdnr/wt/websocketmanager2/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/websocketmanager2/Blueprint.java37
-rw-r--r--sdnr/wt/websocketmanager2/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/websocketmanager2/WebSocketManager.java140
-rw-r--r--sdnr/wt/websocketmanager2/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/websocketmanager2/WebSocketManagerProvider.java95
-rw-r--r--sdnr/wt/websocketmanager2/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/websocketmanager2/WebSocketManagerSocket.java216
-rw-r--r--sdnr/wt/websocketmanager2/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/websocketmanager2/utils/AkkaConfig.java206
-rw-r--r--sdnr/wt/websocketmanager2/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/websocketmanager2/utils/UserScopes.java46
-rw-r--r--sdnr/wt/websocketmanager2/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/websocketmanager2/websocket/SyncWebSocketClient.java91
-rw-r--r--sdnr/wt/websocketmanager2/provider/src/main/resources/org/opendaylight/blueprint/impl-blueprint.xml49
-rw-r--r--sdnr/wt/websocketmanager2/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/websocketmanager2/test/AkkaConfigTest.java74
-rw-r--r--sdnr/wt/websocketmanager2/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/websocketmanager2/test/WebsocketServerConnectTest.java33
-rw-r--r--sdnr/wt/websocketmanager2/provider/src/test/resources/akka-cluster.cfg49
-rw-r--r--sdnr/wt/websocketmanager2/provider/src/test/resources/akka-singlenode.cfg48
12 files changed, 1084 insertions, 0 deletions
diff --git a/sdnr/wt/websocketmanager2/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/websocketmanager2/Blueprint.java b/sdnr/wt/websocketmanager2/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/websocketmanager2/Blueprint.java
new file mode 100644
index 000000000..32d9d7a4b
--- /dev/null
+++ b/sdnr/wt/websocketmanager2/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/websocketmanager2/Blueprint.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt
+ * =================================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * 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.
+ * ============LICENSE_END==========================================================================
+ ******************************************************************************/
+package org.onap.ccsdk.features.sdnr.wt.websocketmanager2;
+
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
+
+public abstract class Blueprint implements AutoCloseable {
+
+ private RpcProviderRegistry rpcProviderRegistry = null;
+
+ public abstract void init();
+
+ public void setRpcProviderRegistry(RpcProviderRegistry rpcProviderRegistry) {
+ this.rpcProviderRegistry = rpcProviderRegistry;
+ }
+
+ public RpcProviderRegistry getRpcProviderRegistry() {
+ return this.rpcProviderRegistry;
+ }
+
+
+}
diff --git a/sdnr/wt/websocketmanager2/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/websocketmanager2/WebSocketManager.java b/sdnr/wt/websocketmanager2/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/websocketmanager2/WebSocketManager.java
new file mode 100644
index 000000000..18066128f
--- /dev/null
+++ b/sdnr/wt/websocketmanager2/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/websocketmanager2/WebSocketManager.java
@@ -0,0 +1,140 @@
+/*******************************************************************************
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt
+ * =================================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * 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.
+ * ============LICENSE_END==========================================================================
+ ******************************************************************************/
+package org.onap.ccsdk.features.sdnr.wt.websocketmanager2;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
+import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
+import org.json.JSONObject;
+import org.onap.ccsdk.features.sdnr.wt.websocketmanager2.WebSocketManagerSocket.EventInputCallback;
+import org.onap.ccsdk.features.sdnr.wt.websocketmanager2.utils.AkkaConfig;
+import org.onap.ccsdk.features.sdnr.wt.websocketmanager2.utils.AkkaConfig.ClusterConfig;
+import org.onap.ccsdk.features.sdnr.wt.websocketmanager2.utils.AkkaConfig.ClusterNodeInfo;
+import org.onap.ccsdk.features.sdnr.wt.websocketmanager2.websocket.SyncWebSocketClient;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.websocketmanager.rev150105.WebsocketEventInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.websocketmanager.rev150105.WebsocketEventOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.websocketmanager.rev150105.WebsocketEventOutputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.websocketmanager.rev150105.WebsocketmanagerService;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class WebSocketManager extends WebSocketServlet implements WebsocketmanagerService {
+
+ private static final long serialVersionUID = -681665669062744439L;
+
+ private static final Logger LOG = LoggerFactory.getLogger(WebSocketManager.class.getName());
+ private static final String APPLICATION_NAME = WebSocketManager.class.getName();
+ private static final int PORT = 8181;
+ private final EventInputCallback rpcEventInputCallback;
+
+ /**
+ * timeout for websocket with no messages in ms
+ */
+ private static final long IDLE_TIMEOUT = 5 * 60 * 1000L;
+
+ private final ArrayList<URI> clusterNodeClients = new ArrayList<>();
+
+ public WebSocketManager() {
+ super();
+ rpcEventInputCallback = message -> {
+ LOG.debug("onMessagePushed: " + message);
+ SyncWebSocketClient client;
+ for (URI clientURI : WebSocketManager.this.clusterNodeClients) {
+ client = new SyncWebSocketClient(clientURI);
+ LOG.debug("try to push message to " + client.getURI());
+ client.openAndSendAndCloseSync(message);
+ }
+ };
+ LOG.info("Create servlet for {}", APPLICATION_NAME);
+ }
+
+ @Override
+ public void configure(WebSocketServletFactory factory) {
+ LOG.info("Configure provider for {}", APPLICATION_NAME);
+ // set a second timeout
+ factory.getPolicy().setIdleTimeout(IDLE_TIMEOUT);
+ factory.getPolicy().setMaxBinaryMessageSize(1);
+ factory.getPolicy().setMaxTextMessageSize(64 * 1024);
+
+ // register Socket as the WebSocket to create on Upgrade
+ factory.register(WebSocketManagerSocket.class);
+
+ AkkaConfig cfg = null;
+ try {
+ cfg = AkkaConfig.load();
+ } catch (Exception e) {
+ LOG.warn("problem loading akka config: " + e.getMessage());
+ }
+ if (cfg != null && cfg.isCluster()) {
+ this.initWSClients(cfg.getClusterConfig());
+ }
+ }
+
+ // ODL in Dublin version generates ListenableFuture that is child of Future.
+ @Override
+ public ListenableFuture<RpcResult<WebsocketEventOutput>> websocketEvent(WebsocketEventInput input) {
+ LOG.debug("Send message '{}'", input);
+ RpcResultBuilder<WebsocketEventOutput> result;
+ try {
+ WebsocketEventOutputBuilder outputBuilder = new WebsocketEventOutputBuilder();
+ final String s = input.getXmlEvent();
+ WebSocketManagerSocket.broadCast(input.getNodeName(), input.getEventType(), s);
+ outputBuilder.setResponse("OK");
+ try {
+ JSONObject o = new JSONObject();
+ o.put(WebSocketManagerSocket.KEY_NODENAME, input.getNodeName());
+ o.put(WebSocketManagerSocket.KEY_EVENTTYPE, input.getEventType());
+ o.put(WebSocketManagerSocket.KEY_XMLEVENT, input.getXmlEvent());
+ this.rpcEventInputCallback.onMessagePushed(o.toString());
+ } catch (Exception err) {
+ LOG.warn("problem pushing messsage to other nodes: " + err.getMessage());
+ }
+ result = RpcResultBuilder.success(outputBuilder);
+ } catch (Exception e) {
+ LOG.warn("Socketproblem: {}", e);
+ result = RpcResultBuilder.failed();
+ result.withError(ErrorType.APPLICATION, "Exception", e);
+ }
+ return result.buildFuture();
+ }
+
+ /**********************************************************
+ * Private functions
+ */
+
+ private void initWSClients(ClusterConfig clusterConfig) {
+ for (ClusterNodeInfo nodeConfig : clusterConfig.getSeedNodes()) {
+ if (clusterConfig.isMe(nodeConfig)) {
+ continue;
+ }
+ String url = String.format("ws://%s:%d/websocket", nodeConfig.getRemoteAddress(), PORT);
+ try {
+ LOG.debug("registering ws client for " + url);
+ clusterNodeClients.add(new URI(url));
+ } catch (URISyntaxException e) {
+ LOG.warn("problem instantiating wsclient for url: " + url);
+ }
+ }
+ }
+}
diff --git a/sdnr/wt/websocketmanager2/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/websocketmanager2/WebSocketManagerProvider.java b/sdnr/wt/websocketmanager2/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/websocketmanager2/WebSocketManagerProvider.java
new file mode 100644
index 000000000..737fe5463
--- /dev/null
+++ b/sdnr/wt/websocketmanager2/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/websocketmanager2/WebSocketManagerProvider.java
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt
+ * =================================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * 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.
+ * ============LICENSE_END==========================================================================
+ ******************************************************************************/
+package org.onap.ccsdk.features.sdnr.wt.websocketmanager2;
+
+import javax.servlet.ServletException;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration;
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.websocketmanager.rev150105.WebsocketmanagerService;
+import org.osgi.service.http.HttpService;
+import org.osgi.service.http.NamespaceException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class WebSocketManagerProvider extends Blueprint {
+
+ private static final Logger LOG = LoggerFactory.getLogger(WebSocketManagerProvider.class);
+ private static final String APPLICATION_NAME = WebSocketManagerProvider.class.getName();
+ private static final String ALIAS = "/websocket";
+
+ private WebSocketManager wsServlet = null;
+ private RpcRegistration<WebsocketmanagerService> websocketService = null;
+
+ public WebSocketManagerProvider() {
+ LOG.info("Creating provider for {}", APPLICATION_NAME);
+ }
+
+ @Override
+ public void init() {
+ LOG.info("Init provider for {}", APPLICATION_NAME);
+ RpcProviderRegistry rpcProviderRegistry = this.getRpcProviderRegistry();
+ if (rpcProviderRegistry != null) {
+ if (wsServlet != null) {
+ this.websocketService = rpcProviderRegistry.addRpcImplementation(WebsocketmanagerService.class,
+ wsServlet);
+ } else {
+ LOG.error("wsServlet not provided");
+ }
+ } else {
+ LOG.error("rpcProviderRegistry not provided");
+ }
+ }
+
+ @Override
+ public void close() throws Exception {
+ LOG.info("Close provider for {}", APPLICATION_NAME);
+ if (websocketService != null) {
+ websocketService.close();
+ }
+ }
+
+ public void onUnbindService(HttpService httpService) {
+ httpService.unregister(ALIAS);
+ wsServlet = null;
+ }
+
+ public void onBindService(HttpService httpService) throws ServletException, NamespaceException {
+ if (httpService == null) {
+ LOG.warn("Unable to inject HttpService into DluxLoader. dlux modules won't work without httpService");
+ } else {
+
+ wsServlet = new WebSocketManager();
+ httpService.registerServlet(ALIAS, wsServlet, null, null);
+ LOG.info("websocket servlet registered.");
+ if(this.websocketService==null)
+ this.init();
+ else
+ LOG.info("websocketservice already initialized");
+ }
+
+ }
+
+ public WebSocketManager getWsServlet() {
+ return wsServlet;
+ }
+
+ public void setWsServlet(WebSocketManager wsServlet) {
+ this.wsServlet = wsServlet;
+ }
+}
diff --git a/sdnr/wt/websocketmanager2/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/websocketmanager2/WebSocketManagerSocket.java b/sdnr/wt/websocketmanager2/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/websocketmanager2/WebSocketManagerSocket.java
new file mode 100644
index 000000000..f445bcd23
--- /dev/null
+++ b/sdnr/wt/websocketmanager2/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/websocketmanager2/WebSocketManagerSocket.java
@@ -0,0 +1,216 @@
+/*******************************************************************************
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt
+ * =================================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * 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.
+ * ============LICENSE_END==========================================================================
+ ******************************************************************************/
+package org.onap.ccsdk.features.sdnr.wt.websocketmanager2;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+
+import org.eclipse.jetty.websocket.api.Session;
+import org.eclipse.jetty.websocket.api.WebSocketAdapter;
+import org.json.JSONObject;
+import org.onap.ccsdk.features.sdnr.wt.websocketmanager2.utils.UserScopes;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class WebSocketManagerSocket extends WebSocketAdapter {
+
+ private static final Logger LOG = LoggerFactory.getLogger(WebSocketManagerSocket.class.getName());
+
+ public static final String MSG_KEY_DATA = "data";
+ public static final String MSG_KEY_SCOPES = "scopes";
+ public static final String MSG_KEY_PARAM = "param";
+ public static final String MSG_KEY_VALUE = "value";
+ public static final String MSG_KEY_SCOPE = "scope";
+
+ public static final String KEY_NODENAME = "nodename";
+ public static final String KEY_EVENTTYPE = "eventtype";
+ public static final String KEY_XMLEVENT = "xmlevent";
+
+ private static final Random RND = new Random();
+
+
+ /**
+ * list of all sessionids
+ */
+ private static final List<String> sessionIds = new ArrayList<>();
+ /**
+ * map of sessionid <=> UserScopes
+ */
+ private static final HashMap<String, UserScopes> userScopesList = new HashMap<>();
+ /**
+ * map of class.hashCode <=> class
+ */
+ private static final HashMap<String, WebSocketManagerSocket> clientList = new HashMap<>();
+ private final String myUniqueSessionId;
+
+ private Session session = null;
+
+ public interface EventInputCallback {
+ void onMessagePushed(final String message) throws Exception;
+ }
+
+ public WebSocketManagerSocket() {
+ this.myUniqueSessionId = _genSessionId();
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ sessionIds.remove(this.myUniqueSessionId);
+ }
+
+ private static String _genSessionId() {
+ String sid = String.valueOf(RND.nextLong());
+ while (sessionIds.contains(sid)) {
+ sid = String.valueOf(RND.nextLong());
+ }
+ sessionIds.add(sid);
+ return sid;
+ }
+
+ @Override
+ public void onWebSocketText(String message) {
+ LOG.info(this.getRemoteAdr() + " has sent " + message);
+ if (!this.manageClientRequest(message)) {
+ this.manageClientRequest2(message);
+ }
+
+ }
+
+ @Override
+ public void onWebSocketBinary(byte[] payload, int offset, int len) {
+
+ }
+
+ @Override
+ public void onWebSocketConnect(Session sess) {
+ this.session = sess;
+ clientList.put(String.valueOf(this.hashCode()), this);
+ LOG.debug("client connected from " + this.getRemoteAdr());
+ }
+
+ @Override
+ public void onWebSocketClose(int statusCode, String reason) {
+ clientList.remove(String.valueOf(this.hashCode()));
+ LOG.debug("client disconnected from " + this.getRemoteAdr());
+ }
+
+ @Override
+ public void onWebSocketError(Throwable cause) {
+
+ LOG.debug("error caused on " + this.getRemoteAdr() + " :" + cause.getMessage());
+ // super.onWebSocketError(cause);
+ }
+
+ private String getRemoteAdr() {
+ String adr = "unknown";
+ try {
+ adr = this.session.getRemoteAddress().toString();
+ } catch (Exception e) {
+ LOG.debug("error resolving adr: {}", e.getMessage());
+ }
+ return adr;
+ }
+
+ /**
+ *
+ * @param request is a json object
+ * {"data":"scopes","scopes":["scope1","scope2",...]}
+ * @return if handled
+ */
+ private boolean manageClientRequest(String request) {
+ boolean ret = false;
+ try {
+ JSONObject jsonMessage = new JSONObject(request);
+ if (jsonMessage.has(MSG_KEY_DATA)) {
+ String data = jsonMessage.getString(MSG_KEY_DATA);
+ if (data.equals(MSG_KEY_SCOPES)) {
+ ret = true;
+ String sessionId = this.getSessionId();
+ UserScopes clientDto = new UserScopes();
+ clientDto.setScopes(jsonMessage.getJSONArray(MSG_KEY_SCOPES));
+ userScopesList.put(sessionId, clientDto);
+ this.send(
+ "You are connected to the Opendaylight Websocket server and scopes are : " + request + "");
+ }
+ }
+ } catch (Exception e) {
+ LOG.warn("problem set scope: " + e.getMessage());
+ this.send("Your request to the Opendaylight Websocket server is >> " + request
+ + " << which failed because of following exception >> " + e.toString());
+ }
+ return ret;
+ }
+
+ /*
+ * broadcast message to all your clients
+ */
+ private void manageClientRequest2(String request) {
+ try {
+ JSONObject o = new JSONObject(request);
+ if (o.has(KEY_NODENAME) && o.has(KEY_EVENTTYPE)) {
+ broadCast(o.getString(KEY_NODENAME), o.getString(KEY_EVENTTYPE), o.getString(KEY_XMLEVENT));
+ }
+ } catch (Exception e) {
+ LOG.warn("handle ws request failed:" + e.getMessage());
+ }
+ }
+
+ private void send(String msg) {
+ try {
+ LOG.trace("sending {}", msg);
+ this.session.getRemote().sendString(msg);
+ } catch (Exception e) {
+ LOG.warn("problem sending message: " + e.getMessage());
+ }
+ }
+
+ private String getSessionId() {
+ return this.myUniqueSessionId;
+ }
+
+ public static void broadCast(String nodeName, String eventType, String xmlEvent) {
+ if (clientList != null && clientList.size() > 0) {
+ for (Map.Entry<String, WebSocketManagerSocket> entry : clientList.entrySet()) {
+ WebSocketManagerSocket socket = entry.getValue();
+ if (socket != null) {
+ try {
+
+ UserScopes clientScopes = userScopesList.get(socket.getSessionId());
+ if (clientScopes != null) {
+ if (clientScopes.hasScope(eventType)) {
+ socket.send(xmlEvent);
+ } else {
+ LOG.debug("client has not scope {}", eventType);
+ }
+ } else {
+ LOG.debug("no scopes for notifications registered");
+ }
+ } catch (Exception ioe) {
+ LOG.warn(ioe.getMessage());
+ }
+ } else {
+ LOG.debug("cannot broadcast. socket is null");
+ }
+ }
+ }
+ }
+
+}
diff --git a/sdnr/wt/websocketmanager2/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/websocketmanager2/utils/AkkaConfig.java b/sdnr/wt/websocketmanager2/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/websocketmanager2/utils/AkkaConfig.java
new file mode 100644
index 000000000..4381595a7
--- /dev/null
+++ b/sdnr/wt/websocketmanager2/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/websocketmanager2/utils/AkkaConfig.java
@@ -0,0 +1,206 @@
+/*******************************************************************************
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt
+ * =================================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * 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.
+ * ============LICENSE_END==========================================================================
+ ******************************************************************************/
+package org.onap.ccsdk.features.sdnr.wt.websocketmanager2.utils;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.onap.ccsdk.features.sdnr.wt.websocketmanager2.WebSocketManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.typesafe.config.Config;
+import com.typesafe.config.ConfigFactory;
+
+public class AkkaConfig{
+
+ private static final Logger LOG = LoggerFactory.getLogger(WebSocketManager.class.getName());
+
+ public static class ClusterNodeInfo
+ {
+ @Override
+ public String toString() {
+ return "ClusterNodeInfo [protocol=" + protocol + ", clusterName=" + clusterName + ", remoteAdr=" + remoteAdr
+ + ", port=" + port + "]";
+ }
+ private final String protocol;
+ private final String clusterName;
+ private final String remoteAdr;
+ private final int port;
+
+ public String getRemoteAddress() {return this.remoteAdr;}
+ public ClusterNodeInfo(String s) throws Exception
+ {
+ final String regex ="([a-z.]*):\\/\\/([a-zA-Z0-9-]*)@([a-zA-Z0-9.-]*):([0-9]*)";
+ final Pattern pattern = Pattern.compile(regex);
+ final Matcher matcher = pattern.matcher(s);
+ if(!matcher.find()) {
+ throw new Exception("invalid seedNode format");
+ }
+ this.protocol=matcher.group(1);
+ this.clusterName=matcher.group(2);
+ this.remoteAdr=matcher.group(3);
+ this.port=Integer.parseInt(matcher.group(4));
+ }
+ }
+ public static class ClusterRoleInfo
+ {
+ @Override
+ public String toString() {
+ return "ClusterRoleInfo [Role=" + Role + ", Index=" + Index + "]";
+ }
+
+ private final String Role;
+ private final int Index;
+ public ClusterRoleInfo(String s) throws Exception {
+ final String regex = "([a-z]*)-([0-9]*)";
+ final Pattern pattern = Pattern.compile(regex);
+ final Matcher matcher = pattern.matcher(s);
+ if(!matcher.find()) {
+ throw new Exception("invalid role format");
+ }
+ this.Role=matcher.group(1);
+ this.Index=Integer.parseInt(matcher.group(2));
+ }
+
+ }
+ public static class ClusterConfig
+ {
+ @Override
+ public String toString() {
+ return "ClusterConfig [seedNodes=" + seedNodes + ", roles=" + roles + "]";
+ }
+ private final List<ClusterNodeInfo> seedNodes;
+ private final List<ClusterRoleInfo> roles;
+ private final ClusterNodeInfo ismeInfo;
+ public ClusterConfig(Config o) throws Exception {
+ {
+ this.seedNodes = new ArrayList<>();
+ List<String> a= o.getStringList("seed-nodes");
+ for(int i=0;i<a.size();i++)
+ {
+ ClusterNodeInfo info=new ClusterNodeInfo(a.get(i));
+ this.seedNodes.add(info);
+ }
+ this.roles=new ArrayList<>();
+ a=o.getStringList("roles");
+ for(int i=0;i<a.size();i++)
+ {
+ ClusterRoleInfo s=new ClusterRoleInfo(a.get(i));
+ this.roles.add(s);
+ }
+ int idx=this.roles.get(0).Index-1;
+ if(idx>=0 && idx<this.seedNodes.size()) {
+ this.ismeInfo=this.seedNodes.get(idx);
+ } else {
+ this.ismeInfo=null;
+ }
+ }
+
+ }
+ public boolean isCluster() {
+ return this.seedNodes!=null?this.seedNodes.size()>1:false;
+ }
+ public boolean isMe(ClusterNodeInfo i) {
+ return this.ismeInfo!=null?this.ismeInfo.equals(i):false;
+ }
+ public List<ClusterNodeInfo> getSeedNodes() {
+ return this.seedNodes;
+ }
+ }
+
+ private static final String DEFAULT_FILENAME = "configuration/initial/akka.conf";
+ private final File file;
+ private final String resourceFilename;
+ private final String fileContent;
+ private ClusterConfig cluserConfig;
+ public ClusterConfig getClusterConfig() {return this.cluserConfig;}
+
+ private AkkaConfig(File file,boolean isResource) {
+ this.file=isResource?null:file;
+ this.fileContent=null;
+ this.resourceFilename=isResource?file.getName():null;
+ }
+ private AkkaConfig(String fileContent) {
+ this.file = null;
+ this.fileContent = fileContent;
+ this.resourceFilename = null;
+ }
+
+
+ @Override
+ public String toString() {
+ return "AkkaConfig [filename=" + file + ", cluserConfig=" + cluserConfig + "]";
+ }
+
+ private void loadFromFile() throws Exception {
+ Config cfg=null;
+ if(this.file!=null) {
+ cfg=ConfigFactory.parseFile(this.file);
+ } else if(this.fileContent!=null) {
+ cfg=ConfigFactory.parseString(this.fileContent);
+ } else if(this.resourceFilename!=null) {
+ cfg=ConfigFactory.parseResources(this.getClass(), this.resourceFilename);
+ }
+
+ if(cfg!=null) {
+ this.cluserConfig=new ClusterConfig(cfg.getConfig("odl-cluster-data").getConfig("akka").getConfig("cluster"));
+ } else
+ {
+ LOG.warn("unable to parse config file");
+ this.cluserConfig=null;
+ }
+ }
+
+ public boolean isCluster()
+ {
+ return this.cluserConfig!=null?this.cluserConfig.isCluster():false;
+ }
+ public static AkkaConfig load() throws Exception
+ {
+ return load(DEFAULT_FILENAME);
+ }
+
+ public static AkkaConfig load(String filename) throws Exception
+ {
+ return load(filename,false);
+ }
+ public static AkkaConfig load(String filename,boolean isResource) throws Exception
+ {
+ AkkaConfig cfg=new AkkaConfig(new File(filename),isResource);
+ cfg.loadFromFile();
+
+ return cfg;
+ }
+ public static AkkaConfig loadContent(String content) throws Exception
+ {
+ AkkaConfig cfg=new AkkaConfig(content);
+ cfg.loadFromFile();
+
+ return cfg;
+ }
+
+
+
+
+
+
+
+}
diff --git a/sdnr/wt/websocketmanager2/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/websocketmanager2/utils/UserScopes.java b/sdnr/wt/websocketmanager2/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/websocketmanager2/utils/UserScopes.java
new file mode 100644
index 000000000..5dd503c73
--- /dev/null
+++ b/sdnr/wt/websocketmanager2/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/websocketmanager2/utils/UserScopes.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt
+ * =================================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * 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.
+ * ============LICENSE_END==========================================================================
+ ******************************************************************************/
+package org.onap.ccsdk.features.sdnr.wt.websocketmanager2.utils;
+
+import org.json.JSONArray;
+
+public class UserScopes {
+
+ private JSONArray scopes;
+
+ /**
+ *
+ * @param jsonArray array of Strings
+ */
+ public void setScopes(JSONArray jsonArray) {
+ this.scopes = jsonArray;
+ }
+
+ public boolean hasScope(String scope) {
+ if (this.scopes == null)
+ return false;
+ for (int i = 0, l = this.scopes.length(); i < l; i++) {
+ if (this.scopes.get(i).toString().equals(scope)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+}
diff --git a/sdnr/wt/websocketmanager2/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/websocketmanager2/websocket/SyncWebSocketClient.java b/sdnr/wt/websocketmanager2/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/websocketmanager2/websocket/SyncWebSocketClient.java
new file mode 100644
index 000000000..0afe06e13
--- /dev/null
+++ b/sdnr/wt/websocketmanager2/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/websocketmanager2/websocket/SyncWebSocketClient.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt
+ * =================================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * 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.
+ * ============LICENSE_END==========================================================================
+ ******************************************************************************/
+package org.onap.ccsdk.features.sdnr.wt.websocketmanager2.websocket;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import org.java_websocket.client.WebSocketClient;
+import org.java_websocket.handshake.ServerHandshake;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SyncWebSocketClient extends WebSocketClient {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SyncWebSocketClient.class.getName());
+ private String messageToSend;
+
+ public SyncWebSocketClient(URI serverUri) {
+ super(serverUri);
+ }
+
+ public SyncWebSocketClient(String uri) throws URISyntaxException {
+ this(new URI(uri));
+ }
+
+ @Override
+ public void onClose(int arg0, String arg1, boolean arg2) {
+ LOG.debug("socket closed: {} {} {}", arg0, arg1, arg2);
+
+ }
+
+ @Override
+ public void onError(Exception arg0) {
+ LOG.warn("error on socket: {}", arg0.getMessage());
+
+ }
+
+ @Override
+ public void onMessage(String arg0) {
+ LOG.debug("received message: {}", arg0);
+
+ }
+
+ @Override
+ public void onOpen(ServerHandshake arg0) {
+ LOG.debug("socket opened");
+ if (this.messageToSend != null) {
+ LOG.debug("try to send: " + this.messageToSend);
+ this.send(this.messageToSend);
+ this.messageToSend = null;
+ }
+
+ }
+
+ public void openAndSendAsync(String message) {
+ this.messageToSend = message;
+ this.connect();
+ }
+
+ public void openAndSendAndCloseSync(String message) {
+ try {
+ this.connectBlocking();
+ } catch (InterruptedException e) {
+ LOG.warn("problem connecting:" + e.getMessage());
+ Thread.currentThread().interrupt();
+ }
+ this.send(message);
+ try {
+ this.closeBlocking();
+ } catch (InterruptedException e) {
+ LOG.warn("problem disconnecting:" + e.getMessage());
+ Thread.currentThread().interrupt();
+ }
+ }
+
+}
diff --git a/sdnr/wt/websocketmanager2/provider/src/main/resources/org/opendaylight/blueprint/impl-blueprint.xml b/sdnr/wt/websocketmanager2/provider/src/main/resources/org/opendaylight/blueprint/impl-blueprint.xml
new file mode 100644
index 000000000..315921dbb
--- /dev/null
+++ b/sdnr/wt/websocketmanager2/provider/src/main/resources/org/opendaylight/blueprint/impl-blueprint.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ============LICENSE_START========================================================================
+ ONAP : ccsdk feature sdnr wt
+ =================================================================================================
+ Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ =================================================================================================
+ 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.
+ ============LICENSE_END==========================================================================
+-->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
+ xmlns:odl="http://opendaylight.org/xmlns/blueprint/v1.0.0"
+ odl:use-default-for-reference-types="true">
+
+<!-- <bean id="wsServlet" -->
+<!-- class="org.onap.ccsdk.sdnr.wt.websocketmanager2.WebSocketManager"> -->
+<!-- </bean> -->
+
+ <reference id="rpcProviderRegistry"
+ interface="org.opendaylight.controller.sal.binding.api.RpcProviderRegistry"
+ odl:type="default" />
+
+ <bean id="provider"
+ class="org.onap.ccsdk.features.sdnr.wt.websocketmanager2.WebSocketManagerProvider"
+ init-method="init" destroy-method="close">
+ <property name="rpcProviderRegistry" ref="rpcProviderRegistry" />
+<!-- <property name="wsServlet" ref="wsServlet" /> -->
+ </bean>
+
+ <reference id="onBindService" availability="mandatory" activation="eager" interface="org.osgi.service.http.HttpService">
+ <reference-listener ref="provider" bind-method="onBindService" unbind-method="onUnbindService"/>
+ </reference>
+<!-- <service -->
+<!-- interface="org.eclipse.jetty.websocket.servlet.WebSocketServlet" -->
+<!-- ref="wsServlet"> -->
+<!-- <service-properties> -->
+<!-- <entry key="alias" value="/websocket" /> -->
+<!-- </service-properties> -->
+<!-- </service> -->
+
+</blueprint>
diff --git a/sdnr/wt/websocketmanager2/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/websocketmanager2/test/AkkaConfigTest.java b/sdnr/wt/websocketmanager2/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/websocketmanager2/test/AkkaConfigTest.java
new file mode 100644
index 000000000..217088b33
--- /dev/null
+++ b/sdnr/wt/websocketmanager2/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/websocketmanager2/test/AkkaConfigTest.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt
+ * =================================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * 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.
+ * ============LICENSE_END==========================================================================
+ ******************************************************************************/
+package org.onap.ccsdk.features.sdnr.wt.websocketmanager2.test;
+
+import static org.junit.Assert.*;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.nio.file.Paths;
+import org.junit.Test;
+import org.onap.ccsdk.features.sdnr.wt.websocketmanager2.utils.AkkaConfig;
+
+public class AkkaConfigTest {
+
+ @Test
+ public void test() throws URISyntaxException, IOException {
+
+ AkkaConfig config=null;
+ try {
+ //config = AkkaConfig.load("akka-singlenode.cfg", true);
+ config = AkkaConfig.loadContent(loadResourceContentAsString("akka-singlenode.cfg"));
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail("error loading singlenode config");
+ }
+ assertEquals("no singlenode config detected",false,config.isCluster());
+ assertEquals("more than one node detected",1,config.getClusterConfig().getSeedNodes().size());
+
+ try {
+ config = AkkaConfig.loadContent(loadResourceContentAsString("akka-cluster.cfg"));
+ } catch (Exception e) {
+ fail("error loading cluster config");
+ }
+ assertEquals("no cluster config detected",true,config.isCluster());
+ assertTrue("only one node detected",config.getClusterConfig().getSeedNodes().size()>1);
+ }
+
+ private String loadResourceContentAsString(String resourceName) throws URISyntaxException, FileNotFoundException, IOException {
+
+ StringBuilder sb = new StringBuilder();
+
+ ClassLoader classLoader = getClass().getClassLoader();
+ File file = Paths.get(classLoader.getResource(resourceName).toURI()).toFile();
+ try(BufferedReader br = new BufferedReader(new FileReader(file))) {
+ String line = br.readLine();
+
+ while (line != null) {
+ sb.append(line);
+ sb.append(System.lineSeparator());
+ line = br.readLine();
+ }
+ }
+ return sb.toString();
+ }
+}
diff --git a/sdnr/wt/websocketmanager2/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/websocketmanager2/test/WebsocketServerConnectTest.java b/sdnr/wt/websocketmanager2/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/websocketmanager2/test/WebsocketServerConnectTest.java
new file mode 100644
index 000000000..b380beca3
--- /dev/null
+++ b/sdnr/wt/websocketmanager2/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/websocketmanager2/test/WebsocketServerConnectTest.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt
+ * =================================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * 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.
+ * ============LICENSE_END==========================================================================
+ ******************************************************************************/
+package org.onap.ccsdk.features.sdnr.wt.websocketmanager2.test;
+
+import org.junit.Test;
+import org.onap.ccsdk.features.sdnr.wt.websocketmanager2.WebSocketManager;
+
+public class WebsocketServerConnectTest {
+
+ @Test
+ public void test() {
+
+ WebSocketManager servlet =new WebSocketManager();
+
+
+
+ }
+}
diff --git a/sdnr/wt/websocketmanager2/provider/src/test/resources/akka-cluster.cfg b/sdnr/wt/websocketmanager2/provider/src/test/resources/akka-cluster.cfg
new file mode 100644
index 000000000..465dcad83
--- /dev/null
+++ b/sdnr/wt/websocketmanager2/provider/src/test/resources/akka-cluster.cfg
@@ -0,0 +1,49 @@
+odl-cluster-data {
+ akka {
+ remote {
+ artery {
+ enabled = off
+ canonical.hostname = "192.168.178.143"
+ canonical.port = 2550
+ }
+ netty.tcp {
+ hostname = "192.168.178.143"
+ port = 2550
+ }
+ # when under load we might trip a false positive on the failure detector
+ # transport-failure-detector {
+ # heartbeat-interval = 4 s
+ # acceptable-heartbeat-pause = 16s
+ # }
+ }
+
+ cluster {
+ # Remove ".tcp" when using artery.
+ seed-nodes = ["akka.tcp://opendaylight-cluster-data@192.168.178.142:2550",
+ "akka.tcp://opendaylight-cluster-data@192.168.178.143:2550",
+ "akka.tcp://opendaylight-cluster-data@192.168.178.144:2550",
+ "akka.tcp://opendaylight-cluster-data@192.168.178.145:2550"]
+
+ roles = ["member-2"]
+
+ }
+
+ persistence {
+ # By default the snapshots/journal directories live in KARAF_HOME. You can choose to put it somewhere else by
+ # modifying the following two properties. The directory location specified may be a relative or absolute path.
+ # The relative path is always relative to KARAF_HOME.
+
+ # snapshot-store.local.dir = "target/snapshots"
+ # journal.leveldb.dir = "target/journal"
+
+ journal {
+ leveldb {
+ # Set native = off to use a Java-only implementation of leveldb.
+ # Note that the Java-only version is not currently considered by Akka to be production quality.
+
+ # native = off
+ }
+ }
+ }
+ }
+}
diff --git a/sdnr/wt/websocketmanager2/provider/src/test/resources/akka-singlenode.cfg b/sdnr/wt/websocketmanager2/provider/src/test/resources/akka-singlenode.cfg
new file mode 100644
index 000000000..19e723319
--- /dev/null
+++ b/sdnr/wt/websocketmanager2/provider/src/test/resources/akka-singlenode.cfg
@@ -0,0 +1,48 @@
+odl-cluster-data {
+ akka {
+ remote {
+ artery {
+ enabled = off
+ canonical.hostname = "127.0.0.1"
+ canonical.port = 2550
+ }
+ netty.tcp {
+ hostname = "127.0.0.1"
+ port = 2550
+ }
+ # when under load we might trip a false positive on the failure detector
+ # transport-failure-detector {
+ # heartbeat-interval = 4 s
+ # acceptable-heartbeat-pause = 16s
+ # }
+ }
+
+ cluster {
+ # Remove ".tcp" when using artery.
+ seed-nodes = ["akka.tcp://opendaylight-cluster-data@127.0.0.1:2550"]
+
+ roles = [
+ "member-1"
+ ]
+
+ }
+
+ persistence {
+ # By default the snapshots/journal directories live in KARAF_HOME. You can choose to put it somewhere else by
+ # modifying the following two properties. The directory location specified may be a relative or absolute path.
+ # The relative path is always relative to KARAF_HOME.
+
+ # snapshot-store.local.dir = "target/snapshots"
+ # journal.leveldb.dir = "target/journal"
+
+ journal {
+ leveldb {
+ # Set native = off to use a Java-only implementation of leveldb.
+ # Note that the Java-only version is not currently considered by Akka to be production quality.
+
+ # native = off
+ }
+ }
+ }
+ }
+}