/**
* GRANITE DATA SERVICES
* Copyright (C) 2006-2015 GRANITE DATA SERVICES S.A.S.
*
* This file is part of the Granite Data Services Platform.
*
* Granite Data Services is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* Granite Data Services is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA, or see <http://www.gnu.org/licenses/>.
*/
package org.granite.config;
import java.io.ByteArrayInputStream;
import java.io.Externalizable;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.granite.clustering.DistributedDataFactory;
import org.granite.config.api.AliasRegistryConfig;
import org.granite.config.api.ConfigurableFactory;
import org.granite.config.api.Configuration;
import org.granite.config.api.GraniteConfigException;
import org.granite.context.GraniteContext;
import org.granite.logging.Logger;
import org.granite.messaging.AliasRegistry;
import org.granite.messaging.DefaultAliasRegistry;
import org.granite.messaging.amf.io.AMF3Deserializer;
import org.granite.messaging.amf.io.AMF3DeserializerSecurizer;
import org.granite.messaging.amf.io.AMF3Serializer;
import org.granite.messaging.amf.io.convert.Converter;
import org.granite.messaging.amf.io.convert.Converters;
import org.granite.messaging.amf.io.util.ActionScriptClassDescriptor;
import org.granite.messaging.amf.io.util.ClassGetter;
import org.granite.messaging.amf.io.util.DefaultClassGetter;
import org.granite.messaging.amf.io.util.JavaClassDescriptor;
import org.granite.messaging.amf.io.util.externalizer.BigDecimalExternalizer;
import org.granite.messaging.amf.io.util.externalizer.BigIntegerExternalizer;
import org.granite.messaging.amf.io.util.externalizer.Externalizer;
import org.granite.messaging.amf.io.util.externalizer.LongExternalizer;
import org.granite.messaging.amf.io.util.externalizer.MapExternalizer;
import org.granite.messaging.amf.process.AMF3MessageInterceptor;
import org.granite.messaging.jmf.SharedContext;
import org.granite.messaging.jmf.codec.ExtendedObjectCodec;
import org.granite.messaging.reflect.Reflection;
import org.granite.messaging.service.DefaultMethodMatcher;
import org.granite.messaging.service.ExceptionConverter;
import org.granite.messaging.service.MethodMatcher;
import org.granite.messaging.service.ServiceInvocationListener;
import org.granite.messaging.service.security.SecurityService;
import org.granite.messaging.service.tide.TideComponentMatcher;
import org.granite.scan.*;
import org.granite.util.StreamUtil;
import org.granite.util.TypeUtil;
import org.granite.util.XMap;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
* @author Franck WOLFF
*/
public class GraniteConfig implements ConvertersConfig, AliasRegistryConfig, AMF3Config, ExternalizersConfig, ScannedItemHandler {
public enum JMF_EXTENSIONS_MODE {
PREPPEND,
APPEND,
REPLACE
}
///////////////////////////////////////////////////////////////////////////
// Static fields.
private static final Logger log = Logger.getLogger(GraniteConfig.class);
private static final String GRANITE_CONFIG_PUBLIC_ID = "-//Granite Data Services//DTD granite-config internal//EN";
private static final String GRANITE_CONFIG_PROPERTIES = "META-INF/granite-config.properties";
final ExternalizerFactory EXTERNALIZER_FACTORY = new ExternalizerFactory();
private static final Externalizer LONG_EXTERNALIZER = new LongExternalizer();
private static final Externalizer BIGINTEGER_EXTERNALIZER = new BigIntegerExternalizer();
private static final Externalizer BIGDECIMAL_EXTERNALIZER = new BigDecimalExternalizer();
private static final Externalizer MAP_EXTERNALIZER = new MapExternalizer();
final ActionScriptClassDescriptorFactory ASC_DESCRIPTOR_FACTORY = new ActionScriptClassDescriptorFactory();
final JavaClassDescriptorFactory JC_DESCRIPTOR_FACTORY = new JavaClassDescriptorFactory();
final TideComponentMatcherFactory TIDE_COMPONENT_MATCHER_FACTORY = new TideComponentMatcherFactory();
///////////////////////////////////////////////////////////////////////////
// Instance fields.
// Should we scan classpath for auto-configured services/externalizers?
private boolean scan = false;
private AliasRegistry aliasRegistry = new DefaultAliasRegistry();
private String MBeanContextName = null;
// Custom AMF3 (De)Serializer configuration.
private Constructor<AMF3Serializer> amf3SerializerConstructor = null;
private Constructor<AMF3Deserializer> amf3DeserializerConstructor = null;
private AMF3DeserializerSecurizer amf3DeserializerSecurizer = null;
// Custom AMF3 message interceptor configuration.
private AMF3MessageInterceptor amf3MessageInterceptor = null;
// Converters configuration.
private List<Class<? extends Converter>> converterClasses = new ArrayList<Class<? extends Converter>>();
private Converters converters = null;
// MethodMatcher configuration.
private MethodMatcher methodMatcher = new DefaultMethodMatcher();
// Invocation listener configuration.
private ServiceInvocationListener invocationListener = null;
// Instantiators configuration.
private final Map<String, String> instantiators = new HashMap<String, String>();
// Class getter configuration.
private ClassGetter classGetter = new DefaultClassGetter();
private boolean classGetterSet = false;
// Externalizers configuration.
private XMap externalizersConfiguration = null;
private final List<Externalizer> scannedExternalizers = new ArrayList<Externalizer>();
private final ConcurrentHashMap<String, Externalizer> externalizersByType
= new ConcurrentHashMap<String, Externalizer>();
private final Map<String, String> externalizersByInstanceOf = new HashMap<String, String>();
private final Map<String, String> externalizersByAnnotatedWith = new HashMap<String, String>();
// JMF extended codecs.
private JMF_EXTENSIONS_MODE jmfExtendedCodecsMode = JMF_EXTENSIONS_MODE.APPEND;
private final List<ExtendedObjectCodec> jmfExtendedCodecs = new ArrayList<ExtendedObjectCodec>();
// JMF default stored strings.
private JMF_EXTENSIONS_MODE jmfDefaultStoredStringsMode = JMF_EXTENSIONS_MODE.APPEND;
private final List<String> jmfDefaultStoredStrings = new ArrayList<String>();
// JMF reflection.
private Reflection jmfReflection = null;
// JMF
private SharedContext sharedContext;
// Java descriptors configuration.
private final ConcurrentHashMap<String, JavaClassDescriptor> javaDescriptorsCache
= new ConcurrentHashMap<String, JavaClassDescriptor>();
private final ConcurrentHashMap<String, Class<? extends JavaClassDescriptor>> javaDescriptorsByType
= new ConcurrentHashMap<String, Class<? extends JavaClassDescriptor>>();
private final Map<String, String> javaDescriptorsByInstanceOf = new HashMap<String, String>();
// AS3 descriptors configuration.
private final ConcurrentHashMap<String, Class<? extends ActionScriptClassDescriptor>> as3DescriptorsByType
= new ConcurrentHashMap<String, Class<? extends ActionScriptClassDescriptor>>();
private final Map<String, String> as3DescriptorsByInstanceOf = new HashMap<String, String>();
// Exception converters
private final List<ExceptionConverter> exceptionConverters = new ArrayList<ExceptionConverter>();
// Tide-enabled Components configuration.
private final ConcurrentHashMap<String, Object[]> enabledTideComponentsByName = new ConcurrentHashMap<String, Object[]>();
private final ConcurrentHashMap<String, Object[]> disabledTideComponentsByName = new ConcurrentHashMap<String, Object[]>();
private final List<TideComponentMatcher> tideComponentMatchers = new ArrayList<TideComponentMatcher>();
// Security service configuration.
private SecurityService securityService = null;
// MessageSelector configuration.
private Constructor<?> messageSelectorConstructor;
// Gravity configuration.
private XMap gravityConfig;
// Clustering
private DistributedDataFactory distributedDataFactory;
///////////////////////////////////////////////////////////////////////////
// Constructor.
public GraniteConfig(String stdConfig, InputStream customConfigIs, Configuration configuration, String MBeanContextName) throws IOException, SAXException {
try {
amf3SerializerConstructor = TypeUtil.getConstructor(AMF3Serializer.class, new Class<?>[]{OutputStream.class});
amf3DeserializerConstructor = TypeUtil.getConstructor(AMF3Deserializer.class, new Class<?>[]{InputStream.class});
} catch (Exception e) {
throw new GraniteConfigException("Could not get constructor for AMF3 (de)serializers", e);
}
this.MBeanContextName = MBeanContextName;
ClassLoader loader = GraniteConfig.class.getClassLoader();
final ByteArrayInputStream dtd = StreamUtil.getResourceAsStream("org/granite/config/granite-config.dtd", loader);
final EntityResolver resolver = new EntityResolver() {
public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
if (GRANITE_CONFIG_PUBLIC_ID.equals(publicId)) {
dtd.reset();
InputSource source = new InputSource(dtd);
source.setPublicId(publicId);
return source;
}
return null;
}
};
// Load standard config.
InputStream is = null;
try {
is = StreamUtil.getResourceAsStream("org/granite/config/granite-config.xml", loader);
XMap doc = new XMap(is, resolver);
forElement(doc, false, null);
} finally {
if (is != null)
is.close();
}
if (stdConfig != null) {
try {
is = StreamUtil.getResourceAsStream(stdConfig, loader);
XMap doc = new XMap(is, resolver);
forElement(doc, false, null);
} finally {
if (is != null)
is.close();
}
}
// Load custom config (override).
if (customConfigIs != null) {
XMap doc = new XMap(customConfigIs, resolver);
forElement(doc, true, configuration != null ? configuration.getGraniteConfigProperties() : null);
}
if (amf3DeserializerSecurizer == null)
log.warn("You should configure a deserializer securizer in your granite-config.xml file in order to prevent potential security exploits!");
}
///////////////////////////////////////////////////////////////////////////
// Classpath scan initialization.
private void scanConfig(String graniteConfigProperties) {
//if config overriding exists
Scanner scanner = ScannerFactory.createScanner(this, graniteConfigProperties != null ? graniteConfigProperties : GRANITE_CONFIG_PROPERTIES);
try {
scanner.scan();
} catch (Exception e) {
log.error(e, "Could not scan classpath for configuration");
}
}
public boolean handleMarkerItem(ScannedItem item) {
try {
return handleProperties(item.loadAsProperties());
} catch (Exception e) {
log.error(e, "Could not load properties: %s", item);
}
return true;
}
public void handleScannedItem(ScannedItem item) {
if ("class".equals(item.getExtension()) && item.getName().indexOf('$') == -1) {
try {
handleClass(item.loadAsClass());
} catch (NoClassDefFoundError e) {
// Ignore errors with Tide classes depending on Gravity
} catch (LinkageError e) {
// Ignore errors with GraniteDS/Hibernate classes depending on Hibernate 3 when using Hibernate 4
} catch (Throwable t) {
log.error(t, "Could not load class: %s", item);
}
}
}
private boolean handleProperties(Properties properties) {
if (properties.getProperty("dependsOn") != null) {
String dependsOn = properties.getProperty("dependsOn");
try {
TypeUtil.forName(dependsOn);
}
catch (ClassNotFoundException e) {
// Class not found, skip scan for this package
return true;
}
}
String classGetterName = properties.getProperty("classGetter");
if (!classGetterSet && classGetterName != null) {
try {
classGetter = TypeUtil.newInstance(classGetterName, ClassGetter.class);
} catch (Throwable t) {
log.error(t, "Could not create instance of: %s", classGetterName);
}
}
String amf3MessageInterceptorName = properties.getProperty("amf3MessageInterceptor");
if (amf3MessageInterceptor == null && amf3MessageInterceptorName != null) {
try {
amf3MessageInterceptor = TypeUtil.newInstance(amf3MessageInterceptorName, AMF3MessageInterceptor.class);
} catch (Throwable t) {
log.error(t, "Could not create instance of: %s", amf3MessageInterceptorName);
}
}
for (Map.Entry<?, ?> me : properties.entrySet()) {
if (me.getKey().toString().startsWith("converter.")) {
String converterName = me.getValue().toString();
try {
converterClasses.add(TypeUtil.forName(converterName, Converter.class));
} catch (Exception e) {
throw new GraniteConfigException("Could not get converter class for: " + converterName, e);
}
}
}
return false;
}
private void handleClass(Class<?> clazz) {
if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers()))
return;
if (Externalizer.class.isAssignableFrom(clazz)) {
try {
scannedExternalizers.add(TypeUtil.newInstance(clazz, Externalizer.class));
} catch (Exception e) {
log.error(e, "Could not create new instance of: %s", clazz);
}
}
if (ExceptionConverter.class.isAssignableFrom(clazz)) {
try {
exceptionConverters.add(TypeUtil.newInstance(clazz, ExceptionConverter.class));
} catch (Exception e) {
if (!clazz.getName().equals("org.granite.tide.hibernate.HibernateValidatorExceptionConverter")) // GDS-582
log.error(e, "Could not create new instance of: %s", clazz);
}
}
}
///////////////////////////////////////////////////////////////////////////
// Property getters.
public boolean getScan() {
return scan;
}
public boolean isRegisterMBeans() {
return MBeanContextName != null;
}
public String getMBeanContextName() {
return MBeanContextName;
}
public ObjectOutput newAMF3Serializer(OutputStream out) {
try {
return amf3SerializerConstructor.newInstance(new Object[]{out});
} catch (Exception e) {
throw new GraniteConfigException("Could not create serializer instance with: " + amf3SerializerConstructor, e);
}
}
public Constructor<?> getAmf3SerializerConstructor() {
return amf3SerializerConstructor;
}
public ObjectInput newAMF3Deserializer(InputStream in) {
try {
return amf3DeserializerConstructor.newInstance(new Object[]{in});
} catch (Exception e) {
throw new GraniteConfigException("Could not create deserializer instance with: " + amf3DeserializerConstructor, e);
}
}
public Constructor<?> getAmf3DeserializerConstructor() {
return amf3DeserializerConstructor;
}
public AMF3DeserializerSecurizer getAmf3DeserializerSecurizer() {
return amf3DeserializerSecurizer;
}
public void setAmf3DeserializerSecurizer(
AMF3DeserializerSecurizer amf3DeserializerSecurizer) {
this.amf3DeserializerSecurizer = amf3DeserializerSecurizer;
}
public AMF3MessageInterceptor getAmf3MessageInterceptor() {
return amf3MessageInterceptor;
}
public void setAmf3MessageInterceptor(AMF3MessageInterceptor amf3MessageInterceptor) {
this.amf3MessageInterceptor = amf3MessageInterceptor;
}
public Map<String, String> getInstantiators() {
return instantiators;
}
public Converters getConverters() {
return converters;
}
public MethodMatcher getMethodMatcher() {
return methodMatcher;
}
public ServiceInvocationListener getInvocationListener() {
return invocationListener;
}
public String getInstantiator(String type) {
return instantiators.get(type);
}
public ClassGetter getClassGetter() {
return classGetter;
}
public XMap getExternalizersConfiguration() {
return externalizersConfiguration;
}
public void setExternalizersConfiguration(XMap externalizersConfiguration) {
this.externalizersConfiguration = externalizersConfiguration;
}
public Externalizer getExternalizer(String type) {
Externalizer externalizer = getElementByType(
type,
EXTERNALIZER_FACTORY,
externalizersByType,
externalizersByInstanceOf,
externalizersByAnnotatedWith,
scannedExternalizers
);
if (externalizer != null)
return externalizer;
if ("java".equals(GraniteContext.getCurrentInstance().getClientType())) {
// Force use of number externalizers when serializing from/to a Java client
if (Long.class.getName().equals(type))
return LONG_EXTERNALIZER;
else if (BigInteger.class.getName().equals(type))
return BIGINTEGER_EXTERNALIZER;
else if (BigDecimal.class.getName().equals(type))
return BIGDECIMAL_EXTERNALIZER;
else {
try {
Class<?> clazz = TypeUtil.forName(type);
if (Map.class.isAssignableFrom(clazz) && !Externalizable.class.isAssignableFrom(clazz))
return MAP_EXTERNALIZER;
}
catch (Exception e) {
}
}
}
return null;
}
public void registerExternalizer(Externalizer externalizer) {
scannedExternalizers.add(externalizer);
}
public Map<String, Externalizer> getExternalizersByType() {
return externalizersByType;
}
public Map<String, String> getExternalizersByInstanceOf() {
return externalizersByInstanceOf;
}
public Map<String, String> getExternalizersByAnnotatedWith() {
return externalizersByAnnotatedWith;
}
public List<Externalizer> getScannedExternalizers() {
return scannedExternalizers;
}
public JMF_EXTENSIONS_MODE getJmfExtendedCodecsMode() {
return jmfExtendedCodecsMode;
}
public List<ExtendedObjectCodec> getJmfExtendedCodecs() {
return jmfExtendedCodecs;
}
public JMF_EXTENSIONS_MODE getJmfDefaultStoredStringsMode() {
return jmfDefaultStoredStringsMode;
}
public Reflection getJmfReflection() {
return jmfReflection;
}
public List<String> getJmfDefaultStoredStrings() {
return jmfDefaultStoredStrings;
}
public Class<? extends ActionScriptClassDescriptor> getActionScriptDescriptor(String type) {
return getElementByType(type, ASC_DESCRIPTOR_FACTORY, as3DescriptorsByType, as3DescriptorsByInstanceOf, null, null);
}
public Map<String, Class<? extends ActionScriptClassDescriptor>> getAs3DescriptorsByType() {
return as3DescriptorsByType;
}
public Map<String, String> getAs3DescriptorsByInstanceOf() {
return as3DescriptorsByInstanceOf;
}
public ConcurrentMap<String, JavaClassDescriptor> getJavaDescriptorsCache() {
return javaDescriptorsCache;
}
public Class<? extends JavaClassDescriptor> getJavaDescriptor(String type) {
return getElementByType(type, JC_DESCRIPTOR_FACTORY, javaDescriptorsByType, javaDescriptorsByInstanceOf, null, null);
}
public Map<String, Class<? extends JavaClassDescriptor>> getJavaDescriptorsByType() {
return javaDescriptorsByType;
}
public Map<String, String> getJavaDescriptorsByInstanceOf() {
return javaDescriptorsByInstanceOf;
}
public boolean isComponentTideEnabled(String componentName, Set<Class<?>> componentClasses, Object instance) {
return TideComponentMatcherFactory.isComponentTideEnabled(enabledTideComponentsByName, tideComponentMatchers, componentName, componentClasses, instance);
}
public boolean isComponentTideDisabled(String componentName, Set<Class<?>> componentClasses, Object instance) {
return TideComponentMatcherFactory.isComponentTideDisabled(disabledTideComponentsByName, tideComponentMatchers, componentName, componentClasses, instance);
}
public List<ExceptionConverter> getExceptionConverters() {
return exceptionConverters;
}
public void registerExceptionConverter(Class<? extends ExceptionConverter> exceptionConverterClass) {
registerExceptionConverter(exceptionConverterClass, false);
}
public void registerExceptionConverter(Class<? extends ExceptionConverter> exceptionConverterClass, boolean first) {
for (ExceptionConverter ec : exceptionConverters) {
if (ec.getClass() == exceptionConverterClass)
return;
}
try {
ExceptionConverter exceptionConverter = TypeUtil.newInstance(exceptionConverterClass, ExceptionConverter.class);
if (first)
exceptionConverters.add(0, exceptionConverter);
else
exceptionConverters.add(exceptionConverter);
}
catch (Exception e) {
log.error(e, "Could not instantiate exception converter: %s", exceptionConverterClass);
}
}
public void registerExceptionConverter(ExceptionConverter exceptionConverter, boolean first) {
for (ExceptionConverter ec : exceptionConverters) {
if (ec.getClass() == exceptionConverter.getClass())
return;
}
if (first)
exceptionConverters.add(0, exceptionConverter);
else
exceptionConverters.add(exceptionConverter);
}
public boolean hasSecurityService() {
return securityService != null;
}
public SecurityService getSecurityService() {
return securityService;
}
public List<TideComponentMatcher> getTideComponentMatchers() {
return tideComponentMatchers;
}
public Map<String, Object[]> getEnabledTideComponentsByName() {
return enabledTideComponentsByName;
}
public Map<String, Object[]> getDisabledTideComponentsByName() {
return disabledTideComponentsByName;
}
public XMap getGravityConfig() {
return gravityConfig;
}
public DistributedDataFactory getDistributedDataFactory() {
return distributedDataFactory;
}
public Constructor<?> getMessageSelectorConstructor() {
return messageSelectorConstructor;
}
public Externalizer setExternalizersByType(String type, String externalizerType) {
return externalizersByType.put(type, EXTERNALIZER_FACTORY.getInstance(externalizerType, this));
}
public String putExternalizersByInstanceOf(String instanceOf, String externalizerType) {
return externalizersByInstanceOf.put(instanceOf, externalizerType);
}
public String putExternalizersByAnnotatedWith(String annotatedWith, String externalizerType) {
return externalizersByAnnotatedWith.put(annotatedWith, externalizerType);
}
///////////////////////////////////////////////////////////////////////////
// Static GraniteConfig loading helpers.
private void forElement(XMap element, boolean custom, String graniteConfigProperties) {
String scan = element.get("@scan");
this.scan = Boolean.TRUE.toString().equals(scan);
loadCustomAMF3Serializer(element, custom);
loadCustomAMF3DeserializerSecurizer(element, custom);
loadCustomAMF3MessageInterceptor(element, custom);
loadCustomConverters(element, custom);
loadCustomMethodMatcher(element, custom);
loadCustomInvocationListener(element, custom);
loadCustomInstantiators(element, custom);
loadCustomClassGetter(element, custom);
loadCustomExternalizers(element, custom);
loadCustomJMFExtendedCodecs(element, custom);
loadCustomJMFDefaultStoredStrings(element, custom);
loadCustomJMFReflection(element, custom);
loadCustomDescriptors(element, custom);
loadCustomExceptionConverters(element, custom);
loadCustomTideComponents(element, custom);
loadCustomSecurity(element, custom);
loadCustomMessageSelector(element, custom);
loadCustomGravity(element, custom);
loadCustomDistributedDataFactory(element, custom);
if (this.scan)
scanConfig(graniteConfigProperties);
finishCustomConverters(custom);
}
private void loadCustomAMF3Serializer(XMap element, boolean custom) {
XMap amf3Serializer = element.getOne("amf3-serializer");
if (amf3Serializer != null) {
String type = amf3Serializer.get("@type");
try {
Class<AMF3Serializer> amf3SerializerClass = TypeUtil.forName(type, AMF3Serializer.class);
amf3SerializerConstructor = TypeUtil.getConstructor(amf3SerializerClass, new Class<?>[]{OutputStream.class});
} catch (Exception e) {
throw new GraniteConfigException("Could not get constructor for AMF3 serializer: " + type, e);
}
}
XMap amf3Deserializer = element.getOne("amf3-deserializer");
if (amf3Deserializer != null) {
String type = amf3Deserializer.get("@type");
try {
Class<AMF3Deserializer> amf3DeserializerClass = TypeUtil.forName(type, AMF3Deserializer.class);
amf3DeserializerConstructor = TypeUtil.getConstructor(amf3DeserializerClass, new Class<?>[]{InputStream.class});
} catch (Exception e) {
throw new GraniteConfigException("Could not get constructor for AMF3 deserializer: " + type, e);
}
}
}
private void loadCustomAMF3DeserializerSecurizer(XMap element, boolean custom) {
XMap securizer = element.getOne("amf3-deserializer-securizer");
if (securizer != null) {
String type = securizer.get("@type");
try {
amf3DeserializerSecurizer = (AMF3DeserializerSecurizer)TypeUtil.newInstance(type);
} catch (Exception e) {
throw new GraniteConfigException("Could not construct amf3 deserializer securizer: " + type, e);
}
String param = securizer.get("@param");
try {
amf3DeserializerSecurizer.setParam(param);
} catch (Exception e) {
throw new GraniteConfigException("Could not set param of amf3 deserializer securizer: " + type + ", param: " + param, e);
}
}
}
private void loadCustomAMF3MessageInterceptor(XMap element, boolean custom) {
XMap interceptor = element.getOne("amf3-message-interceptor");
if (interceptor != null) {
String type = interceptor.get("@type");
try {
amf3MessageInterceptor = (AMF3MessageInterceptor)TypeUtil.newInstance(type);
} catch (Exception e) {
throw new GraniteConfigException("Could not construct amf3 message interceptor: " + type, e);
}
}
}
private void loadCustomDistributedDataFactory(XMap element, boolean custom) {
XMap distributedDataFactory = element.getOne("distributed-data-factory");
if (distributedDataFactory != null) {
String type = distributedDataFactory.get("@type");
try {
this.distributedDataFactory = (DistributedDataFactory)TypeUtil.newInstance(type);
} catch (Exception e) {
throw new GraniteConfigException("Could not construct build distributed data factory: " + type, e);
}
}
}
private void loadCustomConverters(XMap element, boolean custom) {
XMap converters = element.getOne("converters");
if (converters != null) {
// Should we override standard config converters?
String override = converters.get("@override");
if (Boolean.TRUE.toString().equals(override))
converterClasses.clear();
int i = 0;
for (XMap converter : converters.getAll("converter")) {
String type = converter.get("@type");
try {
// For custom config, shifts any standard converters to the end of the list...
converterClasses.add(i++, TypeUtil.forName(type, Converter.class));
} catch (Exception e) {
throw new GraniteConfigException("Could not get converter class for: " + type, e);
}
}
}
}
private void finishCustomConverters(boolean custom) {
try {
converters = new Converters(converterClasses);
} catch (Exception e) {
throw new GraniteConfigException("Could not construct new Converters instance", e);
}
// Cleanup...
if (custom)
converterClasses = null;
}
private void loadCustomMethodMatcher(XMap element, boolean custom) {
XMap methodMatcher = element.getOne("method-matcher");
if (methodMatcher != null) {
String type = methodMatcher.get("@type");
try {
this.methodMatcher = (MethodMatcher)TypeUtil.newInstance(type);
} catch (Exception e) {
throw new GraniteConfigException("Could not construct method matcher: " + type, e);
}
}
}
private void loadCustomInvocationListener(XMap element, boolean custom) {
XMap invocationListener = element.getOne("invocation-listener");
if (invocationListener != null) {
String type = invocationListener.get("@type");
try {
this.invocationListener = (ServiceInvocationListener)TypeUtil.newInstance(type);
} catch (Exception e) {
throw new GraniteConfigException("Could not instantiate ServiceInvocationListener: " + type, e);
}
}
}
private void loadCustomInstantiators(XMap element, boolean custom) {
XMap instantiators = element.getOne("instantiators");
if (instantiators != null) {
for (XMap instantiator : instantiators.getAll("instantiator"))
this.instantiators.put(instantiator.get("@type"), instantiator.get("."));
}
}
private void loadCustomClassGetter(XMap element, boolean custom) {
XMap classGetter = element.getOne("class-getter");
if (classGetter != null) {
String type = classGetter.get("@type");
try {
this.classGetter = (ClassGetter)TypeUtil.newInstance(type);
classGetterSet = true;
} catch (Exception e) {
throw new GraniteConfigException("Could not instantiate ClassGetter: " + type, e);
}
}
}
private void loadCustomExternalizers(XMap element, boolean custom) {
externalizersConfiguration = element.getOne("externalizers/configuration");
for (XMap externalizer : element.getAll("externalizers/externalizer")) {
String externalizerType = externalizer.get("@type");
for (XMap include : externalizer.getAll("include")) {
String type = include.get("@type");
if (type != null)
externalizersByType.put(type, EXTERNALIZER_FACTORY.getInstance(externalizerType, this));
else {
String instanceOf = include.get("@instance-of");
if (instanceOf != null)
externalizersByInstanceOf.put(instanceOf, externalizerType);
else {
String annotatedWith = include.get("@annotated-with");
if (annotatedWith == null)
throw new GraniteConfigException(
"Element 'include' has no attribute 'type', 'instance-of' or 'annotated-with'");
externalizersByAnnotatedWith.put(annotatedWith, externalizerType);
}
}
}
}
}
private void loadCustomJMFExtendedCodecs(XMap element, boolean custom) {
String jmfExtendedCodecsMode = element.get("jmf-extended-codecs/@mode");
if (jmfExtendedCodecsMode != null) {
try {
this.jmfExtendedCodecsMode = JMF_EXTENSIONS_MODE.valueOf(jmfExtendedCodecsMode.toLowerCase());
}
catch (Exception e) {
throw new GraniteConfigException("Illegal JMF extended codecs mode: " + jmfExtendedCodecsMode, e);
}
}
for (XMap codec : element.getAll("jmf-extended-codecs/jmf-extended-codec")) {
String codecType = codec.get("@type");
try {
jmfExtendedCodecs.add((ExtendedObjectCodec)TypeUtil.newInstance(codecType));
}
catch (Exception e) {
throw new GraniteConfigException("Could not instantiate JMF extended codec: " + codecType, e);
}
}
}
private void loadCustomJMFDefaultStoredStrings(XMap element, boolean custom) {
String jmfDefaultStoredStringsMode = element.get("jmf-default-stored-strings/@mode");
if (jmfDefaultStoredStringsMode != null) {
try {
this.jmfDefaultStoredStringsMode = JMF_EXTENSIONS_MODE.valueOf(jmfDefaultStoredStringsMode.toLowerCase());
}
catch (Exception e) {
throw new GraniteConfigException("Illegal JMF default stored strings mode: " + jmfDefaultStoredStringsMode, e);
}
}
for (XMap codec : element.getAll("jmf-default-stored-strings/jmf-default-stored-string"))
jmfDefaultStoredStrings.add(codec.get("@value"));
}
private void loadCustomJMFReflection(XMap element, boolean custom) {
String jmfReflection = element.get("jmf-reflection/@type");
if (jmfReflection == null)
this.jmfReflection = new Reflection(Thread.currentThread().getContextClassLoader());
else {
try {
this.jmfReflection = (Reflection)TypeUtil.newInstance(jmfReflection);
}
catch (Exception e) {
throw new GraniteConfigException("Could not instantiate JMF reflection: " + jmfReflection, e);
}
}
}
/**
* Read custom class descriptors.
* Descriptor must have 'type' or 'instanceof' attribute
* and one of 'java' or 'as3' attributes specified.
*/
private void loadCustomDescriptors(XMap element, boolean custom) {
for (XMap descriptor : element.getAll("descriptors/descriptor")) {
String type = descriptor.get("@type");
if (type != null) {
String java = descriptor.get("@java");
String as3 = descriptor.get("@as3");
if (java == null && as3 == null)
throw new GraniteConfigException(
"Element 'descriptor' has no attributes 'java' or 'as3'\n" + descriptor
);
if (java != null)
javaDescriptorsByType.put(type, JC_DESCRIPTOR_FACTORY.getInstance(java, this));
if (as3 != null)
as3DescriptorsByType.put(type, ASC_DESCRIPTOR_FACTORY.getInstance(as3, this));
} else {
String instanceOf = descriptor.get("@instance-of");
if (instanceOf == null)
throw new GraniteConfigException(
"Element 'descriptor' has no attribute 'type' or 'instance-of'\n" + descriptor
);
String java = descriptor.get("@java");
String as3 = descriptor.get("@as3");
if (java == null && as3 == null) {
throw new GraniteConfigException(
"Element 'descriptor' has no attributes 'java' or 'as3' in:\n" + descriptor
);
}
if (java != null)
javaDescriptorsByInstanceOf.put(instanceOf, java);
if (as3 != null)
as3DescriptorsByInstanceOf.put(instanceOf, as3);
}
}
}
public void setAliasRegistry(AliasRegistry aliasRegistry) {
this.aliasRegistry = aliasRegistry;
}
public AliasRegistry getAliasRegistry() {
return aliasRegistry;
}
public void setSharedContext(SharedContext sharedContext) {
this.sharedContext = sharedContext;
}
public SharedContext getSharedContext() {
return sharedContext;
}
/**
* Read custom class exception converters
* Converter must have 'type' attribute
*/
private void loadCustomExceptionConverters(XMap element, boolean custom) {
for (XMap exceptionConverter : element.getAll("exception-converters/exception-converter")) {
String type = exceptionConverter.get("@type");
ExceptionConverter converter = null;
try {
converter = (ExceptionConverter)TypeUtil.newInstance(type);
exceptionConverters.add(converter);
} catch (Exception e) {
throw new GraniteConfigException("Could not construct exception converter: " + type, e);
}
}
}
private void loadCustomTideComponents(XMap element, boolean custom) {
for (XMap component : element.getAll("tide-components/tide-component")) {
boolean disabled = Boolean.TRUE.toString().equals(component.get("@disabled"));
String type = component.get("@type");
if (type != null)
tideComponentMatchers.add(TIDE_COMPONENT_MATCHER_FACTORY.getTypeMatcher(type, disabled));
else {
String name = component.get("@name");
if (name != null)
tideComponentMatchers.add(TIDE_COMPONENT_MATCHER_FACTORY.getNameMatcher(name, disabled));
else {
String instanceOf = component.get("@instance-of");
if (instanceOf != null)
tideComponentMatchers.add(TIDE_COMPONENT_MATCHER_FACTORY.getInstanceOfMatcher(instanceOf, disabled));
else {
String annotatedWith = component.get("@annotated-with");
if (annotatedWith == null)
throw new GraniteConfigException(
"Element 'component' has no attribute 'type', 'name', 'instance-of' or 'annotated-with'");
tideComponentMatchers.add(TIDE_COMPONENT_MATCHER_FACTORY.getAnnotatedWithMatcher(annotatedWith, disabled));
}
}
}
}
}
private void loadCustomSecurity(XMap element, boolean custom) {
XMap security = element.getOne("security");
if (security != null) {
String type = security.get("@type");
try {
securityService = (SecurityService)TypeUtil.newInstance(type);
} catch (Exception e) {
throw new GraniteConfigException("Could not instantiate SecurityService: " + type, e);
}
Map<String, String> params = new HashMap<String, String>();
for (XMap param : security.getAll("param")) {
String name = param.get("@name");
String value = param.get("@value");
params.put(name, value);
}
try {
securityService.configure(params);
} catch (Exception e) {
throw new GraniteConfigException("Could not configure SecurityService " + type + " with: " + params, e);
}
}
}
public void setSecurityService(SecurityService securityService) {
this.securityService = securityService;
}
private void loadCustomMessageSelector(XMap element, boolean custom) {
XMap selector = element.getOne("message-selector");
if (selector != null) {
String type = selector.get("@type");
try {
messageSelectorConstructor = TypeUtil.getConstructor(type, new Class<?>[]{ String.class });
} catch (Exception e) {
throw new GraniteConfigException("Could not construct message selector: " + type, e);
}
}
}
private void loadCustomGravity(XMap element, boolean custom) {
gravityConfig = element.getOne("gravity");
}
///////////////////////////////////////////////////////////////////////////
// Other helpers.
@SuppressWarnings("unchecked")
private <T, C extends Config> T getElementByType(
String type,
ConfigurableFactory<T, C> factory,
ConcurrentHashMap<String, T> elementsByType,
Map<String, String> elementsByInstanceOf,
Map<String, String> elementsByAnnotatedWith,
List<T> scannedConfigurables) {
// This NULL object is a Java null placeholder: ConcurrentHashMap doesn't allow
// null values...
final T NULL = factory.getNullInstance();
T element = elementsByType.get(type);
if (element != null)
return (NULL == element ? null : element);
element = NULL;
Class<?> typeClass = null;
try {
typeClass = TypeUtil.forName(type);
} catch (Exception e) {
throw new GraniteConfigException("Could not load class: " + type, e);
}
if (elementsByAnnotatedWith != null && NULL == element) {
for (Map.Entry<String, String> entry : elementsByAnnotatedWith.entrySet()) {
String annotation = entry.getKey();
try {
Class<Annotation> annotationClass = TypeUtil.forName(annotation, Annotation.class);
if (typeClass.isAnnotationPresent(annotationClass)) {
element = factory.getInstance(entry.getValue(), (C)this);
break;
}
} catch (Exception e) {
throw new GraniteConfigException("Could not load class: " + annotation, e);
}
}
}
if (elementsByInstanceOf != null && NULL == element) {
for (Map.Entry<String, String> entry : elementsByInstanceOf.entrySet()) {
String instanceOf = entry.getKey();
try {
Class<?> instanceOfClass = TypeUtil.forName(instanceOf);
if (instanceOfClass.isAssignableFrom(typeClass)) {
element = factory.getInstance(entry.getValue(), (C)this);
break;
}
} catch (Exception e) {
throw new GraniteConfigException("Could not load class: " + instanceOf, e);
}
}
}
if (NULL == element)
element = factory.getInstanceForBean(scannedConfigurables, typeClass, (C)this);
T previous = elementsByType.putIfAbsent(type, element);
if (previous != null)
element = previous;
return (NULL == element ? null : element);
}
}