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