001: /*
002: * Conditions Of Use
003: *
004: * This software was developed by employees of the National Institute of
005: * Standards and Technology (NIST), and others.
006: * This software is has been contributed to the public domain.
007: * As a result, a formal license is not needed to use the software.
008: *
009: * This software is provided "AS IS."
010: * NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
011: * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
012: * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
013: * AND DATA ACCURACY. NIST does not warrant or make any representations
014: * regarding the use of the software or the results thereof, including but
015: * not limited to the correctness, accuracy, reliability or usefulness of
016: * the software.
017: *
018: *
019: */
020: package test.tck.msgflow.callflows.subsnotify;
021:
022: import javax.sip.*;
023: import javax.sip.address.*;
024: import javax.sip.header.*;
025: import javax.sip.message.*;
026:
027: import org.apache.log4j.FileAppender;
028: import org.apache.log4j.Level;
029: import org.apache.log4j.Logger;
030: import org.apache.log4j.SimpleLayout;
031:
032: import test.tck.TestHarness;
033: import test.tck.msgflow.callflows.ProtocolObjects;
034:
035: import java.util.*;
036:
037: /**
038: * This class is a Subscriber template.
039: * The subscriber handles upstream forking by a proxy server. The stack is set up to
040: * expect forking of this event type. The test checks that exactly two distinct dialogs
041: * are created.
042: *
043: * This code is released to domain.
044: *
045: * @author M. Ranganathan
046: */
047:
048: public class Subscriber implements SipListener {
049:
050: private SipProvider sipProvider;
051:
052: private static AddressFactory addressFactory;
053:
054: private static MessageFactory messageFactory;
055:
056: private static HeaderFactory headerFactory;
057:
058: private static SipStack sipStack;
059:
060: private ContactHeader contactHeader;
061:
062: private static String transport;
063:
064: private int count;
065:
066: private HashSet dialogs;
067:
068: private static Logger logger = Logger.getLogger(Subscriber.class);
069:
070: static {
071: try {
072: logger.setLevel(Level.INFO);
073: logger.addAppender(new FileAppender(new SimpleLayout(),
074: "logs/subscriberoutputlog.txt"));
075: } catch (Exception ex) {
076: logger.info(ex.getMessage(), ex);
077: TestHarness
078: .fail("Failed to initialize Subscriber, because of "
079: + ex.getMessage());
080: }
081: }
082:
083: private ClientTransaction subscribeTid;
084:
085: private ListeningPoint listeningPoint;
086:
087: private int port;
088:
089: private Dialog subscriberDialog;
090:
091: private Dialog forkedDialog;
092:
093: public Subscriber(ProtocolObjects protObjects) {
094: addressFactory = protObjects.addressFactory;
095: messageFactory = protObjects.messageFactory;
096: headerFactory = protObjects.headerFactory;
097: sipStack = protObjects.sipStack;
098: transport = protObjects.transport;
099: this .dialogs = new HashSet();
100: }
101:
102: public void processRequest(RequestEvent requestReceivedEvent) {
103: Request request = requestReceivedEvent.getRequest();
104: ServerTransaction serverTransactionId = requestReceivedEvent
105: .getServerTransaction();
106: String viaBranch = ((ViaHeader) (request
107: .getHeaders(ViaHeader.NAME).next()))
108: .getParameter("branch");
109:
110: logger.info("\n\nRequest " + request.getMethod()
111: + " received at " + sipStack.getStackName()
112: + " with server transaction id " + serverTransactionId
113: + " branch ID = " + viaBranch);
114:
115: if (request.getMethod().equals(Request.NOTIFY))
116: processNotify(requestReceivedEvent, serverTransactionId);
117:
118: }
119:
120: public void processNotify(RequestEvent requestEvent,
121: ServerTransaction serverTransactionId) {
122: SipProvider provider = (SipProvider) requestEvent.getSource();
123: AbstractSubsnotifyTestCase.assertTrue(
124: "provider must be the same as my provider ",
125: provider == this .sipProvider);
126: Request notify = requestEvent.getRequest();
127: try {
128: logger.info("subscriber: got a notify count "
129: + this .count++);
130: if (serverTransactionId == null) {
131: logger.info("subscriber: null TID.");
132: serverTransactionId = provider
133: .getNewServerTransaction(notify);
134: }
135: Dialog dialog = serverTransactionId.getDialog();
136: AbstractSubsnotifyTestCase.assertTrue("subscriberDialog",
137: subscriberDialog != null);
138: AbstractSubsnotifyTestCase.assertTrue(
139: "Dialog should not be null", dialog != null);
140: if (dialog != subscriberDialog) {
141: if (forkedDialog == null) {
142: forkedDialog = dialog;
143: } else {
144: AbstractSubsnotifyTestCase
145: .assertTrue(
146: "Dialog should be either the subscriber dialog ",
147: forkedDialog == dialog);
148: }
149: }
150:
151: this .dialogs.add(dialog);
152: logger.info("Dialog State = " + dialog.getState());
153:
154: AbstractSubsnotifyTestCase.assertTrue(
155: "Dialog state should be confirmed ", dialog
156: .getState() == DialogState.CONFIRMED);
157:
158: Response response = messageFactory.createResponse(200,
159: notify);
160: // SHOULD add a Contact
161: ContactHeader contact = (ContactHeader) contactHeader
162: .clone();
163: ((SipURI) contact.getAddress().getURI()).setParameter("id",
164: "sub");
165: response.addHeader(contact);
166: logger.info("Transaction State = "
167: + serverTransactionId.getState());
168: AbstractSubsnotifyTestCase
169: .assertTrue(
170: "transaction state should be trying",
171: serverTransactionId.getState() == TransactionState.TRYING);
172: serverTransactionId.sendResponse(response);
173: logger.info("Dialog State = " + dialog.getState());
174: SubscriptionStateHeader subscriptionState = (SubscriptionStateHeader) notify
175: .getHeader(SubscriptionStateHeader.NAME);
176:
177: // Subscription is terminated?
178: String state = subscriptionState.getState();
179: if (state
180: .equalsIgnoreCase(SubscriptionStateHeader.TERMINATED)) {
181: dialog.delete();
182: } else if (state
183: .equalsIgnoreCase(SubscriptionStateHeader.ACTIVE)) {
184: logger.info("Subscriber: sending unSUBSCRIBE");
185:
186: // Else we end it ourselves
187: Request unsubscribe = dialog
188: .createRequest(Request.SUBSCRIBE);
189:
190: logger.info("dialog created:" + unsubscribe);
191: // SHOULD add a Contact (done by dialog), lets mark it to test updates
192: ((SipURI) dialog.getLocalParty().getURI())
193: .setParameter("id", "unsub");
194: ExpiresHeader expires = headerFactory
195: .createExpiresHeader(0);
196: unsubscribe.addHeader(expires);
197: // JvB note : stack should do this!
198: unsubscribe.addHeader(notify
199: .getHeader(EventHeader.NAME)); // copy
200: // event
201: // header
202: logger.info("Sending Unsubscribe : " + unsubscribe);
203: logger.info("unsubscribe dialog " + dialog);
204: ClientTransaction ct = sipProvider
205: .getNewClientTransaction(unsubscribe);
206: AbstractSubsnotifyTestCase.assertTrue(
207: "Dialog mismatch " + ct.getDialog()
208: + " dialog " + dialog,
209: ct.getDialog() == dialog);
210:
211: dialog.sendRequest(ct);
212:
213: } else {
214: logger.info("Subscriber: state now " + state);// pending
215: // usually
216: AbstractSubsnotifyTestCase
217: .assertTrue(
218: "State should be pending was " + state,
219: state
220: .equalsIgnoreCase(SubscriptionStateHeader.PENDING));
221:
222: }
223:
224: } catch (Exception ex) {
225: logger.error("Unexpected exception", ex);
226: TestHarness.fail("Failed to process Notify, because of "
227: + ex.getMessage());
228:
229: }
230: }
231:
232: public void processResponse(ResponseEvent responseReceivedEvent) {
233: logger.info("Got a response");
234: Response response = (Response) responseReceivedEvent
235: .getResponse();
236: Transaction tid = responseReceivedEvent.getClientTransaction();
237:
238: logger.info("Response received with client transaction id "
239: + tid + ":\n" + response.getStatusCode());
240: if (tid == null) {
241: logger.warn("Stray response -- dropping ");
242: return;
243: }
244: logger.info("transaction state is " + tid.getState());
245: logger.info("Dialog = " + tid.getDialog());
246: if (tid.getDialog() != null)
247: logger
248: .info("Dialog State is "
249: + tid.getDialog().getState());
250:
251: if (tid.getDialog() != null)
252: this .dialogs.add(tid.getDialog());
253:
254: }
255:
256: public SipProvider createProvider(int newPort) {
257: try {
258: port = newPort;
259:
260: listeningPoint = sipStack.createListeningPoint("127.0.0.1",
261: this .port, transport);
262:
263: this .sipProvider = sipStack
264: .createSipProvider(listeningPoint);
265: this .sipProvider.setAutomaticDialogSupportEnabled(true);
266: logger.info("udp provider " + sipProvider);
267:
268: } catch (Exception ex) {
269: logger.info(ex.getMessage(), ex);
270: TestHarness.fail("Failed to create SIP Provider on port "
271: + newPort + ", because of " + ex.getMessage());
272: sipProvider = null;
273: }
274: return sipProvider;
275: }
276:
277: /**
278: * when notifierPort is 5065, sends subscription to the forker.
279: * when notifierPort is 5070, sends subscription directly to the notifier.
280: *
281: * @param notifierPort
282: */
283: public void sendSubscribe(int notifierPort) {
284:
285: try {
286:
287: String fromName = "BigGuy";
288: String fromSipAddress = "here.com";
289: String fromDisplayName = "The Master Blaster";
290:
291: String toSipAddress = "there.com";
292: String toUser = "LittleGuy";
293: String toDisplayName = "The Little Blister";
294:
295: // create >From Header
296: SipURI fromAddress = addressFactory.createSipURI(fromName,
297: fromSipAddress);
298:
299: Address fromNameAddress = addressFactory
300: .createAddress(fromAddress);
301: fromNameAddress.setDisplayName(fromDisplayName);
302: FromHeader fromHeader = headerFactory.createFromHeader(
303: fromNameAddress, "12345");
304:
305: // create To Header
306: SipURI toAddress = addressFactory.createSipURI(toUser,
307: toSipAddress);
308: Address toNameAddress = addressFactory
309: .createAddress(toAddress);
310: toNameAddress.setDisplayName(toDisplayName);
311: ToHeader toHeader = headerFactory.createToHeader(
312: toNameAddress, null);
313:
314: // create Request URI
315: SipURI requestURI = addressFactory.createSipURI(toUser,
316: toSipAddress);
317:
318: // Create ViaHeaders
319:
320: ArrayList viaHeaders = new ArrayList();
321: int port = sipProvider.getListeningPoint(transport)
322: .getPort();
323: ViaHeader viaHeader = headerFactory.createViaHeader(
324: "127.0.0.1", port, transport, null);
325:
326: // add via headers
327: viaHeaders.add(viaHeader);
328:
329: // Create a new CallId header
330: CallIdHeader callIdHeader = sipProvider.getNewCallId();
331: // JvB: Make sure that the implementation matches the messagefactory
332: callIdHeader = headerFactory
333: .createCallIdHeader(callIdHeader.getCallId());
334:
335: // Create a new Cseq header
336: CSeqHeader cSeqHeader = headerFactory.createCSeqHeader(1L,
337: Request.SUBSCRIBE);
338:
339: // Create a new MaxForwardsHeader
340: MaxForwardsHeader maxForwards = headerFactory
341: .createMaxForwardsHeader(70);
342:
343: // Create the request.
344: Request request = messageFactory.createRequest(requestURI,
345: Request.SUBSCRIBE, callIdHeader, cSeqHeader,
346: fromHeader, toHeader, viaHeaders, maxForwards);
347: // Create contact headers
348: String host = listeningPoint.getIPAddress();
349:
350: SipURI contactUrl = addressFactory.createSipURI(fromName,
351: host);
352: contactUrl.setPort(listeningPoint.getPort());
353:
354: // Create the contact name address.
355: SipURI contactURI = addressFactory.createSipURI(fromName,
356: host);
357: contactURI.setTransportParam(transport);
358: contactURI.setPort(sipProvider.getListeningPoint(transport)
359: .getPort());
360:
361: Address contactAddress = addressFactory
362: .createAddress(contactURI);
363:
364: // Add the contact address.
365: contactAddress.setDisplayName(fromName);
366:
367: contactHeader = headerFactory
368: .createContactHeader(contactAddress);
369: request.addHeader(contactHeader);
370:
371: // JvB: To test forked SUBSCRIBEs, send it via the Forker
372: // Note: BIG Gotcha: Need to do this before creating the
373: // ClientTransaction!
374:
375: RouteHeader route = headerFactory
376: .createRouteHeader(addressFactory
377: .createAddress("<sip:127.0.0.1:"
378: + notifierPort + ";transport="
379: + transport + ";lr>"));
380: request.addHeader(route);
381: // JvB end added
382:
383: // Create the client transaction.
384: subscribeTid = sipProvider.getNewClientTransaction(request);
385:
386: // Create an event header for the subscription.
387: EventHeader eventHeader = headerFactory
388: .createEventHeader("foo");
389: eventHeader.setEventId("foo");
390: request.addHeader(eventHeader);
391:
392: logger.info("Subscribe Dialog = "
393: + subscribeTid.getDialog());
394:
395: // send the request out.
396:
397: this .subscriberDialog = subscribeTid.getDialog();
398: this .dialogs.add(subscriberDialog);
399:
400: subscribeTid.sendRequest();
401: } catch (Throwable ex) {
402: logger.info(ex.getMessage(), ex);
403: TestHarness
404: .fail("Failed to send Subscribe to notifier port"
405: + notifierPort + ", because of "
406: + ex.getMessage());
407: }
408: }
409:
410: public void processIOException(IOExceptionEvent exceptionEvent) {
411: logger.info("io exception event recieved");
412: AbstractSubsnotifyTestCase.fail("unexpected exception");
413: }
414:
415: public void processTransactionTerminated(
416: TransactionTerminatedEvent transactionTerminatedEvent) {
417: logger.info("transaction terminated");
418:
419: }
420:
421: public void processDialogTerminated(
422: DialogTerminatedEvent dialogTerminatedEvent) {
423: logger.info("dialog terminated event recieved");
424: }
425:
426: public void processTimeout(javax.sip.TimeoutEvent timeoutEvent) {
427:
428: logger.info("Transaction Time out");
429: }
430:
431: public void checkState() {
432: AbstractSubsnotifyTestCase.assertTrue(
433: "Should have two distinct dialogs",
434: this .dialogs.size() == 2);
435: }
436: }
|