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 */ 022package org.granite.config; 023 024import java.io.ByteArrayInputStream; 025import java.io.Externalizable; 026import java.io.IOException; 027import java.io.InputStream; 028import java.io.ObjectInput; 029import java.io.ObjectOutput; 030import java.io.OutputStream; 031import java.lang.annotation.Annotation; 032import java.lang.reflect.Constructor; 033import java.lang.reflect.Modifier; 034import java.math.BigDecimal; 035import java.math.BigInteger; 036import java.util.ArrayList; 037import java.util.HashMap; 038import java.util.List; 039import java.util.Map; 040import java.util.Properties; 041import java.util.Set; 042import java.util.concurrent.ConcurrentHashMap; 043 044import org.granite.clustering.DistributedDataFactory; 045import org.granite.config.api.Configuration; 046import org.granite.context.GraniteContext; 047import org.granite.logging.Logger; 048import org.granite.messaging.AliasRegistry; 049import org.granite.messaging.DefaultAliasRegistry; 050import org.granite.messaging.amf.io.AMF3Deserializer; 051import org.granite.messaging.amf.io.AMF3DeserializerSecurizer; 052import org.granite.messaging.amf.io.AMF3Serializer; 053import org.granite.messaging.amf.io.convert.Converter; 054import org.granite.messaging.amf.io.convert.Converters; 055import org.granite.messaging.amf.io.util.ActionScriptClassDescriptor; 056import org.granite.messaging.amf.io.util.ClassGetter; 057import org.granite.messaging.amf.io.util.DefaultClassGetter; 058import org.granite.messaging.amf.io.util.JavaClassDescriptor; 059import org.granite.messaging.amf.io.util.externalizer.BigDecimalExternalizer; 060import org.granite.messaging.amf.io.util.externalizer.BigIntegerExternalizer; 061import org.granite.messaging.amf.io.util.externalizer.Externalizer; 062import org.granite.messaging.amf.io.util.externalizer.LongExternalizer; 063import org.granite.messaging.amf.io.util.externalizer.MapExternalizer; 064import org.granite.messaging.amf.process.AMF3MessageInterceptor; 065import org.granite.messaging.jmf.codec.ExtendedObjectCodec; 066import org.granite.messaging.reflect.Reflection; 067import org.granite.messaging.service.DefaultMethodMatcher; 068import org.granite.messaging.service.ExceptionConverter; 069import org.granite.messaging.service.MethodMatcher; 070import org.granite.messaging.service.ServiceInvocationListener; 071import org.granite.messaging.service.security.SecurityService; 072import org.granite.messaging.service.tide.TideComponentMatcher; 073import org.granite.scan.*; 074import org.granite.util.StreamUtil; 075import org.granite.util.TypeUtil; 076import org.granite.util.XMap; 077import org.xml.sax.EntityResolver; 078import org.xml.sax.InputSource; 079import org.xml.sax.SAXException; 080 081/** 082 * @author Franck WOLFF 083 */ 084public class GraniteConfig implements ScannedItemHandler { 085 086 public enum JMF_EXTENSIONS_MODE { 087 PREPPEND, 088 APPEND, 089 REPLACE 090 } 091 092 /////////////////////////////////////////////////////////////////////////// 093 // Static fields. 094 095 private static final Logger log = Logger.getLogger(GraniteConfig.class); 096 097 private static final String GRANITE_CONFIG_PUBLIC_ID = "-//Granite Data Services//DTD granite-config internal//EN"; 098 private static final String GRANITE_CONFIG_PROPERTIES = "META-INF/granite-config.properties"; 099 100 final ExternalizerFactory EXTERNALIZER_FACTORY = new ExternalizerFactory(); 101 private static final Externalizer LONG_EXTERNALIZER = new LongExternalizer(); 102 private static final Externalizer BIGINTEGER_EXTERNALIZER = new BigIntegerExternalizer(); 103 private static final Externalizer BIGDECIMAL_EXTERNALIZER = new BigDecimalExternalizer(); 104 private static final Externalizer MAP_EXTERNALIZER = new MapExternalizer(); 105 106 final ActionScriptClassDescriptorFactory ASC_DESCRIPTOR_FACTORY = new ActionScriptClassDescriptorFactory(); 107 final JavaClassDescriptorFactory JC_DESCRIPTOR_FACTORY = new JavaClassDescriptorFactory(); 108 final TideComponentMatcherFactory TIDE_COMPONENT_MATCHER_FACTORY = new TideComponentMatcherFactory(); 109 110 /////////////////////////////////////////////////////////////////////////// 111 // Instance fields. 112 113 // Should we scan classpath for auto-configured services/externalizers? 114 private boolean scan = false; 115 116 private AliasRegistry aliasRegistry = new DefaultAliasRegistry(); 117 118 private String MBeanContextName = null; 119 120 // Custom AMF3 (De)Serializer configuration. 121 private Constructor<AMF3Serializer> amf3SerializerConstructor = null; 122 private Constructor<AMF3Deserializer> amf3DeserializerConstructor = null; 123 124 private AMF3DeserializerSecurizer amf3DeserializerSecurizer = null; 125 126 // Custom AMF3 message interceptor configuration. 127 private AMF3MessageInterceptor amf3MessageInterceptor = null; 128 129 // Converters configuration. 130 private List<Class<? extends Converter>> converterClasses = new ArrayList<Class<? extends Converter>>(); 131 private Converters converters = null; 132 133 // MethodMatcher configuration. 134 private MethodMatcher methodMatcher = new DefaultMethodMatcher(); 135 136 // Invocation listener configuration. 137 private ServiceInvocationListener invocationListener = null; 138 139 // Instantiators configuration. 140 private final Map<String, String> instantiators = new HashMap<String, String>(); 141 142 // Class getter configuration. 143 private ClassGetter classGetter = new DefaultClassGetter(); 144 private boolean classGetterSet = false; 145 146 // Externalizers configuration. 147 private XMap externalizersConfiguration = null; 148 private final List<Externalizer> scannedExternalizers = new ArrayList<Externalizer>(); 149 private final ConcurrentHashMap<String, Externalizer> externalizersByType 150 = new ConcurrentHashMap<String, Externalizer>(); 151 private final Map<String, String> externalizersByInstanceOf = new HashMap<String, String>(); 152 private final Map<String, String> externalizersByAnnotatedWith = new HashMap<String, String>(); 153 154 // JMF extended codecs. 155 private JMF_EXTENSIONS_MODE jmfExtendedCodecsMode = JMF_EXTENSIONS_MODE.APPEND; 156 private final List<ExtendedObjectCodec> jmfExtendedCodecs = new ArrayList<ExtendedObjectCodec>(); 157 158 // JMF default stored strings. 159 private JMF_EXTENSIONS_MODE jmfDefaultStoredStringsMode = JMF_EXTENSIONS_MODE.APPEND; 160 private final List<String> jmfDefaultStoredStrings = new ArrayList<String>(); 161 162 // JMF reflection. 163 private Reflection jmfReflection = null; 164 165 // Java descriptors configuration. 166 private final ConcurrentHashMap<String, Class<? extends JavaClassDescriptor>> javaDescriptorsByType 167 = new ConcurrentHashMap<String, Class<? extends JavaClassDescriptor>>(); 168 private final Map<String, String> javaDescriptorsByInstanceOf = new HashMap<String, String>(); 169 170 // AS3 descriptors configuration. 171 private final ConcurrentHashMap<String, Class<? extends ActionScriptClassDescriptor>> as3DescriptorsByType 172 = new ConcurrentHashMap<String, Class<? extends ActionScriptClassDescriptor>>(); 173 private final Map<String, String> as3DescriptorsByInstanceOf = new HashMap<String, String>(); 174 175 // Exception converters 176 private final List<ExceptionConverter> exceptionConverters = new ArrayList<ExceptionConverter>(); 177 178 // Tide-enabled Components configuration. 179 private final ConcurrentHashMap<String, Object[]> enabledTideComponentsByName = new ConcurrentHashMap<String, Object[]>(); 180 private final ConcurrentHashMap<String, Object[]> disabledTideComponentsByName = new ConcurrentHashMap<String, Object[]>(); 181 private final List<TideComponentMatcher> tideComponentMatchers = new ArrayList<TideComponentMatcher>(); 182 183 // Security service configuration. 184 private SecurityService securityService = null; 185 186 // MessageSelector configuration. 187 private Constructor<?> messageSelectorConstructor; 188 189 // Gravity configuration. 190 private XMap gravityConfig; 191 192 // Clustering 193 private DistributedDataFactory distributedDataFactory; 194 195 /////////////////////////////////////////////////////////////////////////// 196 // Constructor. 197 198 public GraniteConfig(String stdConfig, InputStream customConfigIs, Configuration configuration, String MBeanContextName) throws IOException, SAXException { 199 try { 200 amf3SerializerConstructor = TypeUtil.getConstructor(AMF3Serializer.class, new Class<?>[]{OutputStream.class}); 201 amf3DeserializerConstructor = TypeUtil.getConstructor(AMF3Deserializer.class, new Class<?>[]{InputStream.class}); 202 } catch (Exception e) { 203 throw new GraniteConfigException("Could not get constructor for AMF3 (de)serializers", e); 204 } 205 206 this.MBeanContextName = MBeanContextName; 207 208 ClassLoader loader = GraniteConfig.class.getClassLoader(); 209 210 final ByteArrayInputStream dtd = StreamUtil.getResourceAsStream("org/granite/config/granite-config.dtd", loader); 211 final EntityResolver resolver = new EntityResolver() { 212 public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { 213 if (GRANITE_CONFIG_PUBLIC_ID.equals(publicId)) { 214 dtd.reset(); 215 InputSource source = new InputSource(dtd); 216 source.setPublicId(publicId); 217 return source; 218 } 219 return null; 220 } 221 }; 222 223 // Load standard config. 224 InputStream is = null; 225 try { 226 is = StreamUtil.getResourceAsStream("org/granite/config/granite-config.xml", loader); 227 XMap doc = new XMap(is, resolver); 228 forElement(doc, false, null); 229 } finally { 230 if (is != null) 231 is.close(); 232 } 233 234 if (stdConfig != null) { 235 try { 236 is = StreamUtil.getResourceAsStream(stdConfig, loader); 237 XMap doc = new XMap(is, resolver); 238 forElement(doc, false, null); 239 } finally { 240 if (is != null) 241 is.close(); 242 } 243 } 244 245 // Load custom config (override). 246 if (customConfigIs != null) { 247 XMap doc = new XMap(customConfigIs, resolver); 248 forElement(doc, true, configuration != null ? configuration.getGraniteConfigProperties() : null); 249 } 250 251 if (amf3DeserializerSecurizer == null) 252 log.warn("You should configure a deserializer securizer in your granite-config.xml file in order to prevent potential security exploits!"); 253 } 254 255 256 /////////////////////////////////////////////////////////////////////////// 257 // Classpath scan initialization. 258 259 private void scanConfig(String graniteConfigProperties) { 260 //if config overriding exists 261 Scanner scanner = ScannerFactory.createScanner(this, graniteConfigProperties != null ? graniteConfigProperties : GRANITE_CONFIG_PROPERTIES); 262 try { 263 scanner.scan(); 264 } catch (Exception e) { 265 log.error(e, "Could not scan classpath for configuration"); 266 } 267 } 268 269 public boolean handleMarkerItem(ScannedItem item) { 270 try { 271 return handleProperties(item.loadAsProperties()); 272 } catch (Exception e) { 273 log.error(e, "Could not load properties: %s", item); 274 } 275 return true; 276 } 277 278 public void handleScannedItem(ScannedItem item) { 279 if ("class".equals(item.getExtension()) && item.getName().indexOf('$') == -1) { 280 try { 281 handleClass(item.loadAsClass()); 282 } catch (NoClassDefFoundError e) { 283 // Ignore errors with Tide classes depending on Gravity 284 } catch (LinkageError e) { 285 // Ignore errors with GraniteDS/Hibernate classes depending on Hibernate 3 when using Hibernate 4 286 } catch (Throwable t) { 287 log.error(t, "Could not load class: %s", item); 288 } 289 } 290 } 291 292 private boolean handleProperties(Properties properties) { 293 if (properties.getProperty("dependsOn") != null) { 294 String dependsOn = properties.getProperty("dependsOn"); 295 try { 296 TypeUtil.forName(dependsOn); 297 } 298 catch (ClassNotFoundException e) { 299 // Class not found, skip scan for this package 300 return true; 301 } 302 } 303 304 String classGetterName = properties.getProperty("classGetter"); 305 if (!classGetterSet && classGetterName != null) { 306 try { 307 classGetter = TypeUtil.newInstance(classGetterName, ClassGetter.class); 308 } catch (Throwable t) { 309 log.error(t, "Could not create instance of: %s", classGetterName); 310 } 311 } 312 313 String amf3MessageInterceptorName = properties.getProperty("amf3MessageInterceptor"); 314 if (amf3MessageInterceptor == null && amf3MessageInterceptorName != null) { 315 try { 316 amf3MessageInterceptor = TypeUtil.newInstance(amf3MessageInterceptorName, AMF3MessageInterceptor.class); 317 } catch (Throwable t) { 318 log.error(t, "Could not create instance of: %s", amf3MessageInterceptorName); 319 } 320 } 321 322 for (Map.Entry<?, ?> me : properties.entrySet()) { 323 if (me.getKey().toString().startsWith("converter.")) { 324 String converterName = me.getValue().toString(); 325 try { 326 converterClasses.add(TypeUtil.forName(converterName, Converter.class)); 327 } catch (Exception e) { 328 throw new GraniteConfigException("Could not get converter class for: " + converterName, e); 329 } 330 } 331 } 332 333 return false; 334 } 335 336 private void handleClass(Class<?> clazz) { 337 if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers())) 338 return; 339 340 if (Externalizer.class.isAssignableFrom(clazz)) { 341 try { 342 scannedExternalizers.add(TypeUtil.newInstance(clazz, Externalizer.class)); 343 } catch (Exception e) { 344 log.error(e, "Could not create new instance of: %s", clazz); 345 } 346 } 347 348 if (ExceptionConverter.class.isAssignableFrom(clazz)) { 349 try { 350 exceptionConverters.add(TypeUtil.newInstance(clazz, ExceptionConverter.class)); 351 } catch (Exception e) { 352 if (!clazz.getName().equals("org.granite.tide.hibernate.HibernateValidatorExceptionConverter")) // GDS-582 353 log.error(e, "Could not create new instance of: %s", clazz); 354 } 355 } 356 } 357 358 /////////////////////////////////////////////////////////////////////////// 359 // Property getters. 360 361 public boolean getScan() { 362 return scan; 363 } 364 365 public boolean isRegisterMBeans() { 366 return MBeanContextName != null; 367 } 368 369 public String getMBeanContextName() { 370 return MBeanContextName; 371 } 372 373 374 public ObjectOutput newAMF3Serializer(OutputStream out) { 375 try { 376 return amf3SerializerConstructor.newInstance(new Object[]{out}); 377 } catch (Exception e) { 378 throw new GraniteConfigException("Could not create serializer instance with: " + amf3SerializerConstructor, e); 379 } 380 } 381 382 public Constructor<?> getAmf3SerializerConstructor() { 383 return amf3SerializerConstructor; 384 } 385 386 public ObjectInput newAMF3Deserializer(InputStream in) { 387 try { 388 return amf3DeserializerConstructor.newInstance(new Object[]{in}); 389 } catch (Exception e) { 390 throw new GraniteConfigException("Could not create deserializer instance with: " + amf3DeserializerConstructor, e); 391 } 392 } 393 394 public Constructor<?> getAmf3DeserializerConstructor() { 395 return amf3DeserializerConstructor; 396 } 397 398 public AMF3DeserializerSecurizer getAmf3DeserializerSecurizer() { 399 return amf3DeserializerSecurizer; 400 } 401 public void setAmf3DeserializerSecurizer( 402 AMF3DeserializerSecurizer amf3DeserializerSecurizer) { 403 this.amf3DeserializerSecurizer = amf3DeserializerSecurizer; 404 } 405 406 public AMF3MessageInterceptor getAmf3MessageInterceptor() { 407 return amf3MessageInterceptor; 408 } 409 public void setAmf3MessageInterceptor(AMF3MessageInterceptor amf3MessageInterceptor) { 410 this.amf3MessageInterceptor = amf3MessageInterceptor; 411 } 412 413 public Map<String, String> getInstantiators() { 414 return instantiators; 415 } 416 417 public Converters getConverters() { 418 return converters; 419 } 420 421 public MethodMatcher getMethodMatcher() { 422 return methodMatcher; 423 } 424 425 public ServiceInvocationListener getInvocationListener() { 426 return invocationListener; 427 } 428 429 public String getInstantiator(String type) { 430 return instantiators.get(type); 431 } 432 433 public ClassGetter getClassGetter() { 434 return classGetter; 435 } 436 437 public XMap getExternalizersConfiguration() { 438 return externalizersConfiguration; 439 } 440 441 public void setExternalizersConfiguration(XMap externalizersConfiguration) { 442 this.externalizersConfiguration = externalizersConfiguration; 443 } 444 445 public Externalizer getExternalizer(String type) { 446 Externalizer externalizer = getElementByType( 447 type, 448 EXTERNALIZER_FACTORY, 449 externalizersByType, 450 externalizersByInstanceOf, 451 externalizersByAnnotatedWith, 452 scannedExternalizers 453 ); 454 if (externalizer != null) 455 return externalizer; 456 457 if ("java".equals(GraniteContext.getCurrentInstance().getClientType())) { 458 // Force use of number externalizers when serializing from/to a Java client 459 if (Long.class.getName().equals(type)) 460 return LONG_EXTERNALIZER; 461 else if (BigInteger.class.getName().equals(type)) 462 return BIGINTEGER_EXTERNALIZER; 463 else if (BigDecimal.class.getName().equals(type)) 464 return BIGDECIMAL_EXTERNALIZER; 465 else { 466 try { 467 Class<?> clazz = TypeUtil.forName(type); 468 if (Map.class.isAssignableFrom(clazz) && !Externalizable.class.isAssignableFrom(clazz)) 469 return MAP_EXTERNALIZER; 470 } 471 catch (Exception e) { 472 473 } 474 } 475 } 476 477 return null; 478 } 479 480 public void registerExternalizer(Externalizer externalizer) { 481 scannedExternalizers.add(externalizer); 482 } 483 484 public Map<String, Externalizer> getExternalizersByType() { 485 return externalizersByType; 486 } 487 488 public Map<String, String> getExternalizersByInstanceOf() { 489 return externalizersByInstanceOf; 490 } 491 492 public Map<String, String> getExternalizersByAnnotatedWith() { 493 return externalizersByAnnotatedWith; 494 } 495 496 public List<Externalizer> getScannedExternalizers() { 497 return scannedExternalizers; 498 } 499 500 public JMF_EXTENSIONS_MODE getJmfExtendedCodecsMode() { 501 return jmfExtendedCodecsMode; 502 } 503 504 public List<ExtendedObjectCodec> getJmfExtendedCodecs() { 505 return jmfExtendedCodecs; 506 } 507 508 public JMF_EXTENSIONS_MODE getJmfDefaultStoredStringsMode() { 509 return jmfDefaultStoredStringsMode; 510 } 511 512 public Reflection getJmfReflection() { 513 return jmfReflection; 514 } 515 516 public List<String> getJmfDefaultStoredStrings() { 517 return jmfDefaultStoredStrings; 518 } 519 520 public Class<? extends ActionScriptClassDescriptor> getActionScriptDescriptor(String type) { 521 return getElementByType(type, ASC_DESCRIPTOR_FACTORY, as3DescriptorsByType, as3DescriptorsByInstanceOf, null, null); 522 } 523 524 public Map<String, Class<? extends ActionScriptClassDescriptor>> getAs3DescriptorsByType() { 525 return as3DescriptorsByType; 526 } 527 528 public Map<String, String> getAs3DescriptorsByInstanceOf() { 529 return as3DescriptorsByInstanceOf; 530 } 531 532 533 public Class<? extends JavaClassDescriptor> getJavaDescriptor(String type) { 534 return getElementByType(type, JC_DESCRIPTOR_FACTORY, javaDescriptorsByType, javaDescriptorsByInstanceOf, null, null); 535 } 536 537 public Map<String, Class<? extends JavaClassDescriptor>> getJavaDescriptorsByType() { 538 return javaDescriptorsByType; 539 } 540 541 public Map<String, String> getJavaDescriptorsByInstanceOf() { 542 return javaDescriptorsByInstanceOf; 543 } 544 545 546 public boolean isComponentTideEnabled(String componentName, Set<Class<?>> componentClasses, Object instance) { 547 return TideComponentMatcherFactory.isComponentTideEnabled(enabledTideComponentsByName, tideComponentMatchers, componentName, componentClasses, instance); 548 } 549 550 public boolean isComponentTideDisabled(String componentName, Set<Class<?>> componentClasses, Object instance) { 551 return TideComponentMatcherFactory.isComponentTideDisabled(disabledTideComponentsByName, tideComponentMatchers, componentName, componentClasses, instance); 552 } 553 554 555 public List<ExceptionConverter> getExceptionConverters() { 556 return exceptionConverters; 557 } 558 559 public void registerExceptionConverter(Class<? extends ExceptionConverter> exceptionConverterClass) { 560 registerExceptionConverter(exceptionConverterClass, false); 561 } 562 public void registerExceptionConverter(Class<? extends ExceptionConverter> exceptionConverterClass, boolean first) { 563 for (ExceptionConverter ec : exceptionConverters) { 564 if (ec.getClass() == exceptionConverterClass) 565 return; 566 } 567 try { 568 ExceptionConverter exceptionConverter = TypeUtil.newInstance(exceptionConverterClass, ExceptionConverter.class); 569 if (first) 570 exceptionConverters.add(0, exceptionConverter); 571 else 572 exceptionConverters.add(exceptionConverter); 573 } 574 catch (Exception e) { 575 log.error(e, "Could not instantiate exception converter: %s", exceptionConverterClass); 576 } 577 } 578 579 public void registerExceptionConverter(ExceptionConverter exceptionConverter, boolean first) { 580 for (ExceptionConverter ec : exceptionConverters) { 581 if (ec.getClass() == exceptionConverter.getClass()) 582 return; 583 } 584 if (first) 585 exceptionConverters.add(0, exceptionConverter); 586 else 587 exceptionConverters.add(exceptionConverter); 588 } 589 590 public boolean hasSecurityService() { 591 return securityService != null; 592 } 593 594 public SecurityService getSecurityService() { 595 return securityService; 596 } 597 598 public List<TideComponentMatcher> getTideComponentMatchers() { 599 return tideComponentMatchers; 600 } 601 602 public Map<String, Object[]> getEnabledTideComponentsByName() { 603 return enabledTideComponentsByName; 604 } 605 606 public Map<String, Object[]> getDisabledTideComponentsByName() { 607 return disabledTideComponentsByName; 608 } 609 610 611 public XMap getGravityConfig() { 612 return gravityConfig; 613 } 614 615 public DistributedDataFactory getDistributedDataFactory() { 616 return distributedDataFactory; 617 } 618 619 public Constructor<?> getMessageSelectorConstructor() { 620 return messageSelectorConstructor; 621 } 622 public Externalizer setExternalizersByType(String type, String externalizerType) { 623 return externalizersByType.put(type, EXTERNALIZER_FACTORY.getInstance(externalizerType, this)); 624 } 625 626 public String putExternalizersByInstanceOf(String instanceOf, String externalizerType) { 627 return externalizersByInstanceOf.put(instanceOf, externalizerType); 628 } 629 630 public String putExternalizersByAnnotatedWith(String annotatedWith, String externalizerType) { 631 return externalizersByAnnotatedWith.put(annotatedWith, externalizerType); 632 } 633 634 /////////////////////////////////////////////////////////////////////////// 635 // Static GraniteConfig loading helpers. 636 637 private void forElement(XMap element, boolean custom, String graniteConfigProperties) { 638 String scan = element.get("@scan"); 639 640 this.scan = Boolean.TRUE.toString().equals(scan); 641 642 loadCustomAMF3Serializer(element, custom); 643 loadCustomAMF3DeserializerSecurizer(element, custom); 644 loadCustomAMF3MessageInterceptor(element, custom); 645 loadCustomConverters(element, custom); 646 loadCustomMethodMatcher(element, custom); 647 loadCustomInvocationListener(element, custom); 648 loadCustomInstantiators(element, custom); 649 loadCustomClassGetter(element, custom); 650 loadCustomExternalizers(element, custom); 651 loadCustomJMFExtendedCodecs(element, custom); 652 loadCustomJMFDefaultStoredStrings(element, custom); 653 loadCustomJMFReflection(element, custom); 654 loadCustomDescriptors(element, custom); 655 loadCustomExceptionConverters(element, custom); 656 loadCustomTideComponents(element, custom); 657 loadCustomSecurity(element, custom); 658 loadCustomMessageSelector(element, custom); 659 loadCustomGravity(element, custom); 660 loadCustomDistributedDataFactory(element, custom); 661 662 if (this.scan) 663 scanConfig(graniteConfigProperties); 664 665 finishCustomConverters(custom); 666 } 667 668 private void loadCustomAMF3Serializer(XMap element, boolean custom) { 669 XMap amf3Serializer = element.getOne("amf3-serializer"); 670 if (amf3Serializer != null) { 671 String type = amf3Serializer.get("@type"); 672 try { 673 Class<AMF3Serializer> amf3SerializerClass = TypeUtil.forName(type, AMF3Serializer.class); 674 amf3SerializerConstructor = TypeUtil.getConstructor(amf3SerializerClass, new Class<?>[]{OutputStream.class}); 675 } catch (Exception e) { 676 throw new GraniteConfigException("Could not get constructor for AMF3 serializer: " + type, e); 677 } 678 } 679 680 XMap amf3Deserializer = element.getOne("amf3-deserializer"); 681 if (amf3Deserializer != null) { 682 String type = amf3Deserializer.get("@type"); 683 try { 684 Class<AMF3Deserializer> amf3DeserializerClass = TypeUtil.forName(type, AMF3Deserializer.class); 685 amf3DeserializerConstructor = TypeUtil.getConstructor(amf3DeserializerClass, new Class<?>[]{InputStream.class}); 686 } catch (Exception e) { 687 throw new GraniteConfigException("Could not get constructor for AMF3 deserializer: " + type, e); 688 } 689 } 690 } 691 692 private void loadCustomAMF3DeserializerSecurizer(XMap element, boolean custom) { 693 XMap securizer = element.getOne("amf3-deserializer-securizer"); 694 if (securizer != null) { 695 String type = securizer.get("@type"); 696 try { 697 amf3DeserializerSecurizer = (AMF3DeserializerSecurizer)TypeUtil.newInstance(type); 698 } catch (Exception e) { 699 throw new GraniteConfigException("Could not construct amf3 deserializer securizer: " + type, e); 700 } 701 String param = securizer.get("@param"); 702 try { 703 amf3DeserializerSecurizer.setParam(param); 704 } catch (Exception e) { 705 throw new GraniteConfigException("Could not set param of amf3 deserializer securizer: " + type + ", param: " + param, e); 706 } 707 } 708 } 709 710 private void loadCustomAMF3MessageInterceptor(XMap element, boolean custom) { 711 XMap interceptor = element.getOne("amf3-message-interceptor"); 712 if (interceptor != null) { 713 String type = interceptor.get("@type"); 714 try { 715 amf3MessageInterceptor = (AMF3MessageInterceptor)TypeUtil.newInstance(type); 716 } catch (Exception e) { 717 throw new GraniteConfigException("Could not construct amf3 message interceptor: " + type, e); 718 } 719 } 720 } 721 722 private void loadCustomDistributedDataFactory(XMap element, boolean custom) { 723 XMap distributedDataFactory = element.getOne("distributed-data-factory"); 724 if (distributedDataFactory != null) { 725 String type = distributedDataFactory.get("@type"); 726 try { 727 this.distributedDataFactory = (DistributedDataFactory)TypeUtil.newInstance(type); 728 } catch (Exception e) { 729 throw new GraniteConfigException("Could not construct build distributed data factory: " + type, e); 730 } 731 } 732 } 733 734 private void loadCustomConverters(XMap element, boolean custom) { 735 XMap converters = element.getOne("converters"); 736 if (converters != null) { 737 // Should we override standard config converters? 738 String override = converters.get("@override"); 739 if (Boolean.TRUE.toString().equals(override)) 740 converterClasses.clear(); 741 742 int i = 0; 743 for (XMap converter : converters.getAll("converter")) { 744 String type = converter.get("@type"); 745 try { 746 // For custom config, shifts any standard converters to the end of the list... 747 converterClasses.add(i++, TypeUtil.forName(type, Converter.class)); 748 } catch (Exception e) { 749 throw new GraniteConfigException("Could not get converter class for: " + type, e); 750 } 751 } 752 } 753 } 754 755 private void finishCustomConverters(boolean custom) { 756 try { 757 converters = new Converters(converterClasses); 758 } catch (Exception e) { 759 throw new GraniteConfigException("Could not construct new Converters instance", e); 760 } 761 762 // Cleanup... 763 if (custom) 764 converterClasses = null; 765 } 766 767 private void loadCustomMethodMatcher(XMap element, boolean custom) { 768 XMap methodMatcher = element.getOne("method-matcher"); 769 if (methodMatcher != null) { 770 String type = methodMatcher.get("@type"); 771 try { 772 this.methodMatcher = (MethodMatcher)TypeUtil.newInstance(type); 773 } catch (Exception e) { 774 throw new GraniteConfigException("Could not construct method matcher: " + type, e); 775 } 776 } 777 } 778 779 private void loadCustomInvocationListener(XMap element, boolean custom) { 780 XMap invocationListener = element.getOne("invocation-listener"); 781 if (invocationListener != null) { 782 String type = invocationListener.get("@type"); 783 try { 784 this.invocationListener = (ServiceInvocationListener)TypeUtil.newInstance(type); 785 } catch (Exception e) { 786 throw new GraniteConfigException("Could not instantiate ServiceInvocationListener: " + type, e); 787 } 788 } 789 } 790 791 private void loadCustomInstantiators(XMap element, boolean custom) { 792 XMap instantiators = element.getOne("instantiators"); 793 if (instantiators != null) { 794 for (XMap instantiator : instantiators.getAll("instantiator")) 795 this.instantiators.put(instantiator.get("@type"), instantiator.get(".")); 796 } 797 } 798 799 private void loadCustomClassGetter(XMap element, boolean custom) { 800 XMap classGetter = element.getOne("class-getter"); 801 if (classGetter != null) { 802 String type = classGetter.get("@type"); 803 try { 804 this.classGetter = (ClassGetter)TypeUtil.newInstance(type); 805 classGetterSet = true; 806 } catch (Exception e) { 807 throw new GraniteConfigException("Could not instantiate ClassGetter: " + type, e); 808 } 809 } 810 } 811 812 private void loadCustomExternalizers(XMap element, boolean custom) { 813 externalizersConfiguration = element.getOne("externalizers/configuration"); 814 815 for (XMap externalizer : element.getAll("externalizers/externalizer")) { 816 String externalizerType = externalizer.get("@type"); 817 818 for (XMap include : externalizer.getAll("include")) { 819 String type = include.get("@type"); 820 if (type != null) 821 externalizersByType.put(type, EXTERNALIZER_FACTORY.getInstance(externalizerType, this)); 822 else { 823 String instanceOf = include.get("@instance-of"); 824 if (instanceOf != null) 825 externalizersByInstanceOf.put(instanceOf, externalizerType); 826 else { 827 String annotatedWith = include.get("@annotated-with"); 828 if (annotatedWith == null) 829 throw new GraniteConfigException( 830 "Element 'include' has no attribute 'type', 'instance-of' or 'annotated-with'"); 831 externalizersByAnnotatedWith.put(annotatedWith, externalizerType); 832 } 833 } 834 } 835 } 836 } 837 838 private void loadCustomJMFExtendedCodecs(XMap element, boolean custom) { 839 String jmfExtendedCodecsMode = element.get("jmf-extended-codecs/@mode"); 840 if (jmfExtendedCodecsMode != null) { 841 try { 842 this.jmfExtendedCodecsMode = JMF_EXTENSIONS_MODE.valueOf(jmfExtendedCodecsMode.toLowerCase()); 843 } 844 catch (Exception e) { 845 throw new GraniteConfigException("Illegal JMF extended codecs mode: " + jmfExtendedCodecsMode, e); 846 } 847 } 848 849 for (XMap codec : element.getAll("jmf-extended-codecs/jmf-extended-codec")) { 850 String codecType = codec.get("@type"); 851 852 try { 853 jmfExtendedCodecs.add((ExtendedObjectCodec)TypeUtil.newInstance(codecType)); 854 } 855 catch (Exception e) { 856 throw new GraniteConfigException("Could not instantiate JMF extended codec: " + codecType, e); 857 } 858 } 859 } 860 861 private void loadCustomJMFDefaultStoredStrings(XMap element, boolean custom) { 862 String jmfDefaultStoredStringsMode = element.get("jmf-default-stored-strings/@mode"); 863 if (jmfDefaultStoredStringsMode != null) { 864 try { 865 this.jmfDefaultStoredStringsMode = JMF_EXTENSIONS_MODE.valueOf(jmfDefaultStoredStringsMode.toLowerCase()); 866 } 867 catch (Exception e) { 868 throw new GraniteConfigException("Illegal JMF default stored strings mode: " + jmfDefaultStoredStringsMode, e); 869 } 870 } 871 872 for (XMap codec : element.getAll("jmf-default-stored-strings/jmf-default-stored-string")) 873 jmfDefaultStoredStrings.add(codec.get("@value")); 874 } 875 876 private void loadCustomJMFReflection(XMap element, boolean custom) { 877 String jmfReflection = element.get("jmf-reflection/@type"); 878 if (jmfReflection == null) 879 this.jmfReflection = new Reflection(null); 880 else { 881 try { 882 this.jmfReflection = (Reflection)TypeUtil.newInstance(jmfReflection); 883 } 884 catch (Exception e) { 885 throw new GraniteConfigException("Could not instantiate JMF reflection: " + jmfReflection, e); 886 } 887 } 888 } 889 890 /** 891 * Read custom class descriptors. 892 * Descriptor must have 'type' or 'instanceof' attribute 893 * and one of 'java' or 'as3' attributes specified. 894 */ 895 private void loadCustomDescriptors(XMap element, boolean custom) { 896 for (XMap descriptor : element.getAll("descriptors/descriptor")) { 897 String type = descriptor.get("@type"); 898 if (type != null) { 899 String java = descriptor.get("@java"); 900 String as3 = descriptor.get("@as3"); 901 if (java == null && as3 == null) 902 throw new GraniteConfigException( 903 "Element 'descriptor' has no attributes 'java' or 'as3'\n" + descriptor 904 ); 905 if (java != null) 906 javaDescriptorsByType.put(type, JC_DESCRIPTOR_FACTORY.getInstance(java, this)); 907 if (as3 != null) 908 as3DescriptorsByType.put(type, ASC_DESCRIPTOR_FACTORY.getInstance(as3, this)); 909 } else { 910 String instanceOf = descriptor.get("@instance-of"); 911 if (instanceOf == null) 912 throw new GraniteConfigException( 913 "Element 'descriptor' has no attribute 'type' or 'instance-of'\n" + descriptor 914 ); 915 String java = descriptor.get("@java"); 916 String as3 = descriptor.get("@as3"); 917 if (java == null && as3 == null) { 918 throw new GraniteConfigException( 919 "Element 'descriptor' has no attributes 'java' or 'as3' in:\n" + descriptor 920 ); 921 } 922 if (java != null) 923 javaDescriptorsByInstanceOf.put(instanceOf, java); 924 if (as3 != null) 925 as3DescriptorsByInstanceOf.put(instanceOf, as3); 926 } 927 } 928 } 929 930 public void setAliasRegistry(AliasRegistry aliasRegistry) { 931 this.aliasRegistry = aliasRegistry; 932 } 933 934 public AliasRegistry getAliasRegistry() { 935 return aliasRegistry; 936 } 937 938 /** 939 * Read custom class exception converters 940 * Converter must have 'type' attribute 941 */ 942 private void loadCustomExceptionConverters(XMap element, boolean custom) { 943 for (XMap exceptionConverter : element.getAll("exception-converters/exception-converter")) { 944 String type = exceptionConverter.get("@type"); 945 ExceptionConverter converter = null; 946 try { 947 converter = (ExceptionConverter)TypeUtil.newInstance(type); 948 exceptionConverters.add(converter); 949 } catch (Exception e) { 950 throw new GraniteConfigException("Could not construct exception converter: " + type, e); 951 } 952 } 953 } 954 955 private void loadCustomTideComponents(XMap element, boolean custom) { 956 for (XMap component : element.getAll("tide-components/tide-component")) { 957 boolean disabled = Boolean.TRUE.toString().equals(component.get("@disabled")); 958 String type = component.get("@type"); 959 if (type != null) 960 tideComponentMatchers.add(TIDE_COMPONENT_MATCHER_FACTORY.getTypeMatcher(type, disabled)); 961 else { 962 String name = component.get("@name"); 963 if (name != null) 964 tideComponentMatchers.add(TIDE_COMPONENT_MATCHER_FACTORY.getNameMatcher(name, disabled)); 965 else { 966 String instanceOf = component.get("@instance-of"); 967 if (instanceOf != null) 968 tideComponentMatchers.add(TIDE_COMPONENT_MATCHER_FACTORY.getInstanceOfMatcher(instanceOf, disabled)); 969 else { 970 String annotatedWith = component.get("@annotated-with"); 971 if (annotatedWith == null) 972 throw new GraniteConfigException( 973 "Element 'component' has no attribute 'type', 'name', 'instance-of' or 'annotated-with'"); 974 tideComponentMatchers.add(TIDE_COMPONENT_MATCHER_FACTORY.getAnnotatedWithMatcher(annotatedWith, disabled)); 975 } 976 } 977 } 978 } 979 } 980 981 private void loadCustomSecurity(XMap element, boolean custom) { 982 XMap security = element.getOne("security"); 983 if (security != null) { 984 String type = security.get("@type"); 985 try { 986 securityService = (SecurityService)TypeUtil.newInstance(type); 987 } catch (Exception e) { 988 throw new GraniteConfigException("Could not instantiate SecurityService: " + type, e); 989 } 990 991 Map<String, String> params = new HashMap<String, String>(); 992 for (XMap param : security.getAll("param")) { 993 String name = param.get("@name"); 994 String value = param.get("@value"); 995 params.put(name, value); 996 } 997 try { 998 securityService.configure(params); 999 } catch (Exception e) { 1000 throw new GraniteConfigException("Could not configure SecurityService " + type + " with: " + params, e); 1001 } 1002 } 1003 } 1004 1005 public void setSecurityService(SecurityService securityService) { 1006 this.securityService = securityService; 1007 } 1008 1009 private void loadCustomMessageSelector(XMap element, boolean custom) { 1010 XMap selector = element.getOne("message-selector"); 1011 if (selector != null) { 1012 String type = selector.get("@type"); 1013 try { 1014 messageSelectorConstructor = TypeUtil.getConstructor(type, new Class<?>[]{ String.class }); 1015 } catch (Exception e) { 1016 throw new GraniteConfigException("Could not construct message selector: " + type, e); 1017 } 1018 } 1019 } 1020 1021 private void loadCustomGravity(XMap element, boolean custom) { 1022 gravityConfig = element.getOne("gravity"); 1023 } 1024 1025 /////////////////////////////////////////////////////////////////////////// 1026 // Other helpers. 1027 1028 private <T> T getElementByType( 1029 String type, 1030 ConfigurableFactory<T> factory, 1031 ConcurrentHashMap<String, T> elementsByType, 1032 Map<String, String> elementsByInstanceOf, 1033 Map<String, String> elementsByAnnotatedWith, 1034 List<T> scannedConfigurables) { 1035 1036 // This NULL object is a Java null placeholder: ConcurrentHashMap doesn't allow 1037 // null values... 1038 final T NULL = factory.getNullInstance(); 1039 1040 T element = elementsByType.get(type); 1041 if (element != null) 1042 return (NULL == element ? null : element); 1043 element = NULL; 1044 1045 Class<?> typeClass = null; 1046 try { 1047 typeClass = TypeUtil.forName(type); 1048 } catch (Exception e) { 1049 throw new GraniteConfigException("Could not load class: " + type, e); 1050 } 1051 1052 if (elementsByAnnotatedWith != null && NULL == element) { 1053 for (Map.Entry<String, String> entry : elementsByAnnotatedWith.entrySet()) { 1054 String annotation = entry.getKey(); 1055 try { 1056 Class<Annotation> annotationClass = TypeUtil.forName(annotation, Annotation.class); 1057 if (typeClass.isAnnotationPresent(annotationClass)) { 1058 element = factory.getInstance(entry.getValue(), this); 1059 break; 1060 } 1061 } catch (Exception e) { 1062 throw new GraniteConfigException("Could not load class: " + annotation, e); 1063 } 1064 } 1065 } 1066 1067 if (elementsByInstanceOf != null && NULL == element) { 1068 for (Map.Entry<String, String> entry : elementsByInstanceOf.entrySet()) { 1069 String instanceOf = entry.getKey(); 1070 try { 1071 Class<?> instanceOfClass = TypeUtil.forName(instanceOf); 1072 if (instanceOfClass.isAssignableFrom(typeClass)) { 1073 element = factory.getInstance(entry.getValue(), this); 1074 break; 1075 } 1076 } catch (Exception e) { 1077 throw new GraniteConfigException("Could not load class: " + instanceOf, e); 1078 } 1079 } 1080 } 1081 1082 if (NULL == element) 1083 element = factory.getInstanceForBean(scannedConfigurables, typeClass, this); 1084 1085 T previous = elementsByType.putIfAbsent(type, element); 1086 if (previous != null) 1087 element = previous; 1088 1089 return (NULL == element ? null : element); 1090 } 1091}