FileDocCategorySizeDatePackage
SIPMessageStack.javaAPI DocphoneME MR2 API (J2ME)22438Wed May 02 18:00:42 BST 2007gov.nist.siplite.stack

SIPMessageStack

public abstract class SIPMessageStack extends Object
This class defines a SIP Stack. In order to build a SIP server (UAS/UAC or Proxy etc.) you need to extend this class and instantiate it in your application. After you have done so, call {@link #createMessageProcessor} to create message processors and then start these message processors to get the stack the process messages. This will start the necessary threads that wait for incoming SIP messages. A general note about the handler structures -- handlers are expected to returnResponse for successful message processing and throw SIPServerException for unsuccessful message processing. This code is in the public domain.

Fields Summary
protected com.sun.midp.security.SecurityToken
securityToken
Security token for SIP/SIPS protocol class
protected boolean
tcpFlag
Flag indicating tcp connection in use.
protected boolean
udpFlag
Flag indicating udp connection in use.
protected String
outboundProxy
The outbound proxy location.
protected int
outboundPort
The outbound proxy server port.
protected boolean
toExit
Flag that indicates that the stack is active.
protected String
badMessageLog
Bad message log. The name of a file that stores bum messages for debugging.
protected boolean
debugFlag
Internal flag for debugging
protected String
stackName
Name of the stack.
protected String
stackAddress
IP address of stack.
protected SIPStackMessageFactory
sipMessageFactory
Request factory interface (to be provided by the application).
protected Router
router
Router to determine where to forward the request.
protected int
threadPoolSize
Starts a single processing thread for all UDP messages (otherwise, the stack will start a new thread for each UDP message).
protected int
maxConnections
Max number of simultaneous connections.
private Vector
messageProcessors
A collection of message processors.
Constructors Summary
public SIPMessageStack()
Default constructor.

        this.toExit = false;
        // Set an infinit thread pool size.
        this.threadPoolSize = -1;
        // Max number of simultaneous connections.
        this.maxConnections = -1;
        // Array of message processors.
        messageProcessors = new Vector();
    
public SIPMessageStack(SIPStackMessageFactory messageFactory, String stackAddress, String stackName)
Construcor for the stack. Registers the request and response factories for the stack.

param
messageFactory User-implemented factory for processing messages.
param
stackAddress -- IP address or host name of the stack.
param
stackName -- descriptive name for the stack.

        this();
        sipMessageFactory = messageFactory;
        if (stackAddress == null) {
            throw new IllegalArgumentException
                    ("stack Address not set");
        }

        // Set a descriptive name for the message trace logger.
        ServerLog.description = stackName;
        ServerLog.stackIpAddress = stackAddress;
    
Methods Summary
public voidaddMessageProcessor(MessageProcessor newMessageProcessor)
Adds a new MessageProcessor to the list of running processors for this SIPMessageStack and starts it. You can use this method for dynamic stack configuration. Acknowledgement: This code is contributed by Jeff Keyser.

param
newMessageProcessor the new message processor to register

        if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
            Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
                "addMessageProcessor " +
                newMessageProcessor.getPort() + " / " +
                newMessageProcessor.getTransport());
        }

        synchronized (messageProcessors) {
            messageProcessors.addElement(newMessageProcessor);
            newMessageProcessor.start();
        }
    
public MessageChannelcreateMessageChannel(Hop nextHop)
Creates a new MessageChannel for a given Hop.

