Package org.cipango.server

Source Code of org.cipango.server.SipProxy$BranchIterator

// ========================================================================
// Copyright 2008-2009 NEXCOM Systems
// ------------------------------------------------------------------------
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ========================================================================

package org.cipango.server;

import java.io.Serializable;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;

import javax.servlet.sip.Address;
import javax.servlet.sip.Proxy;
import javax.servlet.sip.ProxyBranch;
import javax.servlet.sip.ServletParseException;
import javax.servlet.sip.SipServletRequest;
import javax.servlet.sip.SipServletResponse;
import javax.servlet.sip.SipURI;
import javax.servlet.sip.TooManyHopsException;
import javax.servlet.sip.URI;
import javax.servlet.sip.ar.SipApplicationRoutingDirective;

import org.cipango.server.session.SessionManager;
import org.cipango.server.session.SessionManager.SessionScope;
import org.cipango.server.session.AppSession;
import org.cipango.server.session.CallSession;
import org.cipango.server.session.Session;
import org.cipango.server.transaction.ClientTransaction;
import org.cipango.server.transaction.ClientTransactionListener;
import org.cipango.server.transaction.ServerTransaction;
import org.cipango.server.transaction.ServerTransactionListener;
import org.cipango.server.transaction.Transaction;
import org.cipango.sip.NameAddr;
import org.cipango.sip.SipGrammar;
import org.cipango.sip.SipHeaders;
import org.cipango.util.TimerTask;

import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.LazyList;

public class SipProxy implements Proxy, ServerTransactionListener, Serializable
{   
  private static final long serialVersionUID = 1L;

  public static final int DEFAULT_TIMEOUT = 15;
  public static final int DEFAULT_TIMER_C = 180;
 
    public static int __maxForwards = 70;
    public static int __timerC = DEFAULT_TIMER_C;
   
    private boolean _started;
   
    private boolean _parallel = true;
    private boolean _recurse = true;
    private boolean _supervised = true;
    private boolean _noCancel = false;
       
    private int _proxyTimeout = DEFAULT_TIMEOUT;
   
    private SipURI _rrUri;
    private SipURI _pathUri;
   
    private ServerTransaction _tx;
    private SipResponse _best;
   
    private int _actives;
   
    private Object _branches;
    private Object _targets;

  public SipProxy(SipRequest request) throws TooManyHopsException
    {
    _tx = (ServerTransaction) request.getTransaction();
        _tx.setListener(this);
                       
        int maxForwards = request.getMaxForwards();
        if (maxForwards == 0)
            throw new TooManyHopsException();
        else if (maxForwards == -1)
            request.setMaxForwards(70);
       
        if (Log.isDebugEnabled())
          Log.debug("Created proxy for tx {}", _tx, null);
    }
 
  /**
   * @see Proxy#cancel()
   */
  public void cancel()
  {
    cancel(null, null, null);
    }
 
  /**
   * @see Proxy#cancel(String[], int[], String[])
   */
  public void cancel(String[] protocol, int[] reasonCode, String[] reasonText)
  {               
    if (_tx.isCompleted())
      throw new IllegalStateException("Transaction has completed");
   
    doCancel(protocol, reasonCode, reasonText);
  }
 
  protected void doCancel(String[] protocol, int[] reasonCode, String[] reasonText)
  {
        for (int i = LazyList.size(_branches); i-->0; )
        {
          Branch branch = (Branch) LazyList.get(_branches, i);
          branch.cancel(protocol, reasonCode, reasonText);
        }
  }
 
  /**
   * @see Proxy#createProxyBranches(List)
   */
  public List<ProxyBranch> createProxyBranches(List<? extends URI> list)
  {
    List<ProxyBranch> branches = new ArrayList<ProxyBranch>();
   
    for (URI uri : list)
    {
      Branch branch = addBranch(uri);
      if (branch != null)
        branches.add(branch);
    }
    return branches;
  }
 
  /**
   * @see Proxy#getAddToPath()
   */
  public boolean getAddToPath()
  {
    return _pathUri != null;
  }

  /**
   * @see Proxy#getNoCancel
   */
  public boolean getNoCancel()
  {
    return _noCancel;
  }
 
