diff --git a/src/main/java/org/cafesip/sipunit/EventSubscriber.java b/src/main/java/org/cafesip/sipunit/EventSubscriber.java index 6a1dd0ac22..71e61166e7 100644 --- a/src/main/java/org/cafesip/sipunit/EventSubscriber.java +++ b/src/main/java/org/cafesip/sipunit/EventSubscriber.java @@ -16,41 +16,19 @@ package org.cafesip.sipunit; -import java.text.ParseException; -import java.util.ArrayList; -import java.util.EventObject; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; - -import javax.sip.Dialog; -import javax.sip.RequestEvent; -import javax.sip.ResponseEvent; -import javax.sip.SipProvider; -import javax.sip.TimeoutEvent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.sip.*; import javax.sip.address.Address; import javax.sip.address.AddressFactory; import javax.sip.address.SipURI; import javax.sip.address.URI; -import javax.sip.header.AcceptHeader; -import javax.sip.header.CSeqHeader; -import javax.sip.header.CallIdHeader; -import javax.sip.header.ContactHeader; -import javax.sip.header.EventHeader; -import javax.sip.header.ExpiresHeader; -import javax.sip.header.FromHeader; -import javax.sip.header.Header; -import javax.sip.header.HeaderFactory; -import javax.sip.header.MaxForwardsHeader; -import javax.sip.header.ReferToHeader; -import javax.sip.header.SubscriptionStateHeader; -import javax.sip.header.ToHeader; -import javax.sip.header.ViaHeader; +import javax.sip.header.*; import javax.sip.message.Request; import javax.sip.message.Response; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import java.text.ParseException; +import java.util.*; /** * The EventSubscriber class represents a generic subscription conforming to the event subscription @@ -590,7 +568,7 @@ private void processRequest(RequestEvent requestEvent) { CSeqHeader rcvSeqHdr = (CSeqHeader) request.getHeader(CSeqHeader.NAME); if (rcvSeqHdr == null) { - EventSubscriber.sendResponse(parent, requestEvent, SipResponse.BAD_REQUEST, + parent.sendResponse(requestEvent, SipResponse.BAD_REQUEST, "no CSEQ header received"); String err = "*** NOTIFY REQUEST ERROR *** (" + targetUri + ") - no CSEQ header received"; @@ -604,7 +582,7 @@ private void processRequest(RequestEvent requestEvent) { if (notifyCSeq != null) { // This is not the first NOTIFY if (rcvSeqHdr.getSeqNumber() <= notifyCSeq.getSeqNumber()) { - EventSubscriber.sendResponse(parent, requestEvent, SipResponse.OK, "OK"); + parent.sendResponse(requestEvent, SipResponse.OK, "OK"); LOG.trace("Received NOTIFY CSEQ {} not new, discarding message", rcvSeqHdr.getSeqNumber()); return; @@ -830,21 +808,13 @@ private void authorizeSubscribe(Response resp, Request msg) throws SubscriptionE } + /** + * @deprecated by instance method call of SipPhone + * @see SipPhone#sendResponse(RequestEvent, int, String) + */ + @Deprecated protected static void sendResponse(SipPhone parent, RequestEvent req, int status, String reason) { - try { - Response response = parent.getMessageFactory().createResponse(status, req.getRequest()); - response.setReasonPhrase(reason); - - if (req.getServerTransaction() != null) { - req.getServerTransaction().sendResponse(response); - return; - } - - ((SipProvider) req.getSource()).sendResponse(response); - } catch (Exception e) { - LOG.error("Failure sending error response (" + reason + ") for received " - + req.getRequest().getMethod() + ", Exception: " + e.toString(), e); - } + parent.sendResponse(req, status, reason); } /** @@ -1021,13 +991,15 @@ public boolean replyToNotify(RequestEvent reqevent, Response response) { return true; } - protected boolean messageForMe(javax.sip.message.Message msg) { - /* - * NOTIFY requests are matched to SUBSCRIBE/REFER requests if they contain the same "Call-ID", a - * "To" header "tag" parameter which matches the "From" header "tag" parameter of the - * SUBSCRIBE/REFER, and the same "Event" header field. - */ - + /** + * NOTIFY requests are matched to SUBSCRIBE/REFER requests if they contain the same "Call-ID", a + * "To" header "tag" parameter which matches the "From" header "tag" parameter of the + * SUBSCRIBE/REFER, and the same "Event" header field. + * + * @param msg The NOTIFY message whose headers will be evaluated and matched + * @return If the message matches to this event subscriber + */ + public boolean messageForMe(javax.sip.message.Message msg) { Request lastSentRequest = getLastSentRequest(); if (lastSentRequest == null) { @@ -1048,19 +1020,19 @@ protected boolean messageForMe(javax.sip.message.Message msg) { return false; } - if (hdr.getCallId().equals(sentHdr.getCallId()) == false) { + if (!hdr.getCallId().equals(sentHdr.getCallId())) { return false; } // check to-tag = from-tag, (my tag), and event header // fields same as in sent request - ToHeader tohdr = (ToHeader) msg.getHeader(ToHeader.NAME); - if (tohdr == null) { + ToHeader toHeader = (ToHeader) msg.getHeader(ToHeader.NAME); + if (toHeader == null) { return false; } - String toTag = tohdr.getTag(); + String toTag = toHeader.getTag(); if (toTag == null) { return false; } @@ -1071,30 +1043,23 @@ protected boolean messageForMe(javax.sip.message.Message msg) { } String fromTag = sentFrom.getTag(); - if (fromTag == null) { - return false; - } - - if (toTag.equals(fromTag) == false) { - return false; - } - - return eventForMe(msg, lastSentRequest); + return fromTag != null && toTag.equals(fromTag) && eventForMe(msg, lastSentRequest); } - protected boolean eventForMe(javax.sip.message.Message msg, Request lastSentRequest) { - EventHeader eventhdr = (EventHeader) msg.getHeader(EventHeader.NAME); - EventHeader sentEventhdr = (EventHeader) lastSentRequest.getHeader(EventHeader.NAME); - - if ((eventhdr == null) || (sentEventhdr == null)) { - return false; - } + /** + * @param msg The inbound NOTIFY request + * @param lastSentRequest The last sent request by an EventSubscriber + * @return If the NOTIFY request and the last sent request event headers match. + */ + public boolean eventForMe(javax.sip.message.Message msg, Request lastSentRequest) { + EventHeader eventHeader = (EventHeader) msg.getHeader(EventHeader.NAME); + EventHeader sentEventHeader = (EventHeader) lastSentRequest.getHeader(EventHeader.NAME); - if (eventhdr.equals(sentEventhdr) == false) { + if (eventHeader == null || sentEventHeader == null) { return false; } - return true; + return eventHeader.equals(sentEventHeader); } private void validateEventHeader(EventHeader receivedHdr, EventHeader sentHdr) diff --git a/src/main/java/org/cafesip/sipunit/SipPhone.java b/src/main/java/org/cafesip/sipunit/SipPhone.java index ed834a085f..0e587a4949 100644 --- a/src/main/java/org/cafesip/sipunit/SipPhone.java +++ b/src/main/java/org/cafesip/sipunit/SipPhone.java @@ -1,6 +1,6 @@ /* * Created on Feb 19, 2005 - * + * * Copyright 2005 CafeSip.org * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except @@ -17,46 +17,25 @@ package org.cafesip.sipunit; +import org.cafesip.sipunit.processing.RequestProcessingResult; +import org.cafesip.sipunit.processing.RequestProcessor; +import org.cafesip.sipunit.processing.notify.ConferenceEventStrategy; +import org.cafesip.sipunit.processing.notify.PresenceEventStrategy; +import org.cafesip.sipunit.processing.notify.ReferEventStrategy; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.text.ParseException; -import java.util.ArrayList; -import java.util.EventObject; -import java.util.HashMap; -import java.util.Hashtable; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.ListIterator; -import java.util.Map; - -import javax.sip.Dialog; -import javax.sip.InvalidArgumentException; -import javax.sip.RequestEvent; -import javax.sip.ResponseEvent; -import javax.sip.TimeoutEvent; +import javax.sip.*; import javax.sip.address.Address; import javax.sip.address.AddressFactory; import javax.sip.address.SipURI; import javax.sip.address.URI; -import javax.sip.header.AuthorizationHeader; -import javax.sip.header.CSeqHeader; -import javax.sip.header.CallIdHeader; -import javax.sip.header.ContactHeader; -import javax.sip.header.EventHeader; -import javax.sip.header.ExpiresHeader; -import javax.sip.header.FromHeader; -import javax.sip.header.Header; -import javax.sip.header.HeaderFactory; -import javax.sip.header.MaxForwardsHeader; -import javax.sip.header.ProxyAuthenticateHeader; -import javax.sip.header.ToHeader; -import javax.sip.header.ViaHeader; -import javax.sip.header.WWWAuthenticateHeader; +import javax.sip.header.*; import javax.sip.message.MessageFactory; import javax.sip.message.Request; import javax.sip.message.Response; +import java.text.ParseException; +import java.util.*; /** * This class provides a test program with User Agent (UA) access to the SIP protocol in the form of @@ -65,10 +44,10 @@ * (SUBSCRIBE/NOTIFY) operations, call refer, etc. In future, a SipPhone object can have more than * one SipCall object associated with it but currently only one is supported. Multiple subscriptions * (buddy/presence, refer) are supported per SipPhone object. - * + * *
* A SipPhone object is created by calling SipStack.createSipPhone(). - * + * *
* Many of the methods in this class return an object or true return value if successful. In case of
* an error or caller-specified timeout, a null object or a false is returned. The
@@ -82,9 +61,9 @@
* indicating the cause of the problem. If an exception was involved, this string will contain the
* name of the Exception class and the exception message. This class has a method, format(), which
* can be called to obtain a human-readable string containing all of this error information.
- *
+ *
* @author Amit Chatterjee, Becky McElroy
- *
+ *
*/
public class SipPhone extends SipSession implements SipActionObject, RequestListener {
@@ -126,6 +105,16 @@ public class SipPhone extends SipSession implements SipActionObject, RequestList
private List
* Initially, a REGISTER message is sent without any user name and password. If the server returns
* an OK, this method returns a true value.
- *
+ *
*
* If any challenge is received in response to sending the REGISTER message (response code
* UNAUTHORIZED or PROXY_AUTHENTICATION_REQUIRED), the SipPhone's credentials list is checked
@@ -167,31 +156,31 @@ protected SipPhone(SipStack stack, String host, String me)
* user, password). Also, the authorization created for this registration is not saved for re-use
* on a later registration. IE, the user/password parameters are for a one-time, single-shot use
* only.
- *
+ *
*
* After responding to the challenge(s) by resending the REGISTER message, this method returns a
* true or false value depending on the outcome as indicated by the server.
- *
+ *
*
* If the contact parameter is null, user@hostname is used where hostname is the SipStack's IP
* address property which defaults to InetAddress.getLocalHost().getHostAddress(), and other
* SipStack properties also apply. Otherwise, the contact parameter given is used in the
* Registration message sent to the server.
- *
+ *
*
* If the expiry parameter is 0, the registration request never expires. Otherwise, the duration,
* given in seconds, is sent to server.
- *
+ *
*
* This method can be called repeatedly to update the expiry or to add new contacts.
- *
+ *
*
* This method determines the contact information for this user agent, whether the registration
* was successful or not. If successful, the contact information may have been updated by the
* server (such as the expiry time, if not specified to this method by the caller). Once this
* method has been called, the test program can get information about the contact for this agent
* by calling the *MyContact*() getter methods.
- *
+ *
* @param user Optional - user name for authenticating with the server. Required if the server
* issues an authentication challenge.
* @param password Optional - used only if the server issues an authentication challenge.
@@ -231,7 +220,7 @@ public boolean register(String user, String password, String contact, int expiry
* is derived from this SipPhone's URI, or address of record (for example, if this SipPhone's
* address of record is "sip:amit@cafesip.org", the REGISTER Request-URI will be sip:cafesip.org).
* Otherwise, the requestUri passed in is used for the REGISTER Request-URI.
- *
+ *
*/
public boolean register(SipURI requestUri, String user, String password, String contact,
int expiry, long timeout) {
@@ -349,7 +338,7 @@ public boolean register(SipURI requestUri, String user, String password, String
* This method is equivalent to the register(String user, String password, String contact, int
* expiry, long timeout) method except with no authorization parameters specified. Call this
* method if no authorization will be needed or after setting up the SipPhone's credentials list.
- *
+ *
* @param contact An URI string (ex: sip:bob@192.0.2.4)
* @param expiry Expiry time in seconds, or 0 if no expiry.
* @return false if registration fails or an error is encountered, true otherwise.
@@ -363,16 +352,16 @@ public boolean register(String contact, int expiry) {
* successful or no unregistration was needed, and false otherwise. Any authorization headers
* required for the last registration are cleared out. If there was no previous registration, this
* method does not send any messages.
- *
+ *
*
* If the contact parameter is null, user@hostname is unregistered where hostname is obtained by
* calling InetAddr.getLocalHost(). Otherwise, the contact parameter value is used in the
* unregistration message sent to the server.
- *
+ *
* @param contact The contact URI (ex: sip:bob@192.0.2.4) to unregister or "*".
* @param timeout The maximum amount of time to wait for a response, in milliseconds. Use a value
* of 0 to wait indefinitely.
- *
+ *
* @return true if the unregistration succeeded or no unregistration was needed, false otherwise.
*/
public boolean unregister(String contact, long timeout) {
@@ -534,13 +523,13 @@ private Response sendRegistrationMessage(Request msg, String user, String passwo
* This method is public for test purposes and for use when using low level SipSession methods for
* sending/receiving messages. A test program using high level SipUnit doesn't need to call this
* method.
- *
+ *
*
* This method modifies the given request to include the authorization header(s) required by the
* given response. It may cache in SipPhone's authorizations list the AuthorizationHeader(s)
* created here for use later. The modified Request object is returned, or null in case of error
* or unresolved challenge.
- *
+ *
*
* For each received challenge present in the response message: SipPhone's credentials list is
* checked first, for the realm entry. If it is not found there, the username parameter passed
@@ -550,7 +539,7 @@ private Response sendRegistrationMessage(Request msg, String user, String passwo
* and the authorization created here is NOT saved for later re-use. If the credentials list
* contains an entry for the challenging realm, then the authorization created here is saved in
* the authorizations list for later re-use.
- *
+ *
* @param response the challenge that was received
* @param req_msg the request originally sent (that was challenged)
* @param username see above
@@ -662,19 +651,19 @@ public Request processAuthChallenge(Response response, Request req_msg, String u
/*
* here's replace code
- *
+ *
* ListIterator msg_headers; if (authorization instanceof ProxyAuthorizationHeader) {
* msg_headers = msg.getHeaders(ProxyAuthorizationHeader.NAME); } else { msg_headers =
* msg.getHeaders(AuthorizationHeader.NAME); }
- *
+ *
* boolean replaced = false;
- *
- *
+ *
+ *
* while (msg_headers.hasNext()) { AuthorizationHeader msg_hdr = (AuthorizationHeader)
* msg_headers .next(); if (msg_hdr.getRealm().equals(realm)) {
* msg_headers.set(authorization); replaced = true; break; } }
- *
- *
+ *
+ *
* if (replaced == false) { msg.addHeader(authorization); // how to bubble auth up - //
* check 1.2 API }
*/
@@ -713,7 +702,7 @@ public Request processAuthChallenge(Response response, Request req_msg) {
* only one SipCall object is supported per SipPhone. In future, when more than one SipCall per
* SipPhone is supported, this method can be called multiple times to create multiple call legs on
* the same SipPhone object.
- *
+ *
* @return A SipCall object unless an error is encountered.
*/
public SipCall createSipCall() {
@@ -735,19 +724,19 @@ protected void dropCall(SipCall call) {
* INVITE response status code is received. The object returned is a SipCall object representing
* the outgoing call leg; that is, the UAC originating a call to the network. Then you can take
* subsequent action on the call by making method calls on the SipCall object.
- *
+ *
*
* Use this method when (1) you want to establish a call without worrying about the details and
* (2) your test program doesn't need to do anything else (ie, it can be blocked) until the
* response code parameter passed to this method is received from the network.
- *
+ *
*
* In case the first condition above is false: If you need to see the (intermediate/provisional)
* response messages as they come in, then use SipPhone.createSipCall() and
* SipCall.initiateOutgoingCall() instead of this method. If your test program can tolerate being
* blocked until the desired response is received, you can still use this method and later look
* back at all the received responses by calling SipCall.getAllReceivedResponses().
- *
+ *
*
* In case the second condition above is false: If your test code is handling both sides of the
* call, or it has to do other things while this call establishment is in progress, then this
@@ -755,8 +744,8 @@ protected void dropCall(SipCall call) {
* returns a SipCall object after the INVITE has been successfully sent. Then, later on you can
* check back with the SipCall object to see the call progress or block on the call establishment,
* at a more convenient time.
- *
- *
+ *
+ *
* @param to The URI string (ex: sip:bob@nist.gov) to which the call should be directed
* @param response The SipResponse status code to look for after sending the INVITE. This method
* returns when that status code is received.
@@ -777,10 +766,10 @@ public SipCall makeCall(String to, int response, long timeout, String viaNonProx
* This method is the same as the basic blocking makeCall() method except that it allows the
* caller to specify a message body and/or additional message headers to add to or replace in the
* outbound message without requiring knowledge of the JAIN-SIP API.
- *
+ *
*
* The extra parameters supported by this method are:
- *
+ *
* @param body A String to be used as the body of the message. Parameters contentType,
* contentSubType must both be non-null to get the body included in the message. Use null
* for no body bytes.
@@ -806,7 +795,7 @@ public SipCall makeCall(String to, int response, long timeout, String viaNonProx
* occur if your headers are not syntactically correct or contain nonsensical values (the
* message may not pass through the local SIP stack). Use null for no replacement of
* message headers.
- *
+ *
*/
public SipCall makeCall(String to, int response, long timeout, String viaNonProxyRoute,
String body, String contentType, String contentSubType, ArrayList
* The extra parameters supported by this method are:
- *
+ *
* @param additionalHeaders ArrayList of javax.sip.header.Header, each element a SIP header to add
* to the outbound message. These headers are added to the message after a correct message
* has been constructed. Note that if you try to add a header that there is only supposed
@@ -924,7 +913,7 @@ public SipCall makeCall(String to, int response, long timeout, String viaNonProx
* etc.) are automatically collected and any received authentication challenges are automatically
* handled as well. The object returned by this method is a SipCall object representing the
* outgoing call leg; that is, the UAC originating a call to the network.
- *
+ *
*
* After calling this method, you can later call one or more of the following methods on the
* returned SipCall object to see what happened (each is nonblocking unless otherwise noted):
@@ -937,20 +926,20 @@ public SipCall makeCall(String to, int response, long timeout, String viaNonProx
* waitOutgoingCallResponse() - BLOCKING - when your test program is done with its tasks and can
* be blocked until the next response is received (if you are interested in something other than
* OK) - use this only if you know that the INVITE transaction is still up.
- *
+ *
*
* Call this method when (1) you want to establish a call without worrying about the details and
* (2) your test program needs to do other tasks after the INVITE is sent but before a
* final/expected response is received (ie, the calling program cannot be blocked during call
* establishment).
- *
+ *
*
* Otherwise: If you need to see or act on any of the (intermediate/provisional) response messages
* as they come in, use SipPhone.createSipCall() and SipCall.initiateOutgoingCall() instead of
* this method. If your test program doesn't need to do anything else until the call is
* established: use the other SipPhone.makeCall() method which conveniently blocks until the
* response code you specify is received from the network.
- *
+ *
* @param to The URI string (ex: sip:bob@nist.gov) to which the call should be directed
* @param viaNonProxyRoute Indicates whether to route the INVITE via Proxy or some other route. If
* null, route the call to the Proxy that was specified when the SipPhone object was
@@ -958,7 +947,7 @@ public SipCall makeCall(String to, int response, long timeout, String viaNonProx
* as "hostaddress:port/transport" i.e. 129.1.22.333:5060/UDP.
* @return A SipCall object representing the outgoing call leg, or null if an error was
* encountered.
- *
+ *
*/
public SipCall makeCall(String to, String viaNonProxyRoute) {
return makeCall(to, viaNonProxyRoute, null, null, null);
@@ -969,10 +958,10 @@ public SipCall makeCall(String to, String viaNonProxyRoute) {
* caller to specify a message body and/or additional JAIN-SIP API message headers to add to or
* replace in the outbound INVITE message. Use of this method requires knowledge of the JAIN-SIP
* API.
- *
+ *
*
* The extra parameters supported by this method are:
- *
+ *
* @param additionalHeaders ArrayList of javax.sip.header.Header, each element a SIP header to add
* to the outbound message. These headers are added to the message after a correct message
* has been constructed. Note that if you try to add a header that there is only supposed
@@ -1009,9 +998,9 @@ public SipCall makeCall(String to, String viaNonProxyRoute, ArrayList
* This method creates a SUBSCRIBE request message, sends it out, and waits for a response to be
* received. It saves the received response and checks for a "proceedable" (positive) status code
* value. Positive response status codes include any of the following: provisional (status / 100
* == 1), UNAUTHORIZED, PROXY_AUTHENTICATION_REQUIRED, OK and ACCEPTED. Any other status code, or
* a response timeout or any other error, is considered fatal to the subscription.
- *
+ *
*
* This method blocks until one of the above outcomes is reached.
- *
+ *
*
* In the case of a positive response status code, this method returns a PresenceSubscriber object
* that will represent the buddy for the life of the subscription and puts the PresenceSubscriber
@@ -1348,14 +1372,14 @@ private void distributeEventError(String err)
* details at any given time such as the subscription state, amount of time left on the
* subscription, termination reason, presence information, details of received responses and
* requests, etc.
- *
+ *
*
* In the case of a positive response status code (a non-null object is returned), you may find
* out more about the response that was just received by calling the PresenceSubscriber methods
* getReturnCode() and getCurrentResponse()/getLastReceivedResponse(). Your next step at this
* point will be to call the PresenceSubscriber's processResponse() method to proceed with the
* SUBSCRIBE processing.
- *
+ *
*
* In the case of a fatal outcome, no subscription object is created and null is returned. In this
* case, call the usual SipUnit failed-operation methods to find out what happened (ie, call this
@@ -1363,7 +1387,7 @@ private void distributeEventError(String err)
* getReturnCode() method will tell you the response status code that was received from the
* network (unless it is an internal SipUnit error code, see the SipSession javadoc for more on
* that).
- *
+ *
* @param uri the URI (ie, sip:bob@nist.gov) of the buddy to be added to the list.
* @param duration the duration in seconds to put in the SUBSCRIBE message. If 0, this is
* equivalent to a fetch except that the buddy stays in the buddy list even though the
@@ -1425,7 +1449,7 @@ public PresenceSubscriber addBuddy(String uri, int duration, String eventId, lon
* This method is the same as addBuddy(uri, duration, eventId, timeout) except that the duration
* is defaulted to the default period defined in the event package RFC (3600 seconds) and no event
* "id" parameter will be included.
- *
+ *
* @param uri the URI (ie, sip:bob@nist.gov) of the buddy to be added to the list.
* @param timeout The maximum amount of time to wait for a SUBSCRIBE response, in milliseconds.
* Use a value of 0 to wait indefinitely.
@@ -1439,7 +1463,7 @@ public PresenceSubscriber addBuddy(String uri, long timeout) {
/**
* This method is the same as addBuddy(uri, duration, eventId, timeout) except that no event "id"
* parameter will be included.
- *
+ *
* @param uri the URI (ie, sip:bob@nist.gov) of the buddy to be added to the list.
* @param duration the duration in seconds to put in the SUBSCRIBE message. If 0, this is
* equivalent to a fetch except that the buddy stays in the buddy list even though the
@@ -1456,7 +1480,7 @@ public PresenceSubscriber addBuddy(String uri, int duration, long timeout) {
/**
* This method is the same as addBuddy(uri, duration, eventId, timeout) except that the duration
* is defaulted to the default period defined in the event package RFC (3600 seconds).
- *
+ *
* @param uri the URI (ie, sip:bob@nist.gov) of the buddy to be added to the list.
* @param eventId the event "id" to use in the SUBSCRIBE message, or null for no event "id"
* parameter. See addBuddy(uri, duration, eventId, timeout) javadoc for details on event
@@ -1475,7 +1499,7 @@ public PresenceSubscriber addBuddy(String uri, String eventId, long timeout) {
* user's presence status and information. Please read the SipUnit User Guide webpage Event
* Subscription (at least the operation overview part) for information on how to use SipUnit
* presence capabilities.
- *
+ *
*
* This method creates a SUBSCRIBE request message with expiry time of 0, sends it out, and waits
* for a response to be received. It saves the received response and checks for a "proceedable"
@@ -1483,10 +1507,10 @@ public PresenceSubscriber addBuddy(String uri, String eventId, long timeout) {
* provisional (status / 100 == 1), UNAUTHORIZED, PROXY_AUTHENTICATION_REQUIRED, OK and ACCEPTED.
* Any other status code, or a response timeout or any other error, is considered fatal to the
* operation.
- *
+ *
*
* This method blocks until one of the above outcomes is reached.
- *
+ *
*
* In the case of a positive response status code, this method returns a PresenceSubscriber object
* representing the user and puts the object in this SipPhone's retired buddy list. The retired
@@ -1496,14 +1520,14 @@ public PresenceSubscriber addBuddy(String uri, String eventId, long timeout) {
* PresenceSubscriber object to proceed through the remainder of the SUBSCRIBE-NOTIFY sequence and
* to find out details such as the subscription state, termination reason, presence information,
* details of received responses and requests, etc.
- *
+ *
*
* In the case of a positive response status code (a non-null object is returned), you may find
* out more about the response that was just received by calling the PresenceSubscriber methods
* getReturnCode() and getCurrentResponse()/getLastReceivedResponse(). Your next step at this
* point will be to call the PresenceSubscriber's processResponse() method to proceed with the
* SUBSCRIBE processing.
- *
+ *
*
* In the case of a fatal outcome, no Subscription object is created and null is returned. In this
* case, call the usual SipUnit failed-operation methods to find out what happened (ie, call this
@@ -1511,7 +1535,7 @@ public PresenceSubscriber addBuddy(String uri, String eventId, long timeout) {
* getReturnCode() method will tell you the response status code that was received from the
* network (unless it is an internal SipUnit error code, see the SipSession javadoc for more on
* that).
- *
+ *
* @param uri the URI (ie, sip:bob@nist.gov) of the user whose presence info is to be fetched.
* @param eventId the event "id" to use in the SUBSCRIBE message, or null for no event "id"
* parameter. Whatever is indicated here will be used subsequently, for error checking the
@@ -1573,7 +1597,7 @@ public PresenceSubscriber fetchPresenceInfo(String uri, String eventId, long tim
* This method is the same as fetchPresenceInfo(uri, eventId, timeout) except that no event "id"
* parameter will be included in the SUBSCRIBE message. When error checking the SUBSCRIBE response
* and NOTIFY from the server, no event "id" parameter will be expected.
- *
+ *
* @param uri the URI (ie, sip:bob@nist.gov) of the user whose presence info is to be fetched.
* @param timeout The maximum amount of time to wait for a SUBSCRIBE response, in milliseconds.
* Use a value of 0 to wait indefinitely.
@@ -1592,13 +1616,13 @@ public PresenceSubscriber fetchPresenceInfo(String uri, long timeout) {
* from the returned object. The user may have been a buddy in the buddy list (but was removed
* from the list by the test program), or fetchPresenceInfo() was previously called for the user
* to get a one-time status report, or the user may still be in the buddy list.
- *
+ *
* @param uri the URI (ie, sip:bob@nist.gov) of the user whose subscription object is to be
* returned.
* @return A PresenceSubscriber object that contains information about the user's last obtained
* presence status and other info, or null if there was never any status fetch done for
* this user and this user was never in the buddy list.
- *
+ *
*/
public PresenceSubscriber getBuddyInfo(String uri) {
synchronized (buddyList) {
@@ -1618,10 +1642,10 @@ public PresenceSubscriber getBuddyInfo(String uri) {
* are still in the buddy list. A given buddy, or subscription, in this list may be active or not
* - ie, subscription termination by the far end does not remove a buddy from this list. Buddies
* are removed from the list only by the test program (by calling removeBuddy()).
- *
+ *
*
* See related methods getBuddyInfo(), getRetiredBuddies().
- *
+ *
* @return a Hashtable of zero or more entries, where the key = URI of the buddy, value =
* PresenceSubscriber object.
*/
@@ -1635,10 +1659,10 @@ public Map
* See related methods getBuddyInfo(), getBuddyList().
- *
+ *
* @return a Hashtable of zero or more entries, where the key = URI of the user, value =
* PresenceSubscriber object.
*/
@@ -1672,12 +1696,12 @@ protected boolean removeRefer(ReferSubscriber ref) {
* Gets the subscription object(s) associated with the given referToUri. The returned object(s)
* contains subscription state, received requests (NOTIFY's) and REFER/SUBSCRIBE responses, etc.
* for outbound REFER subscription(s) associated with the referToUri.
- *
+ *
* @param referToUri the referToUri that was previously passed in to SipPhone.refer(). See javadoc
* there.
* @return ReferSubscriber object(s) associated with the referToUri, or an empty list if there was
* never a call to SipPhone.refer() with that referToUri.
- *
+ *
*/
public List
* See related method getRefererInfo().
- *
+ *
* @return a list of ReferSubscriber objects or an empty list if there are none.
*/
public List
* This method blocks until one of the above outcomes is reached.
- *
+ *
*
* In the case of a positive response status code, this method returns a ReferSubscriber object
* that represents the implicit subscription. You can save the returned object yourself or
@@ -1825,13 +1849,13 @@ public SipURI getUri(String scheme, String userHostPort, String transportUriPara
* REFER-NOTIFY sequence as well as for future SUBSCRIBE-NOTIFY sequences on this subscription and
* also to find out details at any given time such as the subscription state, amount of time left
* on the subscription, termination reason, details of received responses and requests, etc.
- *
+ *
*
* In the case of a positive response status code (a non-null object is returned), you may find
* out more about the response that was just received by calling the ReferSubscriber methods
* getReturnCode() and getCurrentResponse(). Your next step will then be to call the
* ReferSubscriber's processResponse() method to proceed with the REFER processing.
- *
+ *
*
* In the case of a fatal outcome, no subscription object is created and null is returned. In this
* case, call the usual SipUnit failed-operation methods to find out what happened (ie, call this
@@ -1839,7 +1863,7 @@ public SipURI getUri(String scheme, String userHostPort, String transportUriPara
* getReturnCode() method will tell you the response status code that was received from the
* network (unless it is an internal SipUnit error code, see the SipSession javadoc for more on
* that).
- *
+ *
* @param refereeUri The URI (ie, sip:bob@nist.gov) of the far end of the subscription. This is
* the party the REFER request is sent to.
* @param referToUri The URI that the refereeUri is to refer to. You can use SipPhone.getUri() to
@@ -1860,7 +1884,7 @@ public SipURI getUri(String scheme, String userHostPort, String transportUriPara
* viaNonProxyRoute node which is specified as "hostaddress:port/transport" i.e.
* 129.1.22.333:5060/UDP. A route header will be added to the REFER for this, before the
* request is sent.
- *
+ *
* @return ReferSubscriber object representing the implicit subscription if the operation is
* successful so far, null otherwise.
*/
@@ -1873,10 +1897,10 @@ public ReferSubscriber refer(String refereeUri, SipURI referToUri, String eventI
* This method is the same as the basic out-of-dialog refer() method except that it allows the
* caller to specify a message body and/or additional JAIN-SIP API message headers to add to or
* replace in the outbound message. Use of this method requires knowledge of the JAIN-SIP API.
- *
+ *
*
* The extra parameters supported by this method are:
- *
+ *
* @param additionalHeaders ArrayList of javax.sip.header.Header, each element a SIP header to add
* to the outbound message. These headers are added to the message after a correct message
* has been constructed. Note that if you try to add a header that there is only supposed
@@ -1943,10 +1967,10 @@ public ReferSubscriber refer(String refereeUri, SipURI referToUri, String eventI
* This method is the same as the basic out-of-dialog refer() method except that it allows the
* caller to specify a message body and/or additional message headers to add to or replace in the
* outbound message without requiring knowledge of the JAIN-SIP API.
- *
+ *
*
* The extra parameters supported by this method are:
- *
+ *
* @param body A String to be used as the body of the message. Parameters contentType,
* contentSubType must both be non-null to get the body included in the message. Use null
* for no body bytes.
@@ -1972,7 +1996,7 @@ public ReferSubscriber refer(String refereeUri, SipURI referToUri, String eventI
* occur if your headers are not syntactically correct or contain nonsensical values (the
* message may not pass through the local SIP stack). Use null for no replacement of
* message headers.
- *
+ *
*/
public ReferSubscriber refer(String refereeUri, SipURI referToUri, String eventId, long timeout,
String viaNonProxyRoute, String body, String contentType, String contentSubType,
@@ -1995,10 +2019,10 @@ public ReferSubscriber refer(String refereeUri, SipURI referToUri, String eventI
* provisional (status / 100 == 1), UNAUTHORIZED, PROXY_AUTHENTICATION_REQUIRED, OK and ACCEPTED.
* Any other status code, or a response timeout or any other error, is considered fatal to the
* subscription.
- *
+ *
*
* This method blocks until one of the above outcomes is reached.
- *
+ *
*
* In the case of a positive response status code, this method returns a ReferSubscriber object
* that represents the implicit subscription. You can save the returned object yourself or
@@ -2007,13 +2031,13 @@ public ReferSubscriber refer(String refereeUri, SipURI referToUri, String eventI
* REFER-NOTIFY sequence as well as for future SUBSCRIBE-NOTIFY sequences on this subscription and
* also to find out details at any given time such as the subscription state, amount of time left
* on the subscription, termination reason, details of received responses and requests, etc.
- *
+ *
*
* In the case of a positive response status code (a non-null object is returned), you may find
* out more about the response that was just received by calling the ReferSubscriber methods
* getReturnCode() and getCurrentResponse(). Your next step will then be to call the
* ReferSubscriber's processResponse() method to proceed with the REFER processing.
- *
+ *
*
* In the case of a fatal outcome, no subscription object is created and null is returned. In this
* case, call the usual SipUnit failed-operation methods to find out what happened (ie, call this
@@ -2021,7 +2045,7 @@ public ReferSubscriber refer(String refereeUri, SipURI referToUri, String eventI
* getReturnCode() method will tell you the response status code that was received from the
* network (unless it is an internal SipUnit error code, see the SipSession javadoc for more on
* that).
- *
+ *
* @param dialog The existing dialog that this REFER should be associated with. You can get it
* from SipCall.getDialog() or ReferSubscriber.getDialog().
* @param referToUri The URI that the far end of the dialog is to refer to. You can use
@@ -2034,7 +2058,7 @@ public ReferSubscriber refer(String refereeUri, SipURI referToUri, String eventI
* refresh() or unsubscribe().
* @param timeout The maximum amount of time to wait for a response, in milliseconds. Use a value
* of 0 to wait indefinitely.
- *
+ *
* @return ReferSubscriber object representing the implicit subscription if the operation is
* successful so far, null otherwise.
*/
@@ -2046,10 +2070,10 @@ public ReferSubscriber refer(Dialog dialog, SipURI referToUri, String eventId, l
* This method is the same as the basic in-dialog refer() method except that it allows the caller
* to specify a message body and/or additional JAIN-SIP API message headers to add to or replace
* in the outbound message. Use of this method requires knowledge of the JAIN-SIP API.
- *
+ *
*
* The extra parameters supported by this method are:
- *
+ *
* @param additionalHeaders ArrayList of javax.sip.header.Header, each element a SIP header to add
* to the outbound message. These headers are added to the message after a correct message
* has been constructed. Note that if you try to add a header that there is only supposed
@@ -2114,10 +2138,10 @@ public ReferSubscriber refer(Dialog dialog, SipURI referToUri, String eventId, l
* This method is the same as the basic in-dialog refer() method except that it allows the caller
* to specify a message body and/or additional message headers to add to or replace in the
* outbound message without requiring knowledge of the JAIN-SIP API.
- *
+ *
*
* The extra parameters supported by this method are:
- *
+ *
* @param body A String to be used as the body of the message. Parameters contentType,
* contentSubType must both be non-null to get the body included in the message. Use null
* for no body bytes.
@@ -2143,7 +2167,7 @@ public ReferSubscriber refer(Dialog dialog, SipURI referToUri, String eventId, l
* occur if your headers are not syntactically correct or contain nonsensical values (the
* message may not pass through the local SIP stack). Use null for no replacement of
* message headers.
- *
+ *
*/
public ReferSubscriber refer(Dialog dialog, SipURI referToUri, String eventId, long timeout,
String body, String contentType, String contentSubType, ArrayList
+ * Created by TELES AG on 15/01/2018.
+ *
+ * @see RequestProcessor
+ */
+public class RequestProcessingResult {
+
+ private final boolean isProcessed;
+ private final boolean isSuccessful;
+
+ /**
+ * @param isProcessed If the input was accepted and processed
+ * @param isSuccessful If the processing result was successful
+ */
+ public RequestProcessingResult(boolean isProcessed, boolean isSuccessful) {
+ this.isProcessed = isProcessed;
+ this.isSuccessful = isSuccessful;
+ }
+
+ /**
+ * @return True if any strategy was able to accept the input of the request processor
+ */
+ public boolean isProcessed() {
+ return isProcessed;
+ }
+
+ /**
+ * @return True if the accepting strategy was able to successfully process the input of the request processor
+ */
+ public boolean isSuccessful() {
+ return isSuccessful;
+ }
+}
diff --git a/src/main/java/org/cafesip/sipunit/processing/RequestProcessingStrategy.java b/src/main/java/org/cafesip/sipunit/processing/RequestProcessingStrategy.java
new file mode 100644
index 0000000000..5654440e13
--- /dev/null
+++ b/src/main/java/org/cafesip/sipunit/processing/RequestProcessingStrategy.java
@@ -0,0 +1,62 @@
+package org.cafesip.sipunit.processing;
+
+import org.cafesip.sipunit.SipSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.sip.RequestEvent;
+import javax.sip.SipListener;
+
+/**
+ * The request matching strategy is used within every {@link SipListener} subclass which is bound to process an incoming
+ * request.
+ * In order to provide multiple ways of accepting a request from various sources, we introduce this type to provide an
+ * unified way to determine if a request fits a criterion for it to be accepted and processed within a session.
+ *
+ * Created by TELES AG on 12/01/2018.
+ *
+ * @see RequestProcessor
+ * @see SipSession#processRequest(RequestEvent)
+ */
+public abstract class RequestProcessingStrategy
+ * The request processor additionally manages that the request processing strategies do not produce side effects when being
+ * mutated, and provides concurrent access to the strategy handling mechanism. The default strategies which are provided by
+ * this class on instantiation are specified with the dedicated constructor.
+ *
+ * Created by TELES AG on 12/01/2018.
+ *
+ * @see RequestProcessingStrategy
+ */
+public class RequestProcessor
+ * Created by TELES AG on 15/01/2018.
+ */
+public final class ConferenceEventStrategy extends RequestProcessingStrategy
+ * Created by TELES AG on 15/01/2018.
+ */
+public final class PresenceEventStrategy extends RequestProcessingStrategy
+ * Created by TELES AG on 15/01/2018.
+ */
+public final class ReferEventStrategy extends RequestProcessingStrategy
+ * Created by TELES AG on 12/01/2018.
+ */
+public class TestRequestProcessing {
+
+ private RequestProcessingStrategy defaultRequestProcessingStrategy = new RequestProcessingStrategy