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 throw new ServletException("Could not load custom granite-config.xml", e);
121 }
122 finally {
123 if (is != null) try {
124 is.close();
125 } catch (IOException e) {
126 // Ignore...
127 }
128 }
129 }
130
131 return servletGraniteConfig.config;
132 }
133
134 public static synchronized ServletGraniteConfig loadConfig(ServletContext context, GraniteConfig graniteConfig) {
135 ServletGraniteConfig servletGraniteConfig = new ServletGraniteConfig(context, graniteConfig);
136
137 context.setAttribute(GRANITE_CONFIG_KEY, servletGraniteConfig);
138
139 return servletGraniteConfig;
140 }
141
142 private static String getCustomConfigPath(ServletContext context) {
143 String path = null;
144
145 Configuration configuration = (Configuration)context.getAttribute(GRANITE_CONFIG_CONFIGURATION_KEY);
146 if (configuration != null)
147 path = configuration.getGraniteConfig();
148
149 if (path == null)
150 path = ServletParams.get(context, "graniteConfigPath", String.class, GRANITE_CONFIG_DEFAULT);
151
152 return path;
153 }
154
155 public String getCustomConfigPath() {
156 return getCustomConfigPath(context);
157 }
158
159
160 ///////////////////////////////////////////////////////////////////////////
161 // GraniteConfigMBean implementation: attributes.
162
163 public boolean isRegisterMBeans() {
164 return registerMBeans;
165 }
166 public void setRegisterMBeans(boolean registerMBeans) {
167 this.registerMBeans = registerMBeans;
168 }
169
170
171 public synchronized void reload() {
172
173 if (context == null)
174 throw new IllegalStateException("GraniteConfig was not registered in ServletContext");
175
176 ServletGraniteConfig oldConfig = (ServletGraniteConfig)context.getAttribute(GRANITE_CONFIG_KEY);
177
178 try {
179 context.removeAttribute(GRANITE_CONFIG_KEY);
180 GraniteConfig config = loadConfig(context);
181 for (GraniteConfigReloadListener listener : reloadListeners) {
182 try {
183 listener.onReload(context, config);
184 }
185 catch (Exception e) {
186 log.error(e, "Error while calling reload listener: %s", listener);
187 }
188 }
189 }
190 catch (Exception e) {
191 throw new RuntimeException(e.getMessage(), e);
192 }
193 finally {
194 if (context.getAttribute(GRANITE_CONFIG_KEY) == null)
195 context.setAttribute(GRANITE_CONFIG_KEY, oldConfig);
196 }
197 }
198
199
200 ///////////////////////////////////////////////////////////////////////////
201 // GraniteConfigMBean implementation
202
203 public void addReloadListener(GraniteConfigReloadListener listener) {
204 synchronized (reloadListeners) {
205 if (!reloadListeners.contains(listener))
206 reloadListeners.add(listener);
207 }
208 }
209
210 public boolean removeReloadListener(GraniteConfigReloadListener listener) {
211 synchronized (reloadListeners) {
212 return reloadListeners.remove(listener);
213 }
214 }
215
216 public boolean getScan() {
217 return config.getScan();
218 }
219
220 public String getAmf3DeserializerClass() {
221 return MBeanUtil.format(
222 config.getAmf3DeserializerConstructor() != null ?
223 config.getAmf3DeserializerConstructor().getDeclaringClass().getName():
224 null
225 );
226 }
227
228 public String getAmf3SerializerClass() {
229 return MBeanUtil.format(
230 config.getAmf3SerializerConstructor() != null ?
231 config.getAmf3SerializerConstructor().getDeclaringClass().getName():
232 null
233 );
234 }
235
236 public String getAmf3MessageInterceptorClass() {
237 return MBeanUtil.format(
238 config.getAmf3MessageInterceptor() != null ?
239 config.getAmf3MessageInterceptor().getClass().getName() :
240 null
241 );
242 }
243
244 public String getClassGetterClass() {
245 return MBeanUtil.format(
246 config.getClassGetter() != null ?
247 config.getClassGetter().getClass().getName() :
248 null
249 );
250 }
251
252 public String getMessageSelectorClass() {
253 return MBeanUtil.format(
254 config.getMessageSelectorConstructor() != null ?
255 config.getMessageSelectorConstructor().getDeclaringClass().getName() :
256 null
257 );
258 }
259
260 public String getMethodMatcherClass() {
261 return MBeanUtil.format(
262 config.getMethodMatcher() != null ?
263 config.getMethodMatcher().getClass().getName() :
264 null
265 );
266 }
267
268 public String getSecurityServiceClass() {
269 return MBeanUtil.format(
270 config.getSecurityService() != null ?
271 config.getSecurityService().getClass().getName() :
272 null
273 );
274 }
275
276 public String getServiceInvocationListenerClass() {
277 return MBeanUtil.format(
278 config.getInvocationListener() != null ?
279 config.getInvocationListener().getClass().getName() :
280 null
281 );
282 }
283
284 public String showStandardConfig() throws IOException {
285 String s = StreamUtil.getResourceAsString("org/granite/config/granite-config.xml", getClass().getClassLoader());
286 return MBeanUtil.format(s);
287 }
288
289 public String showCustomConfig() throws IOException {
290 String path = getCustomConfigPath();
291
292 InputStream is = context.getResourceAsStream(path);
293 try {
294 String s = StreamUtil.getStreamAsString(is);
295 return MBeanUtil.format(s);
296 }
297 finally {
298 if (is != null)
299 is.close();
300 }
301 }
302
303 public String showConverters() {
304 Converter[] cs = config.getConverters().getConverters();
305 String[] names = new String[cs.length];
306 for (int i = 0; i < cs.length; i++)
307 names[i] = cs[i].getClass().getName();
308 return MBeanUtil.format(names);
309 }
310
311 public String showExceptionConverters() {
312 String[] names = new String[config.getExceptionConverters().size()];
313 for (int i = 0; i < config.getExceptionConverters().size(); i++)
314 names[i] = config.getExceptionConverters().get(i).getClass().getName();
315 return MBeanUtil.format(names);
316 }
317
318 public String showInstantiators() {
319 String[] names = new String[config.getInstantiators().size()];
320 int i = 0;
321 for (Map.Entry<String, String> e : config.getInstantiators().entrySet())
322 names[i++] = e.getKey() + "=" + e.getValue();
323 return MBeanUtil.format(names, true);
324 }
325
326 public String showAs3DescriptorsByInstanceOf() {
327 String[] names = new String[config.getAs3DescriptorsByInstanceOf().size()];
328 int i = 0;
329 for (Map.Entry<String, String> e : config.getAs3DescriptorsByInstanceOf().entrySet())
330 names[i++] = e.getKey() + "=" + e.getValue();
331 return MBeanUtil.format(names, true);
332 }
333
334 public String showAs3DescriptorsByType() {
335 String[] names = new String[config.getAs3DescriptorsByType().size()];
336 int i = 0;
337 for (Map.Entry<String, Class<? extends ActionScriptClassDescriptor>> e : config.getAs3DescriptorsByType().entrySet())
338 names[i++] = e.getKey() + "=" + e.getValue().getName();
339 return MBeanUtil.format(names, true);
340 }
341
342 public String showDisabledTideComponentsByName() {
343 String[] names = new String[config.getDisabledTideComponentsByName().size()];
344 int i = 0;
345 for (Map.Entry<String, Object[]> e : config.getDisabledTideComponentsByName().entrySet())
346 names[i++] = e.getKey() + "=" + e.getValue()[0];
347 return MBeanUtil.format(names, true);
348 }
349
350 public String showEnabledTideComponentsByName() {
351 String[] names = new String[config.getEnabledTideComponentsByName().size()];
352 int i = 0;
353 for (Map.Entry<String, Object[]> e : config.getEnabledTideComponentsByName().entrySet())
354 names[i++] = e.getKey() + "=" + e.getValue()[0];
355 return MBeanUtil.format(names, true);
356 }
357
358 public String showExternalizersByAnnotatedWith() {
359 String[] names = new String[config.getExternalizersByAnnotatedWith().size()];
360 int i = 0;
361 for (Map.Entry<String, String> e : config.getExternalizersByAnnotatedWith().entrySet())
362 names[i++] = e.getKey() + "=" + e.getValue();
363 return MBeanUtil.format(names, true);
364 }
365
366 public String showExternalizersByInstanceOf() {
367 String[] names = new String[config.getExternalizersByInstanceOf().size()];
368 int i = 0;
369 for (Map.Entry<String, String> e : config.getExternalizersByInstanceOf().entrySet())
370 names[i++] = e.getKey() + "=" + e.getValue();
371 return MBeanUtil.format(names, true);
372 }
373
374 public String showExternalizersByType() {
375 List<String> names = new ArrayList<String>(config.getExternalizersByType().size());
376 for (Map.Entry<String, Externalizer> e : config.getExternalizersByType().entrySet()) {
377 if (config.EXTERNALIZER_FACTORY.getNullInstance() != e.getValue())
378 names.add(e.getKey() + "=" + e.getValue().getClass().getName());
379 }
380 return MBeanUtil.format(names.toArray(new String[names.size()]), true);
381 }
382
383 public String showJavaDescriptorsByInstanceOf() {
384 String[] names = new String[config.getJavaDescriptorsByInstanceOf().size()];
385 int i = 0;
386 for (Map.Entry<String, String> e : config.getJavaDescriptorsByInstanceOf().entrySet())
387 names[i++] = e.getKey() + "=" + e.getValue();
388 return MBeanUtil.format(names, true);
389 }
390
391 public String showJavaDescriptorsByType() {
392 String[] names = new String[config.getJavaDescriptorsByType().size()];
393 int i = 0;
394 for (Map.Entry<String, Class<? extends JavaClassDescriptor>> e : config.getJavaDescriptorsByType().entrySet())
395 names[i++] = e.getKey() + "=" + e.getValue().getName();
396 return MBeanUtil.format(names, true);
397 }
398
399 public String showScannedExternalizers() {
400 String[] names = new String[config.getScannedExternalizers().size()];
401 for (int i = 0; i < config.getScannedExternalizers().size(); i++)
402 names[i] = config.getScannedExternalizers().get(i).getClass().getName();
403 return MBeanUtil.format(names);
404 }
405
406 public String showTideComponentMatchers() {
407 String[] names = new String[config.getTideComponentMatchers().size()];
408 for (int i = 0; i < config.getTideComponentMatchers().size(); i++)
409 names[i] = config.getTideComponentMatchers().get(i).toString();
410 return MBeanUtil.format(names);
411 }
412 }