001/* 002 GRANITE DATA SERVICES 003 Copyright (C) 2011 GRANITE DATA SERVICES S.A.S. 004 005 This file is part of Granite Data Services. 006 007 Granite Data Services is free software; you can redistribute it and/or modify 008 it under the terms of the GNU Library General Public License as published by 009 the Free Software Foundation; either version 2 of the License, or (at your 010 option) any later version. 011 012 Granite Data Services is distributed in the hope that it will be useful, but 013 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 014 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License 015 for more details. 016 017 You should have received a copy of the GNU Library General Public License 018 along with this library; if not, see <http://www.gnu.org/licenses/>. 019*/ 020 021package org.granite.gravity; 022 023import java.lang.reflect.Field; 024 025import javax.servlet.ServletConfig; 026import javax.servlet.ServletContext; 027import javax.servlet.ServletException; 028import javax.servlet.http.HttpServlet; 029 030import org.granite.config.ConfigProvider; 031import org.granite.config.GraniteConfig; 032import org.granite.config.GraniteConfigListener; 033import org.granite.config.ServletGraniteConfig; 034import org.granite.config.flex.ServicesConfig; 035import org.granite.config.flex.ServletServicesConfig; 036import org.granite.gravity.config.AbstractActiveMQTopicDestination; 037import org.granite.gravity.config.AbstractJmsTopicDestination; 038import org.granite.gravity.config.AbstractMessagingDestination; 039import org.granite.gravity.config.servlet3.ActiveMQTopicDestination; 040import org.granite.gravity.config.servlet3.JmsTopicDestination; 041import org.granite.gravity.config.servlet3.MessagingDestination; 042import org.granite.gravity.security.GravityDestinationSecurizer; 043import org.granite.util.TypeUtil; 044 045/** 046 * @author Franck WOLFF 047 */ 048public class GravityManager { 049 050 private static final String GRAVITY_KEY = Gravity.class.getName(); 051 052 /** 053 * Parse gravity configuration (granite-config.xml), start gravity by using the specified factory and put it 054 * in ServletContext. If Gravity is already started, returns the previous instance from the servlet context. 055 * <br><br> 056 * This method is intended to be used in {@link HttpServlet#init(ServletConfig)} methods only and 057 * synchronizes on the current ServletContext instance. 058 * 059 * @param servletConfig the servlet config passed in HttpServlet.init(ServletConfig config) method. 060 * @param channelFactory an implementation specific ChannelFactory instance. 061 * @return a newly created and started Gravity instance or previously started one. 062 * @throws ServletException if something goes wrong (GravityFactory not found, Gravity.start() error, etc.) 063 */ 064 public static Gravity start(ServletConfig servletConfig) throws ServletException { 065 return start(servletConfig.getServletContext()); 066 } 067 068 public static Gravity start(ServletContext context) throws ServletException { 069 Gravity gravity = null; 070 071 synchronized (context) { 072 073 gravity = (Gravity)context.getAttribute(GRAVITY_KEY); 074 075 if (gravity == null) { 076 GraniteConfig graniteConfig = ServletGraniteConfig.loadConfig(context); 077 ServicesConfig servicesConfig = ServletServicesConfig.loadConfig(context); 078 079 Class<?> serverFilterClass = (Class<?>)context.getAttribute(GraniteConfigListener.GRANITE_CONFIG_ATTRIBUTE); 080 if (serverFilterClass != null) 081 configureServices(context, serverFilterClass); 082 083 GravityConfig gravityConfig = new GravityConfig(graniteConfig); 084 085 String gravityFactory = gravityConfig.getGravityFactory(); 086 try { 087 GravityFactory factory = TypeUtil.newInstance(gravityFactory, GravityFactory.class); 088 gravity = factory.newGravity(gravityConfig, servicesConfig, graniteConfig); 089 } 090 catch (Exception e) { 091 throw new ServletException("Could not create Gravity instance with factory: " + gravityFactory, e); 092 } 093 094 try { 095 gravity.start(); 096 context.setAttribute(GRAVITY_KEY, gravity); 097 GraniteConfigListener.registerShutdownListener(context, gravity); 098 } 099 catch (Exception e) { 100 throw new ServletException("Gravity initialization error", e); 101 } 102 } 103 } 104 105 return gravity; 106 } 107 108 /** 109 * Reconfigure gravity with the new supplied configuration (after reloading granite-config.xml). 110 * <br><br> 111 * Only these configuration options are taken into account when reconfiguring Gravity: 112 * <ul> 113 * <li>channelIdleTimeoutMillis</li> 114 * <li>longPollingTimeout</li> 115 * <li>retryOnError</li> 116 * <li>maxMessagesQueuedPerChannel</li> 117 * <li>corePoolSize</li> 118 * <li>maximumPoolSize</li> 119 * <li>keepAliveTimeMillis</li> 120 * </ul> 121 * 122 * @param context the ServletContext where the gravity instance is registered. 123 * @param gravityConfig the new (reloaded) GravityConfig. 124 */ 125 public static void reconfigure(ServletContext context, GravityConfig gravityConfig) { 126 synchronized (context) { 127 Gravity gravity = getGravity(context); 128 gravity.reconfigure(gravityConfig, ServletGraniteConfig.getConfig(context)); 129 } 130 } 131 132 /** 133 * Returns a previously started Gravity instance. This method isn't synchronized and should be used in 134 * HttpServlet.doPost(...) methods only. 135 * 136 * @param context the ServletContext from which to retrieve the Gravity instance. 137 * @return the unique and started Gravity instance (or null if {@link #start(ServletConfig, ChannelFactory)} 138 * has never been called). 139 */ 140 public static Gravity getGravity(ServletContext context) { 141 return (Gravity)context.getAttribute(GRAVITY_KEY); 142 } 143 144 145 private static void configureServices(ServletContext servletContext, Class<?> serverFilterClass) throws ServletException { 146 ServicesConfig servicesConfig = ServletServicesConfig.loadConfig(servletContext); 147 148 ConfigProvider configProvider = (ConfigProvider)servletContext.getAttribute(GraniteConfigListener.GRANITE_CONFIG_PROVIDER_ATTRIBUTE); 149 150 for (Field field : serverFilterClass.getDeclaredFields()) { 151 if (field.isAnnotationPresent(MessagingDestination.class)) { 152 MessagingDestination md = field.getAnnotation(MessagingDestination.class); 153 AbstractMessagingDestination messagingDestination = new AbstractMessagingDestination(); 154 messagingDestination.setId(field.getName()); 155 messagingDestination.setNoLocal(md.noLocal()); 156 messagingDestination.setSessionSelector(md.sessionSelector()); 157 initSecurizer(messagingDestination, md.securizer(), configProvider); 158 messagingDestination.initServices(servicesConfig); 159 } 160 else if (field.isAnnotationPresent(JmsTopicDestination.class)) { 161 JmsTopicDestination md = field.getAnnotation(JmsTopicDestination.class); 162 AbstractJmsTopicDestination messagingDestination = new AbstractJmsTopicDestination(); 163 messagingDestination.setId(field.getName()); 164 messagingDestination.setNoLocal(md.noLocal()); 165 messagingDestination.setSessionSelector(md.sessionSelector()); 166 initSecurizer(messagingDestination, md.securizer(), configProvider); 167 messagingDestination.initServices(servicesConfig); 168 messagingDestination.setName(md.name()); 169 messagingDestination.setTextMessages(md.textMessages()); 170 messagingDestination.setAcknowledgeMode(md.acknowledgeMode()); 171 messagingDestination.setConnectionFactory(md.connectionFactory()); 172 messagingDestination.setTransactedSessions(md.transactedSessions()); 173 messagingDestination.setJndiName(md.topicJndiName()); 174 messagingDestination.initServices(servicesConfig); 175 } 176 else if (field.isAnnotationPresent(ActiveMQTopicDestination.class)) { 177 ActiveMQTopicDestination md = field.getAnnotation(ActiveMQTopicDestination.class); 178 AbstractActiveMQTopicDestination messagingDestination = new AbstractActiveMQTopicDestination(); 179 messagingDestination.setId(field.getName()); 180 messagingDestination.setNoLocal(md.noLocal()); 181 messagingDestination.setSessionSelector(md.sessionSelector()); 182 initSecurizer(messagingDestination, md.securizer(), configProvider); 183 messagingDestination.initServices(servicesConfig); 184 messagingDestination.setName(md.name()); 185 messagingDestination.setTextMessages(md.textMessages()); 186 messagingDestination.setAcknowledgeMode(md.acknowledgeMode()); 187 messagingDestination.setConnectionFactory(md.connectionFactory()); 188 messagingDestination.setTransactedSessions(md.transactedSessions()); 189 messagingDestination.setJndiName(md.topicJndiName()); 190 messagingDestination.setBrokerUrl(md.brokerUrl()); 191 messagingDestination.setCreateBroker(md.createBroker()); 192 messagingDestination.setDurable(md.durable()); 193 messagingDestination.setWaitForStart(md.waitForStart()); 194 messagingDestination.setFileStoreRoot(md.fileStoreRoot()); 195 messagingDestination.initServices(servicesConfig); 196 } 197 } 198 } 199 200 private static void initSecurizer(AbstractMessagingDestination messagingDestination, Class<? extends GravityDestinationSecurizer> securizerClass, ConfigProvider configProvider) { 201 if (securizerClass != GravityDestinationSecurizer.class) { 202 if (configProvider != null) 203 messagingDestination.setSecurizer(configProvider.findInstance(securizerClass)); 204 if (messagingDestination.getSecurizer() == null) 205 messagingDestination.setSecurizerClassName(securizerClass.getName()); 206 } 207 } 208}