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