  /**
   * @see Proxy#getOriginalRequest()
   */
  public SipServletRequest getOriginalRequest()
    {
    return _tx.getRequest();
  }
 
  /**
   * @see Proxy#getParallel()
   */
  public boolean getParallel()
    {
    return _parallel;
  }
 
  /**
   * @see Proxy#getPathURI()
   */
  public SipURI getPathURI()
  {
    if (_pathUri == null)
      throw new IllegalStateException("addToPath is not enabled");
    return _pathUri;
  }

  /**
   * @see Proxy#getProxyBranch(URI)
   */
  public ProxyBranch getProxyBranch(URI uri)
  {
    Iterator<Branch> it = new BranchIterator(_branches);
    while (it.hasNext())
    {
      Branch branch = it.next();
      if (branch.getUri().equals(uri))
        return branch;
    }
    return null;
  }
 
  /**
   * @see Proxy#getProxyBranches()
   */
  public List<ProxyBranch> getProxyBranches()
  {
    return LazyList.getList(_branches);
  }
 
  /**
   * @see Proxy#getProxyTimeout()
   */
  public int getProxyTimeout()
  {
    return _proxyTimeout;
  }
 
  /**
   * @see Proxy#getRecordRoute()
   */
  public boolean getRecordRoute()
    {
    return _rrUri != null;
  }
 
  /**
   * @see Proxy#getRecordRouteURI()
   */
  public SipURI getRecordRouteURI()
    {
    if (_rrUri == null)
      throw new IllegalStateException("Record-Routing is not enabled");
       
    return _rrUri;
  }
 
  /**
   * @see Proxy#getRecurse()
   */
  public boolean getRecurse()
    {
    return _recurse;
  }
 
  /**
   * @see Proxy#getSequentialSearchTimeout()
   * @deprecated
   */
  public int getSequentialSearchTimeout()
    {
    return getProxyTimeout();
  }
 
  /**
   * @see Proxy#getStateful()
   * @deprecated
   */
  public boolean getStateful()
    {
    return true;
  }
 
  /**
   * @see Proxy#getSupervised()
   */
  public boolean getSupervised()
    {
    return _supervised;
  }
 
  /**
   * @see Proxy#proxyTo(List)
   */
  public void proxyTo(List<? extends URI> targets)
    {
   
    for (URI uri : targets)
    {
      if (!uri.isSipURI() && getOriginalRequest().getHeader(SipHeaders.ROUTE) == null)
           throw new IllegalArgumentException("Cannot route " + uri);
      addBranch(uri);
    }
    startProxy();
  }
 
  /**
   * @see Proxy#proxyTo(javax.servlet.sip.URI)
   */
  public void proxyTo(URI uri)
    {
    if (!uri.isSipURI() && getOriginalRequest().getHeader(SipHeaders.ROUTE) == null)
         throw new IllegalArgumentException("Cannot route " + uri);
    addBranch(uri);
    startProxy();
  }
 
  /**
   * @see Proxy#setAddToPath(boolean)
   */
  public void setAddToPath(boolean addToPath)
  {
    if (!addToPath)
      _pathUri = null;
    else if (_pathUri == null)
      _pathUri = newProxyURI(false);
  }
 
  /**
   * @see Proxy#setNoCancel(boolean)
   */
  public void setNoCancel(boolean b)
  {
    _noCancel = b;
  }

  /**
   * @see Proxy#setOutboundInterface(InetAddress)
   */
  public void setOutboundInterface(InetAddress address)
  {
    if (address == null)
      throw new NullPointerException("Null address");
   
  }

  /**
   * @see Proxy#setOutboundInterface(InetSocketAddress)
   */
  public void setOutboundInterface(InetSocketAddress address)
  {
    if (address == null)
      throw new NullPointerException("Null address");
  }

  /**
   * @see Proxy#setParallel(boolean)
   */
  public void setParallel(boolean parallel)
    {
    _parallel = parallel;
  }
 
  /**
   * @see Proxy#setProxyTimeout(int)
   */
  public void setProxyTimeout(int seconds)
  {
    if (seconds <= 0)
      throw new IllegalArgumentException("Proxy timeout too low: " + seconds);
    _proxyTimeout = seconds;
  }

