001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026:
027: package javax.microedition.sip;
028:
029: import com.sun.midp.i3test.TestCase;
030: import javax.microedition.io.Connector;
031: import javax.microedition.sip.SipConnectionNotifier;
032: import javax.microedition.sip.SipServerConnection;
033: import javax.microedition.sip.SipClientConnection;
034: import java.io.InputStream;
035: import java.io.OutputStream;
036: import java.io.IOException;
037: import javax.microedition.sip.SipException;
038: import gov.nist.microedition.sip.SipClientConnectionImpl;
039: import gov.nist.microedition.sip.SipServerConnectionImpl;
040:
041: /**
042: * Test for SUBSCRIBE request.
043: *
044: * Let's suppose that there are two applications A and B exchanging
045: * SIP messages. Each application contains UAS and UAC. The corresponding
046: * connection notifier, server connection and client connection will be
047: * designated as NA, SA, CA and NB, SB, CB for A and B respectively.
048: *
049: * This test implements the following call flow:
050: *
051: * CA will send SUBSCRIBE
052: * NB will receive SUBSCRIBE
053: * SB will send 200 OK
054: * CA will receive 200 OK
055: * CB will send NOTIFY
056: * NA will receive NOTIFY
057: * SA will send 200 OK
058: * CB will receive 200 OK
059: */
060: public class TestSubscribeNotify extends TestCase implements
061: SipClientConnectionListener, SipServerConnectionListener {
062:
063: /** Client connection of the application A */
064: SipClientConnection sccA = null;
065:
066: /** Client connection of the application B */
067: SipClientConnection sccB = null;
068:
069: /** Connection notifier of the application A */
070: SipConnectionNotifier scnA = null;
071:
072: /** Connection notifier of the application B */
073: SipConnectionNotifier scnB = null;
074:
075: /** Server connection of the application A */
076: SipServerConnection sscA = null;
077:
078: /** Server connection of the application B */
079: SipServerConnection sscB = null;
080:
081: /** True if a response was received by the client */
082: private boolean responseReceived = false;
083:
084: /** True if NOTIFY request was received by the server */
085: private boolean notifyReceived = false;
086:
087: /** True if a response was sent by the server */
088: private boolean responseSent = false;
089:
090: /**
091: * Opens connections and set up listeners.
092: */
093: private void setup() {
094: try {
095: // Open SIP server connection and listen to port 5060
096: scnA = (SipConnectionNotifier) Connector.open("sip:5060");
097: scnA.setListener(this );
098:
099: // Open SIP server connection and listen to port 5070
100: scnB = (SipConnectionNotifier) Connector.open("sip:5070");
101: scnB.setListener(this );
102:
103: // Initialize connection to 'localhost'
104: sccA = (SipClientConnection) Connector
105: .open("sip:somebody@localhost:5070");
106: sccA.setListener(this );
107: } catch (Exception ex) { // handle Exceptions
108: ex.printStackTrace();
109: fail("Exception '" + ex + "' was thrown.");
110: }
111: }
112:
113: /**
114: * Do cleanup.
115: */
116: private void cleanup() {
117: try {
118: if (sccA != null) {
119: sccA.close();
120: }
121:
122: if (sscA != null) {
123: sscA.close();
124: assertEquals("State should be TERMINATED",
125: SipServerConnectionImpl.TERMINATED,
126: ((SipServerConnectionImpl) sscA).getState());
127: }
128:
129: if (sccB != null) {
130: sccB.close();
131: }
132:
133: if (sscB != null) {
134: sscB.close();
135: assertEquals("State should be TERMINATED",
136: SipServerConnectionImpl.TERMINATED,
137: ((SipServerConnectionImpl) sscB).getState());
138: }
139:
140: if (scnA != null) {
141: scnA.close();
142: }
143:
144: if (scnB != null) {
145: scnB.close();
146: }
147: } catch (IOException ioe) {
148: assertNull("Unexpected IOException during cleanup", ioe);
149: ioe.printStackTrace();
150: }
151: }
152:
153: /**
154: * Sends 'SUBSCRIBE' request.
155: * @param scc client connection
156: */
157: private void sendSubscribe(SipClientConnection scc) {
158: try {
159: // Initialize request and set From, To and Contact headers
160: scc.initRequest("SUBSCRIBE", null);
161: scc.setHeader("From", "sip:sippy.user@localhost");
162: scc.setHeader("To", "sip:sippy.user@localhost");
163: scc.setHeader("Contact",
164: "<sip:UserB@localhost>;expires=3600");
165: scc.setHeader("Expires", "3");
166:
167: try {
168: scc.send();
169: fail("SipException is not thrown when Event header is absent.");
170: } catch (SipException ex) {
171: // ok, SipException was generated
172: }
173:
174: scc.setHeader("Event", "presence.test");
175: scc.send();
176: } catch (Exception ex) { // handle Exceptions
177: ex.printStackTrace();
178: fail("sendSubscribe(): exception '" + ex + "' was thrown.");
179: }
180: }
181:
182: /**
183: * Waits for a response.
184: */
185: private void waitResponseReceived() {
186: synchronized (this ) {
187: try {
188: wait(2000);
189: } catch (Exception e) {
190: fail("Exception was thrown while waiting for response: "
191: + e);
192: }
193:
194: assertTrue("Response was not received!", responseReceived);
195: responseReceived = false;
196:
197: // System.out.println(">>> waitResponseReceived(): ok!");
198: }
199: }
200:
201: /**
202: * Sends NOTIFY.
203: * @param ssc server connection
204: * @param scc client connection
205: */
206: private void sendNotify(SipServerConnection ssc,
207: SipClientConnection scc) {
208: try {
209: SipDialog dialog = ssc.getDialog();
210: assertNotNull("sendNotify(): dialog is null!", dialog);
211:
212: scc = dialog.getNewClientConnection("NOTIFY");
213: sccB = scc;
214: assertNotNull("sendNotify(): scc is null!", scc);
215:
216: assertEquals("State should be INITIALIZED",
217: SipClientConnectionImpl.INITIALIZED,
218: ((SipClientConnectionImpl) scc).getState());
219:
220: scc.setHeader("Subscription-State", "active");
221: scc.setListener(this );
222: scc.send();
223: } catch (Exception ex) { // handle Exceptions
224: ex.printStackTrace();
225: fail("sendNotify(): exception '" + ex + "' was thrown.");
226: }
227: }
228:
229: /**
230: * Waits for NOTIFY.
231: */
232: private void waitNotifyReceived() {
233: synchronized (this ) {
234: try {
235: wait(2000);
236: } catch (Exception e) {
237: fail("Exception was thrown while waiting for NOTIFY: "
238: + e);
239: }
240:
241: assertTrue("NOTIFY was not received!", notifyReceived);
242: notifyReceived = false;
243:
244: // System.out.println(">>> waitNotifyReceived(): ok!");
245: }
246: }
247:
248: /**
249: * Sends a response.
250: * @param scc client connection
251: */
252: private void waitResponseSent(SipClientConnection scc) {
253: synchronized (this ) {
254: try {
255: wait(2000);
256: } catch (Exception e) {
257: fail("Exception was thrown while waiting "
258: + "when the response will bew sent: " + e);
259: }
260:
261: assertTrue("Response was not sent!", responseSent);
262: responseSent = false;
263:
264: // System.out.println(">>> waitResponseSent(): ok!");
265: }
266: }
267:
268: /**
269: * Test for SUBSCRIBE/NOTIFY.
270: */
271: public void testSubscribe() {
272: try {
273: sccA.initRequest("NOTIFY", null);
274: } catch (IllegalArgumentException iae) {
275: // ok, IAE was thrown when NOTIFY on attempt to sent NOTIFY
276: // outside of a dialog.
277: } catch (Exception ex) {
278: ex.printStackTrace();
279: fail("sendNotify(): exception '" + ex
280: + "' instead of IAE was thrown.");
281: }
282:
283: /*
284: * RFC 3265, p. 4:
285: *
286: * A typical flow of messages would be:
287: *
288: * Subscriber Notifier
289: * |-----SUBSCRIBE---->| Request state subscription
290: * |<-------200--------| Acknowledge subscription
291: * |<------NOTIFY------| Return current state information
292: * |--------200------->|
293: * |<------NOTIFY------| Return current state information
294: * |--------200------->|
295: *
296: */
297:
298: sendSubscribe(sccA);
299: waitResponseReceived();
300:
301: sendNotify(sscB, sccB);
302: waitNotifyReceived();
303: waitResponseSent(sccA);
304: waitResponseReceived();
305: }
306:
307: /**
308: * Accept a new connection request and process the request from client.
309: * Send "OK" to client.
310: *
311: * This method is declared in SipServerConnectionListener
312: * The code was copied from TestSipOriginatingInvite
313: *
314: * @param scnLocal Local SIP connection notifier
315: */
316: public void notifyRequest(SipConnectionNotifier scnLocal) {
317: SipServerConnection ssc;
318:
319: // System.out.println(">>> Request received!");
320:
321: try {
322: // block and wait for incoming request.
323: // SipServerConnection is establised and returned
324: // when new request is received.
325: ssc = scnLocal.acceptAndOpen();
326: assertNotNull("ssc is null", ssc);
327:
328: assertEquals("State should be REQUEST_RECEIVED",
329: SipServerConnectionImpl.REQUEST_RECEIVED,
330: ((SipServerConnectionImpl) ssc).getState());
331:
332: if (ssc.getMethod().equalsIgnoreCase("SUBSCRIBE")) {
333: // write message body to respond back to client
334: ssc.initResponse(200);
335:
336: assertEquals("State should be INITIALIZED",
337: SipServerConnectionImpl.INITIALIZED,
338: ((SipServerConnectionImpl) ssc).getState());
339:
340: sscB = ssc;
341: ssc.send();
342: } else if (ssc.getMethod().equalsIgnoreCase("NOTIFY")) {
343: notifyReceived = true;
344:
345: synchronized (this ) {
346: notifyAll();
347: }
348:
349: // send a response
350: ssc.initResponse(200);
351:
352: assertEquals("State should be INITIALIZED",
353: SipServerConnectionImpl.INITIALIZED,
354: ((SipServerConnectionImpl) ssc).getState());
355:
356: sscA = ssc;
357: ssc.send();
358:
359: // wake up the thread waiting until a response is sent
360: responseSent = true;
361:
362: synchronized (this ) {
363: notifyAll();
364: }
365: } else {
366: fail("Unexpected method: " + ssc.getMethod());
367: }
368: } catch (SipException sipex) {
369: sipex.printStackTrace();
370: fail("Unexpected SipException: " + sipex);
371: } catch (Exception e) {
372: e.printStackTrace();
373: fail("Unexpected Exception: " + e);
374: }
375: }
376:
377: /**
378: * Notifier
379: * @param scc client connection
380: */
381: public void notifyResponse(SipClientConnection scc) {
382: try {
383: // retrieve the response received
384: scc.receive(0);
385:
386: // System.out.println(">>> Response received: " +
387: // scc.getStatusCode());
388:
389: if (scc.getStatusCode() == 200) {
390: // handle 200 OK response
391: } else {
392: // handle possible error responses
393: fail("Response code: " + scc.getStatusCode());
394: }
395: } catch (Exception ex) {
396: // handle Exceptions
397: fail("Exception '" + ex + "' was thrown.");
398: }
399:
400: responseReceived = true;
401:
402: synchronized (this ) {
403: notifyAll();
404: }
405: }
406:
407: /**
408: * Run the tests.
409: */
410: public void runTests() {
411: setup();
412:
413: declare("Test for SUBSCRIBE request");
414: testSubscribe();
415:
416: cleanup();
417: }
418: }
|