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

StackConnector

public class StackConnector extends Object implements gov.nist.siplite.SipListener
This class is the connector between the JSR180 and the nist-siplite stack. This class create a stack from the SipConnector.open(SIP_URI) with the listening point equals to the one specified in the SIP URI. If none is specified, a random one is allowed by the system. This class receive the messages from the stack because it's implementing the SipListener class and transmit them to either SipConnectionNotifier or SipClientConnection or both. This class follow the singleton design pattern and is thread-safe This code is in the public domain.

Fields Summary
private com.sun.midp.security.SecurityToken
classSecurityToken
Security token for SIP/SIPS protocol class
private static StackConnector
instance
The unique instance of this class
protected gov.nist.siplite.SipStack
sipStack
The actual stack
private String
localAddress
listen address
private gov.nist.siplite.ListeningPoint
tempListeningPoint
Temporary listening point.
private gov.nist.siplite.SipProvider
tempSipProvider
Temporary sip provider.
protected Vector
connectionNotifiersList
list of connection notifiers
protected Vector
sipDialogList
list of all current dialogs
public static gov.nist.siplite.address.AddressFactory
addressFactory
Address factory handle.
public static gov.nist.siplite.message.MessageFactory
messageFactory
Message factory handle.
public static gov.nist.siplite.header.HeaderFactory
headerFactory
Header factory handle.
private gov.nist.siplite.ListeningPoint
sharedListeningPoint
Shared listening point
private gov.nist.siplite.SipProvider
sharedSipProvider
Shared sipProvider instance
int
sharedPortNumber
Shared port number
Vector
sharedMimeTypes
Indicates mime types used by applications for SipConnectionNotifiers in shared mode
Constructors Summary
private StackConnector(com.sun.midp.security.SecurityToken classSecurityToken)
Constructor Creates the stack

param
classSecurityToken security token for SIP/SIPS protocol class


     
        // Creates the factories to help to construct messages
        messageFactory = new MessageFactory();
        addressFactory = new AddressFactory();
        headerFactory = new HeaderFactory();
    
        com.sun.midp.io.j2me.socket.Protocol conn;

        connectionNotifiersList = new Vector();
        // clientConnectionList = new Vector();
        sipDialogList = new Vector();
        // Create the sipStack
        SipFactory sipFactory  =  SipFactory.getInstance();
        ConfigurationProperties properties = new ConfigurationProperties();
        int randomPort = new DistributedRandom().nextInt(60000)+1024;

        /*
         * Original NIST method for opening the serversocket connection
         * has been replaced by direct calls to instantiate the protocol
         * handler, in order to pass the security token for use of lower
         * level transport connection.
         * Original NIST sequence is :
         *
         * ServerSocketConnection serverSoc =
         *      (ServerSocketConnection)Connector.open("socket://:"+randomPort);
         *
         */

        conn = new com.sun.midp.io.j2me.socket.Protocol();
        ServerSocketConnection serverSoc =
                (ServerSocketConnection)conn.openPrim(classSecurityToken,
                "//:" + randomPort);

        localAddress = serverSoc.getLocalAddress();
        properties.setProperty("javax.sip.IP_ADDRESS", localAddress);
        properties.setProperty("javax.sip.STACK_NAME", "shootme");
        properties.setProperty("gov.nist.javax.sip.LOG_FILE_NAME",
                "/tmp/jsr180-log");
        properties.setProperty("gov.nist.javax.sip.TRACE_LEVEL",
                "0"); // TRACE_PRIVATE

        // Initialise the log file
        serverSoc.close();
        try {
            //  Create SipStack object
            sipStack = sipFactory.createSipStack(properties,
                    classSecurityToken);
            sipStack.setStackConnector(this);
        } catch (PeerUnavailableException e) {
            //  SipStackImpl in the classpath
            // e.printStackTrace();
            throw new IOException(e.getMessage());
        }
        // save security token
        this.classSecurityToken = classSecurityToken;
    
Methods Summary
public voidcloseSharedSipConnectionNotifier(java.lang.String mimeType)
Close a SipConnectionNotifier in shared mode

