/** * Copyright (C) 2010-14 diirt developers. See COPYRIGHT.TXT * All rights reserved. Use is subject to license terms. See LICENSE.TXT */ package org.diirt.datasource.pods.web; import java.net.URI; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Level; import java.util.logging.Logger; import javax.websocket.ClientEndpoint; import javax.websocket.CloseReason; import javax.websocket.ContainerProvider; import javax.websocket.OnClose; import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.WebSocketContainer; import org.diirt.pods.web.common.Message; import org.diirt.pods.web.common.MessageConnectionEvent; import org.diirt.pods.web.common.MessageDecoder; import org.diirt.pods.web.common.MessageEncoder; import org.diirt.pods.web.common.MessageErrorEvent; import org.diirt.pods.web.common.MessagePause; import org.diirt.pods.web.common.MessageResume; import org.diirt.pods.web.common.MessageSubscribe; import org.diirt.pods.web.common.MessageUnsubscribe; import org.diirt.pods.web.common.MessageValueEvent; import org.diirt.pods.web.common.MessageWriteCompletedEvent; /** * * @author carcassi */ @ClientEndpoint ( decoders = { MessageDecoder.class }, encoders = { MessageEncoder.class } ) public class WebPodsClient { private static final Logger log = Logger.getLogger(WebPodsClient.class.getName()); private final Object lock = new Object(); private Session session; private boolean connected = false; private String disconnectReason = "Connection failed"; @OnOpen public void onOpen(Session session) { synchronized(lock) { this.session = session; connected = true; disconnectReason = null; } for (Map.Entry<Integer, WebPodsChannel> entrySet : channels.entrySet()) { WebPodsChannel channel = entrySet.getValue(); subscribeChannel(channel); } } @OnClose public void onClose(Session session, CloseReason closeReason) { synchronized(lock) { this.session = null; connected = false; disconnectReason = closeReason.getReasonPhrase(); } for (Map.Entry<Integer, WebPodsChannel> entrySet : channels.entrySet()) { WebPodsChannel channel = entrySet.getValue(); channel.getListener().onDisconnect(closeReason); } } public boolean isConnected() { synchronized(lock) { return connected; } } public String getDisconnectReason() { synchronized(lock) { return disconnectReason; } } @OnMessage public void onMessage(Message message, Session session) { int channelId = message.getId(); WebPodsChannel channel = channels.get(channelId); if (channel == null) { log.log(Level.WARNING, "Received an event for id " + channelId + " but no listener was found"); return; } WebPodsChannelListener listener = channel.getListener(); if (message instanceof MessageValueEvent) { MessageValueEvent event = (MessageValueEvent) message; listener.onValueEvent(event.getValue()); } else if (message instanceof MessageConnectionEvent) { MessageConnectionEvent event = (MessageConnectionEvent) message; listener.onConnectionEvent(event.isConnected(), event.isWriteConnected()); } else if (message instanceof MessageErrorEvent) { MessageErrorEvent event = (MessageErrorEvent) message; listener.onErrorEvent(event.getError()); } else if (message instanceof MessageWriteCompletedEvent) { MessageWriteCompletedEvent event = (MessageWriteCompletedEvent) message; listener.onWriteCompletedEvent(event.isSuccessful(), event.getError()); } else { log.log(Level.WARNING, "Received unsupported message " + message.getMessage() + " for id " + channelId); } } private final AtomicInteger counter = new AtomicInteger(); private final Map<Integer, WebPodsChannel> channels = new ConcurrentHashMap<>(); public WebPodsChannel subscribe(String channelName, WebPodsChannelListener listener) { int id = counter.incrementAndGet(); WebPodsChannel channel = new WebPodsChannel(channelName, id, this, listener); channels.put(id, channel); subscribeChannel(channel); return channel; } void subscribeChannel(WebPodsChannel channel) { Session currentSession; synchronized(lock) { currentSession = session; } if (currentSession == null) { return; } currentSession.getAsyncRemote().sendObject(new MessageSubscribe(channel.getId(), channel.getChannelName(), null, -1, true)); } void unsubscribeChannel(WebPodsChannel channel) { channels.remove(channel.getId()); Session currentSession; synchronized(lock) { currentSession = session; } if (currentSession == null) { return; } currentSession.getAsyncRemote().sendObject(new MessageUnsubscribe(channel.getId())); } void pauseChannel(WebPodsChannel channel) { channels.remove(channel.getId()); Session currentSession; synchronized(lock) { currentSession = session; } if (currentSession == null) { return; } session.getAsyncRemote().sendObject(new MessagePause(channel.getId())); } void resumeChannel(WebPodsChannel channel) { channels.remove(channel.getId()); Session currentSession; synchronized(lock) { currentSession = session; } if (currentSession == null) { return; } session.getAsyncRemote().sendObject(new MessageResume(channel.getId())); } public static void main(String[] args) throws Exception { WebSocketContainer container = ContainerProvider.getWebSocketContainer(); WebPodsClient client = new WebPodsClient(); container.connectToServer(client, new URI("ws://localhost:8080/web-pods/socket")); WebPodsChannel channel = client.subscribe("sim://noise", new WebPodsChannelListener() { @Override public void onConnectionEvent(boolean connected, boolean writeConnected) { System.out.println("Connected: " + connected + "; Write connected: " + writeConnected); } @Override public void onValueEvent(Object value) { System.out.println("New value: " + value); } }); WebPodsChannel channel2 = client.subscribe("sim://table", new WebPodsChannelListener() { @Override public void onConnectionEvent(boolean connected, boolean writeConnected) { System.out.println("Connected: " + connected + "; Write connected: " + writeConnected); } @Override public void onValueEvent(Object value) { System.out.println("New value: " + value); } }); Thread.sleep(5000); channel.unsubscribe(); Thread.sleep(5000); } }