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
021 package org.granite.config;
022
023 import java.io.IOException;
024 import java.io.InputStream;
025 import java.util.ArrayList;
026 import java.util.List;
027 import java.util.Map;
028
029 import javax.servlet.ServletContext;
030 import javax.servlet.ServletException;
031
032 import org.granite.config.api.Configuration;
033 import org.granite.jmx.MBeanUtil;
034 import org.granite.logging.Logger;
035 import org.granite.messaging.amf.io.convert.Converter;
036 import org.granite.messaging.amf.io.util.ActionScriptClassDescriptor;
037 import org.granite.messaging.amf.io.util.JavaClassDescriptor;
038 import org.granite.messaging.amf.io.util.externalizer.Externalizer;
039 import org.granite.util.ServletParams;
040 import org.granite.util.StreamUtil;
041
042 /**
043 * @author Franck WOLFF
044 */
045 public class ServletGraniteConfig implements ServletGraniteConfigMBean {
046
047 ///////////////////////////////////////////////////////////////////////////
048 // Static fields.
049
050 private static final Logger log = Logger.getLogger(ServletGraniteConfig.class);
051
052 private static final String GRANITE_CONFIG_DEFAULT = "/WEB-INF/granite/granite-config.xml";
053
054 public static final String GRANITE_CONFIG_KEY = GraniteConfig.class.getName() + "_CACHE";
055 public static final String GRANITE_CONFIG_DEFAULT_KEY = GraniteConfig.class.getName() + "_DEFAULT";
056 public static final String GRANITE_CONFIG_CONFIGURATION_KEY = GraniteConfig.class.getName() + "_CONFIG";
057
058 ///////////////////////////////////////////////////////////////////////////
059 // Instance fields.
060
061 private GraniteConfig config = null;
062
063 // Context where this GraniteConfig instance is registered (required for reload operation).
064 private ServletContext context = null;
065
066 // Should Granite MBeans be registered at startup.
067 private boolean registerMBeans = false;
068
069 // Reload listeners.
070 private final List<GraniteConfigReloadListener> reloadListeners = new ArrayList<GraniteConfigReloadListener>();
071
072 ///////////////////////////////////////////////////////////////////////////
073 // Constructor.
074
075 private ServletGraniteConfig(ServletContext context, GraniteConfig config) {
076 this.context = context;
077 this.config = config;
078 }
079
080 ///////////////////////////////////////////////////////////////////////////
081 // Static GraniteConfig loaders.
082
083 public static synchronized GraniteConfig getConfig(ServletContext context) {
084 return ((ServletGraniteConfig)context.getAttribute(GRANITE_CONFIG_KEY)).config;
085 }
086
087 public static synchronized ServletGraniteConfig getServletConfig(ServletContext context) {
088 return (ServletGraniteConfig)context.getAttribute(GRANITE_CONFIG_KEY);
089 }
090
091 public static synchronized GraniteConfig loadConfig(ServletContext context) throws ServletException {
092 ServletGraniteConfig servletGraniteConfig = (ServletGraniteConfig)context.getAttribute(GRANITE_CONFIG_KEY);
093
094 if (servletGraniteConfig == null) {
095 String path = getCustomConfigPath(context);
096
097 InputStream is = context.getResourceAsStream(path);
098 if (is == null) {
099 log.warn("Could not load custom granite-config.xml: %s (file does not exists)", path);
100 path = null;
101 }
102
103 Configuration configuration = (Configuration)context.getAttribute(GRANITE_CONFIG_CONFIGURATION_KEY);
104
105 String stdConfigPath = (String)context.getAttribute(GRANITE_CONFIG_DEFAULT_KEY);
106
107 boolean registerMBeans = ServletParams.get(context, GraniteConfigListener.GRANITE_MBEANS_ATTRIBUTE, Boolean.TYPE, false);
108
109 try {
110 String mbeanContextName = null;
111 // Use reflection for JDK 1.4 compatibility.
112 if (registerMBeans)
113 mbeanContextName = (String)ServletContext.class.getMethod("getContextPath").invoke(context);
114
115 GraniteConfig graniteConfig = new GraniteConfig(stdConfigPath, is, configuration, mbeanContextName);
116
117 servletGraniteConfig = loadConfig(context, graniteConfig);
118 }
119 catch (Exception e) {
120 log.error(e, "Could not load granite-config.xml");
121 throw new ServletException("Could not load custom granite-config.xml", e);
122 }
123 finally {
124 if (is != null) try {
125 is.close();
126 } catch (IOException e) {
127 // Ignore...
128 }
129 }
130 }
131
132 return servletGraniteConfig.config;
133 }
134
135 public static synchronized ServletGraniteConfig loadConfig(ServletContext context, GraniteConfig graniteConfig) {
136 ServletGraniteConfig servletGraniteConfig = new ServletGraniteConfig(context, graniteConfig);
137
138 context.setAttribute(GRANITE_CONFIG_KEY, servletGraniteConfig);
139
140 return servletGraniteConfig;
141 }
142
143 private static String getCustomConfigPath(ServletContext context) {
144 String path = null;
145
146 Configuration configuration = (Configuration)context.getAttribute(GRANITE_CONFIG_CONFIGURATION_KEY);
147 if (configuration != null)
148 path = configuration.getGraniteConfig();
149
150 if (path == null)
151 path = ServletParams.get(context, "graniteConfigPath", String.class, GRANITE_CONFIG_DEFAULT);
152
153 return path;
154 }
155
156 public String getCustomConfigPath() {
157 return getCustomConfigPath(context);
158 }
159
160
161 ///////////////////////////////////////////////////////////////////////////
162 // GraniteConfigMBean implementation: attributes.
163
164 public boolean isRegisterMBeans() {
165 return registerMBeans;
166 }
167 public void setRegisterMBeans(boolean registerMBeans) {
168 this.registerMBeans = registerMBeans;
169 }
170
171
172 public synchronized void reload() {
173
174 if (context == null)
175 throw new IllegalStateException("GraniteConfig was not registered in ServletContext");
176
177 ServletGraniteConfig oldConfig = (ServletGraniteConfig)context.getAttribute(GRANITE_CONFIG_KEY);
178
179 try {
180 context.removeAttribute(GRANITE_CONFIG_KEY);
181 GraniteConfig config = loadConfig(context);
182 for (GraniteConfigReloadListener listener : reloadListeners) {
183 try {
184 listener.onReload(context, config);
185 }
186 catch (Exception e) {
187 log.error(e, "Error while calling reload listener: %s", listener);
188 }
189 }
190 }
191 catch (Exception e) {
192 throw new RuntimeException(e.getMessage(), e);
193 }
194 finally {
195 if (context.getAttribute(GRANITE_CONFIG_KEY) == null)
196 context.setAttribute(GRANITE_CONFIG_KEY, oldConfig);
197 }
198 }
199
200
201 ///////////////////////////////////////////////////////////////////////////
202 // GraniteConfigMBean implementation
203
204 public void addReloadListener(GraniteConfigReloadListener listener) {
205 synchronized (reloadListeners) {
206 if (!reloadListeners.contains(listener))
207 reloadListeners.add(listener);
208 }
209 }
210
211 public boolean removeReloadListener(GraniteConfigReloadListener listener) {
212 synchronized (reloadListeners) {
213 return reloadListeners.remove(listener);
214 }
215 }
216
217 public boolean getScan() {
218 return config.getScan();
219 }
220
221 public String getAmf3DeserializerClass() {
222 return MBeanUtil.format(
223 config.getAmf3DeserializerConstructor() != null ?
224 config.getAmf3DeserializerConstructor().getDeclaringClass().getName():
225 null
226 );
227 }
228
229 public String getAmf3SerializerClass() {
230 return MBeanUtil.format(
231 config.getAmf3SerializerConstructor() != null ?
232 config.getAmf3SerializerConstructor().getDeclaringClass().getName():
233 null
234 );
235 }
236
237 public String getAmf3MessageInterceptorClass() {
238 return MBeanUtil.format(
239 config.getAmf3MessageInterceptor() != null ?
240 config.getAmf3MessageInterceptor().getClass().getName() :
241 null
242 );
243 }
244
245 public String getClassGetterClass() {
246 return MBeanUtil.format(
247 config.getClassGetter() != null ?
248 config.getClassGetter().getClass().getName() :
249 null
250 );
251 }
252
253 public String getMessageSelectorClass() {
254 return MBeanUtil.format(
255 config.getMessageSelectorConstructor() != null ?
256 config.getMessageSelectorConstructor().getDeclaringClass().getName() :
257 null
258 );
259 }
260
261 public String getMethodMatcherClass() {
262 return MBeanUtil.format(
263 config.getMethodMatcher() != null ?
264 config.getMethodMatcher().getClass().getName() :
265 null
266 );
267 }
268
269 public String getSecurityServiceClass() {
270 return MBeanUtil.format(
271 config.getSecurityService() != null ?
272 config.getSecurityService().getClass().getName() :
273 null
274 );
275 }
276
277 public String getServiceInvocationListenerClass() {
278 return MBeanUtil.format(
279 config.getInvocationListener() != null ?
280 config.getInvocationListener().getClass().getName() :
281 null
282 );
283 }
284
285 public String showStandardConfig() throws IOException {
286 String s = StreamUtil.getResourceAsString("org/granite/config/granite-config.xml", getClass().getClassLoader());
287 return MBeanUtil.format(s);
288 }
289
290 public String showCustomConfig() throws IOException {
291 String path = getCustomConfigPath();
292
293 InputStream is = context.getResourceAsStream(path);
294 try {
295 String s = StreamUtil.getStreamAsString(is);
296 return MBeanUtil.format(s);
297 }
298 finally {
299 if (is != null)
300 is.close();
301 }
302 }
303
304 public String showConverters() {
305 Converter[] cs = config.getConverters().getConverters();
306 String[] names = new String[cs.length];
307 for (int i = 0; i < cs.length; i++)
308 names[i] = cs[i].getClass().getName();
309 return MBeanUtil.format(names);
310 }
311
312 public String showExceptionConverters() {
313 String[] names = new String[config.getExceptionConverters().size()];
314 for (int i = 0; i < config.getExceptionConverters().size(); i++)
315 names[i] = config.getExceptionConverters().get(i).getClass().getName();
316 return MBeanUtil.format(names);
317 }
318
319 public String showInstantiators() {
320 String[] names = new String[config.getInstantiators().size()];
321 int i = 0;
322 for (Map.Entry<String, String> e : config.getInstantiators().entrySet())
323 names[i++] = e.getKey() + "=" + e.getValue();
324 return MBeanUtil.format(names, true);
325 }
326
327 public String showAs3DescriptorsByInstanceOf() {
328 String[] names = new String[config.getAs3DescriptorsByInstanceOf().size()];
329 int i = 0;
330 for (Map.Entry<String, String> e : config.getAs3DescriptorsByInstanceOf().entrySet())
331 names[i++] = e.getKey() + "=" + e.getValue();
332 return MBeanUtil.format(names, true);
333 }
334
335 public String showAs3DescriptorsByType() {
336 String[] names = new String[config.getAs3DescriptorsByType().size()];
337 int i = 0;
338 for (Map.Entry<String, Class<? extends ActionScriptClassDescriptor>> e : config.getAs3DescriptorsByType().entrySet())
339 names[i++] = e.getKey() + "=" + e.getValue().getName();
340 return MBeanUtil.format(names, true);
341 }
342
343 public String showDisabledTideComponentsByName() {
344 String[] names = new String[config.getDisabledTideComponentsByName().size()];
345 int i = 0;
346 for (Map.Entry<String, Object[]> e : config.getDisabledTideComponentsByName().entrySet())
347 names[i++] = e.getKey() + "=" + e.getValue()[0];
348 return MBeanUtil.format(names, true);
349 }
350
351 public String showEnabledTideComponentsByName() {
352 String[] names = new String[config.getEnabledTideComponentsByName().size()];
353 int i = 0;
354 for (Map.Entry<String, Object[]> e : config.getEnabledTideComponentsByName().entrySet())
355 names[i++] = e.getKey() + "=" + e.getValue()[0];
356 return MBeanUtil.format(names, true);
357 }
358
359 public String showExternalizersByAnnotatedWith() {
360 String[] names = new String[config.getExternalizersByAnnotatedWith().size()];
361 int i = 0;
362 for (Map.Entry<String, String> e : config.getExternalizersByAnnotatedWith().entrySet())
363 names[i++] = e.getKey() + "=" + e.getValue();
364 return MBeanUtil.format(names, true);
365 }
366
367 public String showExternalizersByInstanceOf() {
368 String[] names = new String[config.getExternalizersByInstanceOf().size()];
369 int i = 0;
370 for (Map.Entry<String, String> e : config.getExternalizersByInstanceOf().entrySet())
371 names[i++] = e.getKey() + "=" + e.getValue();
372 return MBeanUtil.format(names, true);
373 }
374
375 public String showExternalizersByType() {
376 List<String> names = new ArrayList<String>(config.getExternalizersByType().size());
377 for (Map.Entry<String, Externalizer> e : config.getExternalizersByType().entrySet()) {
378 if (config.EXTERNALIZER_FACTORY.getNullInstance() != e.getValue())
379 names.add(e.getKey() + "=" + e.getValue().getClass().getName());
380 }
381 return MBeanUtil.format(names.toArray(new String[names.size()]), true);
382 }
383
384 public String showJavaDescriptorsByInstanceOf() {
385 String[] names = new String[config.getJavaDescriptorsByInstanceOf().size()];
386 int i = 0;
387 for (Map.Entry<String, String> e : config.getJavaDescriptorsByInstanceOf().entrySet())
388 names[i++] = e.getKey() + "=" + e.getValue();
389 return MBeanUtil.format(names, true);
390 }
391
392 public String showJavaDescriptorsByType() {
393 String[] names = new String[config.getJavaDescriptorsByType().size()];
394 int i = 0;
395 for (Map.Entry<String, Class<? extends JavaClassDescriptor>> e : config.getJavaDescriptorsByType().entrySet())
396 names[i++] = e.getKey() + "=" + e.getValue().getName();
397 return MBeanUtil.format(names, true);
398 }
399
400 public String showScannedExternalizers() {
401 String[] names = new String[config.getScannedExternalizers().size()];
402 for (int i = 0; i < config.getScannedExternalizers().size(); i++)
403 names[i] = config.getScannedExternalizers().get(i).getClass().getName();
404 return MBeanUtil.format(names);
405 }
406
407 public String showTideComponentMatchers() {
408 String[] names = new String[config.getTideComponentMatchers().size()];
409 for (int i = 0; i < config.getTideComponentMatchers().size(); i++)
410 names[i] = config.getTideComponentMatchers().get(i).toString();
411 return MBeanUtil.format(names);
412 }
413 }