param
nextHop Hop to create a MessageChannel to.
return
A MessageChannel to the specified Hop, or null if no MessageProcessors support contacting that Hop.
throws
UnknwonHostException If the host in the Hop doesn't exist.

        Host targetHost;
        HostPort targetHostPort;
        MessageProcessor nextProcessor;
        MessageChannel newChannel;

        // Create the host/port of the target hop
        targetHost = new Host();
        targetHost.setHostname(nextHop.getHost());
        targetHostPort = new HostPort();
        targetHostPort.setHost(targetHost);
        targetHostPort.setPort(nextHop.getPort());

        if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
            Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
                "createMessageChannel " + nextHop);
        }

        // Search each processor for the correct transport
        newChannel = null;
        Enumeration processorIterator = messageProcessors.elements();

        while (processorIterator.hasMoreElements() && newChannel == null) {
            nextProcessor =
                    (MessageProcessor) processorIterator.nextElement();
            // If a processor that supports the correct
            // transport is found,
            if (Utils.equalsIgnoreCase
                    (nextHop.getTransport(), nextProcessor.getTransport())) {
                try {
                    // Create a channel to the target host/port
                    newChannel = nextProcessor.
                            createMessageChannel(targetHostPort);
                } catch (IOException e) {
                    e.printStackTrace();
                    // Ignore channel creation error -
                    // try next processor
                }
            }
        }

        if (newChannel == null) { // Message processor was not found
                                  // Try to create it
            try {
                MessageProcessor processor = createMessageProcessor(
                    nextHop.getPort(), nextHop.getTransport());
                // IMPL_NOTE: The previous message processor should be
                // removed on level of re-routing SIP messages
                newChannel = processor.createMessageChannel(targetHostPort);
            } catch (IOException ex) {
            } catch (IllegalArgumentException ex) {
            }
        }
        // Return the newly-created channel
        return newChannel;
    
public MessageProcessorcreateMessageProcessor(int port, java.lang.String transport)
Creates the equivalent of a JAIN listening point and attaches to the stack.

param
port the message processor port address
param
transport the message processor transport type
return
the requested message processor


        if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
            Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
                "createMessageProcessor : " +
                port + " / " + transport);
        }

        if (Utils.equalsIgnoreCase(transport, SIPConstants.TRANSPORT_UDP)) {
            UDPMessageProcessor
                    udpMessageProcessor =
                    new UDPMessageProcessor(this, port);
            this.addMessageProcessor(udpMessageProcessor);
            this.udpFlag = true;
            return udpMessageProcessor;
        } else if (Utils.equalsIgnoreCase(transport,
                                SIPConstants.TRANSPORT_TCP)) {
            TCPMessageProcessor
                    tcpMessageProcessor =
                    new TCPMessageProcessor(this, port);
            this.addMessageProcessor(tcpMessageProcessor);
            this.tcpFlag = true;
            return tcpMessageProcessor;
        } else {
            throw new IllegalArgumentException("bad transport");
        }

    
public java.lang.StringgetBadMessageLog()
Gets the file name of the bad message log.

return
the file where bad messages are logged.

        return this.badMessageLog;
    
public HopgetDefaultRoute()
Gets the default route.

return
the default route

        return this.router.getOutboundProxy();
    
public RouteHeadergetDefaultRouteHeader()
Gets the route header corresponding to the default route.

return
the default route header

        if (router.getOutboundProxy() != null) {
            Hop hop = ((Hop) router.getOutboundProxy());
            return getRouteHeader(hop);
        } else
            return null;
    
public java.lang.StringgetHostAddress()
Gets my address.

return
hostAddress - my host address.

        return this.stackAddress;
    
public MessageProcessorgetMessageProcessor(java.lang.String transport)
Gets a message processor for the given transport.

param
transport the transport to be checked
return
the message processor for the transport

        synchronized (messageProcessors) {
            Enumeration it = messageProcessors.elements();
            while (it.hasMoreElements()) {
                MessageProcessor mp = (MessageProcessor) it.nextElement();
                if (Utils.equalsIgnoreCase(mp.getTransport(), transport)) {
                    return mp;
                }
            }

            return null;
        }
    
public java.util.VectorgetMessageProcessors()
Gets an array of running MessageProcessors on this SIPMessageStack. Acknowledgement: Jeff Keyser suggested that applications should have access to the running message processors and contributed this code.

return
an array of running message processors.

        return messageProcessors;
    
public HopgetNextHop()
Gets the default next hop from the router.