param
mimeType MIME type of the SipConnectionNotifier


        // Ignore when sharedMimeTypes already removed
        if (sharedMimeTypes == null) {
            return;
        }

        sharedMimeTypes.removeElement((String)mimeType);

        if (sharedMimeTypes.size() == 0) {
            try {
                sipStack.deleteListeningPoint(sharedListeningPoint);
                sipStack.deleteSipProvider(sharedSipProvider);
            } catch (ObjectInUseException oiue) {
                throw new IOException(oiue.getMessage());
            }

            sharedMimeTypes = null;

            /*
             * There are no more associated listening points in shared mode;
             * so stop the stack
             */
            sipStack.stopStack();
        }
    
public javax.microedition.sip.SipConnectionNotifiercreateSharedSipConnectionNotifier(boolean secure, java.lang.String transport, java.lang.String mimeType)
Creates a sip connection notifier in shared mode. In shared mode, SipConnectionNotifier is supposed to use a single shared port or listening point for all applications

param
secure flag to specify whether to use or not the secure layer
param
transport transport protocol name
param
mimeType parameter for filtering incomming SIP packets or null
return
the sip connection notifier that will receive request
throws
IOException if we cannot create the sip connection notifier for whatsoever reason


        if (sharedMimeTypes != null) {
            for (int i = 0; i < sharedMimeTypes.size(); i++) {
                if (mimeType.equalsIgnoreCase(
                        ((String)sharedMimeTypes.elementAt(i)))) {
                    throw new IOException("Application type is already " +
                            "reserved");
                }
            }
        } else {
            sharedMimeTypes = new Vector();
        }

        /*
         * Add the mimeType to sharedMimeTypes vector
         */
        sharedMimeTypes.addElement((String)mimeType);

        /*
         * SipConnectionNotifier in shared mode must use shared system SIP port
         * and shared SIP identity. So a shared listening point and sipProvider
         * must be used for every SipConnectionNotifier in shared mode
         */

        if ((sharedListeningPoint == null) &&
            (sharedSipProvider == null)) {

            // select a free port
            sharedPortNumber = selectPort(sharedPortNumber, transport);

            sharedListeningPoint =
                this.tempListeningPoint; // initialized by "selectPort()"
            sharedSipProvider =
                this.tempSipProvider; // initialized by "selectPort()"
        }

        SipConnectionNotifier sipConnectionNotifier =
                new SipConnectionNotifierImpl(sharedSipProvider, localAddress,
                sharedPortNumber, this.classSecurityToken, mimeType, true);
        // ((SipConnectionNotifierImpl)sipConnectionNotifier).start();
        // Add the the newly created sip connection notifier to the list of
        // connection notifiers
        this.connectionNotifiersList.addElement(sipConnectionNotifier);

        return sipConnectionNotifier;
    
public javax.microedition.sip.SipClientConnectioncreateSipClientConnection(gov.nist.siplite.address.SipURI inputURI)
Creates a sip Client Connection to send a request to the following SIP URI user@host:portNumber;parameters

param
inputURI input SIP URI
return
the sip client connection


        SipClientConnection sipClientConnection =
                new SipClientConnectionImpl(inputURI, this.classSecurityToken);
        return sipClientConnection;
    
public javax.microedition.sip.SipConnectionNotifiercreateSipConnectionNotifier(int portNumber, boolean secure, java.lang.String transport, java.lang.String mimeType)
Create a sip connection notifier on a specific port using or not the sip secure layer and with some restrictive parameters to receive requests

param
portNumber the number of the port on which we must listen for incoming requests or -1 to select random port
param
secure flag to specify whether to use or not the secure layer
param
transport transport protocol name
param
mimeType parameter for filtering incomming SIP packets or null
return
the sip connection notifier that will receive request
throws
IOException if we cannot create the sip connection notifier for whatsoever reason


        // select a free port (if need)
        portNumber = selectPort(portNumber, transport);

        SipConnectionNotifier sipConnectionNotifier =
                new SipConnectionNotifierImpl(tempSipProvider, localAddress,
                portNumber, this.classSecurityToken, mimeType, false);
        // ((SipConnectionNotifierImpl)sipConnectionNotifier).start();
        // Add the the newly created sip connection notifier to the list of
        // connection notifiers
        this.connectionNotifiersList.addElement(sipConnectionNotifier);

        return sipConnectionNotifier;
    
