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.config; 022 023import java.io.IOException; 024import java.io.InputStream; 025import java.util.ArrayList; 026import java.util.List; 027import java.util.Map; 028 029import javax.servlet.ServletContext; 030import javax.servlet.ServletException; 031 032import org.granite.config.api.Configuration; 033import org.granite.jmx.MBeanUtil; 034import org.granite.logging.Logger; 035import org.granite.messaging.amf.io.convert.Converter; 036import org.granite.messaging.amf.io.util.ActionScriptClassDescriptor; 037import org.granite.messaging.amf.io.util.JavaClassDescriptor; 038import org.granite.messaging.amf.io.util.externalizer.Externalizer; 039import org.granite.util.ServletParams; 040import org.granite.util.StreamUtil; 041 042/** 043 * @author Franck WOLFF 044 */ 045public 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}