/src/java/org/opensrf/net/xmpp/XMPPSession.java
Java | 263 lines | 137 code | 46 blank | 80 comment | 22 complexity | 472d01326275bc38d8b2f8f81664f10e MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause
- package org.opensrf.net.xmpp;
- import java.io.*;
- import java.net.Socket;
- import java.util.Map;
- import java.util.Iterator;
- import java.util.concurrent.ConcurrentHashMap;
- /**
- * Represents a single XMPP session. Sessions are responsible for writing to
- * the stream and for managing a stream reader.
- */
- public class XMPPSession {
- /** Initial jabber message */
- public static final String JABBER_CONNECT =
- "<stream:stream to='%s' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>";
- /** Basic auth message */
- public static final String JABBER_BASIC_AUTH =
- "<iq id='123' type='set'><query xmlns='jabber:iq:auth'>" +
- "<username>%s</username><password>%s</password><resource>%s</resource></query></iq>";
- public static final String JABBER_DISCONNECT = "</stream:stream>";
- private static Map threadConnections = new ConcurrentHashMap();
- /** jabber domain */
- private String host;
- /** jabber port */
- private int port;
- /** jabber username */
- private String username;
- /** jabber password */
- private String password;
- /** jabber resource */
- private String resource;
- /** XMPP stream reader */
- XMPPReader reader;
- /** Fprint-capable socket writer */
- PrintWriter writer;
- /** Raw socket output stream */
- OutputStream outStream;
- /** The raw socket */
- Socket socket;
- /** The process-wide session. All communication occurs
- * accross this single connection */
- private static XMPPSession globalSession;
- /**
- * Creates a new session.
- * @param host The jabber domain
- * @param port The jabber port
- */
- public XMPPSession( String host, int port ) {
- this.host = host;
- this.port = port;
- }
- /**
- * Returns the global, process-wide session
- */
- /*
- public static XMPPSession getGlobalSession() {
- return globalSession;
- }
- */
- public static XMPPSession getThreadSession() {
- return (XMPPSession) threadConnections.get(new Long(Thread.currentThread().getId()));
- }
- /**
- * Sets the given session as the global session for the current thread
- * @param ses The session
- */
- public static void setThreadSession(XMPPSession ses) {
- /* every time we create a new connection, clean up any dead threads.
- * this is cheaper than cleaning up the dead threads at every access. */
- cleanupThreadSessions();
- threadConnections.put(new Long(Thread.currentThread().getId()), ses);
- }
- /**
- * Analyzes the threadSession data to see if there are any sessions
- * whose controlling thread has gone away.
- */
- private static void cleanupThreadSessions() {
- Thread threads[] = new Thread[Thread.activeCount()];
- Thread.enumerate(threads);
- for(Iterator i = threadConnections.keySet().iterator(); i.hasNext(); ) {
- boolean found = false;
- Long id = (Long) i.next();
- for(Thread t : threads) {
- if(t.getId() == id.longValue()) {
- found = true;
- break;
- }
- }
- if(!found)
- threadConnections.remove(id);
- }
- }
- /**
- * Sets the global, process-wide section
- */
- /*
- public static void setGlobalSession(XMPPSession ses) {
- globalSession = ses;
- }
- */
- /** true if this session is connected to the server */
- public boolean connected() {
- return (
- reader != null &&
- reader.getXMPPStreamState() == XMPPReader.XMPPStreamState.CONNECTED &&
- !socket.isClosed()
- );
- }
- /**
- * Connects to the network.
- * @param username The jabber username
- * @param password The jabber password
- * @param resource The Jabber resource
- */
- public void connect(String username, String password, String resource) throws XMPPException {
- this.username = username;
- this.password = password;
- this.resource = resource;
- try {
- /* open the socket and associated streams */
- socket = new Socket(host, port);
- /** the session maintains control over the output stream */
- outStream = socket.getOutputStream();
- writer = new PrintWriter(outStream, true);
- /** pass the input stream to the reader */
- reader = new XMPPReader(socket.getInputStream());
- } catch(IOException ioe) {
- throw new
- XMPPException("unable to communicate with host " + host + " on port " + port);
- }
- /* build the reader thread */
- Thread thread = new Thread(reader);
- thread.setDaemon(true);
- thread.start();
- synchronized(reader) {
- /* send the initial jabber message */
- sendConnect();
- reader.waitCoreEvent(10000);
- }
- if( reader.getXMPPStreamState() != XMPPReader.XMPPStreamState.CONNECT_RECV )
- throw new XMPPException("unable to connect to jabber server");
- synchronized(reader) {
- /* send the basic auth message */
- sendBasicAuth();
- reader.waitCoreEvent(10000);
- }
- if(!connected())
- throw new XMPPException("Authentication failed");
- }
- /** Sends the initial jabber message */
- private void sendConnect() {
- reader.setXMPPStreamState(XMPPReader.XMPPStreamState.CONNECT_SENT);
- writer.printf(JABBER_CONNECT, host);
- }
- /** Send the basic auth message */
- private void sendBasicAuth() {
- reader.setXMPPStreamState(XMPPReader.XMPPStreamState.AUTH_SENT);
- writer.printf(JABBER_BASIC_AUTH, username, password, resource);
- }
- /**
- * Sends an XMPPMessage.
- * @param msg The message to send.
- */
- public synchronized void send(XMPPMessage msg) throws XMPPException {
- checkConnected();
- try {
- String xml = msg.toXML();
- outStream.write(xml.getBytes());
- } catch (Exception e) {
- throw new XMPPException(e.toString());
- }
- }
- /**
- * @throws XMPPException if we are no longer connected.
- */
- private void checkConnected() throws XMPPException {
- if(!connected())
- throw new XMPPException("Disconnected stream");
- }
- /**
- * Receives messages from the network.
- * @param timeout Maximum number of milliseconds to wait for a message to arrive.
- * If timeout is negative, this method will wait indefinitely.
- * If timeout is 0, this method will not block at all, but will return a
- * message if there is already a message available.
- */
- public XMPPMessage recv(long timeout) throws XMPPException {
- XMPPMessage msg;
- if(timeout < 0) {
- while(true) { /* wait indefinitely for a message to arrive */
- reader.waitCoreEvent(timeout);
- msg = reader.popMessageQueue();
- if( msg != null ) return msg;
- checkConnected();
- }
- } else {
- while(timeout >= 0) { /* wait at most 'timeout' milleseconds for a message to arrive */
- msg = reader.popMessageQueue();
- if( msg != null ) return msg;
- timeout -= reader.waitCoreEvent(timeout);
- msg = reader.popMessageQueue();
- if( msg != null ) return msg;
- checkConnected();
- if(timeout == 0) break;
- }
- }
- return reader.popMessageQueue();
- }
- /**
- * Disconnects from the jabber server and closes the socket
- */
- public void disconnect() {
- try {
- outStream.write(JABBER_DISCONNECT.getBytes());
- socket.close();
- } catch(Exception e) {}
- }
- }