2014-10-16 15 views
9

Ho sfogliato molti esempi di Web Socket, diapositive di presentazione e sono per lo più concentrati su scenari piuttosto semplici in cui la comunicazione client-server viene avviata dal client.Come implementare push to client utilizzando Java EE 7 WebSockets?

Sono interessato a un altro scenario, che sembra essere altrettanto pratico: puro server push al client.

Esempio che ho in mente è un'applicazione che aggiorna il valore delle azioni su un sito web. Immaginiamo che esista un sistema di borsa valori esterno, che invia un messaggio JMS per ogni variazione di valore di azioni sottoscritte.

Mi piacerebbe sapere come tradurre tale evento JMS in entrata in un server push e in modo efficiente e idiomatico da un punto di vista Java EE 7.

Per quanto posso capire le specifiche, dovrei scrivere un endpoint WebSocket

@ServerEndpoint("/demo") 
public class WSEndpoint { 
    private static final Logger LOG = Logger.getLogger(WSEndpoint.class); 

    @OnMessage 
    public void onMessage(String message, Session session) { 
    LOG.info("Received : " + message + ", session:" + session.getId()); 
    } 

    @OnOpen 
    public void open(Session session) { 
    LOG.info("Open session:" + session.getId());   
    } 

    @OnClose 
    public void close(Session session, CloseReason c) { 
    log.info("Close session:" + session.getId()); 
    } 
} 

Tutto è facile quando sto ottenendo un messaggio dal frontend, posso fare quello che mi piace in Metodo @OnMessage. Ma nel mio esempio non avrò alcun messaggio dal client, riceverò un evento da qualche sistema esterno.

Ci sono alcuni approcci. Ad esempio, posso creare un thread in un metodo @OnOpen, come dimostrato in this blog. In pratica, questo approccio potrebbe mostrare un difetto poiché per ogni cliente avrei bisogno di creare un nuovo thread potenzialmente longevo.

Uno può fare meglio utilizzando i canali NIO con i selettori, ma ciò richiederebbe una sorta di gestione dei canali "fatti a mano". Fattibile, ma piuttosto ingombrante

Un'altra soluzione sarebbe quella di eseguire il ping di qualche altro sistema per gli aggiornamenti, ma ancora una volta sarebbe un po 'brutto. Inoltre, non sono nemmeno sicuro se un metodo @OnOpen debba essere utilizzato in questo modo.

Idealmente un messaggio JMS in entrata attiverà un push Web Socket al client. Qualche idea su come implementare qualcosa di simile?

+1

https://blogs.oracle.com/brunoborges/entry/integrating_websockets_and_jms_with –

+0

Grazie per il link. Sembra abbastanza buono (al punto 7 c'è l'implementazione push effettiva). È fatto nel modo seguente: dobbiamo creare un insieme di tutte le sessioni (set sincronizzato statico). Quindi, se vogliamo inviare push al client, passiamo attraverso quel set e attiviamo le push. Ci sono alcuni inconvenienti di questo approccio, ma nulla che non possa essere superato. –

+0

La nostra domanda è strettamente correlata: https://stackoverflow.com/questions/27037570/find-websocket-session-by-id-in-java-ee-7/27045235 – Ihromant

risposta

4

Probabilmente questo non è il modo più elegante ma solo per dimostrare un'idea. Il metodo broadcast() invierà un messaggio a tutti i client connessi.

@ServerEndpoint("/echo") 
public class ServerEndPoint { 

    private static Set<Session> userSessions = Collections.newSetFromMap(new ConcurrentHashMap<Session, Boolean>()); 

    @OnOpen 
    public void onOpen(Session userSession) { 
     userSessions.add(userSession); 
    } 

    @OnClose 
    public void onClose(Session userSession) { 
     userSessions.remove(userSession); 
    } 

    @OnMessage 
    public void onMessage(String message, Session userSession) { 
     broadcast(message); 
    } 

    public static void broadcast(String msg) { 
     for (Session session : userSessions) { 
      session.getAsyncRemote().sendText(msg); 
     } 
    } 

} 
+0

è meglio usare il metodo getAsyncRemote() o getBasicRemote()? –

1

lo faccio in questo modo (non è necessaria alcuna richiesta del cliente):

@ServerEndpoint("/hello") 
public class HelloWebSocket { 

    @OnOpen 
    public void greetTheClient(Session session){ 
     try { 
     session.getBasicRemote().sendText("Hello stranger"); 

    } catch (IOException ioe) { 
     System.out.println(ioe.getMessage()); 
    } 
    } 
}