protected javax.microedition.sip.SipDialogfindDialog(java.lang.String dialogID)
find in the dialog list, the sip dialog with the same dialog ID as the one in parameter

param
dialogID dialogID to test against
return
the sip dialog with the same dialog ID

        Enumeration e = sipDialogList.elements();
        while (e.hasMoreElements()) {
            SipDialog sipDialog = (SipDialog)e.nextElement();
            if (sipDialog.getDialogID() != null &&
                    sipDialog.getDialogID().equals(dialogID)) {
                return sipDialog;
            }
        }
        return null;
    
protected static java.lang.StringgenerateTag()
generate a random tag that can be used either in the FromHeader or in the ToHeader

return
the randomly generated tag

        return String.valueOf(new Random().nextInt(Integer.MAX_VALUE));
    
public java.util.VectorgetConnectionNotifiersList()
Gets the current connection notifier list.

return
the connection notifier list

        return connectionNotifiersList;
    
public static synchronized gov.nist.microedition.sip.StackConnectorgetInstance(com.sun.midp.security.SecurityToken classSecurityToken)
Get the unique instance of this class

param
classSecurityToken security token for SIP/SIPS protocol class
return
the unique instance of this class

        if (instance == null)
            instance = new StackConnector(classSecurityToken);
        return instance;
    
public javax.microedition.sip.SipConnectionNotifiergetSipConnectionNotifier(int portNumber, java.lang.String acceptContactType)
Retrieve from the list of connection notifier the one that use the same port as in parameter

param
portNumber the port number
param
acceptContactType MIME type as in Accept-Contact header
return
the connection notifier matching the same port

        Enumeration e = connectionNotifiersList.elements();
        while (e.hasMoreElements()) {
            SipConnectionNotifier sipConnectionNotifier =
                    (SipConnectionNotifier)e.nextElement();
            try {
                if (sipConnectionNotifier.getLocalPort() != portNumber) {
                    continue;
                }

                if (acceptContactType != null) {
                    String scnMimeType =
                            ((SipConnectionNotifierImpl)sipConnectionNotifier).
                            getMIMEType();
                    if (scnMimeType != null) {
                        if (scnMimeType.equalsIgnoreCase(acceptContactType) ||
                                "*".equals(acceptContactType)) {
                            return sipConnectionNotifier;
                        }
                    }
                } else {
                    return sipConnectionNotifier;
                }
            } catch (IOException ioe) {
                // Intentionally ignored.
            }
        }
        return null;
    
public gov.nist.siplite.SipStackgetSipStack()
Gets the current SipStack object.

return
the current SipStack object

        return sipStack;
    
public voidprocessRequest(gov.nist.siplite.RequestEvent requestEvent)
Processes the current transaction event.

param
requestEvent the protocol transition event

        try {
            String acceptContactType = null;
            Request request = requestEvent.getRequest();
            AcceptContactHeader acHdr = request.getAcceptContact();
            if (acHdr != null) { // Accept-Contact header present
                acceptContactType = acHdr.getType();
            }

            // Retrieve the SipConnectionNotifier from the transaction
            SipConnectionNotifierImpl sipConnectionNotifier = null;
            ServerTransaction serverTransaction =
                    requestEvent.getServerTransaction();
            if (serverTransaction != null)
                sipConnectionNotifier =
                        (SipConnectionNotifierImpl)serverTransaction
                        .getApplicationData();
            // If it's a new request coming in, the
            // sipConnectionNotifier will certainly be null, so
            // retrieve from the list of connection notifier the one
            // that use the same port as in parameter
            if (sipConnectionNotifier == null) {
                SipProvider sipProvider = (SipProvider)requestEvent.getSource();
                ListeningPoint listeningPoint = sipProvider.getListeningPoint();
                sipConnectionNotifier =
                        ((SipConnectionNotifierImpl)
                        getSipConnectionNotifier(listeningPoint.getPort(),
                            acceptContactType));
                if ((serverTransaction != null) &&
                    (sipConnectionNotifier != null)) {
                    serverTransaction.setApplicationData(sipConnectionNotifier);
                }
            }

            if (sipConnectionNotifier != null) {
                sipConnectionNotifier.notifyRequestReceived(request);
            } else {
                // No need to throw any RuntimeException; just log the error
                if (Logging.REPORT_LEVEL <= Logging.WARNING) {
                    Logging.report(Logging.WARNING, LogChannels.LC_JSR180,
                        "we cannot find any connection notifier" +
                            "matching to handle this request");
                }
            }
        } catch (NullPointerException npe) {
            // npe.printStackTrace();
        } catch (IllegalArgumentException iae) {
            // iae.printStackTrace();
        }
    
