All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.mobicents.servlet.sip.undertow.SipContextImpl Maven / Gradle / Ivy

/*
 * TeleStax, Open Source Cloud Communications
 * Copyright 2011-2015, Telestax Inc and individual contributors
 * by the @authors tag.
 *
 * This program is free software: you can redistribute it and/or modify
 * under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation; either version 3 of
 * the License, or (at your option) any later version.
 *
 * 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see 
 */
package org.mobicents.servlet.sip.undertow;

import io.undertow.server.session.SessionManager;
import io.undertow.servlet.api.Deployment;
import io.undertow.servlet.api.ServletInfo;
import io.undertow.servlet.api.ThreadSetupAction.Handle;
import io.undertow.servlet.core.Lifecycle;
import io.undertow.servlet.core.ManagedFilter;
import io.undertow.servlet.core.ManagedServlet;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

import javax.servlet.Servlet;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletException;
import javax.servlet.sip.SipFactory;
import javax.servlet.sip.SipServlet;
import javax.servlet.sip.SipServletContextEvent;
import javax.servlet.sip.SipServletListener;
import javax.servlet.sip.SipServletRequest;
import javax.servlet.sip.TimerService;

import org.apache.log4j.Logger;
import org.mobicents.io.undertow.servlet.api.DeploymentInfoFacade;
import org.mobicents.servlet.sip.SipConnector;
import org.mobicents.servlet.sip.annotation.ConcurrencyControlMode;
import org.mobicents.servlet.sip.core.MobicentsSipServlet;
import org.mobicents.servlet.sip.core.SipApplicationDispatcher;
import org.mobicents.servlet.sip.core.SipContext;
import org.mobicents.servlet.sip.core.SipContextEvent;
import org.mobicents.servlet.sip.core.SipContextEventType;
import org.mobicents.servlet.sip.core.SipListeners;
import org.mobicents.servlet.sip.core.SipManager;
import org.mobicents.servlet.sip.core.descriptor.MobicentsSipServletMapping;
import org.mobicents.servlet.sip.core.message.MobicentsSipServletRequest;
import org.mobicents.servlet.sip.core.message.MobicentsSipServletResponse;
import org.mobicents.servlet.sip.core.security.MobicentsSipLoginConfig;
import org.mobicents.servlet.sip.core.security.SipDigestAuthenticator;
import org.mobicents.servlet.sip.core.session.MobicentsSipApplicationSession;
import org.mobicents.servlet.sip.core.session.MobicentsSipSession;
import org.mobicents.servlet.sip.core.session.MobicentsSipSessionsUtil;
import org.mobicents.servlet.sip.core.session.SipApplicationSessionCreationThreadLocal;
import org.mobicents.servlet.sip.core.session.SipSessionsUtilImpl;
import org.mobicents.servlet.sip.core.timers.DefaultProxyTimerService;
import org.mobicents.servlet.sip.core.timers.DefaultSipApplicationSessionTimerService;
import org.mobicents.servlet.sip.core.timers.ProxyTimerService;
import org.mobicents.servlet.sip.core.timers.ProxyTimerServiceImpl;
import org.mobicents.servlet.sip.core.timers.SipApplicationSessionTimerService;
import org.mobicents.servlet.sip.core.timers.SipServletTimerService;
import org.mobicents.servlet.sip.core.timers.StandardSipApplicationSessionTimerService;
import org.mobicents.servlet.sip.core.timers.TimerServiceImpl;
import org.mobicents.servlet.sip.dns.MobicentsDNSResolver;
import org.mobicents.servlet.sip.listener.SipConnectorListener;
import org.mobicents.servlet.sip.message.SipFactoryFacade;
import org.mobicents.servlet.sip.message.SipFactoryImpl;
import org.mobicents.servlet.sip.ruby.SipRubyController;
import org.mobicents.servlet.sip.startup.ConvergedServletContextImpl;
import org.mobicents.servlet.sip.undertow.security.SipSecurityUtils;
import org.mobicents.servlet.sip.undertow.security.authentication.SipDigestAuthenticationMechanism;
import org.wildfly.extension.undertow.Host;
import org.wildfly.extension.undertow.ListenerService;

/**
 *
 * This class is based on org.mobicents.servlet.sip.startup.SipStandardContext from sip-servlet-as7 project, re-implemented for
 * jboss as10 (wildfly) by:
 *
 * @author [email protected]
 */
public class SipContextImpl implements SipContext {

    private static final Logger logger = Logger.getLogger(SipContextImpl.class);

    // as mentionned per JSR 289 Section 6.1.2.1 default lifetime for an
    // application session is 3 minutes
    private static int DEFAULT_LIFETIME = 3;

    private Deployment deployment;

    protected DeploymentInfoFacade deploymentInfoFacade;
    protected transient SipApplicationDispatcher sipApplicationDispatcher = null;

    protected boolean hasDistributableManager;
    // timer service used to schedule sip application session expiration timer
    protected transient SipApplicationSessionTimerService sasTimerService = null;
    protected TimerServiceType sasTimerServiceType = null;
    // timer service used to schedule sip servlet originated timer tasks
    protected transient SipServletTimerService timerService = null;
    // timer service used to schedule proxy timer tasks
    protected transient ProxyTimerService proxyTimerService = null;
    protected TimerServiceType proxyTimerServiceType = null;
    protected transient SipListeners sipListeners;
    protected transient SipFactoryFacade sipFactoryFacade;
    protected transient SipSessionsUtilImpl sipSessionsUtil;
    protected transient SipSecurityUtils sipSecurityUtils;
    protected transient SipDigestAuthenticator sipDigestAuthenticator;
    protected transient String securityDomain;

    protected String displayName;

    private transient ThreadLocal sipApplicationSessionsAccessedThreadLocal = new ThreadLocal();
    // http://code.google.com/p/mobicents/issues/detail?id=2534 &&
    // http://code.google.com/p/mobicents/issues/detail?id=2526
    private transient ThreadLocal isManagedThread = new ThreadLocal();

    ConvergedServletContextImpl context;

    private ClassLoader sipContextClassLoader;
    private Host hostOfDeployment;
    List> webServerListeners = new LinkedList<>();

    // http://code.google.com/p/sipservlets/issues/detail?id=195
    private ScheduledFuture gracefulStopFuture;
    
    // default constructor:
    public SipContextImpl() {
    }

    public void init(Deployment deployment, ClassLoader sipContextClassLoader) throws ServletException {
        if (logger.isDebugEnabled()) {
            logger.debug("Initializing the sip context");
        }

        this.setSipApplicationSessionTimeout(DEFAULT_LIFETIME);
        // pipeline.setBasic(new SipStandardContextValve());
        this.sipListeners = new UndertowSipListenersHolder(this);
        this.deploymentInfoFacade.setChildrenMap(new HashMap());
        this.deploymentInfoFacade.setChildrenMapByClassName(new HashMap());
        int idleTime = this.getSipApplicationSessionTimeout();
        if (idleTime <= 0) {
            idleTime = 1;
        }
        this.deploymentInfoFacade.setMainServlet(false);

        if (this.sipContextClassLoader == null) {
            this.sipContextClassLoader = sipContextClassLoader;
        }

        addDeploymentToContext(deployment);
        // if (this.getParent() != null) {
        // // Add the main configuration listener for sip applications
        // LifecycleListener sipConfigurationListener = new ();
        // this.addLifecycleListener(sipConfigurationListener);
        // setDelegate(true);
        // }
        // call the super method to correctly initialize the context and fire
        // up the
        // init event on the new registered SipContextConfig, so that the
        // standardcontextconfig
        // is correctly initialized too

        prepareServletContext();

        if (logger.isDebugEnabled()) {
            logger.debug("sip context Initialized");
        }
    }

    private void addDeploymentToContext(Deployment deployment) throws ServletException {
        this.deployment = deployment;
    }

    public synchronized void start() throws ServletException {
        if (logger.isDebugEnabled()) {
            logger.debug("Starting the sip context " + this.getApplicationName());
        }

        prepareServletContext();

        // FIXME: kakonyii: DistributableSipManager handling implementation
        hasDistributableManager = false;
        ((UndertowSipManager) this.getSessionManager()).setMobicentsSipFactory(sipApplicationDispatcher.getSipFactory());
        ((UndertowSipManager) this.getSessionManager()).setContainer(this);

        // JSR 289 16.2 Servlet Selection
        // When using this mechanism (the main-servlet) for servlet selection,
        // if there is only one servlet in the application then this
        // declaration is optional and the lone servlet becomes the main servlet
        String mainServlet = this.getMainServlet();
        Map childrenMap = this.getChildrenMap();
        if ((mainServlet == null || mainServlet.length() < 1) && childrenMap.size() == 1) {
            setMainServlet(childrenMap.keySet().iterator().next());
        }

        sipSecurityUtils = new SipSecurityUtils(this);

        String realmName = null;
        if (((SipLoginConfig) this.getSipLoginConfig()) != null) {
            realmName = ((SipLoginConfig) this.getSipLoginConfig()).getRealmName();
        }
        sipDigestAuthenticator = new SipDigestAuthenticationMechanism(realmName, sipApplicationDispatcher.getSipFactory()
                .getHeaderFactory());
        // JSR 289 Section 2.1.1 Step 3.Invoke SipApplicationRouter.applicationDeployed() for this application.
        // called implicitly within sipApplicationDispatcher.addSipApplication
        sipApplicationDispatcher.addSipApplication(this.getApplicationName(), this);

        // lests starts sipServlets too!!
        ArrayList lifecycles = new ArrayList<>();
        for (MobicentsSipServlet sipServlet : this.getChildrenMap().values()) {
            lifecycles.add((SipServletImpl) sipServlet);
        }
        for (Lifecycle object : lifecycles) {
            object.start();
        }
        final TreeMap> loadOnStartup = new TreeMap<>();
        for (MobicentsSipServlet sipServlet : this.getChildrenMap().values()) {
            SipServletImpl servlet = (SipServletImpl) sipServlet;

            Integer loadOnStartupNumber = servlet.getServletInfo().getLoadOnStartup();
            if (loadOnStartupNumber != null) {
                if (loadOnStartupNumber < 0) {
                    continue;
                }
                List list = loadOnStartup.get(loadOnStartupNumber);
                if (list == null) {
                    loadOnStartup.put(loadOnStartupNumber, list = new ArrayList<>());
                }
                list.add(servlet);
            }
        }
        for (Map.Entry> load : loadOnStartup.entrySet()) {
            for (ManagedServlet servlet : load.getValue()) {
                servlet.createServlet();
            }
        }
        if (deployment.getDeploymentInfo().isEagerFilterInit()) {
            for (ManagedFilter filter : deployment.getFilters().getFilters().values()) {
                filter.createFilter();
            }
        }

        if (logger.isDebugEnabled()) {
            logger.debug("sip application session timeout for this context is " + this.getSipApplicationSessionTimeout()
                    + " minutes");
        }

        if (logger.isDebugEnabled()) {
            logger.debug("http session timeout for this context is "
                    + this.deploymentInfoFacade.getDeploymentInfo().getDefaultSessionTimeout() + " minutes");
        }
        if (logger.isDebugEnabled()) {
            logger.debug("sip context started " + this.getApplicationName());
        }
    }

    public synchronized void stop() throws ServletException {
        String name = this.getApplicationName();
        if (logger.isDebugEnabled()) {
            logger.debug("Stopping the sip context " + name);
        }

        ((UndertowSipManager) this.getSessionManager()).dumpSipSessions();
        ((UndertowSipManager) this.getSessionManager()).dumpSipApplicationSessions();
        logger.warn("number of active sip sessions : " + ((UndertowSipManager) this.getSessionManager()).getActiveSipSessions());
        logger.warn("number of active sip application sessions : "
                + ((UndertowSipManager) this.getSessionManager()).getActiveSipApplicationSessions());

        // lests stop sipServlets lifecycle objects:
        ArrayList lifecycles = new ArrayList<>();
        for (MobicentsSipServlet sipServlet : this.getChildrenMap().values()) {
            lifecycles.add((SipServletImpl) sipServlet);
        }
        for (Lifecycle object : lifecycles) {
            object.stop();
        }

        // this should happen after so that applications can still do some processing
        // in destroy methods to notify that context is getting destroyed and app removed
        sipListeners.deallocateServletsActingAsListeners();
        this.deploymentInfoFacade.getSipApplicationListeners().clear();
        this.deploymentInfoFacade.getSipServletMappings().clear();

        this.getChildrenMap().clear();
        this.deploymentInfoFacade.getChildrenMapByClassName().clear();
        if (sipApplicationDispatcher != null) {
            if (this.getApplicationName() != null) {
                sipApplicationDispatcher.removeSipApplication(this.getApplicationName());
            } else {
                logger.error("the application name is null for the following context : " + name);
            }
        }
        if (sasTimerService != null && sasTimerService.isStarted()) {
            sasTimerService.stop();
        }
        // Issue 1478 : nullify the ref to avoid reusing it
        sasTimerService = null;
        // Issue 1791 : don't check is the service is started it makes the stop
        // of tomcat hang
        if (timerService != null) {
            timerService.stop();
        }
        if (proxyTimerService != null) {
            proxyTimerService.stop();
        }
        // Issue 1478 : nullify the ref to avoid reusing it
        timerService = null;
        getServletContext().setAttribute(javax.servlet.sip.SipServlet.TIMER_SERVICE, null);
        if (logger.isDebugEnabled()) {
            logger.debug("sip context stopped " + name);
        }
    }

    public boolean listenerStop() {
        boolean ok = true;
        if (logger.isDebugEnabled())
            logger.debug("Sending application stop events");

        List servletContextListeners = sipListeners.getServletContextListeners();
        if (servletContextListeners != null) {
            ServletContextEvent event = new ServletContextEvent(getServletContext());
            for (ServletContextListener servletContextListener : servletContextListeners) {
                if (servletContextListener == null)
                    continue;

                try {
                    // FIXME: fireContainerEvent("beforeContextDestroyed", servletContextListener);
                    servletContextListener.contextDestroyed(event);
                    // FIXME: fireContainerEvent("afterContextDestroyed", servletContextListener);
                } catch (Throwable t) {
                    // FIXME: fireContainerEvent("afterContextDestroyed", servletContextListener);
                    // getLogger().error
                    // (sm.getString("standardContext.listenerStop",
                    // servletContextListener.getClass().getName()), t);
                    // getLogger().error
                    // (MESSAGES.errorSendingContextDestroyedEvent(servletContextListener.getClass().getName()), t);

                    logger.error("Failed to destroy servletContext.", t);
                    t.printStackTrace();
                    ok = false;
                }
            }
        }

        sipListeners.clean();

        return ok;
    }

    public void prepareServletContextServices() {
        if (sipFactoryFacade == null) {
            sipFactoryFacade = new SipFactoryFacade((SipFactoryImpl) sipApplicationDispatcher.getSipFactory(), this);
        }
        if (sipSessionsUtil == null) {
            sipSessionsUtil = new SipSessionsUtilImpl(this);
        }
        if (timerService == null) {
            // FIXME: distributable not supported
            // if(getDistributable() && hasDistributableManager) {
            // if(logger.isInfoEnabled()) {
            // logger.info("Using the Fault Tolerant Timer Service to schedule fault tolerant timers in a distributed environment");
            // }
            // timerService = new FaultTolerantTimerServiceImpl((DistributableSipManager)getSipManager());
            // } else {
            // timerService = new TimerServiceImpl();
            // }
            timerService = new TimerServiceImpl(sipApplicationDispatcher.getSipService(), getApplicationName());
        }
        if (proxyTimerService == null) {
            if(proxyTimerServiceType != null && proxyTimerServiceType == TimerServiceType.STANDARD) {
                proxyTimerService = new ProxyTimerServiceImpl(getApplicationName());
            } else if(proxyTimerServiceType != null && proxyTimerServiceType == TimerServiceType.DEFAULT) {
                proxyTimerService = new DefaultProxyTimerService(getApplicationName());
            } else {
                proxyTimerService = new ProxyTimerServiceImpl(getApplicationName());
            }
        }
        if (sasTimerService == null /*kakonyii: prevent creating sasTimerService's threads multiple times by commenting this out: || !sasTimerService.isStarted()*/) {
            // FIXME: distributable not supported
            // distributable if(getDistributable() && hasDistributableManager) {
            // sasTimerService = new FaultTolerantSasTimerService((DistributableSipManager)getSipManager(), 4);
            // } else {
            // sasTimerService = new StandardSipApplicationSessionTimerService();
            // }
            if(sasTimerServiceType != null && sasTimerServiceType == TimerServiceType.STANDARD){
                sasTimerService = new StandardSipApplicationSessionTimerService(getApplicationName());
            }else if (sasTimerServiceType != null && sasTimerServiceType == TimerServiceType.DEFAULT){
                sasTimerService = new DefaultSipApplicationSessionTimerService(getApplicationName());
            }else{
                sasTimerService = new StandardSipApplicationSessionTimerService(getApplicationName());
            }
        }
    }

    protected void prepareServletContext() throws ServletException {
        this.prepareServletContextServices();

        // needed when restarting applications through the tomcat manager
        this.getServletContext().setAttribute(javax.servlet.sip.SipServlet.SIP_FACTORY, sipFactoryFacade);
        this.getServletContext().setAttribute(javax.servlet.sip.SipServlet.TIMER_SERVICE, timerService);
        this.getServletContext().setAttribute(javax.servlet.sip.SipServlet.SUPPORTED,
                Arrays.asList(sipApplicationDispatcher.getExtensionsSupported()));
        this.getServletContext().setAttribute("javax.servlet.sip.100rel", Boolean.TRUE);
        this.getServletContext().setAttribute(javax.servlet.sip.SipServlet.SUPPORTED_RFCs,
                Arrays.asList(sipApplicationDispatcher.getRfcSupported()));
        this.getServletContext().setAttribute(javax.servlet.sip.SipServlet.SIP_SESSIONS_UTIL, sipSessionsUtil);
        this.getServletContext().setAttribute(javax.servlet.sip.SipServlet.OUTBOUND_INTERFACES,
                sipApplicationDispatcher.getOutboundInterfaces());
        this.getServletContext().setAttribute("org.mobicents.servlet.sip.SIP_CONNECTORS",
                sipApplicationDispatcher.getSipService().findSipConnectors());
        this.getServletContext().setAttribute("org.mobicents.servlet.sip.DNS_RESOLVER",
                new MobicentsDNSResolver(sipApplicationDispatcher.getDNSServerLocator()));
    }

    public void addChild(SipServletImpl sipServletImpl) {
        Map childrenMap = this.deploymentInfoFacade.getChildrenMap();
        Map childrenMapByClassName = this.deploymentInfoFacade.getChildrenMapByClassName();
        SipServletImpl existingServlet = (SipServletImpl) childrenMap.get(sipServletImpl.getName());
        if (existingServlet != null) {
            logger.warn(sipServletImpl.getName() + " servlet already present, removing the previous one. "
                    + "This might be due to the fact that the definition of the servlet "
                    + "is present both in annotations and in sip.xml");
            // we remove the previous one (annoations) because it may not have init parameters that has been defined in
            // sip.xml
            // See TCK Test ContextTest.testContext1
            childrenMap.remove(sipServletImpl.getName());
            childrenMapByClassName.remove(sipServletImpl.getServletInfo().getName());
            // super.removeChild(existingServlet);
        }
        childrenMap.put(sipServletImpl.getName(), sipServletImpl);
        childrenMapByClassName.put(sipServletImpl.getServletInfo().getName(), sipServletImpl);
        // super.addChild(sipServletImpl);
    }

    public void removeChild(SipServletImpl sipServletImpl) {
        // super.removeChild(sipServletImpl);
        Map childrenMap = this.deploymentInfoFacade.getChildrenMap();
        Map childrenMapByClassName = this.deploymentInfoFacade.getChildrenMapByClassName();

        childrenMap.remove(sipServletImpl.getName());
        childrenMapByClassName.remove(sipServletImpl.getServletInfo().getName());
    }

    public void setApplicationDispatcher(SipApplicationDispatcher dispatcher) throws ServletException {
        sipApplicationDispatcher = dispatcher;
        if (sipApplicationDispatcher == null) {
            throw new ServletException("cannot find any application dispatcher for this context " + this.getApplicationName());
        }
    }

    public boolean contextListenerStart() throws ServletException{
        if (logger.isDebugEnabled())
            logger.debug("Configuring sip listeners");

        // Instantiate the required listeners
        ClassLoader loader = this.getSipContextClassLoader();
        boolean ok = sipListeners.loadListeners(findSipApplicationListeners(), loader);
        if (!ok) {
            return ok;
        }

        List servletContextListeners = sipListeners.getServletContextListeners();
        if (servletContextListeners != null) {
            ServletContextEvent event = new ServletContextEvent(getServletContext());
            for (ServletContextListener servletContextListener : servletContextListeners) {
                if (servletContextListener == null)
                    continue;

                try {
                    // FIXME: fireContainerEvent("beforeContextInitialized", servletContextListener);
                    servletContextListener.contextInitialized(event);
                    // FIXME: fireContainerEvent("afterContextInitialized", servletContextListener);
                } catch (Throwable t) {
                    // FIXME: fireContainerEvent("afterContextInitialized", servletContextListener);
                    // getLogger().error
                    // (sm.getString("standardContext.listenerStart",
                    // servletContextListener.getClass().getName()), t);
                    // getLogger().error
                    // (MESSAGES.errorSendingContextInitializedEvent(servletContextListener.getClass().getName()), t);
                    ok = false;
                    logger.error("Failed to initialize context!", t);
                }
            }
        }

        return (ok);
    }

    public SessionManager getSessionManager() {
        return this.deployment.getSessionManager();
    }

    public ConvergedServletContextImpl getServletContext() {
        if (context == null) {
            context = new ConvergedServletContextImpl(deployment.getServletContext());
            context.addSipContext(this);
        }
        return context;
    }

    @Override
    public String getApplicationName() {
        return this.deploymentInfoFacade.getApplicationName();
    }

    @Override
    public String getApplicationNameHashed() {
        return sipApplicationDispatcher.getHashFromApplicationName(getApplicationName());
    }

    @Override
    public boolean hasDistributableManager() {
        return this.hasDistributableManager;
    }

    @Override
    public void setApplicationName(String applicationName) {
        deploymentInfoFacade.setApplicationName(applicationName);
    }

    @Override
    public String getDescription() {
        return this.deploymentInfoFacade.getDescription();
    }

    @Override
    public void setDescription(String description) {
        deploymentInfoFacade.setDescription(description);

    }

    @Override
    public String getLargeIcon() {
        return this.deploymentInfoFacade.getLargeIcon();
    }

    @Override
    public void setLargeIcon(String largeIcon) {
        this.deploymentInfoFacade.setLargeIcon(largeIcon);
    }

    @Override
    public SipListeners getListeners() {
        return this.sipListeners;
    }

    @Override
    public void setListeners(SipListeners listeners) {
        this.sipListeners = (UndertowSipListenersHolder) listeners;

    }

    @Override
    public boolean isMainServlet() {
        return deploymentInfoFacade.isMainServlet();
    }

    @Override
    public String getMainServlet() {
        return deploymentInfoFacade.getMainServlet();
    }

    @Override
    public void setMainServlet(String mainServlet) {
        this.deploymentInfoFacade.setMainServlet(mainServlet);
        this.deploymentInfoFacade.setServletHandler(mainServlet);
        this.deploymentInfoFacade.setMainServlet(true);
    }

    @Override
    public void setServletHandler(String servletHandler) {
        this.deploymentInfoFacade.setServletHandler(servletHandler);

    }

    @Override
    public String getServletHandler() {
        return this.deploymentInfoFacade.getServletHandler();
    }

    @Override
    public int getProxyTimeout() {
        return this.deploymentInfoFacade.getProxyTimeout();
    }

    @Override
    public void setProxyTimeout(int proxyTimeout) {
        this.deploymentInfoFacade.setProxyTimeout(proxyTimeout);

    }

    @Override
    public int getSipApplicationSessionTimeout() {
        return this.deploymentInfoFacade.getSipApplicationSessionTimeout();
    }

    @Override
    public void setSipApplicationSessionTimeout(int proxyTimeout) {
        this.deploymentInfoFacade.setSipApplicationSessionTimeout(proxyTimeout);

    }

    @Override
    public String getSmallIcon() {
        return this.deploymentInfoFacade.getSmallIcon();
    }

    @Override
    public void setSmallIcon(String smallIcon) {
        this.deploymentInfoFacade.setSmallIcon(smallIcon);

    }

    @Override
    public void addSipApplicationListener(String listener) {
        this.deploymentInfoFacade.addSipApplicationListener(listener);
        // FIXME: fireContainerEvent("addSipApplicationListener", listener);

    }

    @Override
    public void removeSipApplicationListener(String listener) {
        this.deploymentInfoFacade.removeSipApplicationListener(listener);
        // FIXME: fireContainerEvent("removeSipApplicationListener", listener);
    }

    @Override
    public String[] findSipApplicationListeners() {
        return this.deploymentInfoFacade.findSipApplicationListeners();
    }

    @Override
    public Method getSipApplicationKeyMethod() {
        return this.deploymentInfoFacade.getSipApplicationKeyMethod();
    }

    @Override
    public void setSipApplicationKeyMethod(Method sipApplicationKeyMethod) {
        this.deploymentInfoFacade.setSipApplicationKeyMethod(sipApplicationKeyMethod);

    }

    @Override
    public void setSipLoginConfig(MobicentsSipLoginConfig config) {
        this.deploymentInfoFacade.setSipLoginConfig(config);

    }

    @Override
    public MobicentsSipLoginConfig getSipLoginConfig() {
        return this.deploymentInfoFacade.getSipLoginConfig();
    }

    @Override
    public void addSipServletMapping(MobicentsSipServletMapping sipServletMapping) {
        this.deploymentInfoFacade.addSipServletMapping(sipServletMapping);

    }

    @Override
    public void removeSipServletMapping(MobicentsSipServletMapping sipServletMapping) {
        this.deploymentInfoFacade.removeSipServletMapping(sipServletMapping);

    }

    @Override
    public List findSipServletMappings() {
        return this.deploymentInfoFacade.findSipServletMappings();
    }

    @Override
    public MobicentsSipServletMapping findSipServletMappings(SipServletRequest sipServletRequest) {
        return this.deploymentInfoFacade.findSipServletMappings(sipServletRequest);
    }

    @Override
    public SipManager getSipManager() {
        return (SipManager) this.deployment.getSessionManager();
    }

    @Override
    public SipApplicationDispatcher getSipApplicationDispatcher() {
        return this.sipApplicationDispatcher;
    }

    @Override
    public String getEngineName() {
        // FIXME: kakonyii: i think this is not necessary for wildfy, have to review later
        return null;
    }

    // @Override
    // public String getBasePath() {
    // FIXME: kakonyii: this method was used in SipStandardContext's start() method to add missing components as necessary,
    // review later to figure out how to do something similar in wildfly
    // return null;
    // }

    // callers: SipApplicationDispatcher.addSipApplications()
    @Override
    public boolean notifySipContextListeners(SipContextEvent event) {
        boolean ok = true;
        if (logger.isDebugEnabled()) {
            logger.debug(this.deploymentInfoFacade.getSipServlets().size() + " container to notify of " + event.getEventType());
        }
        if (event.getEventType() == SipContextEventType.SERVLET_INITIALIZED) {
            if (!timerService.isStarted()) {
                timerService.start();
            }
            if (!proxyTimerService.isStarted()) {
                proxyTimerService.start();
            }
            if (!sasTimerService.isStarted()) {
                sasTimerService.start();
            }
        }

        // if(this.available) {
        enterSipApp(null, null, false, true);
        boolean batchStarted = enterSipAppHa(true);
        try {

            for (String servletName : this.deploymentInfoFacade.getSipServlets().keySet()) {
                SipServletImpl managedServlet = (SipServletImpl) this.getChildrenMap().get(servletName);
                if (logger.isDebugEnabled()) {
                    logger.debug("managedServlet " + managedServlet.getServletInfo().getName() + ", class : "
                            + managedServlet.getClass().getName());
                }
                try {
                    final ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();

                    try {
                        final ClassLoader cl = this.getSipContextClassLoader();
                        Thread.currentThread().setContextClassLoader(cl);
                        // http://code.google.com/p/sipservlets/issues/detail?id=135
                        // kakonyii: in SipStandardContext, there was a threadBindingListener which handled thread context switches (to get proper jndi context namespace selector, etc),
                        // in wildfly we use threadSetupAction from the deployment object for that purpose:
                        bindThreadBindingListener();

                        Servlet sipServlet = managedServlet.getServlet().getInstance();
                        if (sipServlet instanceof SipServlet) {
                            // Fix for issue 1086 (http://code.google.com/p/mobicents/issues/detail?id=1086) :
                            // Cannot send a request in SipServletListener.initialize() for servlet-selection applications
                            boolean servletHandlerWasNull = false;
                            if (this.getServletHandler() == null) {
                                this.setServletHandler(managedServlet.getServletInfo().getName());
                                servletHandlerWasNull = true;
                            }

                            switch (event.getEventType()) {
                                case SERVLET_INITIALIZED: {
                                    SipServletContextEvent sipServletContextEvent = new SipServletContextEvent(
                                            getServletContext(), (SipServlet) sipServlet);
                                    List sipServletListeners = sipListeners.getSipServletsListeners();
                                    if (logger.isDebugEnabled()) {
                                        logger.debug(sipServletListeners.size()
                                                + " SipServletListener to notify of servlet initialization");
                                    }
                                    for (SipServletListener sipServletListener : sipServletListeners) {
                                        sipServletListener.servletInitialized(sipServletContextEvent);
                                    }
                                    break;
                                }
                                case SIP_CONNECTOR_ADDED: {
                                    // reload the outbound interfaces if they have changed
                                    this.getServletContext().setAttribute(javax.servlet.sip.SipServlet.OUTBOUND_INTERFACES,
                                            sipApplicationDispatcher.getOutboundInterfaces());
                                    // https://code.google.com/p/sipservlets/issues/detail?id=246
                                    this.getServletContext().setAttribute("org.mobicents.servlet.sip.SIP_CONNECTORS",
                                            sipApplicationDispatcher.getSipService().findSipConnectors());

                                    List sipConnectorListeners = sipListeners.getSipConnectorListeners();
                                    if (logger.isDebugEnabled()) {
                                        logger.debug(sipConnectorListeners.size()
                                                + " SipConnectorListener to notify of sip connector addition");
                                    }
                                    for (SipConnectorListener sipConnectorListener : sipConnectorListeners) {
                                        sipConnectorListener.sipConnectorAdded((SipConnector) event.getEventObject());
                                    }
                                    break;
                                }
                                case SIP_CONNECTOR_REMOVED: {
                                    // reload the outbound interfaces if they have changed
                                    this.getServletContext().setAttribute(javax.servlet.sip.SipServlet.OUTBOUND_INTERFACES,
                                            sipApplicationDispatcher.getOutboundInterfaces());
                                    // https://code.google.com/p/sipservlets/issues/detail?id=246
                                    this.getServletContext().setAttribute("org.mobicents.servlet.sip.SIP_CONNECTORS",
                                            sipApplicationDispatcher.getSipService().findSipConnectors());

                                    List sipConnectorListeners = sipListeners.getSipConnectorListeners();
                                    if (logger.isDebugEnabled()) {
                                        logger.debug(sipConnectorListeners.size()
                                                + " SipConnectorListener to notify of sip connector removal");
                                    }
                                    for (SipConnectorListener sipConnectorListener : sipConnectorListeners) {
                                        sipConnectorListener.sipConnectorRemoved((SipConnector) event.getEventObject());
                                    }
                                    break;
                                }
                            }
                            if (servletHandlerWasNull) {
                                this.setServletHandler("");
                            }
                        }
                    } finally {
                        // http://code.google.com/p/sipservlets/issues/detail?id=135
                        // kakonyii: in SipStandardContext, there was a threadBindingListener which handled thread context switches (to get proper jndi context namespace selector, etc),
                        // in wildfly we use threadSetupAction from the deployment object for that purpose:
                        unbindThreadBindingListener();
                        Thread.currentThread().setContextClassLoader(oldClassLoader);
                    }
                } catch (ServletException e) {
                    logger.error("Cannot allocate the servlet " + managedServlet.getClass() + " for notifying the listener "
                            + " of the event " + event.getEventType(), e);
                    ok = false;
                } catch (Throwable e) {
                    logger.error("An error occured when notifying the servlet " + managedServlet.getClass() + " of the event "
                            + event.getEventType(), e);
                    ok = false;
                }

                // FIXME: kakonyii: do we need this deallocation in wildfly?
                // try {
                // if(sipServlet != null) {
                // wrapper.deallocate(sipServlet);
                // }
                // } catch (ServletException e) {
                // logger.error("Deallocate exception for servlet" + wrapper.getName(), e);
                // ok = false;
                // } catch (Throwable e) {
                // logger.error("Deallocate exception for servlet" + wrapper.getName(), e);
                // ok = false;
                // }
            }
        } finally {
            exitSipAppHa(null, null, batchStarted);
            exitSipApp(null, null);
        }
        // }
        return ok;
    }

    @Override
    public void enterSipApp(MobicentsSipApplicationSession sipApplicationSession, MobicentsSipSession sipSession,
            boolean checkIsManagedThread, boolean isContainerManaged) {
        switch (this.getConcurrencyControlMode()) {
            case SipSession:
                if (sipSession != null) {
                    sipSession.acquire();
                }
                break;
            case SipApplicationSession:
                if (logger.isDebugEnabled()) {
                    logger.debug("checkIsManagedThread " + checkIsManagedThread + " , isManagedThread " + isManagedThread.get()
                            + ", isContainerManaged " + isContainerManaged);
                }
                // http://code.google.com/p/mobicents/issues/detail?id=2534 &&
                // http://code.google.com/p/mobicents/issues/detail?id=2526
                if (!checkIsManagedThread || (checkIsManagedThread && Boolean.TRUE.equals(isManagedThread.get()))) {
                    if (isManagedThread.get() == null) {
                        isManagedThread.set(Boolean.TRUE);
                    }
                    if (sipApplicationSession != null) {
                        SipApplicationSessionCreationThreadLocal sipApplicationSessionCreationThreadLocal = sipApplicationSessionsAccessedThreadLocal
                                .get();
                        if (sipApplicationSessionCreationThreadLocal == null) {
                            sipApplicationSessionCreationThreadLocal = new SipApplicationSessionCreationThreadLocal();
                            sipApplicationSessionsAccessedThreadLocal.set(sipApplicationSessionCreationThreadLocal);
                        }
                        boolean notPresent = sipApplicationSessionCreationThreadLocal.getSipApplicationSessions().add(
                                sipApplicationSession);
                        if (notPresent && isContainerManaged) {
                            if (logger.isDebugEnabled()) {
                                logger.debug("acquiring sipApplicationSession=" + sipApplicationSession
                                        + " since it is not present in our local thread of accessed sip application sessions ");
                            }
                            sipApplicationSession.acquire();
                        } else if (logger.isDebugEnabled()) {
                            if (!isContainerManaged) {
                                logger.debug("not acquiring sipApplicationSession=" + sipApplicationSession
                                        + " since application specified the container shouldn't manage it ");
                            } else {
                                logger.debug("not acquiring sipApplicationSession=" + sipApplicationSession
                                        + " since it is present in our local thread of accessed sip application sessions ");
                            }
                        }
                    }
                } else {
                    if (logger.isDebugEnabled()) {
                        logger.debug("not acquiring sipApplicationSession=" + sipApplicationSession
                                + " since isManagedThread is " + isManagedThread.get());
                    }
                }
                break;
            case None:
                break;
        }
    }

    @Override
    public void exitSipApp(MobicentsSipApplicationSession sipApplicationSession, MobicentsSipSession sipSession) {
        switch (this.getConcurrencyControlMode()) {
            case SipSession:
                if (sipSession != null) {
                    sipSession.release();
                } else {
                    if (logger.isDebugEnabled()) {
                        logger.debug("NOT RELEASING SipSession on exit sipApplicationSession=" + sipApplicationSession
                                + " sipSession=" + sipSession + " semaphore=null");
                    }
                }
                break;
            case SipApplicationSession:
                boolean wasSessionReleased = false;
                SipApplicationSessionCreationThreadLocal sipApplicationSessionCreationThreadLocal = sipApplicationSessionsAccessedThreadLocal
                        .get();
                if (sipApplicationSessionCreationThreadLocal != null) {
                    for (MobicentsSipApplicationSession sipApplicationSessionAccessed : sipApplicationSessionsAccessedThreadLocal
                            .get().getSipApplicationSessions()) {
                        sipApplicationSessionAccessed.release();
                        if (sipApplicationSessionAccessed.equals(sipApplicationSession)) {
                            wasSessionReleased = true;
                        }
                    }
                    sipApplicationSessionsAccessedThreadLocal.get().getSipApplicationSessions().clear();
                    sipApplicationSessionsAccessedThreadLocal.set(null);
                    sipApplicationSessionsAccessedThreadLocal.remove();
                }
                isManagedThread.set(null);
                isManagedThread.remove();
                if (!wasSessionReleased) {
                    if (sipApplicationSession != null) {
                        sipApplicationSession.release();
                    } else {
                        if (logger.isDebugEnabled()) {
                            logger.debug("NOT RELEASING SipApplicationSession on exit sipApplicationSession="
                                    + sipApplicationSession + " sipSession=" + sipSession + " semaphore=null");
                        }
                    }
                }
                break;
            case None:
                break;
        }

    }

    @Override
    public boolean enterSipAppHa(boolean startCacheActivity) {
        boolean batchStarted = false;
        return batchStarted;
    }

    @Override
    public void exitSipAppHa(MobicentsSipServletRequest request, MobicentsSipServletResponse response, boolean batchStarted) {
        // FIXME: distributable not supported
    }

    @Override
    public SipFactory getSipFactoryFacade() {
        return sipFactoryFacade;
    }

    @Override
    public MobicentsSipSessionsUtil getSipSessionsUtil() {
        return sipSessionsUtil;
    }

    @Override
    public TimerService getTimerService() {
        return timerService;
    }

    @Override
    public ProxyTimerService getProxyTimerService() {
        return proxyTimerService;
    }

    @Override
    public SipApplicationSessionTimerService getSipApplicationSessionTimerService() {

        return sasTimerService;
    }

    @Override
    public void setConcurrencyControlMode(ConcurrencyControlMode mode) {
        this.deploymentInfoFacade.setConcurrencyControlMode(mode);
        if (this.deploymentInfoFacade.getConcurrencyControlMode() != null && logger.isDebugEnabled()) {
            logger.debug("Concurrency Control set to " + this.deploymentInfoFacade.getConcurrencyControlMode().toString()
                    + " for application " + this.deploymentInfoFacade.getApplicationName());
        }
    }

    @Override
    public ConcurrencyControlMode getConcurrencyControlMode() {
        return this.deploymentInfoFacade.getConcurrencyControlMode();
    }

    @Override
    public void setSipRubyController(SipRubyController rubyController) {
        this.deploymentInfoFacade.setRubyController(rubyController);

    }

    @Override
    public SipRubyController getSipRubyController() {
        return this.deploymentInfoFacade.getRubyController();
    }

    @Override
    public String getPath() {
        // kakonyii: currrently we use this method at ConvergedSessionDelegate encodeURL()
        return this.deployment.getServletContext().getContextPath();
        //return this.deploymentInfoFacade.getDeploymentInfo().getContextPath();
    }

    @Override
    public MobicentsSipServlet findSipServletByClassName(String canonicalName) {
        if (canonicalName == null)
            return (null);
        return this.deploymentInfoFacade.getChildrenMapByClassName().get(canonicalName);
    }

    @Override
    public MobicentsSipServlet findSipServletByName(String name) {
        if (name == null)
            return (null);
        return this.deploymentInfoFacade.getChildrenMap().get(name);
    }

    @Override
    public ClassLoader getSipContextClassLoader() {
        return sipContextClassLoader;
    }

    @Override
    public Map getChildrenMap() {
        return this.deploymentInfoFacade.getChildrenMap();
    }

    @Override
    public boolean isPackageProtectionEnabled() {
        // Got from org.apache.catalina.security.SecurityUtil:
        boolean packageDefinitionEnabled = (System.getProperty("package.definition") == null && System
                .getProperty("package.access") == null) ? false : true;
        boolean isSecurityEnabled = (System.getSecurityManager() != null);

        if (packageDefinitionEnabled && isSecurityEnabled) {
            return true;
        }
        return false;
    }

    @Override
    public boolean authorize(MobicentsSipServletRequest request) {
        String servletInfoName = request.getSipSession().getHandler();
        ServletInfo servletInfo = this.getDeploymentInfoFacade().getSipServlets().get(servletInfoName);

        return sipSecurityUtils.authorize(request, servletInfo, this.getSipApplicationDispatcher().getSipStack());

    }

    @Override
    public SipDigestAuthenticator getDigestAuthenticator() {
        return this.sipDigestAuthenticator;
    }

    private Handle handle;
    public void bindThreadBindingListener() {
        handle=getDeployment().getThreadSetupAction().setup(null);
    }
    public void unbindThreadBindingListener() {
        handle.tearDown();
    }

    @Override
    public void enterSipContext() {
        final ClassLoader cl = getSipContextClassLoader();
        Thread.currentThread().setContextClassLoader(cl);
        // http://code.google.com/p/sipservlets/issues/detail?id=135
        // kakonyii: in SipStandardContext, there was a threadBindingListener which handled thread context switches (to get proper jndi context namespace selector, etc),
        // in wildfly we use threadSetupAction from the deployment object for that purpose:
        bindThreadBindingListener();
    }

    @Override
    public void exitSipContext(ClassLoader oldClassLoader) {
        // http://code.google.com/p/sipservlets/issues/detail?id=135
        // kakonyii: in SipStandardContext, there was a threadBindingListener which handled thread context switches (to get proper jndi context namespace selector, etc),
        // in wildfly we use threadSetupAction from the deployment object for that purpose:
        unbindThreadBindingListener();
        Thread.currentThread().setContextClassLoader(oldClassLoader);
    }

    public String getDisplayName() {
        return displayName;
    }

    public void setDisplayName(String displayName) {
        this.displayName = displayName;
    }

    public DeploymentInfoFacade getDeploymentInfoFacade() {
        return deploymentInfoFacade;
    }

    public Deployment getDeployment() {
        return deployment;
    }

    public String getSecurityDomain() {
        return securityDomain;
    }

    public void setSecurityDomain(String securityDomain) {
        this.securityDomain = securityDomain;
    }

    public Host getHostOfDeployment() {
        return hostOfDeployment;
    }

    public void setHostOfDeployment(Host hostOfDeployment) {
        this.hostOfDeployment = hostOfDeployment;
    }

    public List> getWebServerListeners() {
        return webServerListeners;
    }

    public void setWebServerListeners(List> webServerListeners) {
        this.webServerListeners = webServerListeners;
    }

    public enum TimerServiceType{
        STANDARD,
        DEFAULT;
    }

    @Override
	public void stopGracefully(long timeToWait) {
		// http://code.google.com/p/sipservlets/issues/detail?id=195 
		// Support for Graceful Shutdown of SIP Applications and Overall Server
		if(logger.isInfoEnabled()) {
			logger.info("Stopping the Context " + getApplicationName() + " Gracefully in " + timeToWait + " ms");
		}
		// Guarantees that the application won't be routed any initial requests anymore but will still handle subsequent requests
		List applicationsUndeployed = new ArrayList();
		applicationsUndeployed.add(getApplicationName());
		sipApplicationDispatcher.getSipApplicationRouter().applicationUndeployed(applicationsUndeployed);
		if(timeToWait == 0) {
			// equivalent to forceful stop
			if(gracefulStopFuture != null) {
				gracefulStopFuture.cancel(false);
			}
			try {
				stop();
			} catch (ServletException e) {
				logger.error("The server couldn't be stopped", e);
			}
		} else { 
			long gracefulStopTaskInterval = 30000;
			if(timeToWait > 0 && timeToWait < gracefulStopTaskInterval) {
				// if the time to Wait is positive and < to the gracefulStopTaskInterval then we schedule the task directly once to the time to wait
				gracefulStopFuture = sipApplicationDispatcher.getAsynchronousScheduledExecutor().schedule(new ContextGracefulStopTask(this, timeToWait), timeToWait, TimeUnit.MILLISECONDS);         
			} else {
				// if the time to Wait is > to the gracefulStopTaskInterval or infinite (negative value) then we schedule the task to run every gracefulStopTaskInterval, not needed to be exactly precise on the timeToWait in this case
				gracefulStopFuture = sipApplicationDispatcher.getAsynchronousScheduledExecutor().scheduleWithFixedDelay(new ContextGracefulStopTask(this, timeToWait), gracefulStopTaskInterval, gracefulStopTaskInterval, TimeUnit.MILLISECONDS);                      
			}
		}		
	}

	@Override
	public boolean isStoppingGracefully() {
		if(gracefulStopFuture != null)
			return true;
		return false;
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy