/* * 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 java.util.*; import javax.sip.*; import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.service.protocol.event.*; import net.java.sip.communicator.util.*; /** * Keeps a list of all calls currently active and maintained by this protocol * povider. Offers methods for finding a call by its ID, participant dialog * and others. * * @author Emil Ivov */ public class ActiveCallsRepository extends CallChangeAdapter { private static final Logger logger = Logger.getLogger(ActiveCallsRepository.class); /** * The operation set that created us. Instance is mainly used for firing * events when necessary. */ private final OperationSetBasicTelephonySipImpl parentOperationSet; /** * A table mapping call ids against call instances. */ private Hashtable<String, CallSipImpl> activeCalls = new Hashtable<String, CallSipImpl>(); public ActiveCallsRepository(OperationSetBasicTelephonySipImpl opSet) { this.parentOperationSet = opSet; } /** * Adds the specified call to the list of calls tracked by this repository. * @param call CallSipImpl */ public void addCall(CallSipImpl call) { activeCalls.put(call.getCallID(), call); call.addCallChangeListener(this); } /** * If <tt>evt</tt> indicates that the call has been ended we remove it from * the repository. * @param evt the <tt>CallChangeEvent</tt> instance containing the source * calls and its old and new state. */ public void callStateChanged(CallChangeEvent evt) { if(evt.getEventType().equals(CallChangeEvent.CALL_STATE_CHANGE) && evt.getNewValue().equals(CallState.CALL_ENDED)) { CallSipImpl sourceCall = this.activeCalls.remove(evt.getSourceCall().getCallID()); logger.trace("Removing call " + sourceCall + " from the list of " + "active calls because it entered an ENDED state"); this.parentOperationSet.fireCallEvent( CallEvent.CALL_ENDED, sourceCall); } } /** * Returns an iterator over all currently active (non-ended) calls. * * @return an iterator over all currently active (non-ended) calls. */ public Iterator<CallSipImpl> getActiveCalls() { return new LinkedList<CallSipImpl>(activeCalls.values()).iterator(); } /** * Returns the call that contains the specified dialog (i.e. it is * established between us and one of the other call participants). * <p> * @param dialog the jain sip <tt>Dialog</tt> whose containing call we're * looking for. * @return the <tt>CallSipImpl</tt> containing <tt>dialog</tt> or null * if no call contains the specified dialog. */ public CallSipImpl findCall(Dialog dialog) { Iterator<CallSipImpl> activeCalls = getActiveCalls(); if(dialog == null) { logger.debug("Cannot find a participant with a null dialog. " +"Returning null"); return null; } if(logger.isTraceEnabled()) { logger.trace("Looking for participant with dialog: " + dialog + " among " + this.activeCalls.size() + " calls"); } while(activeCalls.hasNext()) { CallSipImpl call = activeCalls.next(); if(call.contains(dialog)) return call; } return null; } /** * Returns the call participant whose associated jain sip dialog matches * <tt>dialog</tt>. * * @param dialog the jain sip dialog whose corresponding participant we're * looking for. * @return the call participant whose jain sip dialog is the same as the * specified or null if no such call participant was found. */ public CallParticipantSipImpl findCallParticipant(Dialog dialog) { if(dialog == null) { logger.debug("Cannot find a participant with a null dialog. " +"Returning null"); return null; } if(logger.isTraceEnabled()) { logger.trace("Looking for participant with dialog: " + dialog + " among " + this.activeCalls.size() + " calls"); } for (Iterator<CallSipImpl> activeCalls = getActiveCalls(); activeCalls.hasNext();) { CallSipImpl call = activeCalls.next(); CallParticipantSipImpl callParticipant = call.findCallParticipant(dialog); if(callParticipant != null) { logger.trace("Returning participant " + callParticipant); return callParticipant; } } return null; } /** * Returns the <code>CallParticipantSipImpl</code> instances with * <code>Dialog</code>s matching CallID, local and remote tags. * * @param callID * @param localTag * @param remoteTag * @return the <code>List</code> of <code>CallParticipantSipImpl</code> * instances with <code>Dialog</code>s matching the specified * CallID, local and remote tags */ public List<CallParticipantSipImpl> findCallParticipants(String callID, String localTag, String remoteTag) { if (logger.isTraceEnabled()) { logger.trace("Looking for call participant with callID " + callID + ", localTag " + localTag + ", and remoteTag " + remoteTag + " among " + this.activeCalls.size() + " calls."); } List<CallParticipantSipImpl> callParticipants = new ArrayList<CallParticipantSipImpl>(); for (Iterator<CallSipImpl> activeCalls = getActiveCalls(); activeCalls.hasNext();) { CallSipImpl call = activeCalls.next(); if (!callID.equals(call.getCallID())) continue; for (Iterator<CallParticipant> callParticipantIter = call.getCallParticipants(); callParticipantIter.hasNext();) { CallParticipantSipImpl callParticipant = (CallParticipantSipImpl) callParticipantIter.next(); Dialog dialog = callParticipant.getDialog(); if (dialog != null) { String dialogLocalTag = dialog.getLocalTag(); if (((localTag == null) || "0".equals(localTag)) ? ((dialogLocalTag == null) || "0".equals(dialogLocalTag)) : localTag.equals(dialogLocalTag)) { String dialogRemoteTag = dialog.getRemoteTag(); if (((remoteTag == null) || "0".equals(remoteTag)) ? ((dialogRemoteTag == null) || "0".equals(dialogRemoteTag)) : remoteTag.equals(dialogRemoteTag)) { callParticipants.add(callParticipant); } } } } } return callParticipants; } }