package xdi2.client.impl.websocket.endpoint; import java.io.IOException; import java.io.Reader; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.websocket.CloseReason; import javax.websocket.CloseReason.CloseCodes; import javax.websocket.Session; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import xdi2.client.impl.websocket.XDIWebSocketClient; import xdi2.client.impl.websocket.XDIWebSocketClient.Callback; import xdi2.core.Graph; import xdi2.core.impl.memory.MemoryGraphFactory; import xdi2.core.io.MimeType; import xdi2.core.io.XDIReader; import xdi2.core.io.XDIReaderRegistry; import xdi2.core.syntax.XDIAddress; import xdi2.core.util.CopyUtil; import xdi2.messaging.Message; import xdi2.messaging.MessageEnvelope; import xdi2.messaging.response.FullMessagingResponse; import xdi2.messaging.response.FutureMessagingResponse; import xdi2.messaging.response.LightMessagingResponse; import xdi2.messaging.response.TransportMessagingResponse; import xdi2.messaging.util.MessagingCloneUtil; public class WebSocketClientMessageHandler implements javax.websocket.MessageHandler.Whole<Reader> { private static final Logger log = LoggerFactory.getLogger(WebSocketClientMessageHandler.class); private Session session; public WebSocketClientMessageHandler(Session session) { this.session = session; } @Override public void onMessage(Reader reader) { if (log.isDebugEnabled()) log.debug("Incoming WebSocket message on session " + this.getSession().getId()); // read properties XDIWebSocketClient webSocketClient = (XDIWebSocketClient) this.getSession().getUserProperties().get("xdiWebSocketClient"); // construct graph from reader Graph graph; try { graph = read(this.getSession(), reader); if (graph == null) return; } catch (IOException ex) { try { log.error("I/O exception: " + ex.getMessage(), ex); this.getSession().close(new CloseReason(CloseCodes.UNEXPECTED_CONDITION, "I/O exception: " + ex.getMessage())); return; } catch (IOException ex2) { log.error("Cannot close session: " + ex.getMessage(), ex); return; } } // message envelope? messaging response? MessageEnvelope graphMessageEnvelope = MessageEnvelope.fromGraph(graph); MessageEnvelope callbackMessageEnvelope = null; TransportMessagingResponse callbackMessagingResponse = null; List<FutureMessagingResponse> callbackFutureMessagingResponses = new ArrayList<FutureMessagingResponse> (); Map<FutureMessagingResponse, XDIAddress> callbackFutureMessageXDIAddresses = new HashMap<FutureMessagingResponse, XDIAddress> (); Map<FutureMessagingResponse, FullMessagingResponse> callbackFutureFullMessagingResponses = new HashMap<FutureMessagingResponse, FullMessagingResponse> (); if (graphMessageEnvelope.getMessageCount() > 0) { Graph callbackMessageEnvelopeGraph = MemoryGraphFactory.getInstance().openGraph(); Graph callbackFullMessagingResponseGraph = MemoryGraphFactory.getInstance().openGraph(); for (Message message : graphMessageEnvelope.getMessages()) { if (message.getCorrelationXDIAddress() == null) { // this message should be sent to WebSocketClient.onMessageEnvelope() callback CopyUtil.copyGraph(MessagingCloneUtil.cloneMessage(message, false).getMessageEnvelope().getGraph(), callbackMessageEnvelopeGraph, null); } else { // this message should be sent to WebSocketClient.onMessagingResponse() callback CopyUtil.copyGraph(MessagingCloneUtil.cloneMessage(message, false).getMessageEnvelope().getGraph(), callbackFullMessagingResponseGraph, null); FutureMessagingResponse futureMessagingResponse = webSocketClient.getFutureMessagingResponses().get(message.getCorrelationXDIAddress()); if (futureMessagingResponse != null) { webSocketClient.removeFutureMessagingResponse(message.getCorrelationXDIAddress()); // this message should be sent to FutureMessagingResponse.onMessagingResponse() callback FullMessagingResponse fullMessagingResponse = FullMessagingResponse.fromMessageEnvelope(MessagingCloneUtil.cloneMessage(message, false).getMessageEnvelope()); callbackFutureMessagingResponses.add(futureMessagingResponse); callbackFutureMessageXDIAddresses.put(futureMessagingResponse, message.getCorrelationXDIAddress()); callbackFutureFullMessagingResponses.put(futureMessagingResponse, fullMessagingResponse); } } } if (! callbackMessageEnvelopeGraph.isEmpty()) callbackMessageEnvelope = MessageEnvelope.fromGraph(callbackMessageEnvelopeGraph); if (! callbackFullMessagingResponseGraph.isEmpty()) callbackMessagingResponse = FullMessagingResponse.fromGraph(callbackFullMessagingResponseGraph); } else { // this graph should be sent to WebSocketClient.onMessagingResponse() callback callbackMessagingResponse = LightMessagingResponse.fromGraph(graph); } // callbacks Callback callback = webSocketClient.getCallback(); if (callback != null && callbackMessageEnvelope != null) { if (log.isDebugEnabled()) log.debug("Calling WebSocketClient.onMessageEnvelope() with " + callbackMessageEnvelope); callback.onMessageEnvelope(callbackMessageEnvelope); } if (callback != null && callbackMessagingResponse != null) { if (log.isDebugEnabled()) log.debug("Calling WebSocketClient.onMessagingResponse() with " + callbackMessagingResponse.getClass().getSimpleName() + ": " + callbackMessagingResponse.getGraph()); callback.onMessagingResponse(callbackMessagingResponse); } for (FutureMessagingResponse callbackFutureMessagingResponse : callbackFutureMessagingResponses) { XDIAddress callbackFutureMessageXDIAddress = callbackFutureMessageXDIAddresses.get(callbackFutureMessagingResponse); FullMessagingResponse callbackFutureFullMessagingResponse = callbackFutureFullMessagingResponses.get(callbackFutureMessagingResponse); if (log.isDebugEnabled()) log.debug("Calling FutureMessagingResponse.onMessagingResponse() with " + callbackFutureMessageXDIAddress + " and " + callbackFutureFullMessagingResponse.getClass().getSimpleName() + ": " + callbackFutureFullMessagingResponse.getGraph()); callbackFutureMessagingResponse.onMessagingResponse(callbackFutureMessageXDIAddress, callbackFutureFullMessagingResponse); } } /* * Getters and setters */ public Session getSession() { return this.session; } /* * Helper methods */ private static Graph read(Session session, Reader reader) throws IOException { // try to find an appropriate reader for the provided mime type XDIReader xdiReader = null; String contentType = session.getNegotiatedSubprotocol(); MimeType recvMimeType = contentType != null ? new MimeType(contentType) : null; xdiReader = recvMimeType != null ? XDIReaderRegistry.forMimeType(recvMimeType) : null; if (xdiReader == null) xdiReader = XDIReaderRegistry.getDefault(); // read everything into an in-memory XDI graph (a message envelope) if (log.isDebugEnabled()) log.debug("Reading message in " + recvMimeType + " with reader " + xdiReader.getClass().getSimpleName() + "."); Graph graph; try { graph = MemoryGraphFactory.getInstance().openGraph(); xdiReader.read(graph, reader); } catch (IOException ex) { throw ex; } catch (Exception ex) { log.error("Cannot parse XDI graph: " + ex.getMessage(), ex); throw new IOException("Cannot parse XDI graph: " + ex.getMessage(), ex); } finally { reader.close(); } if (log.isDebugEnabled()) log.debug("Graph received: " + graph); // done return graph; } }