public voidprocessResponse(gov.nist.siplite.ResponseEvent responseEvent)
Processes the resposne event.

param
responseEvent the transition reply event

        try {
            Response response = responseEvent.getResponse();

            // Retrieve the SipClientConnection from the transaction
            ClientTransaction clientTransaction =
                    responseEvent.getClientTransaction();
            SipClientConnectionImpl sipClientConnection =
                (SipClientConnectionImpl)clientTransaction.getApplicationData();

            if (sipClientConnection != null) {
                // translate null when client transactions are same
                if (sipClientConnection.getClientTransaction()
                    .equals(clientTransaction)) {
                    sipClientConnection.notifyResponseReceived(response, null);
                } else { // send new client transaction
                    sipClientConnection.notifyResponseReceived(response,
                        clientTransaction);
                }
            } else {
                throw new RuntimeException(
                    "we cannot find any client connection" +
                        "matching to handle this request");
            }
        } catch (NullPointerException npe) {
            // npe.printStackTrace();
        } catch (IllegalArgumentException iae) {
            // iae.printStackTrace();
        }
    
public voidprocessTimeout(gov.nist.siplite.TimeoutEvent timeoutEvent)
Process a timeout event.

param
timeoutEvent state transition timeout event


    
public static synchronized voidreleaseInstance()
remove the instance of the stack.

        instance = null;
    
private intselectPort(int portNumber, java.lang.String transport)
Create a listening point ans sip provider on given or random selected port. When port is selected successfully, ListeningPoint and SipProvider instances are created.

param
portNumber the number of the port on which we must listen for incoming requests or -1 to select random port
param
transport transport protocol name
return
the selected port number
throws
IOException if given port is busy


        boolean isRandomPort = (portNumber == -1);
        final int MAX_ATTEMPTS = 1000;
        int attemps = 0;

        if (isRandomPort) {
            // Try the default port first.
            portNumber = SIPConstants.DEFAULT_NONTLS_PORT;
        }
        
        do {
            if (attemps++ > MAX_ATTEMPTS) {
                throw new IOException("Cannot select a port!");
            }

            // Creates the listening point
            // IMPL_NOTE : Use the parameters to restrain the incoming messages
            try {
                tempListeningPoint =
                    sipStack.createListeningPoint(portNumber, transport);
            } catch (TransportNotSupportedException tnse) {
                // tnse.printStackTrace();
                throw new IOException(tnse.getMessage());
            } catch (IllegalArgumentException iae) {
                if (isRandomPort) { // port is busy
                    // Select a random port from 1024 to 10000.
                    portNumber = new DistributedRandom().nextInt(8975) + 1024;
                    continue;
                } else {
                    throw new IOException(iae.getMessage());
                }
            }

            // Creates the sip provider
            try {
                tempSipProvider =
                    sipStack.createSipProvider(tempListeningPoint);
            } catch (ObjectInUseException oiue) {
                if (isRandomPort) { // port is busy
                    // Select a random port from 1024 to 10000.
                    portNumber = new DistributedRandom().nextInt(8975) + 1024;
                    continue;
                } else {
                    // oiue.printStackTrace();
                    throw new ObjectInUseException(oiue.getMessage());
                }
            }
            
            isRandomPort = false;
            
            // Add this class as a listener for incoming messages
            try {
                tempSipProvider.addSipListener(this);
            } catch (TooManyListenersException tmle) {
                // tmle.printStackTrace();
                throw new IOException(tmle.getMessage());
            }
        } while (isRandomPort);

        return portNumber;