  /**
   * @see Proxy#setRecordRoute(boolean)
   */
  public void setRecordRoute(boolean recordRoute)
    {
    if (_started)
      throw new IllegalStateException("Proxy has already been started");
   
    if (!recordRoute)
      _rrUri = null;
    else if (_rrUri == null)
      _rrUri = newProxyURI(true);
  }
 
  /**
   * @see Proxy#setRecurse(boolean)
   */
  public void setRecurse(boolean recurse)
    {
    _recurse = recurse;
  }
 
  /**
   * @see Proxy#setSequentialSearchTimeout(int)
   * @deprecated
   */
  public void setSequentialSearchTimeout(int seconds)
    {
        setProxyTimeout(seconds);
  }
 
  /**
   * @see Proxy#setStateful(boolean)
   * @deprecated
   */
  public void setStateful(boolean b) { }
 
  /**
   * @see Proxy#setSupervised(boolean)
   */
  public void setSupervised(boolean supervised)
    {
    _supervised = supervised;
  }
 
  /**
   * @see Proxy#startProxy()
   */
  public void startProxy()
    {
    _started = true;
   
    if (_tx.isCompleted())
          throw new IllegalStateException("Transaction has completed");
   
    if (!_parallel && _actives > 0)
      return;
   
    // Patch TMP fix for CIPANGO 8
    CallSession callSession = _tx.getRequest().getCallSession();
    SessionManager cm = callSession.getServer().getSessionManager();
     
      SessionScope work = cm.openScope(callSession);
      try
      {
      // End patch
        while (LazyList.size(_targets) > 0)
            {
          Branch branch = (Branch) LazyList.get(_targets, 0);
          _targets = LazyList.remove(_targets, 0);
               
                if (Log.isDebugEnabled())
                  Log.debug("Proxying to {} ", branch.getUri(), null);
               
                branch.start();

          if (!_parallel) break;
        }
      // Patch TMP fix for CIPANGO 8
      }
      finally
      {
        work.close();
      }
      // End patch
  }
 
  // ----------------------------------------------------------------
 
  private SipURI newProxyURI(boolean applicationId)
  {
    SipConnector connector = _tx.getRequest().getConnection().getConnector();
           
    SipURI rrUri = (SipURI) connector.getSipUri().clone();
    rrUri.setParameter("lr", "");
   
    if (applicationId)
    {
      AppSession appSession = _tx.getRequest().appSession();
      rrUri.setParameter(ID.APP_SESSION_ID_PARAMETER, appSession.getAppId());
    }

    return rrUri;
  }
 
  private boolean isInTargetSet(URI uri)
  {
    if (_branches == null)
      return false;
   
    Iterator<Branch> it = new BranchIterator(_branches);
    while (it.hasNext())
    {
      if (it.next().getUri().equals(uri))
        return true;
    }
    return false;
  }
 
  protected Branch addTarget(URI uri)
  {
    URI target = uri.clone();
    if (target.isSipURI())
    {
      SipURI sipUri = (SipURI) target;
      sipUri.removeParameter("method");
      Iterator<String> it = sipUri.getHeaderNames();
      while (it.hasNext())
      {
        it.remove();
      }
    }
    if (isInTargetSet(target))
    {
      if (Log.isDebugEnabled())
        Log.debug("target {} is already in target set", target);
      return null;
    }
    else
    {
      if (Log.isDebugEnabled())
        Log.debug("adding target {} to target set", target);
     
      Branch branch = new Branch(target);
      _targets = LazyList.add(_targets, branch);
      return branch;
    }
  }
 
  protected Branch addBranch(URI uri)
  {
    if (_tx.isCompleted())
      throw new IllegalStateException("transaction completed");
       
    Branch branch = addTarget(uri);
    if (branch != null)
    {
      branch.setRecurse(getRecurse());
      branch.setRecordRoute(getRecordRoute());
      branch.setAddToPath(getAddToPath());
      branch.setProxyBranchTimeout(getProxyTimeout());
     
      _branches = LazyList.add(_branches, branch);
    }
    return branch;
  }
  
    public void handleCancel(ServerTransaction tx, SipRequest cancel)
    {
        cancel.setSession(_tx.getRequest().session());
        cancel();
        try
        {
            cancel.session().invokeServlet(cancel);
        }
        catch (Exception e)
        {
            Log.debug(e);
        }
    }
   
    public void transactionTerminated(Transaction transaction)
    {
     
    }
 
  private void tryFinal()
    {
    assert (_actives == 0);
   
      if (Log.isDebugEnabled())
        Log.debug("tryFinal, branches: {}, untried: {}", _branches, _targets);
       
      if (_best == null)
      {
      _best = (SipResponse) getOriginalRequest().createResponse(SipServletResponse.SC_REQUEST_TIMEOUT);
      _best.setToTag(ID.newTag());
      }
     
        if (Log.isDebugEnabled())
          Log.debug("final response is {}", _best, null);
       
        _best.setBranchResponse(false);
        invokeServlet(_best);
      
        if (_actives > 0)
        {
            if (Log.isDebugEnabled())
              Log.debug("new branch(es) created in callback {}", _branches, null);
            return;
        }
    forward(_best);
  }
 
    private void invokeServlet(SipResponse response)
    {
        if (_supervised)   
            response.session().invokeServlet(response);
    }
   
  private void forward(SipResponse response)
    { 
       
        /*
        if (_tx.getRequest().getTo().getParameter("tag") == null)
        {
            if (response.getStatus() < 300 && (response.isInvite() || response.isSubscribe()))
            {
                response.session().registerProxy(response);
            }
        }
        */
    if (response.getStatus() >= 300)
      response.session().updateState(response, false);
        _tx.send(response);
    response.setCommitted(true);
  }   
 
  class TimeoutC implements Runnable, Serializable
  {
    private static final long serialVersionUID = 1L;
   
    private Branch _branch;
   
    public TimeoutC(Branch branch)
    {
      _branch = branch;
    }
   
    public void run()
    {
      _branch.timeoutTimerC();
    }
  }
 
    class Branch implements ProxyBranch, ClientTransactionListener, Serializable
   
    private static final long serialVersionUID = 1L;
 
    private URI _uri;
      private SipRequest _request;
      private SipResponse _response;
     
        private ClientTransaction _ctx;
        private boolean _provisional = false;
        private TimerTask _timerC;

        private boolean _branchRecurse;
       
        private SipURI _branchPathUri;
        private SipURI _branchRRUri;
       
        private int _branchTimeout;
       
        private Object _recursedBranches;
       
        public Branch(URI uri)
        {
          _uri = uri;
          _request = (SipRequest) ((SipRequest) getOriginalRequest()).clone();
          _request.setProxyImpl(((SipRequest) getOriginalRequest()).getProxyImpl());
          if (getOriginalRequest().isInitial())
            _request.setRoutingDirective(SipApplicationRoutingDirective.CONTINUE, getOriginalRequest());
        }
       
        /**
         * @see ProxyBranch#cancel()
         */
        public void cancel()
        {
          cancel(null, null, null);
        }
       
        /**
         * @see ProxyBranch#cancel(String[], int[], String[])
         */
        public void cancel(String[] protocol, int[] reasonCode, String[] reasonText)
        {
          if (!_ctx.isCompleted())
          {
            stopTimerC();
             
              SipRequest cancel = (SipRequest) _ctx.getRequest().createCancel();
            if (protocol != null)
            {
              for (int i = 0; i < protocol.length; i++)
              {
                String reason = protocol[i]
                                + ";cause=" + reasonCode[i]
                                + ";reason=\"" + SipGrammar.escapeQuoted(reasonText[i]) + "\"";
                cancel.addHeader(SipHeaders.REASON, reason);
              }
            }
            _ctx.cancel(cancel);
          }
         
          for (int i = LazyList.size(_recursedBranches); i-->0;)
          {
            ((Branch) LazyList.get(_recursedBranches, i)).cancel(protocol, reasonCode, reasonText);
          }
    }
       
        /**
         * @see ProxyBranch#getAddToPath()
         */
        public boolean getAddToPath()
        {
      return  _branchPathUri != null;
    }
       
        /**
         * @see ProxyBranch#getPathURI()
         */
        public SipURI getPathURI()
    {
      return _branchPathUri;
    }
       
        /**
         * @see ProxyBranch#getProxy()
         */
        public Proxy getProxy()
    {
      return SipProxy.this;
    }
       
        /**
         * @see ProxyBranch#getProxyBranchTimeout()
         */
        public int getProxyBranchTimeout()
    {
      return _branchTimeout;
    }
       
