diff --git a/src/net/java/sip/communicator/impl/protocol/sip/ClientCapabilities.java b/src/net/java/sip/communicator/impl/protocol/sip/ClientCapabilities.java index 430e5b95e..ac0315804 100644 --- a/src/net/java/sip/communicator/impl/protocol/sip/ClientCapabilities.java +++ b/src/net/java/sip/communicator/impl/protocol/sip/ClientCapabilities.java @@ -25,7 +25,7 @@ * @author Emil Ivov */ public class ClientCapabilities - implements SipListener + implements MethodProcessor { private static Logger logger = Logger.getLogger(ClientCapabilities.class); @@ -48,7 +48,7 @@ public ClientCapabilities(ProtocolProviderServiceSipImpl protocolProvider) { this.provider = protocolProvider; provider.registerMethodProcessor(Request.OPTIONS, this); - + provider.addRegistrationStateChangeListener(new RegistrationListener()); } @@ -58,7 +58,7 @@ public ClientCapabilities(ProtocolProviderServiceSipImpl protocolProvider) * * @param requestEvent the incoming options request. */ - public void processRequest(RequestEvent requestEvent) + public boolean processRequest(RequestEvent requestEvent) { Response optionsOK = null; try @@ -101,7 +101,7 @@ public void processRequest(RequestEvent requestEvent) { //What else could we do apart from logging? logger.warn("Failed to create an incoming OPTIONS request", ex); - return; + return false; } try @@ -120,58 +120,64 @@ public void processRequest(RequestEvent requestEvent) { //What else could we do apart from logging? logger.warn("Failed to send an incoming OPTIONS request", ex); - return; + return false; } catch (SipException ex) { //What else could we do apart from logging? logger.warn("Failed to send an incoming OPTIONS request", ex); - return; + return false; } + + return true; } /** * ignore. don't needed. * @param dialogTerminatedEvent unused */ - public void processDialogTerminated( + public boolean processDialogTerminated( DialogTerminatedEvent dialogTerminatedEvent) { - + return false; } /** * ignore. don't needed. * @param exceptionEvent unused */ - public void processIOException(IOExceptionEvent exceptionEvent) + public boolean processIOException(IOExceptionEvent exceptionEvent) { + return false; } /** * ignore for the time being * @param responseEvent unused */ - public void processResponse(ResponseEvent responseEvent) + public boolean processResponse(ResponseEvent responseEvent) { + return false; } /** * ignore for the time being. * @param timeoutEvent unused */ - public void processTimeout(TimeoutEvent timeoutEvent) + public boolean processTimeout(TimeoutEvent timeoutEvent) { disconnect(); + return true; } /** * ignore for the time being. * @param transactionTerminatedEvent unused */ - public void processTransactionTerminated( + public boolean processTransactionTerminated( TransactionTerminatedEvent transactionTerminatedEvent) { + return false; } /** diff --git a/src/net/java/sip/communicator/impl/protocol/sip/MethodProcessor.java b/src/net/java/sip/communicator/impl/protocol/sip/MethodProcessor.java new file mode 100644 index 000000000..9b864c734 --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/sip/MethodProcessor.java @@ -0,0 +1,114 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.protocol.sip; + +import javax.sip.*; + +/** + * Represents a processor of events with a specific method received in + * {@link ProtocolProviderServiceSipImpl} much like SipListener but + * with the addition of signaling whether the specified event was indeed handled + * in the processor and needs no further processing in other processors + * registered for the same method. + * + * @author Lubomir Marinov + */ +public interface MethodProcessor +{ + + /** + * Process an asynchronously reported DialogTerminatedEvent. When a dialog + * transitions to the Terminated state, the stack keeps no further records + * of the dialog. This notification can be used by applications to clean up + * any auxiliary data that is being maintained for the given dialog. + * + * @param dialogTerminatedEvent an event that indicates that the dialog has + * transitioned into the terminated state + * @return true if the specified event has been handled by this + * processor and shouldn't be offered to other processors registered + * for the same method; false, otherwise + */ + boolean processDialogTerminated(DialogTerminatedEvent dialogTerminatedEvent); + + /** + * Process an asynchronously reported IO Exception. Asynchronous IO + * Exceptions may occur as a result of errors during retransmission of + * requests. The transaction state machine requires to report IO Exceptions + * to the application immediately (according to RFC 3261). This method + * enables an implementation to propagate the asynchronous handling of IO + * Exceptions to the application. + * + * @param exceptionEvent the Exception event that is reported to the + * application + * @return true if the specified event has been handled by this + * processor and shouldn't be offered to other processors registered + * for the same method; false, otherwise + */ + boolean processIOException(IOExceptionEvent exceptionEvent); + + /** + * Processes a Request received on a + * ProtocolProviderServiceSipImpl upon which this processor is + * registered. + * + * @param requestEvent requestEvent fired from the + * ProtocolProviderServiceSipImpl to the processor + * representing a Request received from the network + * @return true if the specified event has been handled by this + * processor and shouldn't be offered to other processors registered + * for the same method; false, otherwise + */ + boolean processRequest(RequestEvent requestEvent); + + /** + * Processes a Response received on a + * ProtocolProviderServiceSipImpl upon which this processor is + * registered. + * + * @param responseEvent the responseEvent fired from the + * ProtocolProviderServiceSipImpl to the processor + * representing a Response received from the network + * @return true if the specified event has been handled by this + * processor and shouldn't be offered to other processors registered + * for the same method; false, otherwise + */ + boolean processResponse(ResponseEvent responseEvent); + + /** + * Processes a retransmit or expiration Timeout of an underlying + * {@link Transaction} handled by this SipListener. This Event notifies the + * application that a retransmission or transaction Timer expired in the + * SipProvider's transaction state machine. The TimeoutEvent encapsulates + * the specific timeout type and the transaction identifier either client or + * server upon which the timeout occurred. The type of Timeout can by + * determined by: + * timeoutType = timeoutEvent.getTimeout().getValue(); + * + * @param timeoutEvent the timeoutEvent received indicating either the + * message retransmit or transaction timed out + * @return true if the specified event has been handled by this + * processor and shouldn't be offered to other processors registered + * for the same method; false, otherwise + */ + boolean processTimeout(TimeoutEvent timeoutEvent); + + /** + * Process an asynchronously reported TransactionTerminatedEvent. When a + * transaction transitions to the Terminated state, the stack keeps no + * further records of the transaction. This notification can be used by + * applications to clean up any auxiliary data that is being maintained for + * the given transaction. + * + * @param transactionTerminatedEvent an event that indicates that the + * transaction has transitioned into the terminated state + * @return true if the specified event has been handled by this + * processor and shouldn't be offered to other processors registered + * for the same method; false, otherwise + */ + boolean processTransactionTerminated( + TransactionTerminatedEvent transactionTerminatedEvent); +} diff --git a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetBasicInstantMessagingSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetBasicInstantMessagingSipImpl.java index 6631373d6..e07f2a4fc 100644 --- a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetBasicInstantMessagingSipImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetBasicInstantMessagingSipImpl.java @@ -95,7 +95,7 @@ public class OperationSetBasicInstantMessagingSipImpl offlineMessageSupported = true; sipProvider.registerMethodProcessor(Request.MESSAGE, - new SipMessageListener()); + new BasicInstantMessagingMethodProcessor()); this.sipStatusEnum = sipProvider.getSipStatusEnum(); } @@ -686,31 +686,34 @@ else if (evt instanceof MessageDeliveryFailedEvent) /** * Class for listening incoming packets. */ - private class SipMessageListener - implements SipListener + private class BasicInstantMessagingMethodProcessor + implements MethodProcessor { - public void processDialogTerminated( + public boolean processDialogTerminated( DialogTerminatedEvent dialogTerminatedEvent) { // never fired + return false; } - public void processIOException(IOExceptionEvent exceptionEvent) + public boolean processIOException(IOExceptionEvent exceptionEvent) { // never fired + return false; } - public void processTransactionTerminated( + public boolean processTransactionTerminated( TransactionTerminatedEvent transactionTerminatedEvent) { // nothing to do + return false; } /** * * @param timeoutEvent TimeoutEvent */ - public void processTimeout(TimeoutEvent timeoutEvent) + public boolean processTimeout(TimeoutEvent timeoutEvent) { synchronized (messageProcessors) { @@ -721,7 +724,7 @@ public void processTimeout(TimeoutEvent timeoutEvent) = (SipMessageProcessor)iter.next(); if(!listener.processTimeout(timeoutEvent, sentMsg)) - return; + return true; } } @@ -730,7 +733,7 @@ public void processTimeout(TimeoutEvent timeoutEvent) if (timeoutEvent.isServerTransaction()) { logger.warn("The sender has probably not received our OK"); - return; + return false; } Request req = timeoutEvent.getClientTransaction().getRequest(); @@ -753,7 +756,7 @@ public void processTimeout(TimeoutEvent timeoutEvent) if (toHeader == null) { logger.error("received a request without a to header"); - return; + return false; } Contact to = opSetPersPresence.resolveContactID( @@ -797,15 +800,20 @@ public void processTimeout(TimeoutEvent timeoutEvent) MessageDeliveryFailedEvent.INTERNAL_ERROR, new Date()); fireMessageEvent(evt); + + return true; } /** * Process a request from a distant contact - * + * * @param requestEvent the RequestEvent containing the newly - * received request. + * received request. + * @return true if the specified event has been handled by this + * processor and shouldn't be offered to other processors + * registered for the same method; false, otherwise */ - public void processRequest(RequestEvent requestEvent) + public boolean processRequest(RequestEvent requestEvent) { synchronized (messageProcessors) { @@ -816,7 +824,7 @@ public void processRequest(RequestEvent requestEvent) = (SipMessageProcessor)iter.next(); if(!listener.processMessage(requestEvent)) - return; + return true; } } @@ -841,7 +849,7 @@ public void processRequest(RequestEvent requestEvent) if (fromHeader == null) { logger.error("received a request without a from header"); - return; + return false; } Contact from = opSetPersPresence.resolveContactID( @@ -910,15 +918,20 @@ public void processRequest(RequestEvent requestEvent) = new MessageReceivedEvent( newMessage, from, new Date()); fireMessageEvent(msgReceivedEvt); + + return true; } /** * Process a response from a distant contact. - * + * * @param responseEvent the ResponseEvent containing the newly - * received SIP response. + * received SIP response. + * @return true if the specified event has been handled by this + * processor and shouldn't be offered to other processors + * registered for the same method; false, otherwise */ - public void processResponse(ResponseEvent responseEvent) + public boolean processResponse(ResponseEvent responseEvent) { synchronized (messageProcessors) { @@ -929,7 +942,7 @@ public void processResponse(ResponseEvent responseEvent) = (SipMessageProcessor)iter.next(); if(!listener.processResponse(responseEvent, sentMsg)) - return; + return true; } } @@ -956,7 +969,7 @@ public void processResponse(ResponseEvent responseEvent) { // should never happen logger.error("send a request without a to header"); - return; + return false; } Contact to = opSetPersPresence.resolveContactID(toHeader.getAddress() @@ -981,7 +994,7 @@ public void processResponse(ResponseEvent responseEvent) new Date()); fireMessageEvent(evt); - return; + return false; } // we retrieve the original message @@ -1005,7 +1018,7 @@ public void processResponse(ResponseEvent responseEvent) new Date()); fireMessageEvent(evt); - return; + return true; } // status 401/407 = proxy authentification @@ -1083,6 +1096,8 @@ else if (status >= 200) // we don't need this message anymore sentMsg.remove(key); } + + return true; } /** diff --git a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetBasicTelephonySipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetBasicTelephonySipImpl.java index 389658411..918b9fbfa 100644 --- a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetBasicTelephonySipImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetBasicTelephonySipImpl.java @@ -28,8 +28,8 @@ */ public class OperationSetBasicTelephonySipImpl extends AbstractOperationSetBasicTelephony - implements OperationSetAdvancedTelephony, - SipListener + implements MethodProcessor, + OperationSetAdvancedTelephony { private static final Logger logger = Logger.getLogger(OperationSetBasicTelephonySipImpl.class); @@ -475,8 +475,11 @@ private void throwOperationFailedException(String message, int errorCode, * @param requestEvent requestEvent fired from the SipProvider to the * SipListener representing a Request received from the * network. + * @return true if the specified event has been handled by this + * processor and shouldn't be offered to other processors registered + * for the same method; false, otherwise */ - public void processRequest(RequestEvent requestEvent) + public boolean processRequest(RequestEvent requestEvent) { ServerTransaction serverTransaction = requestEvent.getServerTransaction(); @@ -497,7 +500,7 @@ public void processRequest(RequestEvent requestEvent) logger.error("Failed to create a new server" + "transaction for an incoming request\n" + "(Next message contains the request)", ex); - return; + return false; } catch (TransactionUnavailableException ex) { @@ -505,10 +508,12 @@ public void processRequest(RequestEvent requestEvent) logger.error("Failed to create a new server" + "transaction for an incoming request\n" + "(Next message contains the request)", ex); - return; + return false; } } + boolean processed = false; + // INVITE if (requestMethod.equals(Request.INVITE)) { @@ -521,6 +526,7 @@ public void processRequest(RequestEvent requestEvent) logger.debug("request is an INVITE. Dialog state=" + dialogState); processInvite(jainSipProvider, serverTransaction, request); + processed = true; } else { @@ -532,29 +538,35 @@ public void processRequest(RequestEvent requestEvent) else if (requestMethod.equals(Request.ACK)) { processAck(serverTransaction, request); + processed = true; } // BYE else if (requestMethod.equals(Request.BYE)) { processBye(serverTransaction, request); + processed = true; } // CANCEL else if (requestMethod.equals(Request.CANCEL)) { processCancel(serverTransaction, request); + processed = true; } // REFER else if (requestMethod.equals(Request.REFER)) { logger.debug("received REFER"); processRefer(serverTransaction, request, jainSipProvider); + processed = true; } // NOTIFY else if (requestMethod.equals(Request.NOTIFY)) { logger.debug("received NOTIFY"); - processNotify(serverTransaction, request); + processed = processNotify(serverTransaction, request); } + + return processed; } /** @@ -562,11 +574,15 @@ else if (requestMethod.equals(Request.NOTIFY)) * * @param transactionTerminatedEvent -- an event that indicates that the * transaction has transitioned into the terminated state. + * @return true if the specified event has been handled by this + * processor and shouldn't be offered to other processors registered + * for the same method; false, otherwise */ - public void processTransactionTerminated( + public boolean processTransactionTerminated( TransactionTerminatedEvent transactionTerminatedEvent) { // nothing to do here. + return false; } /** @@ -575,8 +591,11 @@ public void processTransactionTerminated( * * @param responseEvent the responseEvent that we received * ProtocolProviderService. + * @return true if the specified event has been handled by this + * processor and shouldn't be offered to other processors registered + * for the same method; false, otherwise */ - public void processResponse(ResponseEvent responseEvent) + public boolean processResponse(ResponseEvent responseEvent) { ClientTransaction clientTransaction = responseEvent.getClientTransaction(); @@ -595,6 +614,7 @@ public void processResponse(ResponseEvent responseEvent) SipProvider sourceProvider = (SipProvider) responseEvent.getSource(); int responseStatusCode = response.getStatusCode(); + boolean processed = false; switch (responseStatusCode) { @@ -603,6 +623,7 @@ public void processResponse(ResponseEvent responseEvent) if (method.equals(Request.INVITE)) { processInviteOK(clientTransaction, response); + processed = true; } else if (method.equals(Request.BYE)) { @@ -613,21 +634,25 @@ else if (method.equals(Request.BYE)) // Ringing case Response.RINGING: processRinging(clientTransaction, response); + processed = true; break; // Session Progress case Response.SESSION_PROGRESS: processSessionProgress(clientTransaction, response); + processed = true; break; // Trying case Response.TRYING: processTrying(clientTransaction, response); + processed = true; break; // Busy here. case Response.BUSY_HERE: processBusyHere(clientTransaction, response); + processed = true; break; // Accepted @@ -635,6 +660,7 @@ else if (method.equals(Request.BYE)) if (Request.REFER.equals(method)) { processReferAccepted(clientTransaction, response); + processed = true; } break; @@ -643,6 +669,7 @@ else if (method.equals(Request.BYE)) case Response.PROXY_AUTHENTICATION_REQUIRED: processAuthenticationChallenge(clientTransaction, response, sourceProvider); + processed = true; break; // errors @@ -659,10 +686,13 @@ else if (method.equals(Request.BYE)) if (callParticipant != null) callParticipant.setState(CallParticipantState.FAILED); + + processed = true; } // ignore everything else. break; } + return processed; } /** @@ -1159,14 +1189,17 @@ private void processAuthenticationChallenge( * * @param timeoutEvent the timeoutEvent received indicating either the * message retransmit or transaction timed out. + * @return true if the specified event has been handled by this + * processor and shouldn't be offered to other processors registered + * for the same method; false, otherwise */ - public void processTimeout(TimeoutEvent timeoutEvent) + public boolean processTimeout(TimeoutEvent timeoutEvent) { Transaction transaction; if (timeoutEvent.isServerTransaction()) { // don't care. or maybe a stack bug? - return; + return false; } else { @@ -1179,13 +1212,14 @@ public void processTimeout(TimeoutEvent timeoutEvent) if (callParticipant == null) { logger.debug("Got a headless timeout event." + timeoutEvent); - return; + return false; } // change status callParticipant.setState(CallParticipantState.FAILED, "The remote party has not replied!" + "The call will be disconnected"); + return true; } /** @@ -1198,11 +1232,15 @@ public void processTimeout(TimeoutEvent timeoutEvent) * * @param exceptionEvent The Exception event that is reported to the * application. + * @return true if the specified event has been handled by this + * processor and shouldn't be offered to other processors registered + * for the same method; false, otherwise */ - public void processIOException(IOExceptionEvent exceptionEvent) + public boolean processIOException(IOExceptionEvent exceptionEvent) { logger.error("Got an asynchronous exception event. host=" + exceptionEvent.getHost() + " port=" + exceptionEvent.getPort()); + return true; } /** @@ -1210,8 +1248,11 @@ public void processIOException(IOExceptionEvent exceptionEvent) * * @param dialogTerminatedEvent -- an event that indicates that the dialog * has transitioned into the terminated state. + * @return true if the specified event has been handled by this + * processor and shouldn't be offered to other processors registered + * for the same method; false, otherwise */ - public void processDialogTerminated( + public boolean processDialogTerminated( DialogTerminatedEvent dialogTerminatedEvent) { CallParticipantSipImpl callParticipant = @@ -1220,11 +1261,12 @@ public void processDialogTerminated( if (callParticipant == null) { - return; + return false; } // change status callParticipant.setState(CallParticipantState.DISCONNECTED); + return true; } /** @@ -2005,7 +2047,7 @@ && referToCallStateChanged(referToCallListenerSource, * @param notifyRequest the Request.NOTIFY request to be * processed */ - private void processNotify(ServerTransaction serverTransaction, + private boolean processNotify(ServerTransaction serverTransaction, Request notifyRequest) { @@ -2018,7 +2060,7 @@ private void processNotify(ServerTransaction serverTransaction, if ((eventHeader == null) || !"refer".equals(eventHeader.getEventType())) { - return; + return false; } SubscriptionStateHeader ssHeader = @@ -2028,7 +2070,7 @@ private void processNotify(ServerTransaction serverTransaction, { logger .error("NOTIFY of refer event type with no Subscription-State header."); - return; + return false; } Dialog dialog = serverTransaction.getDialog(); @@ -2037,7 +2079,7 @@ private void processNotify(ServerTransaction serverTransaction, if (participant == null) { logger.debug("Received a stray refer NOTIFY request."); - return; + return false; } // OK @@ -2053,7 +2095,7 @@ private void processNotify(ServerTransaction serverTransaction, logger.error(message, ex); participant.setState(CallParticipantState.DISCONNECTED, message); - return; + return false; } try { @@ -2066,7 +2108,7 @@ private void processNotify(ServerTransaction serverTransaction, logger.error(message, ex); participant.setState(CallParticipantState.DISCONNECTED, message); - return; + return false; } if (SubscriptionStateHeader.TERMINATED.equals(ssHeader.getState()) @@ -2096,6 +2138,8 @@ private void processNotify(ServerTransaction serverTransaction, participant.setState(CallParticipantState.DISCONNECTED); } } + + return true; } /** diff --git a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetDTMFSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetDTMFSipImpl.java index 9113d1976..e28c2011e 100644 --- a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetDTMFSipImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetDTMFSipImpl.java @@ -21,15 +21,15 @@ * tested. * * It should actually only be considered as a draft, since it was not heavily - * tested, and just developped enough to get the DTMF function work I copied + * tested, and just developed enough to get the DTMF function work I copied * and adapted code of the OpSetBasicTelephony implementation for SIP to make * this code. * * @author JM HEITZ */ public class OperationSetDTMFSipImpl - implements SipListener, - OperationSetDTMF + implements MethodProcessor, + OperationSetDTMF { /** * logger for the class @@ -143,35 +143,42 @@ private void sayInfo(CallParticipantSipImpl callParticipant, /** * Does nothing - * + * * @param requestEvent the event request + * @return true if the specified event has been handled by this + * processor and shouldn't be offered to other processors registered + * for the same method; false, otherwise */ - public void processRequest(RequestEvent requestEvent) + public boolean processRequest(RequestEvent requestEvent) { if (requestEvent == null) { logger.debug("requestEvent null"); } logger.error("We don't cope with requests" + requestEvent); + return false; } /** * Just look if the DTMF signal was well received, and log it - * + * * @param responseEvent the response event + * @return true if the specified event has been handled by this + * processor and shouldn't be offered to other processors registered + * for the same method; false, otherwise */ - public void processResponse(ResponseEvent responseEvent) + public boolean processResponse(ResponseEvent responseEvent) { if (responseEvent == null) { logger.debug("null responseEvent"); - return; + return false; } Response response = responseEvent.getResponse(); if (response == null) { logger.debug("null response"); - return; + return false; } int code = response.getStatusCode(); logger.debug("DTMF status code=" + code); @@ -183,59 +190,74 @@ public void processResponse(ResponseEvent responseEvent) { logger.debug("DTMF succeeded"); } + return true; } /** * In case of timeout, just terminate the transaction - * + * * @param timeoutEvent the timeout event + * @return true if the specified event has been handled by this + * processor and shouldn't be offered to other processors registered + * for the same method; false, otherwise */ - public void processTimeout(TimeoutEvent timeoutEvent) + public boolean processTimeout(TimeoutEvent timeoutEvent) { //we do nothing logger.error("ioexception :" + timeoutEvent); - + return false; } /** * Just log the exception - * + * * @param exceptionEvent the event we have to handle + * @return true if the specified event has been handled by this + * processor and shouldn't be offered to other processors registered + * for the same method; false, otherwise */ - public void processIOException(IOExceptionEvent exceptionEvent) + public boolean processIOException(IOExceptionEvent exceptionEvent) { //we do nothing if (exceptionEvent == null) { logger.debug("ioexception null"); - return; + return false; } logger.error("ioexception :" + exceptionEvent); + return false; } /** * Just log the end of the transaction - * + * * @param transactionTerminatedEvent the event we have to handle + * @return true if the specified event has been handled by this + * processor and shouldn't be offered to other processors registered + * for the same method; false, otherwise */ - public void processTransactionTerminated( + public boolean processTransactionTerminated( TransactionTerminatedEvent transactionTerminatedEvent) { //we do nothing logger.info("Transaction Terminated :" + transactionTerminatedEvent); + return false; } /** * Just log the end of the dialog - * + * * @param dialogTerminatedEvent the event we have to handle + * @return true if the specified event has been handled by this + * processor and shouldn't be offered to other processors registered + * for the same method; false, otherwise */ - - public void processDialogTerminated( + public boolean processDialogTerminated( DialogTerminatedEvent dialogTerminatedEvent) { //we do nothing logger.info("Dialog Terminated :" + dialogTerminatedEvent); + return false; } /** diff --git a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetPresenceSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetPresenceSipImpl.java index e28cbd488..170a9878a 100644 --- a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetPresenceSipImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetPresenceSipImpl.java @@ -39,7 +39,7 @@ */ public class OperationSetPresenceSipImpl extends AbstractOperationSetPersistentPresence - implements SipListener + implements MethodProcessor { private static final Logger logger = Logger.getLogger(OperationSetPresenceSipImpl.class); @@ -1673,14 +1673,17 @@ public void unsubscribe(Contact contact) /** * Analyzes the incoming responseEvent and then forwards it to the * proper event handler. - * + * * @param responseEvent the responseEvent that we received - * ProtocolProviderService. + * ProtocolProviderService. + * @return true if the specified event has been handled by this + * processor and shouldn't be offered to other processors registered + * for the same method; false, otherwise */ - public void processResponse(ResponseEvent responseEvent) + public boolean processResponse(ResponseEvent responseEvent) { if (this.presenceEnabled == false) { - return; + return false; } ClientTransaction clientTransaction = responseEvent @@ -1691,11 +1694,12 @@ public void processResponse(ResponseEvent responseEvent) if (cseq == null) { logger.error("An incoming response did not contain a CSeq header"); - return; + return false; } String method = cseq.getMethod(); SipProvider sourceProvider = (SipProvider)responseEvent.getSource(); + boolean processed = false; // SUBSCRIBE if (method.equals(Request.SUBSCRIBE)) { @@ -1721,6 +1725,7 @@ public void processResponse(ResponseEvent responseEvent) try { processAuthenticationChallenge(clientTransaction, response, sourceProvider); + processed = true; } catch (OperationFailedException e) { logger.error("can't handle the challenge", e); } @@ -1731,11 +1736,12 @@ public void processResponse(ResponseEvent responseEvent) synchronized (this.waitedCallIds) { this.waitedCallIds.remove(idheader.getCallId()); } + processed = true; } // any other cases (200/202) will imply a NOTIFY, so we will // handle the end of a subscription there - return; + return processed; } @@ -1749,7 +1755,7 @@ public void processResponse(ResponseEvent responseEvent) if (expHeader == null) { // not conform to rfc3265 logger.error("no Expires header in this response"); - return; + return false; } if (contact.getResfreshTask() != null) { @@ -1798,7 +1804,7 @@ public void processResponse(ResponseEvent responseEvent) logger.debug("failed to finalize the subscription of the" + "contact", e); - return; + return false; } } } @@ -1819,7 +1825,7 @@ else if(response.getStatusCode() >= Response.BAD_REQUEST) if (min == null) { logger.error("no minimal expires value in this 423 " + "response"); - return; + return false; } Request request = responseEvent.getClientTransaction() @@ -1831,7 +1837,7 @@ else if(response.getStatusCode() >= Response.BAD_REQUEST) exp.setExpires(min.getExpires()); } catch (InvalidArgumentException e) { logger.error("can't set the new expires value", e); - return; + return false; } ClientTransaction transac = null; @@ -1840,17 +1846,17 @@ else if(response.getStatusCode() >= Response.BAD_REQUEST) .getNewClientTransaction(request); } catch (TransactionUnavailableException e) { logger.error("can't create the client transaction", e); - return; + return false; } try { transac.sendRequest(); } catch (SipException e) { logger.error("can't send the new request", e); - return; + return false; } - return; + return true; // UNAUTHORIZED (401/407) } else if (response.getStatusCode() == Response.UNAUTHORIZED || response.getStatusCode() == Response @@ -1912,8 +1918,30 @@ else if(response.getStatusCode() >= Response.BAD_REQUEST) response.getReasonPhrase()); } } + + processed = true; + // NOTIFY - } else if (method.equals(Request.NOTIFY)) { + } + else if (method.equals(Request.NOTIFY)) + { + + /* + * Make sure we're working only on responses to NOTIFY requests + * we're interested in. + */ + Request notifyRequest = clientTransaction.getRequest(); + if (notifyRequest != null) + { + EventHeader eventHeader = + (EventHeader) notifyRequest.getHeader(EventHeader.NAME); + if ((eventHeader == null) + || !"presence".equalsIgnoreCase(eventHeader.getEventType())) + { + return false; + } + } + // if it's a final response to a NOTIFY, we try to remove it from // the list of waited NOTIFY end if (response.getStatusCode() != Response.UNAUTHORIZED @@ -1988,6 +2016,8 @@ else if(response.getStatusCode() >= Response.BAD_REQUEST) } } + processed = true; + // PUBLISH } else if (method.equals(Request.PUBLISH)) { // if it's a final response to a PUBLISH, we try to remove it from @@ -2012,7 +2042,7 @@ else if(response.getStatusCode() >= Response.BAD_REQUEST) // must be one (rfc3903) if (etHeader == null) { logger.debug("can't find the ETag header"); - return; + return false; } this.distantPAET = etHeader.getETag(); @@ -2023,7 +2053,7 @@ else if(response.getStatusCode() >= Response.BAD_REQUEST) if (expires == null) { logger.error("no Expires header in the response"); - return; + return false; } // if it's a response to an unpublish request (Expires: 0), @@ -2031,7 +2061,7 @@ else if(response.getStatusCode() >= Response.BAD_REQUEST) if (expires.getExpires() == 0) { this.distantPAET = null; - return; + return true; } // just to be sure to not have two refreshing task @@ -2057,7 +2087,7 @@ else if(response.getStatusCode() >= Response.BAD_REQUEST) response, sourceProvider); } catch (OperationFailedException e) { logger.error("can't handle the challenge", e); - return; + return false; } // INTERVAL TOO BRIEF (423) } else if (response.getStatusCode() == Response.INTERVAL_TOO_BRIEF) @@ -2069,7 +2099,7 @@ else if(response.getStatusCode() >= Response.BAD_REQUEST) if (min == null) { logger.error("can't find a min expires header in the 423" + " error message"); - return; + return false; } // send a new publish with the new expires value @@ -2078,7 +2108,7 @@ else if(response.getStatusCode() >= Response.BAD_REQUEST) req = createPublish(min.getExpires(), true); } catch (OperationFailedException e) { logger.error("can't create the new publish request", e); - return; + return false; } ClientTransaction transac = null; @@ -2088,14 +2118,14 @@ else if(response.getStatusCode() >= Response.BAD_REQUEST) .getNewClientTransaction(req); } catch (TransactionUnavailableException e) { logger.error("can't create the client transaction", e); - return; + return false; } try { transac.sendRequest(); } catch (SipException e) { logger.error("can't send the PUBLISH request", e); - return; + return false; } // CONDITIONAL REQUEST FAILED (412) @@ -2110,7 +2140,7 @@ else if(response.getStatusCode() >= Response.BAD_REQUEST) req = createPublish(this.subscriptionDuration, true); } catch (OperationFailedException e) { logger.error("can't create the new publish request", e); - return; + return false; } ClientTransaction transac = null; @@ -2120,14 +2150,14 @@ else if(response.getStatusCode() >= Response.BAD_REQUEST) .getNewClientTransaction(req); } catch (TransactionUnavailableException e) { logger.error("can't create the client transaction", e); - return; + return false; } try { transac.sendRequest(); } catch (SipException e) { logger.error("can't send the PUBLISH request", e); - return; + return false; } // with every other error, we consider that we have to start a new @@ -2138,7 +2168,7 @@ else if(response.getStatusCode() >= Response.BAD_REQUEST) this.distantPAET = null; if (this.useDistantPA == false) { - return; + return true; } logger.debug("we enter into the peer to peer mode as the " @@ -2154,7 +2184,11 @@ else if(response.getStatusCode() >= Response.BAD_REQUEST) // republish our presence state } + + processed = true; } + + return processed; } /** @@ -2404,14 +2438,17 @@ private ClientTransaction createNotify(ContactSipImpl contact, byte[] doc, /** * Process a request from a distant contact - * + * * @param requestEvent the RequestEvent containing the newly - * received request. + * received request. + * @return true if the specified event has been handled by this + * processor and shouldn't be offered to other processors registered + * for the same method; false, otherwise */ - public void processRequest(RequestEvent requestEvent) + public boolean processRequest(RequestEvent requestEvent) { if (this.presenceEnabled == false) { - return; + return false; } ServerTransaction serverTransaction = requestEvent @@ -2433,7 +2470,7 @@ public void processRequest(RequestEvent requestEvent) + "transaction for an incoming request\n" + "(Next message contains the request)" , ex); - return; + return false; } catch (TransactionUnavailableException ex) { @@ -2442,7 +2479,7 @@ public void processRequest(RequestEvent requestEvent) + "transaction for an incoming request\n" + "(Next message contains the request)" , ex); - return; + return false; } } @@ -2456,9 +2493,10 @@ public void processRequest(RequestEvent requestEvent) // listener is ? // don't send a 489 / Bad event answer here - return; + return false; } + boolean processed = false; // NOTIFY if (request.getMethod().equals(Request.NOTIFY)) { @@ -2472,7 +2510,7 @@ public void processRequest(RequestEvent requestEvent) // notify must contain one (rfc3265) if (sstateHeader == null) { logger.error("no subscription state in this request"); - return; + return false; } // first handle the case of a contact still pending @@ -2514,7 +2552,7 @@ public void processRequest(RequestEvent requestEvent) request); } catch (ParseException e) { logger.error("failed to create the 481 response", e); - return; + return false; } try { @@ -2527,7 +2565,7 @@ public void processRequest(RequestEvent requestEvent) " to send the response", e); } - return; + return true; } // if we don't understand the content @@ -2544,7 +2582,7 @@ public void processRequest(RequestEvent requestEvent) request); } catch (ParseException e) { logger.error("failed to create the OK response", e); - return; + return false; } // we want PIDF @@ -2556,7 +2594,7 @@ public void processRequest(RequestEvent requestEvent) } catch (ParseException e) { // should not happen logger.error("failed to create the accept header", e); - return; + return false; } response.setHeader(acceptHeader); @@ -2604,7 +2642,7 @@ public void processRequest(RequestEvent requestEvent) .createResponse(Response.OK, request); } catch (ParseException e) { logger.error("failed to create the OK response", e); - return; + return false; } try { @@ -2625,6 +2663,8 @@ public void processRequest(RequestEvent requestEvent) setPidfPresenceStatus(new String(request.getRawContent())); } + processed = true; + // SUBSCRIBE } else if (request.getMethod().equals(Request.SUBSCRIBE)) { FromHeader from = (FromHeader) request.getHeader(FromHeader.NAME); @@ -2679,7 +2719,7 @@ public void processRequest(RequestEvent requestEvent) .createResponse(Response.INTERVAL_TOO_BRIEF, request); } catch (Exception e) { logger.error("Error while creating the response 423", e); - return; + return false; } MinExpiresHeader min = null; @@ -2689,7 +2729,7 @@ public void processRequest(RequestEvent requestEvent) } catch (InvalidArgumentException e) { // should not happen logger.error("can't create the min expires header", e); - return; + return false; } response.setHeader(min); @@ -2697,10 +2737,10 @@ public void processRequest(RequestEvent requestEvent) serverTransaction.sendResponse(response); } catch (Exception e) { logger.error("Error while sending the response 423", e); - return; + return false; } - return; + return true; } // is it a subscription refresh ? (no need for synchronize the @@ -2723,7 +2763,7 @@ public void processRequest(RequestEvent requestEvent) .createResponse(Response.OK, request); } catch (Exception e) { logger.error("Error while creating the response 200", e); - return; + return false; } // add the expire header @@ -2732,7 +2772,7 @@ public void processRequest(RequestEvent requestEvent) .createExpiresHeader(expires); } catch (InvalidArgumentException e) { logger.error("Can't create the expires header"); - return; + return false; } response.setHeader(expHeader); @@ -2740,10 +2780,10 @@ public void processRequest(RequestEvent requestEvent) serverTransaction.sendResponse(response); } catch (Exception e) { logger.error("Error while sending the response 200", e); - return; + return false; } - return; + return true; } Dialog dialog = contact.getServerDialog(); @@ -2767,7 +2807,7 @@ public void processRequest(RequestEvent requestEvent) .createResponse(Response.OK, request); } catch (Exception e) { logger.error("Error while creating the response 200", e); - return; + return false; } // add the expire header @@ -2776,7 +2816,7 @@ public void processRequest(RequestEvent requestEvent) .createExpiresHeader(0); } catch (InvalidArgumentException e) { logger.error("Can't create the expires header", e); - return; + return false; } response.setHeader(expHeader); @@ -2784,7 +2824,7 @@ public void processRequest(RequestEvent requestEvent) serverTransaction.sendResponse(response); } catch (Exception e) { logger.error("Error while sending the response 200", e); - return; + return false; } // then terminate the subscription with an ultimate NOTIFY @@ -2797,17 +2837,17 @@ public void processRequest(RequestEvent requestEvent) SubscriptionStateHeader.TIMEOUT); } catch (OperationFailedException e) { logger.error("failed to create the new notify", e); - return; + return false; } try { dialog.sendRequest(transac); } catch (Exception e) { logger.error("Can't send the request", e); - return; + return false; } - return; + return true; } // if the contact was already subscribed, we close the last @@ -2829,7 +2869,7 @@ public void processRequest(RequestEvent requestEvent) SubscriptionStateHeader.REJECTED); } catch (OperationFailedException e) { logger.error("failed to create the new notify", e); - return; + return false; } contact.setServerDialog(null); @@ -2847,7 +2887,7 @@ public void processRequest(RequestEvent requestEvent) dialog.sendRequest(transac); } catch (Exception e) { logger.error("Can't send the request", e); - return; + return false; } } @@ -2866,7 +2906,7 @@ public void processRequest(RequestEvent requestEvent) .createResponse(Response.OK, request); } catch (Exception e) { logger.error("Error while creating the response 200", e); - return; + return false; } // add the expire header @@ -2875,7 +2915,7 @@ public void processRequest(RequestEvent requestEvent) .createExpiresHeader(expires); } catch (InvalidArgumentException e) { logger.error("Can't create the expires header", e); - return; + return false; } response.setHeader(expHeader); @@ -2883,7 +2923,7 @@ public void processRequest(RequestEvent requestEvent) serverTransaction.sendResponse(response); } catch (Exception e) { logger.error("Error while sending the response 200", e); - return; + return false; } // send a NOTIFY @@ -2896,14 +2936,14 @@ public void processRequest(RequestEvent requestEvent) null); } catch (OperationFailedException e) { logger.error("failed to create the new notify", e); - return; + return false; } try { dialog.sendRequest(transac); } catch (Exception e) { logger.error("Can't send the request", e); - return; + return false; } // add him to our watcher list @@ -2916,6 +2956,8 @@ public void processRequest(RequestEvent requestEvent) contact.setTimeoutTask(timeout); getTimer().schedule(timeout, expires * 1000); + processed = true; + // PUBLISH } else if (request.getMethod().equals(Request.PUBLISH)) { // we aren't supposed to receive a publish so just say "not @@ -2928,59 +2970,79 @@ public void processRequest(RequestEvent requestEvent) .createResponse(Response.NOT_IMPLEMENTED, request); } catch (Exception e) { logger.error("Error while creating the response 501", e); - return; + return false; } try { serverTransaction.sendResponse(response); } catch (Exception e) { logger.error("Error while sending the response 501", e); - return; + return false; } + + processed = true; } + + return processed; } /** * Called when a dialog is terminated - * + * * @param dialogTerminatedEvent DialogTerminatedEvent + * @return true if the specified event has been handled by this + * processor and shouldn't be offered to other processors registered + * for the same method; false, otherwise */ - public void processDialogTerminated( + public boolean processDialogTerminated( DialogTerminatedEvent dialogTerminatedEvent) { // never fired + return false; } /** * Called when an IO error occurs - * + * * @param exceptionEvent IOExceptionEvent + * @return true if the specified event has been handled by this + * processor and shouldn't be offered to other processors registered + * for the same method; false, otherwise */ - public void processIOException(IOExceptionEvent exceptionEvent) + public boolean processIOException(IOExceptionEvent exceptionEvent) { // never fired + return false; } /** * Called when a transaction is terminated - * + * * @param transactionTerminatedEvent TransactionTerminatedEvent + * @return true if the specified event has been handled by this + * processor and shouldn't be offered to other processors registered + * for the same method; false, otherwise */ - public void processTransactionTerminated( + public boolean processTransactionTerminated( TransactionTerminatedEvent transactionTerminatedEvent) { // nothing to do + return false; } /** * Called when a timeout occur - * + * * @param timeoutEvent TimeoutEvent + * @return true if the specified event has been handled by this + * processor and shouldn't be offered to other processors registered + * for the same method; false, otherwise */ - public void processTimeout(TimeoutEvent timeoutEvent) + public boolean processTimeout(TimeoutEvent timeoutEvent) { logger.error("timeout reached, it looks really abnormal: " + timeoutEvent.toString()); + return false; } /** diff --git a/src/net/java/sip/communicator/impl/protocol/sip/ProtocolProviderServiceSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/ProtocolProviderServiceSipImpl.java index d72991001..7ec94cb56 100644 --- a/src/net/java/sip/communicator/impl/protocol/sip/ProtocolProviderServiceSipImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/sip/ProtocolProviderServiceSipImpl.java @@ -29,6 +29,7 @@ * A SIP implementation of the Protocol Provider Service. * * @author Emil Ivov + * @author Lubomir Marinov */ public class ProtocolProviderServiceSipImpl extends AbstractProtocolProviderService @@ -128,7 +129,8 @@ public class ProtocolProviderServiceSipImpl * implement the SipListener interface). Whenever a new message arrives we * extract its method and hand it to the processor instance registered */ - private Hashtable methodProcessors = new Hashtable(); + private final Hashtable> methodProcessors = + new Hashtable>(); /** * The name of the property under which the jain-sip-ri would expect to find @@ -1064,17 +1066,22 @@ public void processResponse(ResponseEvent responseEvent) //find the object that is supposed to take care of responses with the //corresponding method - SipListener processor = (SipListener)methodProcessors.get(method); + List processors = methodProcessors.get(method); - if(processor == null) + if (processors != null) { - return; - } - - logger.debug("Found one processor for method " + method - + ", processor is=" + processor.toString()); + logger.debug("Found " + processors.size() + + " processor(s) for method " + method); - processor.processResponse(responseEvent); + for (Iterator processorIter = + processors.iterator(); processorIter.hasNext();) + { + if (processorIter.next().processResponse(responseEvent)) + { + break; + } + } + } } /** @@ -1083,7 +1090,7 @@ public void processResponse(ResponseEvent responseEvent) * application that a retransmission or transaction Timer expired in the * SipProvider's transaction state machine. The TimeoutEvent encapsulates * the specific timeout type and the transaction identifier either client or - * server upon which the timeout occured. The type of Timeout can by + * server upon which the timeout occurred. The type of Timeout can by * determined by: * timeoutType = timeoutEvent.getTimeout().getValue(); * @@ -1110,18 +1117,23 @@ public void processTimeout(TimeoutEvent timeoutEvent) //find the object that is supposed to take care of responses with the //corresponding method - SipListener processor - = (SipListener)methodProcessors.get(request.getMethod()); + String method = request.getMethod(); + List processors = methodProcessors.get(method); - if (processor == null) + if (processors != null) { - return; - } + logger.debug("Found " + processors.size() + + " processor(s) for method " + method); - logger.debug("Found one processor for method " + request.getMethod() - + ", processor is=" + processor.toString()); - - processor.processTimeout(timeoutEvent); + for (Iterator processorIter = + processors.iterator(); processorIter.hasNext();) + { + if (processorIter.next().processTimeout(timeoutEvent)) + { + break; + } + } + } } /** @@ -1156,18 +1168,24 @@ public void processTransactionTerminated(TransactionTerminatedEvent //find the object that is supposed to take care of responses with the //corresponding method - SipListener processor - = (SipListener)methodProcessors.get(request.getMethod()); + String method = request.getMethod(); + List processors = methodProcessors.get(method); - if(processor == null) + if (processors != null) { - return; - } - - logger.debug("Found one processor for method " + request.getMethod() - + ", processor is=" + processor.toString()); + logger.debug("Found " + processors.size() + + " processor(s) for method " + method); - processor.processTransactionTerminated(transactionTerminatedEvent); + for (Iterator processorIter = + processors.iterator(); processorIter.hasNext();) + { + if (processorIter.next().processTransactionTerminated( + transactionTerminatedEvent)) + { + break; + } + } + } } /** @@ -1273,17 +1291,22 @@ public void processRequest(RequestEvent requestEvent) //find the object that is supposed to take care of responses with the //corresponding method - SipListener processor = (SipListener)methodProcessors.get(method); + List processors = methodProcessors.get(method); - if(processor == null) + if (processors != null) { - return; - } - - logger.debug("Found one processor for method " + method - + ", processor is=" + processor.toString()); + logger.debug("Found " + processors.size() + + " processor(s) for method " + method); - processor.processRequest(requestEvent); + for (Iterator processorIter = + processors.iterator(); processorIter.hasNext();) + { + if (processorIter.next().processRequest(requestEvent)) + { + break; + } + } + } } /** @@ -2080,33 +2103,50 @@ else if(proxyTransport.equalsIgnoreCase(ListeningPoint.TLS)) } /** - * Registers methodProcessor in the methorProcessors - * table so that it would receives all messages in a transaction initiated - * by a method request. If any previous processors exist for the - * same method, they will be replaced by this one. - * + * Registers methodProcessor in the methorProcessors table + * so that it would receives all messages in a transaction initiated by a + * method request. If any previous processors exist for the same + * method, they will be replaced by this one. + * * @param method a String representing the SIP method that we're registering - * the processor for (e.g. INVITE, REGISTER, or SUBSCRIBE). - * @param methodProcessor a SipListener implementation that would - * handle all messages received within a method transaction. + * the processor for (e.g. INVITE, REGISTER, or SUBSCRIBE). + * @param methodProcessor a MethodProcessor implementation that + * would handle all messages received within a method + * transaction. */ - public void registerMethodProcessor(String method, - SipListener methodProcessor) + public void registerMethodProcessor(String method, + MethodProcessor methodProcessor) { - this.methodProcessors.put(method, methodProcessor); + List processors = methodProcessors.get(method); + if (processors == null) + { + processors = new LinkedList(); + methodProcessors.put(method, processors); + } + if (processors.contains(methodProcessor) == false) + { + processors.add(methodProcessor); + } } /** * Unregisters methodProcessor from the methorProcessors * table so that it won't receive further messages in a transaction * initiated by a method request. - * + * * @param method the name of the method whose processor we'd like to - * unregister. + * unregister. + * @param methodProcessor */ - public void unregisterMethodProcessor(String method) + public void unregisterMethodProcessor(String method, + MethodProcessor methodProcessor) { - this.methodProcessors.remove(method); + List processors = methodProcessors.get(method); + if ((processors != null) && processors.remove(methodProcessor) + && (processors.size() <= 0)) + { + methodProcessors.remove(method); + } } /** diff --git a/src/net/java/sip/communicator/impl/protocol/sip/SipRegistrarConnection.java b/src/net/java/sip/communicator/impl/protocol/sip/SipRegistrarConnection.java index 4768548d3..9a54a589d 100644 --- a/src/net/java/sip/communicator/impl/protocol/sip/SipRegistrarConnection.java +++ b/src/net/java/sip/communicator/impl/protocol/sip/SipRegistrarConnection.java @@ -25,7 +25,7 @@ * @author Emil Ivov */ public class SipRegistrarConnection - implements SipListener + implements MethodProcessor { private static final Logger logger = Logger.getLogger(SipRegistrarConnection.class); @@ -879,13 +879,16 @@ private SipProvider getRegistrarJainSipProvider() } /** - * Analyses the incoming responseEvent and then forwards it to the + * Analyzes the incoming responseEvent and then forwards it to the * proper event handler. - * + * * @param responseEvent the responseEvent that we received - * ProtocolProviderService. + * ProtocolProviderService. + * @return true if the specified event has been handled by this + * processor and shouldn't be offered to other processors registered + * for the same method; false, otherwise */ - public void processResponse(ResponseEvent responseEvent) + public boolean processResponse(ResponseEvent responseEvent) { ClientTransaction clientTransaction = responseEvent .getClientTransaction(); @@ -898,14 +901,17 @@ public void processResponse(ResponseEvent responseEvent) Response responseClone = (Response) response.clone(); SipProvider sourceProvider = (SipProvider)responseEvent.getSource(); + boolean processed = false; //OK if (response.getStatusCode() == Response.OK) { processOK(clientTransaction, response); + processed = true; } //NOT_IMPLEMENTED else if (response.getStatusCode() == Response.NOT_IMPLEMENTED) { processNotImplemented(clientTransaction, response); + processed = true; } //Trying else if (response.getStatusCode() == Response.TRYING) { @@ -919,6 +925,7 @@ else if (response.getStatusCode() == Response.UNAUTHORIZED processAuthenticationChallenge(clientTransaction , response , sourceProvider); + processed = true; } //403 FORBIDDEN else if (response.getStatusCode() == Response.FORBIDDEN) @@ -926,6 +933,7 @@ else if (response.getStatusCode() == Response.FORBIDDEN) processForbidden(clientTransaction , response , sourceProvider); + processed = true; } //errors else if ( response.getStatusCode() / 100 == 4 ) @@ -939,8 +947,11 @@ else if ( response.getStatusCode() / 100 == 4 ) , "Received an error while trying to register. " + "Server returned error:" + response.getReasonPhrase() ); + processed = true; } //ignore everything else. + + return processed; } /** @@ -1045,73 +1056,91 @@ private void processForbidden( /** - * Process an asynchronously reported DialogTerminatedEvent. - * When a dialog transitions to the Terminated state, the stack - * keeps no further records of the dialog. This notification can be used by - * applications to clean up any auxiliary data that is being maintained - * for the given dialog. - * - * @param dialogTerminatedEvent -- an event that indicates that the - * dialog has transitioned into the terminated state. + * Process an asynchronously reported DialogTerminatedEvent. When a dialog + * transitions to the Terminated state, the stack keeps no further records + * of the dialog. This notification can be used by applications to clean up + * any auxiliary data that is being maintained for the given dialog. + * + * @param dialogTerminatedEvent -- an event that indicates that the dialog + * has transitioned into the terminated state. + * @return true if the specified event has been handled by this + * processor and shouldn't be offered to other processors registered + * for the same method; false, otherwise * @since v1.2 */ - public void processDialogTerminated(DialogTerminatedEvent + public boolean processDialogTerminated(DialogTerminatedEvent dialogTerminatedEvent) { + return false; } /** * Processes a Request received on a SipProvider upon which this SipListener * is registered. *

+ * * @param requestEvent requestEvent fired from the SipProvider to the - * SipListener representing a Request received from the network. + * SipListener representing a Request received from the network. + * @return true if the specified event has been handled by this + * processor and shouldn't be offered to other processors registered + * for the same method; false, otherwise */ - public void processRequest(RequestEvent requestEvent) + public boolean processRequest(RequestEvent requestEvent) { /** @todo send not implemented */ + return false; } /** * Processes a retransmit or expiration Timeout of an underlying * {@link Transaction}handled by this SipListener. - * + * * @param timeoutEvent the timeoutEvent received indicating either the - * message retransmit or transaction timed out. + * message retransmit or transaction timed out. + * @return true if the specified event has been handled by this + * processor and shouldn't be offered to other processors registered + * for the same method; false, otherwise */ - public void processTimeout(TimeoutEvent timeoutEvent) + public boolean processTimeout(TimeoutEvent timeoutEvent) { - //don't alert the user if we're already off - if(getRegistrationState().equals(RegistrationState.UNREGISTERED)) - return; - - setRegistrationState( - RegistrationState.CONNECTION_FAILED - , RegistrationStateChangeEvent.REASON_NOT_SPECIFIED - , "A timeout occurred while trying to connect to the server."); + // don't alert the user if we're already off + if (getRegistrationState().equals(RegistrationState.UNREGISTERED) == false) + { + setRegistrationState(RegistrationState.CONNECTION_FAILED, + RegistrationStateChangeEvent.REASON_NOT_SPECIFIED, + "A timeout occurred while trying to connect to the server."); + } + return true; } /** - * Process an asynchronously reported TransactionTerminatedEvent. - * When a transaction transitions to the Terminated state, the stack - * keeps no further records of the transaction. - * + * Process an asynchronously reported TransactionTerminatedEvent. When a + * transaction transitions to the Terminated state, the stack keeps no + * further records of the transaction. + * * @param transactionTerminatedEvent an event that indicates that the - * transaction has transitioned into the terminated state. + * transaction has transitioned into the terminated state. + * @return true if the specified event has been handled by this + * processor and shouldn't be offered to other processors registered + * for the same method; false, otherwise */ - public void processTransactionTerminated(TransactionTerminatedEvent + public boolean processTransactionTerminated(TransactionTerminatedEvent transactionTerminatedEvent) { //doesn't mean anything. we do failure handling in processTimeout + return false; } /** * Process an asynchronously reported IO Exception. - * + * * @param exceptionEvent The Exception event that is reported to the - * application. + * application. + * @return true if the specified event has been handled by this + * processor and shouldn't be offered to other processors registered + * for the same method; false, otherwise */ - public void processIOException(IOExceptionEvent exceptionEvent) + public boolean processIOException(IOExceptionEvent exceptionEvent) { setRegistrationState( RegistrationState.CONNECTION_FAILED @@ -1120,6 +1149,7 @@ public void processIOException(IOExceptionEvent exceptionEvent) + "[" + exceptionEvent.getHost() + "]:" + exceptionEvent.getPort() + "/" + exceptionEvent.getTransport()); + return true; } /**