001/**
002 *   GRANITE DATA SERVICES
003 *   Copyright (C) 2006-2013 GRANITE DATA SERVICES S.A.S.
004 *
005 *   This file is part of the Granite Data Services Platform.
006 *
007 *   Granite Data Services is free software; you can redistribute it and/or
008 *   modify it under the terms of the GNU Lesser General Public
009 *   License as published by the Free Software Foundation; either
010 *   version 2.1 of the License, or (at your option) any later version.
011 *
012 *   Granite Data Services is distributed in the hope that it will be useful,
013 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
014 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
015 *   General Public License for more details.
016 *
017 *   You should have received a copy of the GNU Lesser General Public
018 *   License along with this library; if not, write to the Free Software
019 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
020 *   USA, or see <http://www.gnu.org/licenses/>.
021 */
022package org.granite.gravity;
023
024import javax.servlet.ServletConfig;
025import javax.servlet.ServletContext;
026import javax.servlet.ServletException;
027import javax.servlet.http.HttpServlet;
028
029import org.granite.config.ConfigProvider;
030import org.granite.config.GraniteConfig;
031import org.granite.config.GraniteConfigListener;
032import org.granite.config.ServletGraniteConfig;
033import org.granite.config.flex.ServicesConfig;
034import org.granite.config.flex.ServletServicesConfig;
035import org.granite.util.TypeUtil;
036
037/**
038 * @author Franck WOLFF
039 */
040public class GravityManager {
041
042        private static final String GRAVITY_KEY = Gravity.class.getName();
043        
044        /**
045         * Parse gravity configuration (granite-config.xml), start gravity by using the specified factory and put it
046         * in ServletContext. If Gravity is already started, returns the previous instance from the servlet context.
047         * <br><br>
048         * This method is intended to be used in {@link HttpServlet#init(ServletConfig)} methods only and
049         * synchronizes on the current ServletContext instance.
050         * 
051         * @param servletConfig the servlet config passed in HttpServlet.init(ServletConfig config) method.
052         * @return a newly created and started Gravity instance or previously started one.
053         * @throws ServletException if something goes wrong (GravityFactory not found, Gravity.start() error, etc.)
054         */
055    public static Gravity start(ServletConfig servletConfig) throws ServletException {
056        return start(servletConfig.getServletContext());
057    }
058    
059    public static Gravity start(ServletContext context) throws ServletException {
060        Gravity gravity = null;
061        
062        synchronized (context) {
063                
064                gravity = (Gravity)context.getAttribute(GRAVITY_KEY);
065                
066                if (gravity == null) {
067                        GraniteConfig graniteConfig = ServletGraniteConfig.loadConfig(context);
068                        ServicesConfig servicesConfig = ServletServicesConfig.loadConfig(context);
069                    
070                        GravityServiceConfigurator serviceConfigurator = (GravityServiceConfigurator)context.getAttribute(GraniteConfigListener.GRANITE_CONFIG_ATTRIBUTE);
071                        if (serviceConfigurator != null)
072                                serviceConfigurator.configureGravityServices(context);
073                    
074                        GravityConfig gravityConfig = new GravityConfig(graniteConfig);
075                        
076                        String gravityFactory = gravityConfig.getGravityFactory();
077                        try {
078                                        GravityFactory factory = TypeUtil.newInstance(gravityFactory, GravityFactory.class);
079                                        gravity = factory.newGravity(gravityConfig, servicesConfig, graniteConfig, GraniteConfigListener.getSharedContext(context));
080                                } 
081                        catch (Exception e) {
082                                        throw new ServletException("Could not create Gravity instance with factory: " + gravityFactory, e);
083                                }
084                
085                        try {
086                            gravity.start();
087                            context.setAttribute(GRAVITY_KEY, gravity);
088
089                    if (context.getAttribute(GraniteConfigListener.GRANITE_CONFIG_PROVIDER_ATTRIBUTE) != null)
090                        ((ConfigProvider)context.getAttribute(GraniteConfigListener.GRANITE_CONFIG_PROVIDER_ATTRIBUTE)).initGravity(gravity);
091
092                            GraniteConfigListener.registerShutdownListener(context, gravity);
093                        }
094                        catch (Exception e) {
095                            throw new ServletException("Gravity initialization error", e);
096                        }
097                }
098        }
099
100        return gravity;
101    }
102    
103    
104    public static interface GravityServiceConfigurator {
105        
106        public void configureGravityServices(ServletContext context) throws ServletException;
107    }
108    
109    
110    /**
111     * Reconfigure gravity with the new supplied configuration (after reloading granite-config.xml).
112     * <br><br>
113     * Only these configuration options are taken into account when reconfiguring Gravity:
114     * <ul>
115     *  <li>channelIdleTimeoutMillis</li>
116     *  <li>longPollingTimeout</li>
117     *  <li>retryOnError</li>
118     *  <li>maxMessagesQueuedPerChannel</li>
119     *  <li>corePoolSize</li>
120     *  <li>maximumPoolSize</li>
121     *  <li>keepAliveTimeMillis</li>
122     * </ul>
123     * 
124     * @param context the ServletContext where the gravity instance is registered.
125     * @param gravityConfig the new (reloaded) GravityConfig. 
126     */
127    public static void reconfigure(ServletContext context, GravityConfig gravityConfig) {
128        synchronized (context) {
129                Gravity gravity = getGravity(context);
130                gravity.reconfigure(gravityConfig, ServletGraniteConfig.getConfig(context));
131        }
132    }
133    
134    /**
135     * Returns a previously started Gravity instance. This method isn't synchronized and should be used in
136     * HttpServlet.doPost(...) methods only.
137     * 
138     * @param context the ServletContext from which to retrieve the Gravity instance. 
139     * @return the unique and started Gravity instance (or null if {@link #start(ServletConfig)}
140     *          has never been called).
141     */
142    public static Gravity getGravity(ServletContext context) {
143        return (Gravity)context.getAttribute(GRAVITY_KEY);
144    }
145    
146}