return
the default next hop

        return (Hop) this.router.getOutboundProxy();

    
public intgetPort(java.lang.String transport)
Gets port of the message processor (based on the transport). If multiple ports are enabled for the same transport then the first one is retrieved.

param
transport is the transport for which to get the port.
return
the message processor port
exception
IllegalArgumentException if the transport is not supported

        synchronized (messageProcessors) {
            Enumeration it = messageProcessors.elements();
            while (it.hasMoreElements()) {
                MessageProcessor mp = (MessageProcessor) it.nextElement();
                if (Utils.equalsIgnoreCase(mp.getTransport(), transport))
                    return mp.getPort();
            }
            throw new IllegalArgumentException
                    ("Transport not supported " + transport);
        }
    
public RouteHeadergetRouteHeader(Hop hop)
Gets the route header for this hop.

param
hop the hop to be processed
return
the route header for the hop.

        HostPort hostPort = new HostPort();
        Host h = new Host(hop.getHost());
        hostPort.setHost(h);
        hostPort.setPort(hop.getPort());
        gov.nist.siplite.address.SipURI uri = new SipURI();
        uri.setHostPort(hostPort);
        uri.setScheme(SIPConstants.SCHEME_SIP);

        try {
            uri.setTransportParam(hop.getTransport());
        } catch (ParseException ex) {
            InternalErrorHandler.handleException(ex);
        }

        Address address = new Address();
        address.setURI(uri);
        RouteHeader route = new RouteHeader();
        route.setAddress(address);

        return route;
    
public RoutergetRouter()
Gets the router algorithm.

return
Router router

        return router;
    
protected com.sun.midp.security.SecurityTokengetSecurityToken()
Return a security token associated with the protocol class

return
Security token

        return securityToken;
    
public java.lang.StringgetStackName()
Gets the Stack name.

return
name of the stack.

        return this.stackName;
    
public synchronized booleanisAlive()
Returns the status of the toExit flag.

return
true if the stack object is alive and false otherwise.

        return !toExit;
    
public booleanisTransportEnabled(java.lang.String transport)
Returns true if a transport is enabled.

param
transport is the transport to check.
return
true if transport is enabled

        synchronized (messageProcessors) {
            Enumeration it = messageProcessors.elements();
            while (it.hasMoreElements()) {
                MessageProcessor mp = (MessageProcessor) it.nextElement();
                if (Utils.equalsIgnoreCase(mp.getTransport(), transport))
                    return true;
            }
            return false;
        }
    
public booleanisTransportEnabled(java.lang.String transport, int port)
Returns true if the transport is enabled for a given port.

param
transport transport to check
param
port port to check transport at.
return
true if transport is enabled

        synchronized (messageProcessors) {
            Enumeration it = messageProcessors.elements();
            while (it.hasMoreElements()) {
                MessageProcessor mp = (MessageProcessor) it.nextElement();
                if (Utils.equalsIgnoreCase(mp.getTransport(), transport) &&
                        mp.getPort() == port)
                    return true;
            }
            return false;
        }
    
public voidlogBadMessage(java.lang.String message)
Logs a bad message (invoked when a parse exception arises).

param
message is a string that contains the bad message to log.



                               
        
        if (badMessageLog != null) {
            if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
                Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
                    message + badMessageLog);
            }
        }
    
protected SIPServerRequestInterfacenewSIPServerRequest(Request siprequest, MessageChannel msgchan)
Generates a new SIPSeverRequest from the given Request. A SIPServerRequest is generated by the application SIPServerRequestFactoryImpl. The application registers the factory implementation at the time the stack is initialized.

param
siprequest Request for which we want to generate thsi SIPServerRequest.
param
msgchan Message channel for the request for which we want to generate the SIPServerRequest
return
Generated SIPServerRequest.

        return sipMessageFactory.newSIPServerRequest
                (siprequest, msgchan);
    
SIPServerResponseInterfacenewSIPServerResponse(Response sipresponse, MessageChannel msgchan)
Generates a new SIPSeverResponse from the given Response.

param
sipresponse Response from which the SIPServerResponse is to be generated. Note - this just calls the factory interface to do its work. The factory interface is provided by the user.
param
msgchan Message channel for the SIPServerResponse
return
SIPServerResponse generated from this SIP Response

        return sipMessageFactory.newSIPServerResponse
                (sipresponse, msgchan);
    
public voidremoveMessageProcessor(MessageProcessor oldMessageProcessor)
Removes a MessageProcessor from this SIPMessageStack. Acknowledgement: Code contributed by Jeff Keyser.

param
oldMessageProcessor

        synchronized (messageProcessors) {

            if (messageProcessors.removeElement(oldMessageProcessor)) {

                oldMessageProcessor.stop();
            }
        }
    
public voidsetHostAddress(java.lang.String stackAddress)
Sets my address.

param
stackAddress -- A string containing the stack address.

        if (stackAddress.indexOf(':") != stackAddress.lastIndexOf(':")
        && stackAddress.trim().charAt(0) != '[")
            this.stackAddress = '[" + stackAddress + ']";
        else
            this.stackAddress = stackAddress;
    
public voidsetMaxConnections(int nconnections)
Sets the max # of simultaneously handled TCP connections.

param
nconnections the new max connections

        this.maxConnections = nconnections;
    
protected voidsetMessageFactory(SIPStackMessageFactory messageFactory)
Sets the message factory.

param
messageFactory -- messageFactory to set.

        this.sipMessageFactory = messageFactory;
    
public voidsetRouter(Router router)
Sets the router algorithm.

param
router A class that implements the Router interface.

        this.router = router;
    
protected voidsetSecurityToken(com.sun.midp.security.SecurityToken token)
Set the security token associated with the protocol class

param
token Security token from SIP/SIPS Protocol class

        securityToken = token;
    
public voidsetSingleThreaded()
Sets the flag that instructs the stack to only start a single thread for sequentially processing incoming udp messages (thus serializing the processing). Caution: If the user-defined function called by the processing thread blocks, then the entire server will block.

        this.threadPoolSize = 1;
    
public voidsetStackMessageFactory(SIPStackMessageFactory messageFactory)
Sets the server Request and response factories.

param
messageFactory User-implemented factory for processing messages.

        sipMessageFactory = messageFactory;
    
public voidsetStackName(java.lang.String stackName)
Sets the descriptive name of the stack.

param
stackName -- descriptive name of the stack.

        this.stackName = stackName;
        ServerLog.setDescription(stackName);
        ServerLog.stackIpAddress = stackAddress;
    
public voidsetThreadPoolSize(int size)
Sets the thread pool size for processing incoming UDP messages. Limit the total number of threads for processing udp messages. Caution: If the user-defined function called by the processing thread blocks, then the entire server will block.

param
size the new thread pool size

        this.threadPoolSize = size;
    
public voidstopStack()
Makes the stack close all accept connections and return. This is useful if you want to start/stop the stack several times from your application. Caution : use of this function could cause peculiar bugs as messages are prcessed asynchronously by the stack.

        synchronized (this.messageProcessors) {
            // Threads must periodically check this flag.
            this.toExit = true;
            Vector processorList;
            processorList = getMessageProcessors();
            /*
             * IMPL_NOTE:
             * Normally, messageprocessors are already stopped before
             * stopStack() is explicitely invoked from close() of
             * SipConnectionNotifier. So it is not needed to iterate through the
             * list. However, this part of the code is not yet removed as it is
             * not known if sipStack() needs to be closed independantly.
             * A safetly check is added before invoking stop() for a message
             * processor to verify if it was already closed
             */
            for (int i = 0; i < processorList.size(); i++) {
                MessageProcessor mp =
                        (MessageProcessor) processorList.elementAt(i);
                if (!mp.toExit()) {
                    mp.stop();
                }
            }
            processorList.removeAllElements();
        }