]> git.evergreen-ils.org Git - OpenSRF.git/blob - src/java/org/opensrf/net/xmpp/XMPPSession.java
11e0c7d45bfe2bc0c66a6bafbfe08a729418e7ff
[OpenSRF.git] / src / java / org / opensrf / net / xmpp / XMPPSession.java
1 package org.opensrf.net.xmpp;
2
3 import java.io.*;
4 import java.net.Socket;
5
6
7 /**
8  * Represents a single XMPP session.  Sessions are responsible for writing to
9  * the stream and for managing a stream reader.
10  */
11 public class XMPPSession {
12
13     /** Initial jabber message */
14     public static final String JABBER_CONNECT = 
15         "<stream:stream to='%s' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>";
16
17     /** Basic auth message */
18     public static final String JABBER_BASIC_AUTH =  
19         "<iq id='123' type='set'><query xmlns='jabber:iq:auth'>" +
20         "<username>%s</username><password>%s</password><resource>%s</resource></query></iq>";
21
22     public static final String JABBER_DISCONNECT = "</stream:stream>";
23
24     /** jabber domain */
25     private String host;
26     /** jabber port */
27     private int port;
28     /** jabber username */
29     private String username;
30     /** jabber password */
31     private String password;
32     /** jabber resource */
33     private String resource;
34
35     /** XMPP stream reader */
36     XMPPReader reader;
37     /** Fprint-capable socket writer */
38     PrintWriter writer;
39     /** Raw socket output stream */
40     OutputStream outStream;
41     /** The raw socket */
42     Socket socket;
43
44     /** The process-wide session.  All communication occurs
45      * accross this single connection */
46     private static XMPPSession globalSession;
47
48
49     /**
50      * Creates a new session.
51      * @param host The jabber domain
52      * @param port The jabber port
53      */
54     public XMPPSession( String host, int port ) {
55         this.host = host;
56         this.port = port;
57     }
58
59     /**
60      * Returns the global, process-wide session
61      */
62     public static XMPPSession getGlobalSession() {
63         return globalSession;
64     }
65
66     /**
67      * Sets the global, process-wide section
68      */
69     public static void setGlobalSession(XMPPSession ses) {
70         globalSession = ses;
71     }
72
73
74     /** true if this session is connected to the server */
75     public boolean connected() {
76         return (
77             reader != null && 
78             reader.getXMPPStreamState() == 
79                 XMPPReader.XMPPStreamState.CONNECTED);
80     }
81
82
83     /**
84      * Connects to the network.
85      * @param username The jabber username
86      * @param password The jabber password
87      * @param resource The Jabber resource
88      */
89     public void connect(String username, String password, String resource) throws XMPPException {
90
91         this.username = username;
92         this.password = password;
93         this.resource = resource;
94
95         try { 
96             /* open the socket and associated streams */
97             socket = new Socket(host, port);
98
99             /** the session maintains control over the output stream */
100             outStream = socket.getOutputStream();
101             writer = new PrintWriter(outStream, true);
102
103             /** pass the input stream to the reader */
104             reader = new XMPPReader(socket.getInputStream());
105
106         } catch(IOException ioe) {
107             throw new 
108                 XMPPException("unable to communicate with host " + host + " on port " + port);
109         }
110
111         /* build the reader thread */
112         Thread thread = new Thread(reader);
113         thread.setDaemon(true);
114         thread.start();
115
116         synchronized(reader) {
117             /* send the initial jabber message */
118             sendConnect();
119             reader.waitCoreEvent(10000);
120         }
121         if( reader.getXMPPStreamState() != XMPPReader.XMPPStreamState.CONNECT_RECV ) 
122             throw new XMPPException("unable to connect to jabber server");
123
124         synchronized(reader) {
125             /* send the basic auth message */
126             sendBasicAuth(); 
127             reader.waitCoreEvent(10000);
128         }
129         if(!connected()) 
130             throw new XMPPException("Authentication failed");
131     }
132
133     /** Sends the initial jabber message */
134     private void sendConnect() {
135         reader.setXMPPStreamState(XMPPReader.XMPPStreamState.CONNECT_SENT);
136         writer.printf(JABBER_CONNECT, host);
137     }
138
139     /** Send the basic auth message */
140     private void sendBasicAuth() {
141         reader.setXMPPStreamState(XMPPReader.XMPPStreamState.AUTH_SENT);
142         writer.printf(JABBER_BASIC_AUTH, username, password, resource);
143     }
144
145
146     /**
147      * Sends an XMPPMessage.
148      * @param msg The message to send.
149      */
150     public synchronized void send(XMPPMessage msg) throws XMPPException {
151         checkConnected();
152         try {
153             String xml = msg.toXML();
154             outStream.write(xml.getBytes()); 
155         } catch (Exception e) {
156             throw new XMPPException(e.toString());
157         }
158     }
159
160
161     /**
162      * @throws XMPPException if we are no longer connected.
163      */
164     private void checkConnected() throws XMPPException {
165         if(!connected())
166             throw new XMPPException("Disconnected stream");
167     }
168
169
170     /**
171      * Receives messages from the network.  
172      * @param timeout Maximum number of milliseconds to wait for a message to arrive.
173      * If timeout is negative, this method will wait indefinitely.
174      * If timeout is 0, this method will not block at all, but will return a 
175      * message if there is already a message available.
176      */
177     public XMPPMessage recv(long timeout) throws XMPPException {
178
179         XMPPMessage msg;
180
181         if(timeout < 0) {
182
183             while(true) { /* wait indefinitely for a message to arrive */
184                 reader.waitCoreEvent(timeout);
185                 msg = reader.popMessageQueue();
186                 if( msg != null ) return msg;
187                 checkConnected();
188             }
189
190         } else {
191
192             while(timeout >= 0) { /* wait at most 'timeout' milleseconds for a message to arrive */
193                 timeout -= reader.waitCoreEvent(timeout);
194                 msg = reader.popMessageQueue();
195                 if( msg != null ) return msg;
196                 checkConnected();
197             }
198         }
199
200         return null;
201     }
202
203
204     /**
205      * Disconnects from the jabber server and closes the socket
206      */
207     public void disconnect() {
208         try {
209             outStream.write(JABBER_DISCONNECT.getBytes());
210             socket.close();
211         } catch(Exception e) {}
212     }
213 }
214