        /**
         * @see ProxyBranch#getRecordRoute()
         */
        public boolean getRecordRoute()
    {
      return _branchRRUri != null;
    }

        /**
         * @see ProxyBranch#getRecordRouteURI()
         */
    public SipURI getRecordRouteURI()
    {
      if (_branchRRUri == null)
        throw new IllegalStateException("Record-Routing is not enabled");
     
      return _branchRRUri;
    }
       
    /**
     * @see ProxyBranch#getRecurse()
     */
    public boolean getRecurse()
    {
      return _branchRecurse;
    }
   
    /**
     * @see ProxyBranch#getRecursedProxyBranches()
     */
    public List<ProxyBranch> getRecursedProxyBranches()
    {
      return LazyList.getList(_recursedBranches);
    }
   
    /**
     * @see ProxyBranch#getRequest()
     */
    public SipServletRequest getRequest()
    {
      return _request;
    }

    /**
     * @see ProxyBranch#getResponse()
     */
    public SipServletResponse getResponse()
    {
      return _response;
    }
   
    /**
     * @see ProxyBranch#isStarted()
     */
    public boolean isStarted()
    {
      return _ctx != null;
    }
   
    /**
     * @see ProxyBranch#setAddToPath(boolean)
     */
    public void setAddToPath(boolean b)
      {
      if (!b)
        _branchPathUri = null;
      else if (_branchPathUri == null)
        _branchPathUri = (SipURI) (_pathUri != null ? _pathUri.clone() : newProxyURI(false));
    }
   
    /**
     * @see ProxyBranch#setOutboundInterface(InetAddress)
     */
    public void setOutboundInterface(InetAddress address)
    {
      if (!_tx.getRequest().session().isValid())
        throw new IllegalStateException("Session not valid");
      if (address == null)
        throw new NullPointerException("Null address");
    }
   
    /**
     * @see ProxyBranch#setOutboundInterface(InetSocketAddress)
     */
    public void setOutboundInterface(InetSocketAddress address)
    {
      if (!_tx.getRequest().session().isValid())
        throw new IllegalStateException("Session not valid");
      if (address == null)
        throw new NullPointerException("Null address");
    }

    /**
     * @see ProxyBranch#setProxyBranchTimeout(int)
     */
    public void setProxyBranchTimeout(int seconds)
    {
      if (seconds <= 0 || seconds > _proxyTimeout)
        throw new IllegalArgumentException("Invalid branch timeout: " + seconds);
      _branchTimeout = seconds;
    }
   
    /**
     * @see ProxyBranch#setRecordRoute(boolean)
     */
    public void setRecordRoute(boolean b)
    {
      if (isStarted())
        throw new IllegalStateException("Proxy branch is started");
     
      if (!b)
        _branchRRUri = null;
      else if (_branchRRUri == null)
        _branchRRUri = (SipURI) (_rrUri != null ? _rrUri.clone() : newProxyURI(true));
    }
   
    /**
     * @see ProxyBranch#setRecurse(boolean)
     */
    public void setRecurse(boolean recurse)
    {
      _branchRecurse = recurse; 
    }

        public URI getUri()
        {
          return _uri;
        }
       
    protected void start()
    {
            int mf = _request.getMaxForwards();
            if (mf == -1)
                mf = __maxForwards;
            else
                mf--;
           
      _request.setMaxForwards(mf);
      _request.setRequestURI(_uri);
     
      if (_branchRRUri != null)
        _request.addRecordRoute(new NameAddr(_branchRRUri));
     
      if (_branchPathUri != null && _request.isRegister())
        _request.addAddressHeader(SipHeaders.PATH, new NameAddr(_branchPathUri), true);
       
      //_ctx = _request.getCallSession().getServer().sendRequest(_request, this);
      try
      {
        _ctx = _request.session().sendRequest(_request, this);
     
        if (_request.isInvite())
          startTimerC();
     
        _actives++;
      }
      catch (Exception e)
      {
        Log.debug(e);
        // TODO
      }
    }
       
        public void startTimerC()
        {
          _timerC = _tx.getCallSession().schedule(new TimeoutC(this), __timerC * 1000);
        }
       
