FileDocCategorySizeDatePackage
SipConnectionNotifierImpl.javaAPI DocphoneME MR2 API (J2ME)14604Wed May 02 18:00:42 BST 2007gov.nist.microedition.sip

SipConnectionNotifierImpl.java

/*
 * Portions Copyright  2000-2007 Sun Microsystems, Inc. All Rights
 * Reserved.  Use is subject to license terms.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License version
 * 2 only, as published by the Free Software Foundation.
 * 
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License version 2 for more details (a copy is
 * included at /legal/license.txt).
 * 
 * You should have received a copy of the GNU General Public License
 * version 2 along with this work; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 * 
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
 * Clara, CA 95054 or visit www.sun.com if you need additional
 * information or have any questions.
 */
/*
 * SipConnectionNotifierImpl.java
 *
 * Created on Jan 29, 2004
 *
 */
package gov.nist.microedition.sip;

import java.util.Vector;

import java.io.IOException;
import java.io.InterruptedIOException;

import javax.microedition.io.Connection;

import javax.microedition.sip.SipConnectionNotifier;
import javax.microedition.sip.SipDialog;
import javax.microedition.sip.SipException;
import javax.microedition.sip.SipServerConnection;
import javax.microedition.sip.SipServerConnectionListener;

import gov.nist.siplite.ListeningPoint;
import gov.nist.siplite.ObjectInUseException;
import gov.nist.siplite.SipProvider;
import gov.nist.siplite.SipStack;
import gov.nist.siplite.message.Request;
import gov.nist.siplite.stack.Dialog;
import gov.nist.siplite.stack.ServerTransaction;
import gov.nist.siplite.header.*;
import gov.nist.siplite.address.*;
import com.sun.midp.security.SecurityToken;
import com.sun.midp.log.Logging;
import com.sun.midp.log.LogChannels;
 
/**
 * SIP Connection notifier implementation.
 *
 * <a href="{@docRoot}/uncopyright.html">This code is in the public domain.</a>
 */
