Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.brutusin.rpc.client.wskt.WebsocketEndpoint Maven / Gradle / Ivy
package org.brutusin.rpc.client.wskt;
import java.io.IOException;
import java.net.ConnectException;
import java.net.URI;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.websocket.ClientEndpointConfig;
import javax.websocket.CloseReason;
import javax.websocket.ContainerProvider;
import javax.websocket.Decoder;
import javax.websocket.DeploymentException;
import javax.websocket.Encoder;
import javax.websocket.Endpoint;
import javax.websocket.EndpointConfig;
import javax.websocket.Extension;
import javax.websocket.HandshakeResponse;
import javax.websocket.MessageHandler;
import javax.websocket.Session;
import javax.websocket.WebSocketContainer;
import org.brutusin.commons.Trie;
import org.brutusin.json.ParseException;
import org.brutusin.json.spi.JsonCodec;
import org.brutusin.json.spi.JsonNode;
import org.brutusin.rpc.RpcRequest;
import org.brutusin.rpc.RpcResponse;
import org.brutusin.rpc.client.RpcCallback;
public class WebsocketEndpoint {
private static final Logger LOGGER = Logger.getLogger(WebsocketEndpoint.class.getName());
private final URI endpoint;
private final AtomicInteger reqCounter = new AtomicInteger();
private final Map serviceMap = new HashMap();
private final Map rpcCallbacks = new HashMap();
private final Map topicCallbacks = new HashMap();
private final LinkedList reconnectingQueue = new LinkedList();
private final LinkedList> initialQueue = new LinkedList();
private final Thread pingThread;
private Websocket websocket;
private boolean reconnecting;
public WebsocketEndpoint (URI endpoint, Config cfg) {
if (cfg == null ) {
cfg = new ConfigurationBuilder().build();
}
this .endpoint = endpoint;
final int pingSeconds = cfg.getPingSeconds();
doExec(new RpcCallback() {
public void call (RpcResponse response) {
if (response.getError() != null ) {
LOGGER.severe(response.toString());
return ;
}
JsonNode services = response.getResult();
for (int i = 0 ; i < services.getSize(); i++) {
JsonNode service = services.get(i);
serviceMap.put(service.get("id" ).asString(), service);
}
for (Trie req : initialQueue) {
exec(req.getElement1(), req.getElement2(), req.getElement3());
}
initialQueue.clear();
}
}, "rpc.wskt.services" , null , true );
this .pingThread = new Thread() {
@Override
public void run () {
while (!isInterrupted()) {
try {
Thread.sleep(1000 * pingSeconds);
doExec(new RpcCallback() {
public void call (RpcResponse response) {
if (response.getError() != null ) {
LOGGER.severe(response.toString());
}
}
}, "rpc.wskt.ping" , null , false );
} catch (InterruptedException ie) {
break ;
}
}
}
};
pingThread.setDaemon(true );
pingThread.start();
}
private synchronized void reconnect () {
if (reconnecting) {
return ;
}
reconnecting = true ;
if (this .websocket != null ) {
try {
this .websocket.close();
} catch (IOException ex) {
throw new RuntimeException(ex);
}
this .websocket.setMessageListener(null );
this .websocket = null ;
}
final ClientEndpointConfig cec = new ClientEndpointConfig() {
public List getPreferredSubprotocols () {
return Collections.EMPTY_LIST;
}
public List getExtensions () {
return Collections.EMPTY_LIST;
}
public List> getEncoders() {
return Collections.EMPTY_LIST;
}
public List> getDecoders() {
return Collections.EMPTY_LIST;
}
public Map getUserProperties () {
return new HashMap();
}
public ClientEndpointConfig.Configurator getConfigurator () {
return new Configurator() {
@Override
public void beforeRequest (Map > headers) {
System.out.println(headers);
}
@Override
public void afterResponse (HandshakeResponse hr) {
super .afterResponse(hr);
}
};
}
};
final WebSocketContainer webSocketContainer = ContainerProvider.getWebSocketContainer();
new Thread() {
@Override
public void run () {
try {
webSocketContainer.connectToServer(new Endpoint() {
@Override
public void onOpen (final Session session, EndpointConfig config) {
try {
synchronized (WebsocketEndpoint.this ) {
WebsocketEndpoint.this .websocket = new Websocket() {
@Override
public void send (String message) throws IOException {
session.getBasicRemote().sendText(message);
}
@Override
public void close () throws IOException {
session.close(new CloseReason(CloseReason.CloseCodes.NORMAL_CLOSURE, null ));
}
};
WebsocketEndpoint.this .websocket.setMessageListener(new MessageListener() {
@Override
public void onMessage (String message) {
try {
JsonNode response = JsonCodec.getInstance().parse(message);
if (response.get("jsonrpc" ) != null ) {
RpcResponse rpcResponse = new RpcResponse();
if (response.get("error" ) != null ) {
rpcResponse.setError(JsonCodec.getInstance().load(response.get("error" ), RpcResponse.Error.class));
}
rpcResponse.setResult(response.get("result" ));
Integer id = response.get("id" ).asInteger();
rpcResponse.setId(id);
RpcCallback callback = rpcCallbacks.remove(id);
callback.call(rpcResponse);
} else {
String topic = response.get("topic" ).asString();
TopicCallback callback = topicCallbacks.get(topic);
callback.call(response.get("message" ));
}
} catch (ParseException ex) {
Logger.getLogger(WebsocketEndpoint.class.getName()).log(Level.SEVERE, null , ex);
}
}
});
session.addMessageHandler(new MessageHandler.Whole() {
@Override
public void onMessage (String message) {
MessageListener messageListener = WebsocketEndpoint.this .websocket.getMessageListener();
if (message != null ) {
messageListener.onMessage(message);
}
}
});
for (RpcRequest req : reconnectingQueue) {
sendRequest(req, true );
}
reconnectingQueue.clear();
for (String topic : topicCallbacks.keySet()) {
try {
doExec(null , "rpc.topics.subscribe" , JsonCodec.getInstance().parse("{\"id\":\"" + topic + "\"}" ), true );
} catch (ParseException ex) {
throw new AssertionError();
}
}
}
} catch (Exception ex) {
LOGGER.log(Level.SEVERE, ex.getMessage(), ex);
}
}
@Override
public void onClose (Session session, CloseReason closeReason) {
synchronized (WebsocketEndpoint.this ) {
WebsocketEndpoint.this .websocket = null ;
}
}
@Override
public void onError (Session session, Throwable thr) {
Logger.getLogger(WebsocketEndpoint.class.getName()).log(Level.SEVERE, null , thr);
}
}, cec, endpoint);
} catch (DeploymentException ex) {
LOGGER.log(Level.SEVERE, "Websocket deployment failed " + endpoint + ". " + ex.getMessage());
} catch (Exception ex) {
LOGGER.log(Level.SEVERE, ex.getMessage(), ex);
} finally {
synchronized (WebsocketEndpoint.this ) {
reconnecting = false ;
}
}
}
}.start();
}
private synchronized void sendRequest (RpcRequest request, boolean enqueueIfNotAvailable) {
if (this .websocket == null ) {
if (enqueueIfNotAvailable) {
reconnectingQueue.add(request);
} else if (request.getId() != null ) {
rpcCallbacks.remove(request.getId());
}
reconnect();
} else {
try {
this .websocket.send(JsonCodec.getInstance().transform(request));
} catch (IOException ex) {
if (!enqueueIfNotAvailable && request.getId() != null ) {
rpcCallbacks.remove(request.getId());
}
LOGGER.severe(ex.getMessage());
}
}
}
private synchronized void doExec (RpcCallback callback, String serviceId, JsonNode input, boolean enqueueIfNotAvailable) {
Integer reqId = null ;
if (callback != null ) {
reqId = reqCounter.getAndIncrement();
rpcCallbacks.put(reqId, callback);
}
RpcRequest request = new RpcRequest();
request.setJsonrpc("2.0" );
request.setId(reqId);
request.setParams(input);
request.setMethod(serviceId);
sendRequest(request, enqueueIfNotAvailable);
}
public synchronized void exec (RpcCallback callback, String serviceId, JsonNode input) {
if (serviceId == null ) {
throw new IllegalArgumentException("execParam.service is required" );
}
if (serviceMap.size() > 0 ) {
JsonNode service = serviceMap.get(serviceId);
if (service == null ) {
throw new IllegalArgumentException("Service not found: '" + serviceId + "'" );
}
doExec(callback, serviceId, input, true );
} else {
initialQueue.add(new Trie(callback, serviceId, input));
}
}
public synchronized void subscribe (String topicId, TopicCallback callback) {
topicCallbacks.put(topicId, callback);
if (this .websocket != null ) {
try {
exec(null , "rpc.topics.subscribe" , JsonCodec.getInstance().parse("{\"id\":\"" + topicId + "\"}" ));
} catch (ParseException ex) {
throw new AssertionError();
}
}
}
public synchronized void unsubscribe (String topicId) {
if (!topicCallbacks.containsKey(topicId)) {
throw new IllegalArgumentException("Not subscribed to topic " + topicId);
}
try {
topicCallbacks.remove(topicId);
exec(null , "rpc.topics.unsubscribe" , JsonCodec.getInstance().parse("{\"id\":\"" + topicId + "\"}" ));
} catch (ParseException ex) {
throw new AssertionError();
}
}
public void close () throws IOException {
this .pingThread.interrupt();
if (this .websocket != null ) {
this .websocket.close();
}
}
}