        public void updateTimerC()
        {
          if (_timerC == null)
            return;
         
          _provisional = true;
       
          _tx.getCallSession().cancel(_timerC);
          _timerC = _tx.getCallSession().schedule(new TimeoutC(this), __timerC * 1000);
        }
       
        public void stopTimerC()
        {
          _tx.getCallSession().cancel(_timerC);
          _timerC = null;
        }
       
        public void timeoutTimerC()
        {
          _timerC = null;
          Log.debug("Timer C timed out for branch {}", _ctx.getBranch(), null);
          if (_provisional)
          {
            cancel();
          }
          else
          {
            SipResponse timeout = _ctx.create408();
            handleResponse(timeout);
          }
        }

    public void handleResponse(SipResponse response)
      {  
      _response = response;
     
      int status = response.getStatus();
     
      if (status == 100)
        return;
         
          if (_tx.isCompleted() && !response.is2xx())
      {
        if (Log.isDebugEnabled())
          Log.debug("Dropping response " + response.getStatus() + " since proxy is completed");
        return;
      }
         
          if (Log.isDebugEnabled())
            Log.debug("Got response {}", response, null);
         
          SipRequest request = _tx.getRequest();
         
          Session session = request.session();
         
          if (request.isInitial() && status < 300)
          {
            if (!session.isSameDialog(response))
            {
              AppSession appSession = session.appSession();
              Session derived = appSession.getSession(response);
              if (derived == null)
                derived = appSession.createDerivedSession(session);
              session = derived;
           
          }
     
          response.setSession(session);
      if (status < 300)
        session.updateState(response, false);
         
      response.removeTopVia();
      response.setProxyBranch(this);
     
      if (status < 200)
          {
        if (response.isInvite())
          updateTimerC();
             
        invokeServlet(response);
        forward(response);
      }
          else
          {
            _actives--;
           
            stopTimerC();
             
        if ((300 <= status && status < 400) && _branchRecurse)
              {
          try
                  {
            Iterator<Address> it = response.getAddressHeaders(SipHeaders.CONTACT);
            while (it.hasNext())
                      {
              Address contact = (Address) it.next();
              if (contact.getURI().isSipURI())
              {
                Branch branch = addTarget(contact.getURI());
                if (branch != null)
                {
                  _recursedBranches = LazyList.add(_recursedBranches, branch);
                  branch.setRecurse(_branchRecurse);
                }
              }
            }
          }
                  catch (ServletParseException e)
                  {
            Log.ignore(e);
          }
              }
       
        if (_best == null ||
            (_best.getStatus() < 600 && (status < _best.getStatus() || status >= 600)))
              {
          _best = response;
        }
       
        if (status >= 600)
              {
          SipProxy.this.doCancel(null, null, null);
        }
       
        if (status < 300)
              {
                  invokeServlet(response);
          forward(response);
         
          SipProxy.this.doCancel(null, null, null);
        }
              else
              {
                if (LazyList.size(_targets) > 0)
                  startProxy();
               
                if (_actives > 0)
                {
                  response.setBranchResponse(true);
                  invokeServlet(response);
                }
                else
                {
                  tryFinal();
                }
              }
      }
    }
   
    public void transactionTerminated(Transaction transaction)
    { 
    }
    }
 
  class BranchIterator implements Iterator<Branch>
  {
    private Iterator<Branch> _it;
   
    private Object _branches;
    private Branch _next;
    private int _index;
   
    public BranchIterator(Object branches)
    {
      _branches = branches;
      _index = 0;
    }

    public boolean hasNext()
    {
      if (_next == null)
      {
        if (_it != null && _it.hasNext())
        {
          _next = _it.next();
        }
        else
        {
          if (_index < LazyList.size(_branches))
          {
            Branch branch = (Branch) LazyList.get(_branches, _index++);
            _next = branch;
            if (LazyList.size(branch._recursedBranches) > 0)
            {
              _it = new BranchIterator(branch._recursedBranches);
            }
          }
        }
      }
      return _next != null;
    }

    public Branch next()
    {
      if (hasNext())
      {
        Branch next = _next;
        _next = null;
        return next;
      }
      throw new NoSuchElementException();
    }

    public void remove()
    { 
    }
  }
}
TOP

Related Classes of org.cipango.server.SipProxy$BranchIterator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.