public class SipConnectionNotifierImpl
        implements SipConnectionNotifier { // , Runnable {
    /**
     * Security token for SIP/SIPS protocol class
     */
    private SecurityToken classSecurityToken;
    /**
     * Listener interface for incoming SIP requests.
     */
    private SipServerConnectionListener sipServerConnectionListener = null;
    /**
     * Messages received held in this vector
     */
    private Vector messageQueue = null;
    /**
     * flag to know the state of the connection (open or close)
     */
    private boolean connectionOpen;
    /**
     * listen address
     */
    private String localHost = null;
    /**
     * port number
     */
    private int localPort;
    /**
     * The Sip Provider for this connection Notifier
     */
    private SipProvider sipProvider = null;
    /**
     * Asynchronous notifier thread handle.
     */
    private Thread listeningThread = null;
    /**
     * Stack of associtaed connectors.
     */
    private StackConnector stackConnector = null;
    /**
     * Type value from 
     * connector.open(...type="application/vnd.company.battleships"...)
     */
    private String mimeType = null;
    /**
     * Boolean flag to indicate that this object is in waiting state during 
     * acceptAndOpen()
     */
    private boolean waitingForAcceptAndOpen = false;

    /**
     * Indicates whether this SipConnectionNotifier is opened in shared mode
     * or not
     */
    boolean sharedMode = false;
    
    /**
     * Constructor called by the Connector.open() method
     * @param sipProvider the network service provider
     * @param localAddress the local connection end point
     * @param localPort the port number on which the listener will wait for
     * incoming messages
     * @param classSecurityToken Security Token from SIP/SIPS protocol class
     * @param mimeType MIMEtype associated with SipConnectionNotifier; used for 
     *         filtering incomming SIP packets; null if not available
     * @param sharedMode Flag to indicate that SipConnectionNotifier is in
     *        shared Mode
     * @throws IOException if an I/OO error is detected
     */
    protected SipConnectionNotifierImpl(
            SipProvider sipProvider,
            String localAddress,
            int localPort,
            SecurityToken classSecurityToken,
            String mimeType,
            boolean sharedMode) {
        this.classSecurityToken = classSecurityToken;
        this.sipProvider = sipProvider;
        this.localHost = localAddress;
        this.localPort = localPort;
        this.mimeType = mimeType;
        this.sharedMode = sharedMode;
        
        // Setting default value to attributes
        connectionOpen = true;
        messageQueue = new Vector();
        try {
            stackConnector = StackConnector.getInstance(classSecurityToken);
        } catch (IOException ioe) {
            if (Logging.REPORT_LEVEL <= Logging.WARNING) {
                Logging.report(Logging.WARNING, LogChannels.LC_JSR180,
                    "can't create SipConnectionNotifier : " + ioe);
                ioe.printStackTrace();
            }
        }
    }

    /**
     * Accept and open the client connection.
     * @return connection handle
     * @see javax.microedition.sip.SipConnectionNotifier#acceptAndOpen()
     */
    public SipServerConnection acceptAndOpen()
    throws IOException, InterruptedIOException, SipException {
        if (!isConnectionOpen()) {
            throw new InterruptedIOException("Connection was closed!");
        }

        waitingForAcceptAndOpen = true;
        
        // IMPL_NOTE : handle the two others exceptions

        // create the sipServerConnection when a request is received
        // through the processRequest method the processRequest method
        // will add the Request in the Queue and notify()
        if (messageQueue == null || messageQueue.size() < 1) {
            synchronized (this) {
                try {
                    wait();
                } catch (InterruptedException ie) {
                    if (Logging.REPORT_LEVEL <= Logging.WARNING) {
                        Logging.report(Logging.WARNING, LogChannels.LC_JSR180,
                        "SipConnectionNotifierImpl.acceptAndOpen() :" +
                                "InterruptedException during wait() : " + ie);
                        ie.printStackTrace();
                    }
                } catch (IllegalMonitorStateException imse) {
                    if (Logging.REPORT_LEVEL <= Logging.WARNING) {
                        Logging.report(Logging.WARNING, LogChannels.LC_JSR180,
                        "SipConnectionNotifierImpl.acceptAndOpen() :" +
                                "Illgeal monitor state during wait(): " + imse);
                       imse.printStackTrace();
                    }   
                }
            }
        }
        
        if (!isConnectionOpen()) {
            throw new InterruptedIOException("Connection is interrupted!");
        }

        waitingForAcceptAndOpen = false;
                
        // Get the request received from the message queue
        Request request = (Request)messageQueue.firstElement();
        // Set up the dialog
        SipDialog sipDialog = null;
        ServerTransaction serverTransaction =
                (ServerTransaction)request.getTransaction();
        // Get the nist-siplite dialog
        Dialog dialog = serverTransaction.getDialog();

        // If the method is an INVITE, SUBSCRIBE or REFER, we create
        // a new dialog and add it to the list of dialog we have.
        String method = request.getMethod();
        
        if (stackConnector.getSipStack().isDialogCreated(method)) {
            // request URI
            URI reqURI = null;
            ContactList cl = request.getContactHeaders();
            if (cl != null) {
                if (cl.size() > 0) {
                    ContactHeader ch = (ContactHeader)cl.getFirst();
                    Address addr = (Address)ch.getValue();
                    if (addr != null) {
                        reqURI = addr.getURI();
                    }
                }
            }
        
            if (reqURI == null) {
                reqURI = request.getFromHeader().getAddress().getURI();
            }
            sipDialog = new SipDialogImpl(
                    dialog,
                    this,
                    classSecurityToken);
            stackConnector.sipDialogList.addElement(sipDialog);

            if (method.equals(Request.INVITE)) {
                ((SipDialogImpl)sipDialog).setWaitForBye(true);
            }
        } else if ((dialog != null) &&
                   (!request.getMethod().equals(Request.CANCEL))) {
            sipDialog = stackConnector.findDialog(dialog.getDialogId());
        }
        // IMPL_NOTE : check security access before returning the connection
        SipServerConnection sipServerConnection =
                new SipServerConnectionImpl(
                request,
                sipDialog,
                this);
        // We remove the request from the queue
        messageQueue.removeElementAt(0);

        return sipServerConnection;
    }

    /**
     * Sets a listener for incoming SIP requests. If a listener is
     * already set it
     * will be overwritten. Setting listener to null will remove the current
     * listener.
     * @param sscl  listener for incoming SIP requests
     * @throws IOException  if the connection was closed
     */
    public void setListener(SipServerConnectionListener sscl)
    throws IOException {
        if (!isConnectionOpen())
            throw new IOException("Connection was closed!");
        this.sipServerConnectionListener = sscl;

    }

    /**
     * Gets the local IP address for this SIP connection.
     * @return local IP address. Returns null if the address is not available.
     * @throws IOException - if the connection was closed
     */
    public String getLocalAddress() throws IOException {
        if (!isConnectionOpen())
            throw new IOException("Connection was closed!");
        return localHost;
    }

    /**
     * Gets the local port for this SIP connection.
     * @return local port number, that the notifier is listening to.
     * Returns 0 if the port is not available.
     * @throws IOException - if the connection was closed
     */
    public int getLocalPort() throws IOException {
        if (!isConnectionOpen())
            throw new IOException("Connection was closed!");
        return this.localPort;
    }

    /**
     * Closes the connection notifier handling.
     * @exception IOException if an error occurs while terminating
     * @see javax.microedition.io.Connection#close()
     */
    public void close() throws IOException {
        if (!isConnectionOpen()) { // connection is already closed
            return;
        }
        // stop the listening points and sipProvider
        if (sharedMode) {
            stackConnector.closeSharedSipConnectionNotifier(mimeType);
        } else {
            SipStack sipStack = sipProvider.getSipStack();
            ListeningPoint listeningPoint = sipProvider.getListeningPoint();

            try {
                sipStack.deleteListeningPoint(listeningPoint);
                sipStack.deleteSipProvider(sipProvider);
            } catch (ObjectInUseException oiue) {
                throw new IOException(oiue.getMessage());
            }
            /*
             * sipStack should be closed only if there are no more
             * associated listening points
             */
            if (!sipStack.getListeningPoints().hasMoreElements()) {
                sipStack.stopStack();
            }
        }
        
        // Removing the connection from the connection list held by
        // the stackConnector
        stackConnector.connectionNotifiersList.removeElement(this);


        // Notification that the connection has been closed
        connectionOpen = false;
        
        if (waitingForAcceptAndOpen) {
            synchronized (this) {
                try {
                    notify();
                } catch (IllegalMonitorStateException imse) {
                    if (Logging.REPORT_LEVEL <= Logging.WARNING) {
                        Logging.report(Logging.WARNING, LogChannels.LC_JSR180,
                        "SipConnectionNotifierImpl.close() :" +
                                "Illgeal monitor state during wait(): " + imse);
                       imse.printStackTrace();
                    }   
                }
            }
        }
        // listeningThread = null;
    }

    /**
     *
     */

    /**
     * The stack connector notifies this class when it receive a new request
     * @param request - the new received request
     */
    protected void notifyRequestReceived(Request request) {
        messageQueue.addElement(request);
        // We notify the listener that a request has been received
        if (this.sipServerConnectionListener != null)
            try { // The user code is called 
                sipServerConnectionListener.notifyRequest(this);
            } catch (Throwable exc) { // Ignore any user exception
                if (Logging.REPORT_LEVEL <= Logging.WARNING) {
                    Logging.report(Logging.WARNING, LogChannels.LC_JSR180,
                        "Exception in notifyRequest() method has been thrown");
                }
            }
        synchronized (this) {
            try {
                notify();
            } catch (IllegalMonitorStateException imse) {
                imse.printStackTrace();
            }
        }
    }

    /**
     * Gets the sip provider.
     * @return the sip provider
     */
    protected SipProvider getSipProvider() {
        return sipProvider;
    }

    /**
     * Gets the connection state.
     * @return true when connection is opened
     */
    protected boolean isConnectionOpen() {
        return connectionOpen;
    }

    /**
     * Get the MIME type for this SipConnectionNotifier
     *
     * @return MIMEtype of the SipConnectionNotifier
     */
    protected String getMIMEType() {
        return mimeType;
    } 
    
    /**
     * Gets the current stack connector.
     * @return the current stack connector
     */
    protected StackConnector getStackConnector() {
        return stackConnector;
    }

}