added java jabber layer
[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     /** jabber domain */
23     private String host;
24     /** jabber port */
25     private int port;
26     /** jabber username */
27     private String username;
28     /** jabber password */
29     private String password;
30     /** jabber resource */
31     private String resource;
32
33     /** XMPP stream reader */
34     XMPPReader reader;
35     /** Fprint-capable socket writer */
36     PrintWriter writer;
37     /** Raw socket output stream */
38     OutputStream outStream;
39
40
41
42     /**
43      * Creates a new session.
44      * @param host The jabber domain
45      * @param port The jabber port
46      */
47     public XMPPSession( String host, int port ) {
48         this.host = host;
49         this.port = port;
50     }
51
52
53     /** true if this session is connected to the server */
54     public boolean connected() {
55         return (
56             reader != null && 
57             reader.getXMPPStreamState() == XMPPReader.XMPPStreamState.CONNECTED);
58     }
59
60
61     /**
62      * Connects to the network.
63      * @param username The jabber username
64      * @param password The jabber password
65      * @param resource The Jabber resource
66      */
67     public void connect(String username, String password, String resource) throws XMPPException {
68
69         this.username = username;
70         this.password = password;
71         this.resource = resource;
72
73         Socket socket;
74
75         try { 
76             /* open the socket and associated streams */
77             socket = new Socket(host, port);
78
79             /** the session maintains control over the output stream */
80             outStream = socket.getOutputStream();
81             writer = new PrintWriter(outStream, true);
82
83             /** pass the input stream to the reader */
84             reader = new XMPPReader(socket.getInputStream());
85
86         } catch(IOException ioe) {
87             throw new 
88                 XMPPException("unable to communicate with host " + host + " on port " + port);
89         }
90
91         /* build the reader thread */
92         Thread thread = new Thread(reader);
93         thread.setDaemon(true);
94         thread.start();
95
96         /* send the initial jabber message */
97         sendConnect();
98         reader.waitCoreEvent(10000);
99         if( reader.getXMPPStreamState() != XMPPReader.XMPPStreamState.CONNECT_RECV ) 
100             throw new XMPPException("unable to connect to jabber server");
101
102         /* send the basic auth message */
103         sendBasicAuth(); /* XXX add support for other auth mechanisms */
104         reader.waitCoreEvent(10000);
105         if(!connected())
106             throw new XMPPException("Authentication failed");
107     }
108
109     /** Sends the initial jabber message */
110     private void sendConnect() {
111         writer.printf(JABBER_CONNECT, host);
112         reader.setXMPPStreamState(XMPPReader.XMPPStreamState.CONNECT_SENT);
113     }
114
115     /** Send the basic auth message */
116     private void sendBasicAuth() {
117         writer.printf(JABBER_BASIC_AUTH, username, password, resource);
118         reader.setXMPPStreamState(XMPPReader.XMPPStreamState.AUTH_SENT);
119     }
120
121
122     /**
123      * Sends an XMPPMessage.
124      * @param msg The message to send.
125      */
126     public void send(XMPPMessage msg) throws XMPPException {
127         checkConnected();
128         try {
129             outStream.write(msg.toXML().getBytes()); 
130         } catch (Exception e) {
131             throw new XMPPException(e.toString());
132         }
133     }
134
135
136     /**
137      * @throws XMPPException if we are no longer connected.
138      */
139     private void checkConnected() throws XMPPException {
140         if(!connected())
141             throw new XMPPException("Disconnected stream");
142     }
143
144
145     /**
146      * Receives messages from the network.  
147      * @param timeout Maximum number of milliseconds to wait for a message to arrive.
148      * If timeout is negative, this method will wait indefinitely.
149      * If timeout is 0, this method will not block at all, but will return a 
150      * message if there is already a message available.
151      */
152     public XMPPMessage recv(int timeout) throws XMPPException {
153
154         XMPPMessage msg;
155
156         if(timeout < 0) {
157
158             while(true) { /* wait indefinitely for a message to arrive */
159                 reader.waitCoreEvent(timeout);
160                 msg = reader.popMessageQueue();
161                 if( msg != null ) return msg;
162                 checkConnected();
163             }
164
165         } else {
166
167             while(timeout >= 0) { /* wait at most 'timeout' milleseconds for a message to arrive */
168                 timeout -= reader.waitCoreEvent(timeout);
169                 msg = reader.popMessageQueue();
170                 if( msg != null ) return msg;
171                 checkConnected();
172             }
173         }
174
175         return null;
176     }
177 }
178