All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.graphwalker.websocket.WebSocketServer Maven / Gradle / Ivy

There is a newer version: 4.3.3
Show newest version
package org.graphwalker.websocket;

/*
 * #%L
 * GraphWalker As A Service
 * %%
 * Copyright (C) 2005 - 2014 GraphWalker
 * %%
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 * #L%
 */

import org.graphwalker.core.event.EventType;
import org.graphwalker.core.event.Observer;
import org.graphwalker.core.machine.Context;
import org.graphwalker.core.machine.Machine;
import org.graphwalker.core.machine.SimpleMachine;
import org.graphwalker.core.model.Element;
import org.graphwalker.io.factory.gw3.GW3ContextFactory;
import org.graphwalker.modelchecker.ContextChecker;
import org.graphwalker.modelchecker.ContextsChecker;
import org.java_websocket.WebSocket;
import org.java_websocket.handshake.ClientHandshake;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetSocketAddress;
import java.util.*;

/**
 * A WebSocketServer with an API for working with GraphWalker as a service.
 * 

* The websocket API has the following methods: *

    *
  • loadModel
    * Loads a model into the service. The model must use JSON notation for a GraphWalker model. * The notation has the following format:
    *
     * {
     * "command":"loadModel",
     * "model":{
     * "name":"Small model",
     * "id":"m1",
     * "generator":"random(edge_coverage(100))",
     * "startElementId":"e0",
     * "vertices":[
     * {
     * "name":"v_VerifySomeAction",
     * "id":"n0",
     * "requirements":[
     * "UC01 2.2.1"
     * ]
     * },
     * {
     * "name":"v_VerifySomeOtherAction",
     * "id":"n1"
     * }
     * ],
     * "edges":[
     * {
     * "name":"e_FirstAction",
     * "id":"e0",
     * "actions":[
     * "index = 0;",
     * "str = '';"
     * ],
     * "targetVertexId":"n0"
     * },
     * {
     * "name":"e_AnotherAction",
     * "id":"e1",
     * "guard":"index <= 3",
     * "sourceVertexId":"n0",
     * "targetVertexId":"n1"
     * },
     * {
     * "name":"e_SomeOtherAction",
     * "id":"e2",
     * "actions":[
     * "index++;"
     * ],
     * "sourceVertexId":"n1",
     * "targetVertexId":"n1"
     * },
     * {
     * "id":"e3",
     * "sourceVertexId":"n1",
     * "targetVertexId":"n0"
     * }
     * ]
     * }
     * }
     *      
    *

    *

  • getModel
    * Will return the model with the given id modelId from the service.
    *
     * {
     * "command":"getModel",
     * "modelId":"someId"
     * }
     *      
    *

    *

  • start
    * Tells the service to get the machine ready to execute the model(s). *
     * {
     * "command":"start"
     * }
     *      
    *

    *

  • getNext
    * Asks the service for the next element to be executed. *
     * {
     * "command":"getNext"
     * }
     *      
    *

    *

  • hasNext
    * Asks the service if all conditions for all generators has been met or not. *
     * {
     * "command":"hasNext"
     * }
     *      
    *

    *

  • restart
    * Requests the service to reset the execution of the the models to the initial state. *
     * {
     * "command":"restart"
     * }
     *      
    *

    *

  • getData
    * Asks the service for the value of the given attribute. *
     * {
     * "command":"getData"
     * }
     *      
    *

    *

  • addModel
    * Asks the service to create a new empty model with the given id. *
     * {
     * "command": "addModel",
     * "id": "someModelId"
     * }
     *      
    *

    *

  • removeModel
    * Removes the model with the given modelId from the service. *
     * {
     * "command":"removeModel"
     * }
     *      
    *

    *

  • addVertex
    * Adds a vertex to the model with the given modelId and * vertexId to the service. *
     * {
     * "command": "addVertex",
     * "modelId": "somModelId",
     * "vertexId": "someVertexId"
     * }
     *      
    *

    *

  • addEdge
    * Adds an edge to the model with the given modelId to the service. *
     * {
     * "command":"addEdge"
     * }
     *      
    *

    *

  • updateVertex
    * Updates attribute(s) to the vertex with given id and modelId from the service. *
     * {
     * "command":"updateVertex"
     * }
     *      
    *

    *

  • updateEdge
    * Updates attribute(s) to the edge with given id and modelId from the service. *
     * {
     * "command":"updateEdge"
     * }
     *      
    *

    *

  • removeVertex
    * Removes the vertex with the given id from and modelId from the service. *
     * {
     * "command":"removeVertex"
     * }
     *      
    *

    *

  • removeEdge
    * Removes the edge with the given id from and modelId from the service. *
     * {
     * "command":"removeEdge"
     * }
     *      
    *

    *

*/ public class WebSocketServer extends org.java_websocket.server.WebSocketServer implements Observer { private static final Logger logger = LoggerFactory.getLogger(WebSocketServer.class); private Set sockets; private Map machines; public WebSocketServer(int port) { super(new InetSocketAddress(port)); sockets = new HashSet<>(); machines = new HashMap<>(); } public WebSocketServer(InetSocketAddress address) { super(address); sockets = new HashSet<>(); machines = new HashMap<>(); } @Override public void onOpen(WebSocket socket, ClientHandshake handshake) { sockets.add(socket); machines.put(socket, null); logger.info(socket.getRemoteSocketAddress().getAddress().getHostAddress() + " is now connected"); } @Override public void onClose(WebSocket socket, int code, String reason, boolean remote) { sockets.remove(socket); machines.remove(socket); logger.info(socket.getRemoteSocketAddress().getAddress().getHostAddress() + " has disconnected"); } @Override public void onMessage(WebSocket socket, String message) { logger.debug("Received message from: " + socket.getRemoteSocketAddress().getAddress().getHostAddress() + " : " + message); JSONObject response = new JSONObject(); JSONObject root; try { root = new JSONObject(message); } catch (JSONException e) { logger.error(e.getMessage()); response.put("message", "Unknown command: " + e.getMessage()); response.put("success", false); socket.send(response.toString()); return; } String command = root.getString("command").toUpperCase(); switch (command) { case "START": response.put("command", "start"); response.put("success", false); List gw3Contexts = null; try { gw3Contexts = new GW3ContextFactory().createMultiple(root.getJSONObject("gw3").toString()); Machine machine = new SimpleMachine(gw3Contexts); machine.addObserver(this); machines.put(socket, machine); response.put("success", true); } catch (Exception e) { logger.error(e.getMessage()); List issues = checkContexts(socket, gw3Contexts); issues.add(e.getMessage()); sendIssues(socket, issues); } break; case "GETNEXT": { response.put("command", "getNext"); response.put("success", false); Machine machine = machines.get(socket); if (machine != null) { try { machine.getNextStep(); response.put("modelId", machine.getCurrentContext().getModel().getId()); response.put("elementId", machine.getCurrentContext().getCurrentElement().getId()); response.put("name", machine.getCurrentContext().getCurrentElement().getName()); response.put("success", true); } catch (Exception e) { logger.error(e.getMessage()); List issues = checkContexts(socket, machine.getContexts()); issues.add(e.getMessage()); sendIssues(socket, issues); } } else { response.put("message", "The GraphWalker state machine is not initiated. Is a model loaded, and started?"); } break; } case "HASNEXT": { response.put("command", "hasNext"); response.put("success", false); Machine machine = machines.get(socket); try { if (machine == null) { response.put("message", "The GraphWalker state machine is not initiated. Is a model loaded, and started?"); } else if (machine.hasNextStep()) { response.put("success", true); response.put("hasNext", true); } else { response.put("success", true); response.put("hasNext", false); } } catch (Exception e) { logger.error(e.getMessage()); List issues = checkContexts(socket, machine.getContexts()); issues.add(e.getMessage()); sendIssues(socket, issues); } break; } case "GETDATA": { response.put("command", "getData"); response.put("success", false); Machine machine = machines.get(socket); if (machine != null) { JSONObject obj = new JSONObject(); try { JSONObject data = new JSONObject(); for (Map.Entry k : machine.getCurrentContext().getKeys().entrySet()) { data.put(k.getKey(), k.getValue()); } obj.put("modelId", machine.getCurrentContext().getModel().getId()); obj.put("data", data); obj.put("result", "ok"); response.put("data", data); response.put("success", true); } catch (Exception e) { logger.error(e.getMessage()); List issues = checkContexts(socket, machine.getContexts()); issues.add(e.getMessage()); sendIssues(socket, issues); } } else { response.put("message", "The GraphWalker state machine is not initiated. Is a model loaded, and started?"); } break; } default: response.put("message", "Unknown command"); response.put("success", false); break; } logger.debug("Sending response to: " + socket.getRemoteSocketAddress().getAddress().getHostAddress() + " : " + response.toString()); socket.send(response.toString()); } private List checkContexts(WebSocket socket, List contexts) { if (contexts == null) { return new ArrayList<>(); } return ContextsChecker.hasIssues(contexts); } private void sendIssues(WebSocket socket, List issues) { if (!issues.isEmpty()) { JSONObject jsonIssue = new JSONObject(); jsonIssue.put("command", "issues"); JSONArray jsonIssues = new JSONArray(); for (String issue : issues) { jsonIssues.put(issue); } jsonIssue.put("issues", jsonIssues); logger.debug("Sending response to: " + socket.getRemoteSocketAddress().getAddress().getHostAddress() + " : " + jsonIssue.toString()); socket.send(jsonIssue.toString()); } else { JSONObject jsonIssue = new JSONObject(); jsonIssue.put("command", "noIssues"); logger.debug("Sending response to: " + socket.getRemoteSocketAddress().getAddress().getHostAddress() + " : " + jsonIssue.toString()); socket.send(jsonIssue.toString()); } } @Override public void onError(WebSocket socket, Exception ex) { ex.printStackTrace(); } @Override public void update(Machine machine, Element element, EventType type) { logger.info("Received an update from a GraphWalker machine"); Iterator it = machines.entrySet().iterator(); while (it.hasNext()) { Map.Entry pairs = (Map.Entry) it.next(); if (machine == pairs.getValue()) { logger.info("Event: " + type); WebSocket conn = (WebSocket) pairs.getKey(); if (type == EventType.AFTER_ELEMENT) { JSONObject jsonObject = new JSONObject(); jsonObject.put("command", "visitedElement"); jsonObject.put("modelId", machine.getCurrentContext().getModel().getId()); jsonObject.put("elementId", element.getId()); jsonObject.put("visitedCount", machine.getProfiler().getVisitCount(element)); jsonObject.put("totalCount", machine.getProfiler().getTotalVisitCount()); jsonObject.put("stopConditionFulfillment", machine.getCurrentContext().getPathGenerator().getStopCondition().getFulfilment()); JSONObject data = new JSONObject(); for (Map.Entry k : machine.getCurrentContext().getKeys().entrySet()) { data.put(k.getKey(), k.getValue()); } jsonObject.put("data", data); conn.send(jsonObject.toString()); } } } } public void startService() { start(); logger.info("GraphWalkerServer started on port: " + getPort()); // Shutdown event Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { @Override public void run() { System.out.println(); System.out.println("GraphWalkerServer shutting down"); System.out.println(); logger.info("GraphWalkerServer shutting down"); } })); while (true) { try { Thread.sleep(10); } catch (InterruptedException i) { break; } } } public Set getSockets() { return sockets; } public Map getMachines() { return machines; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy