Package com.ericsson.ssa.container.sim

Source Code of com.ericsson.ssa.container.sim.ApplicationRouterSelector

/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
* Copyright (c) Ericsson AB, 2004-2008. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License").  You
* may not use this file except in compliance with the License. You can obtain
* a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
* or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code.  If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [year]
* [name of copyright owner]"
*
* Contributor(s):
*
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license."  If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above.  However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package com.ericsson.ssa.container.sim;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.imageio.spi.ServiceRegistry;
import javax.servlet.sip.ar.SipApplicationRouter;

import javax.servlet.sip.ar.spi.SipApplicationRouterProvider;
import org.jvnet.glassfish.comms.util.LogUtil;


/**
* The ApplicationDispatcher is the Layer in the sip-stack that is responsible
* for invoking applications. It uses the Application Router to determine which
* application to invoke.
*
* ApplicationDispatcher maintains two references to application routers.
* One is the application router that is present in the system by default,
* typically the AlphabeticalRouter (unless configured otherwise).
*
* The administrator has the possibility of deploying a custom application
* router by using the 'asadmin deploy' command line.
*
* @author Robert Handl, Per Pettersson, Kristoffer Gronowski, Yvo Bogers
*/
public class ApplicationRouterSelector  {

    /* Singleton instance */
    private static ApplicationRouterSelector _instance = new ApplicationRouterSelector();
    private static TreeMap<String, ServletDispatcher> m_contextMapping = new TreeMap<String, ServletDispatcher>();
    private static final Logger m_logger = LogUtil.SIP_LOGGER.getLogger();
   
    private ClassLoader saved = null;
   
    /*
     * The runtime router is the one used during traffic.
     * At startup the runtimeRouter is determined. The system will not
     * start without a runtimeRouter.
     */
    private SipApplicationRouter runtimeRouter = null;
   
    /*
     * A default router reference is remembered when a custom router is deployed
     * over it. The ApplicationDispatcher resorts to the default whenever the
     * custom router is undeployed again.
     */
    private SipApplicationRouter defaultRouter = null;
    /**
     * The customDeplyedRouter is a router that is explicitly deployed
     * with an asadamin deploy command. However, it does not have to be
     * the router runtime router.
     */
    private SipApplicationRouter customDeployedRouter = null;
    private transient Properties customDeployedRouterProperties;

    private transient String customDeployedRouterName;
       
    public static SipApplicationRouter findSPIRouter(String providerName) {
        return findSPIRouter(providerName, Thread.currentThread().getContextClassLoader());
    }
   
    public static SipApplicationRouter findSPIRouter(String providerName, ClassLoader loader) {
        for (Iterator<? extends SipApplicationRouterProvider> results = ServiceRegistry.lookupProviders(SipApplicationRouterProvider.class, loader); results.hasNext(); /*nothing*/) {
            SipApplicationRouterProvider type = results.next();
            if (providerName == null || providerName.equals(type.getClass().getName())) {
                // first of specific is returned
                if (m_logger.isLoggable(Level.FINEST)){
                    m_logger.log(Level.FINEST,  "found SPI {0}", new Object[]{type});
                }
                return type.getSipApplicationRouter(); // return matched
            }
        }
        return null; // not found
    }
   
    private void selectAndInitRouter() {
        SipApplicationRouter newRouter = chooseApplicationRouter();
        if (newRouter == runtimeRouter) {
            if (m_logger.isLoggable(Level.FINEST)){
                m_logger.log(Level.FINEST,  "No change in router. Keep using {0}", new Object[]{newRouter.getClass().getName()});
            }
            // nothing changed
            return;
        } else if (newRouter == null) {
            // not allowed
            // do not change the runtimeRouter...
            if (m_logger.isLoggable(Level.FINEST)){
                m_logger.log(Level.FINEST,  "Not changing runtime router", new Object[]{runtimeRouter.getClass().getName()});
            }
            return;
        } else {
            // new non-null router selected
            if (runtimeRouter != null) {
                setRouterContext();
                try {
                    // allow the currently active runtime application router to cleanup
                    // its resources
                    if (runtimeRouter != null){
                        if (m_logger.isLoggable(Level.FINE)){
                            m_logger.log(Level.FINE,
                                    "Overwriting previously active AR: {0} with new AR {1}",
                                    new Object[]{runtimeRouter.getClass().getName(), newRouter.getClass().getName()});
                        }
                        runtimeRouter.destroy();
                    }
                } finally {
                    resetRouterContext();
                }
            }
            if (m_logger.isLoggable(Level.FINEST)){
                m_logger.log(Level.FINEST,
                        "setting new AR {0}",
                        new Object[]{newRouter.getClass().getName()});
            }
            runtimeRouter = newRouter;
            setRouterContext();
            try {
                // initialize the new application router with the currently
                // active list of applications.
                // XXX or other way around?
                if ((newRouter == customDeployedRouter) && (customDeployedRouterProperties != null)) {
                  newRouter.init(customDeployedRouterProperties);                 
                } else {
                newRouter.init();
                }
                newRouter.applicationDeployed(new ArrayList<String>(m_contextMapping.keySet()));
            } finally {
                resetRouterContext();
            }

        }
    }
   
    private SipApplicationRouter chooseApplicationRouter() {
        try {
            String preferredRouter = System.getProperty("javax.servlet.sip.ar.spi.SipApplicationRouterProvider");
            if (preferredRouter != null) {
                // try to load the preferred router
                if (customDeployedRouter != null && preferredRouter.equals(customDeployedRouter.getClass().getName())) {
                    if (m_logger.isLoggable(Level.FINEST)){
                        m_logger.log(Level.FINEST,
                                "choosing preferred/deployed router",
                                new Object[]{customDeployedRouter.getClass().getName()});
                    }
                    return customDeployedRouter;
                } else {
                    // try the classpath
                    SipApplicationRouter cprouter = findSPIRouter(preferredRouter);
                    if (cprouter != null) {
                        if (m_logger.isLoggable(Level.FINEST)){
                            m_logger.log(Level.FINEST,
                                    "choosing preferred router from the classpath",
                                    new Object[]{cprouter.getClass().getName()});
                        }
                        return cprouter;
                    }
                }
            }
            // no preferred router or preferred router not found
            if (customDeployedRouter != null) {
                if (m_logger.isLoggable(Level.FINEST)){
                    m_logger.log(Level.FINEST,
                            "choosing non preferred deployed router",
                            new Object[]{customDeployedRouter.getClass().getName()});
                }
                return customDeployedRouter; // prefer the custom router
            } else {
                SipApplicationRouter cprouter = findSPIRouter(null); // find first in CP
                if (cprouter != null) {
                    if (m_logger.isLoggable(Level.FINEST)){
                        m_logger.log(Level.FINEST,
                                "choosing non preferred classpath router",
                                new Object[]{customDeployedRouter.getClass().getName()});
                    }
                    return cprouter;
                }
            }
        } catch (Throwable t) {
            if (m_logger.isLoggable(Level.INFO)){
                m_logger.log(Level.INFO,
                        "choosing application router failed, falling back to default",
                        t);
            }
        }

        // if all else fails fallback to the defaultRouter
        if (m_logger.isLoggable(Level.FINEST)){
            m_logger.log(Level.FINEST,
                    "choosing default router",
                    new Object[]{defaultRouter.getClass().getName()});
        }
        return defaultRouter;
    }
   
    /**
     * Return an instance of <code>ApplicationRouterSelecor</code>.
     *
     * @return A <code>ApplicationRouterSelecor</code>.
     */
    public static ApplicationRouterSelector getInstance() {
        return _instance;
    }
   
    public synchronized void start() {
       
        if(runtimeRouter == null) {
            selectAndInitRouter();
        }

        if (runtimeRouter == null) {
            throw new RuntimeException(
                    "Can not start without application router.");
        }
        if (m_logger.isLoggable(Level.INFO)) {
            m_logger.log(Level.INFO,
                    "started Application Dispatcher with router {0}",
                    new Object[]{runtimeRouter.getClass().getName()});
        }
    }

    public synchronized void stop() {
        setRouterContext();
        try {
            runtimeRouter.destroy();
        } finally {
            resetRouterContext();
        }

        if (m_logger.isLoggable(Level.INFO)) {
            m_logger.log(Level.INFO,
                    "stopped Application Dispatcher and router {0}",
                    new Object[]{runtimeRouter.getClass().getName()});
        }
    }

    /**
     * Registers a Servlet Dispatcher associated to a application Name
     *
     * @param applicationName
     *           The application name.
     * @param servletDispatcher
     *           A <code>ServletDispatcher</code>.
     */
    public void addServletDispatcher(String applicationName,
            ServletDispatcher servletDispatcher) {

        // Notify the application router
        List<String> apps = new ArrayList<String>(1);
        apps.add(applicationName);

        setRouterContext();

        try {
            runtimeRouter.applicationDeployed(apps);
        } finally {
            resetRouterContext();
        }
    }

    /**
     * Deregisters a Servlet Dispatcher for a specified application
     *
     * @param applicationName
     */
    public void removeServletDispatcher(String applicationName) {
        // Notify the application router
        List<String> apps = new ArrayList<String>(1);
        apps.add(applicationName);

        setRouterContext();
        try {
            runtimeRouter.applicationUndeployed(apps);
        } finally {
            resetRouterContext();
        }
    }
   
    /**
     * Set a custom Application Router. A custom deployed application router
     * will take precedence over the default application router.
     *
     * @param aRouter
     */
    public void setCustomApplicationRouter(String moduleName, SipApplicationRouter aRouter, Properties aCustomProps) {
        m_logger.log(Level.FINE, "Setting custom Application Router: " + aRouter);
        customDeployedRouter = aRouter;
        customDeployedRouterProperties = aCustomProps;
        customDeployedRouterName = moduleName;
        selectAndInitRouter();
    }
   
    /**
     * Fall back to the default application router
     *
     * @return false if no default is available, in which case custom router is
     * not unset. true otherwise.
     */
    public boolean unsetCustomApplicationRouter(String moduleName) {
        if (moduleName.equals(customDeployedRouterName)) {
            // undeploying the top most custome router
            // XXX in the future we should set the customDeployedRouter
            // to the next one in the stack instead of setting it to null
            customDeployedRouterName = null;
            customDeployedRouterProperties = null;
            if (runtimeRouter == customDeployedRouter) {
                customDeployedRouter = null;
                // recalculate the new router
                selectAndInitRouter();
            } else {
                customDeployedRouter = null;
            }
        } //else it is not the top most router
        return true;
    }
    /**
     * Specify the default Application Router classname. The Application
     * Dispatcher will use java reflection to instantiate the default
     * application router. The default application router is used for routing
     * SIP traffic. It is possible to override this behaviour by calling
     * setCustomApplicationRouter.
     *
     * This method will not initialize the router yet. This will happen when
     * the start() method is called.
     *
     * @param className
     */
    public void setApplicationRouterClass(String className) {
        if (m_logger.isLoggable(Level.FINE)) {
            m_logger.log(Level.FINE, "Instantiating default Application Router : " + className);
        }

        try {
            Class ar = Class.forName(className);
            defaultRouter = (SipApplicationRouter) ar.newInstance();

        } catch (ClassNotFoundException e) {
            m_logger.log(Level.WARNING,
                    "Failed to instantiate ApplicationRouter", e);
        } catch (InstantiationException e) {
            m_logger.log(Level.WARNING,
                    "Failed to instantiate ApplicationRouter", e);
        } catch (IllegalAccessException e) {
            m_logger.log(Level.WARNING,
                    "Failed to instantiate ApplicationRouter", e);
        }
    }
   
    /**
     * Utility method for setting the context classloader.
     * Move this to common module?
     */
    @SuppressWarnings("unchecked")
    private ClassLoader _setContextClassLoader(ClassLoader newClassLoader) {

        // Can reference only final local variables from dopriveleged block
        final ClassLoader classLoaderToSet = newClassLoader;

        final Thread currentThread = Thread.currentThread();
        ClassLoader originalClassLoader = currentThread.getContextClassLoader();

        if (classLoaderToSet != originalClassLoader) {
            if (System.getSecurityManager() == null) {
                currentThread.setContextClassLoader(classLoaderToSet);
            } else {
                java.security.AccessController.doPrivileged(
                        new java.security.PrivilegedAction() {
                            public java.lang.Object run() {
                                currentThread.setContextClassLoader
                                (classLoaderToSet);
                                return null;
                            }
                        }
                );
            }
        }
        return originalClassLoader;
    }
   
     /**
      * Sets the context for invoking the application router
      */
    public void setRouterContext() {
        try {
            if(runtimeRouter == null) {
                selectAndInitRouter();
            }
            ClassLoader routerCL = runtimeRouter.getClass().getClassLoader();
            saved = _setContextClassLoader(routerCL);
        } catch (Exception e) {
            if (m_logger.isLoggable(Level.WARNING)) {
                m_logger.log(Level.WARNING, e.getMessage(), e);
            }
        }
    }

    /**
     * Resets the context after invoking the application router
     */
    public void resetRouterContext() {
        try {
            _setContextClassLoader(saved);
        } catch (Exception e) {
            if (m_logger.isLoggable(Level.WARNING)) {
                m_logger.log(Level.WARNING, e.getMessage(), e);
            }
        }
    }
   
    public SipApplicationRouter getRuntimeRouter(){
        return runtimeRouter;
    }   
}
TOP

Related Classes of com.ericsson.ssa.container.sim.ApplicationRouterSelector

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.