/* * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.mobicents.servlet.sip.startup; import gov.nist.javax.sip.SipStackExt; import java.io.File; import java.util.TooManyListenersException; import javax.sip.SipStack; import org.apache.catalina.LifecycleException; import org.apache.catalina.connector.Connector; import org.apache.catalina.core.StandardService; import org.apache.log4j.Logger; import org.mobicents.servlet.sip.JainSipUtils; import org.mobicents.servlet.sip.annotation.ConcurrencyControlMode; import org.mobicents.servlet.sip.core.CongestionControlPolicy; import org.mobicents.servlet.sip.core.DNSAddressResolver; import org.mobicents.servlet.sip.core.ExtendedListeningPoint; import org.mobicents.servlet.sip.core.SipApplicationDispatcher; /** * Sip Servlet implementation of the <code>SipService</code> interface. * This class inherits from the Tomcat StandardService. It adds a SipApplicationDispatcher * that will be listen for sip messages received by the sip stacks started by * the sip connectors associated with this context. * This has one attribute which is the sipApplicationDispatcherClassName allowing one * to specify the class name of the sipApplicationDispacther to easily replace * the default sipApplicationDispatcher with a custom one. * * @author <A HREF="mailto:jean.deruelle@gmail.com">Jean Deruelle</A> */ public class SipStandardService extends StandardService implements SipService { //the logger private static transient Logger logger = Logger.getLogger(SipStandardService.class); /** * The descriptive information string for this implementation. */ private static final String info = "org.mobicents.servlet.sip.startup.SipStandardService/1.0"; //the sip application dispatcher class name defined in the server.xml protected String sipApplicationDispatcherClassName; //instatiated class from the sipApplicationDispatcherClassName of the sip application dispatcher protected SipApplicationDispatcher sipApplicationDispatcher; protected int sipMessageQueueSize = 1500; protected int memoryThreshold = 90; protected long congestionControlCheckingInterval = 30000; protected String concurrencyControlMode = ConcurrencyControlMode.SipSession.toString(); protected String congestionControlPolicy = CongestionControlPolicy.ErrorResponse.toString(); protected String additionalParameterableHeaders; protected boolean bypassResponseExecutor; protected boolean bypassRequestExecutor; //the sip application router class name defined in the server.xml // private String sipApplicationRouterClassName; //this should be made available to the application router as a system prop protected String darConfigurationFileLocation; // protected boolean connectorsStartedExternally = false; @Override public String getInfo() { return (info); } @Override public void addConnector(Connector connector) { ExtendedListeningPoint extendedListeningPoint = (ExtendedListeningPoint) connector.getProtocolHandler().getAttribute(ExtendedListeningPoint.class.getSimpleName()); if(extendedListeningPoint != null) { try { extendedListeningPoint.getSipProvider().addSipListener(sipApplicationDispatcher); sipApplicationDispatcher.getSipNetworkInterfaceManager().addExtendedListeningPoint(extendedListeningPoint); } catch (TooManyListenersException e) { logger.error("Connector.initialize", e); } } super.addConnector(connector); } @Override public void removeConnector(Connector connector) { ExtendedListeningPoint extendedListeningPoint = (ExtendedListeningPoint) connector.getProtocolHandler().getAttribute(ExtendedListeningPoint.class.getSimpleName()); if(extendedListeningPoint != null) { extendedListeningPoint.getSipProvider().removeSipListener(sipApplicationDispatcher); sipApplicationDispatcher.getSipNetworkInterfaceManager().removeExtendedListeningPoint(extendedListeningPoint); } super.removeConnector(connector); } @Override public void initialize() throws LifecycleException { //load the sip application disptacher from the class name specified in the server.xml file //and initializes it StaticServiceHolder.sipStandardService = this; try { sipApplicationDispatcher = (SipApplicationDispatcher) Class.forName(sipApplicationDispatcherClassName).newInstance(); } catch (InstantiationException e) { throw new LifecycleException("Impossible to load the Sip Application Dispatcher",e); } catch (IllegalAccessException e) { throw new LifecycleException("Impossible to load the Sip Application Dispatcher",e); } catch (ClassNotFoundException e) { throw new LifecycleException("Impossible to load the Sip Application Dispatcher",e); } catch (ClassCastException e) { throw new LifecycleException("Sip Application Dispatcher defined does not implement " + SipApplicationDispatcher.class.getName(),e); } if(darConfigurationFileLocation != null) { if(!darConfigurationFileLocation.startsWith("file:///")) { darConfigurationFileLocation = "file:///" + System.getProperty("catalina.home").replace(File.separatorChar, '/') + "/" + darConfigurationFileLocation; } System.setProperty("javax.servlet.sip.dar", darConfigurationFileLocation); } super.initialize(); sipApplicationDispatcher.setDomain(this.domain); sipApplicationDispatcher.setMemoryThreshold(getMemoryThreshold()); sipApplicationDispatcher.setCongestionControlCheckingInterval(getCongestionControlCheckingInterval()); sipApplicationDispatcher.setCongestionControlPolicyByName(getCongestionControlPolicy()); sipApplicationDispatcher.setQueueSize(getSipMessageQueueSize()); sipApplicationDispatcher.setConcurrencyControlMode(ConcurrencyControlMode.valueOf(getConcurrencyControlMode())); sipApplicationDispatcher.setBypassRequestExecutor(bypassRequestExecutor); sipApplicationDispatcher.setBypassResponseExecutor(bypassResponseExecutor); sipApplicationDispatcher.init(); } @Override public void start() throws LifecycleException { super.start(); synchronized (connectors) { for (Connector connector : connectors) { //Jboss sepcific loading case Boolean isSipConnector = (Boolean) connector.getProtocolHandler().getAttribute("isSipConnector"); if(isSipConnector != null && isSipConnector) { if(logger.isDebugEnabled()) { logger.debug("Attaching the sip application dispatcher " + "as a sip listener to connector listening on port " + connector.getPort()); } connector.getProtocolHandler().setAttribute(SipApplicationDispatcher.class.getSimpleName(), sipApplicationDispatcher); connectorsStartedExternally = true; } //Tomcat specific loading case ExtendedListeningPoint extendedListeningPoint = (ExtendedListeningPoint) connector.getProtocolHandler().getAttribute(ExtendedListeningPoint.class.getSimpleName()); SipStack sipStack = (SipStack) connector.getProtocolHandler().getAttribute(SipStack.class.getSimpleName()); if(extendedListeningPoint != null && sipStack != null) { // for nist sip stack set the DNS Address resolver allowing to make DNS SRV lookups if(sipStack instanceof SipStackExt) { if(logger.isDebugEnabled()) { logger.debug(sipStack.getStackName() +" will be using DNS SRV lookups as AddressResolver"); } ((SipStackExt) sipStack).setAddressResolver(new DNSAddressResolver(sipApplicationDispatcher)); } try { extendedListeningPoint.getSipProvider().addSipListener(sipApplicationDispatcher); sipApplicationDispatcher.getSipNetworkInterfaceManager().addExtendedListeningPoint(extendedListeningPoint); connectorsStartedExternally = false; } catch (TooManyListenersException e) { throw new LifecycleException(e); } } } } if(!connectorsStartedExternally) { sipApplicationDispatcher.start(); } if(this.getSipMessageQueueSize() <= 0) throw new IllegalArgumentException("Message queue size can not be 0 or less"); } @Override public void stop() throws LifecycleException { //Tomcat specific unloading case synchronized (connectors) { for (Connector connector : connectors) { ExtendedListeningPoint extendedListeningPoint = (ExtendedListeningPoint) connector.getProtocolHandler().getAttribute(ExtendedListeningPoint.class.getSimpleName()); if(extendedListeningPoint != null) { extendedListeningPoint.getSipProvider().removeSipListener(sipApplicationDispatcher); sipApplicationDispatcher.getSipNetworkInterfaceManager().removeExtendedListeningPoint(extendedListeningPoint); } } } if(!connectorsStartedExternally) { sipApplicationDispatcher.stop(); } super.stop(); } /** * Retrieve the sip application dispatcher class name * @return the sip application dispatcher class name */ public String getSipApplicationDispatcherClassName() { return sipApplicationDispatcherClassName; } /** * Set the sip application dispatcher class name * @param sipApplicationDispatcherClassName the sip application dispatcher class name to be set */ public void setSipApplicationDispatcherClassName(String sipApplicationDispatcherName) { this.sipApplicationDispatcherClassName = sipApplicationDispatcherName; } /** * @return the sipApplicationDispatcher */ public SipApplicationDispatcher getSipApplicationDispatcher() { return sipApplicationDispatcher; } /** * @param sipApplicationDispatcher the sipApplicationDispatcher to set */ public void setSipApplicationDispatcher( SipApplicationDispatcher sipApplicationDispatcher) { this.sipApplicationDispatcher = sipApplicationDispatcher; } // /** // * @return the sipApplicationRouterClassName // */ // public String getSipApplicationRouterClassName() { // return sipApplicationRouterClassName; // } // // /** // * @param sipApplicationRouterClassName the sipApplicationRouterClassName to set // */ // public void setSipApplicationRouterClassName( // String sipApplicationRouterClassName) { // this.sipApplicationRouterClassName = sipApplicationRouterClassName; // } /** * @return the darConfigurationFileLocation */ public String getDarConfigurationFileLocation() { return darConfigurationFileLocation; } /** * @param darConfigurationFileLocation the darConfigurationFileLocation to set */ public void setDarConfigurationFileLocation(String darConfigurationFileLocation) { this.darConfigurationFileLocation = darConfigurationFileLocation; } /** * Message queue size. If the number of pending requests exceeds this number they are rejected. * * @return */ public int getSipMessageQueueSize() { return sipMessageQueueSize; } /** * Message queue size. If the number of pending requests exceeds this number they are rejected. * * @return */ public void setSipMessageQueueSize(int sipMessageQueueSize) { this.sipMessageQueueSize = sipMessageQueueSize; } /** * ConcurrencyControl control mode is SipSession, AppSession or None * Specifies the isolation level of concurrently executing requests. * * @return */ public String getConcurrencyControlMode() { return concurrencyControlMode; } /** * ConcurrencyControl control mode is SipSession, AppSession or None * Specifies the isolation level of concurrently executing requests. * * @return */ public void setConcurrencyControlMode(String concurrencyControlMode) { this.concurrencyControlMode = concurrencyControlMode; } /** * @param memoryThreshold the memoryThreshold to set */ public void setMemoryThreshold(int memoryThreshold) { this.memoryThreshold = memoryThreshold; } /** * @return the memoryThreshold */ public int getMemoryThreshold() { return memoryThreshold; } /** * @param congestionControlPolicy the congestionControlPolicy to set */ public void setCongestionControlPolicy(String congestionControlPolicy) { this.congestionControlPolicy = congestionControlPolicy; } /** * @return the congestionControlPolicy */ public String getCongestionControlPolicy() { return congestionControlPolicy; } /** * @param congestionControlCheckingInterval the congestionControlCheckingInterval to set */ public void setCongestionControlCheckingInterval( long congestionControlCheckingInterval) { this.congestionControlCheckingInterval = congestionControlCheckingInterval; } /** * @return the congestionControlCheckingInterval */ public long getCongestionControlCheckingInterval() { return congestionControlCheckingInterval; } public String getAdditionalParameterableHeaders() { return additionalParameterableHeaders; } public void setAdditionalParameterableHeaders( String additionalParameterableHeaders) { this.additionalParameterableHeaders = additionalParameterableHeaders; String[] headers = additionalParameterableHeaders.split(","); for(String header : headers) { if(header != null && header.length()>0) { JainSipUtils.parameterableHeadersNames.add(header); } } } /** * @return the bypassResponseExecutor */ public boolean isBypassResponseExecutor() { return bypassResponseExecutor; } /** * @param bypassResponseExecutor the bypassResponseExecutor to set */ public void setBypassResponseExecutor(boolean bypassResponseExecutor) { this.bypassResponseExecutor = bypassResponseExecutor; } /** * @return the bypassRequestExecutor */ public boolean isBypassRequestExecutor() { return bypassRequestExecutor; } /** * @param bypassRequestExecutor the bypassRequestExecutor to set */ public void setBypassRequestExecutor(boolean bypassRequestExecutor) { this.bypassRequestExecutor = bypassRequestExecutor; } }