/* * Copyright 2002-2011 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.flex.core.io; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.converter.Converter; import org.springframework.core.convert.converter.ConverterRegistry; import org.springframework.core.convert.support.GenericConversionService; import org.springframework.flex.config.MessageBrokerConfigProcessor; import flex.messaging.MessageBroker; import flex.messaging.io.PropertyProxy; import flex.messaging.io.PropertyProxyRegistry; /** * Base {@link MessageBrokerConfigProcessor} implementation that installs an alternative {@link PropertyProxy} implementation for * enhanced serialization and deserialization of specific types. The alternative implementation uses Sping's {@link ConversionService} * to allow specialized conversion of certain property types and is more flexible in the types it can handle. * * <p> * The installed {@code SpringPropertyProxy} instances may be configured to use field-based property access (instead of requiring getters and setters) by * setting the {@link AbstractAmfConversionServiceConfigProcessor#setUseDirectFieldAccess(boolean) useDirectFieldAccess} property to {@code true}. Additionally, * types that do not have a default no-arg constructur can be handled, as long as they provide a constructor annotated with {@link AmfCreator}. * * <p> * Subclasses are expected to supply their own mechanisms for determining the list of types to register and may apply additional configuration of the * {@code ConversionService}, such as provisioning additional custom {@link Converter Converters}. * * @see SpringPropertyProxy * * @author Jeremy Grelle */ public abstract class AbstractAmfConversionServiceConfigProcessor implements MessageBrokerConfigProcessor, InitializingBean { protected final Log log = LogFactory.getLog(getClass()); private ConversionService conversionService; private boolean useDirectFieldAccess = false; /** * * {@inheritDoc} */ public void afterPropertiesSet() throws Exception { this.conversionService = conversionService != null ? conversionService : getDefaultConversionService(); } /** * * {@inheritDoc} */ public final MessageBroker processAfterStartup(MessageBroker broker) { registerAmfProxies(this.conversionService, this.useDirectFieldAccess); return broker; } /** * * {@inheritDoc} */ public final MessageBroker processBeforeStartup(MessageBroker broker) { return broker; } /** * Sets the {@link ConversionService} implementation to be used by all registered {@link SpringPropertyProxy} instances. * @param conversionService the conversion service to be used */ public void setConversionService(ConversionService conversionService) { this.conversionService = conversionService; } /** * When true, configures the registered {@link SpringPropertyProxy} instances to access fields directly, rather than * requiring strict JavaBean compliance. Defaults to false. * * @param useDirectFieldAccess determines whether fields should be accessed directly. */ public void setUseDirectFieldAccess(boolean useDirectFieldAccess) { this.useDirectFieldAccess = useDirectFieldAccess; } /** * Called during initialization, the default implementation configures and registers a {@link SpringPropertyProxy} instance * for each type returned by {@link AbstractAmfConversionServiceConfigProcessor#findTypesToRegister() findTypesToRegister}. * @param conversionService the conversion service to be used for property conversion * @param useDirectFieldAccess determines whether fields should be accessed directly */ protected void registerAmfProxies(ConversionService conversionService, boolean useDirectFieldAccess) { Set<Class<?>> typesToRegister = findTypesToRegister(); if (log.isInfoEnabled()) { log.info("Types detected for AMF serialization support: "+typesToRegister.toString()); } for (Class<?> type : typesToRegister) { registerPropertyProxy(SpringPropertyProxy.proxyFor(type, useDirectFieldAccess, conversionService)); } } /** * Registers the given {@link SpringPropertyProxy} with the BlazeDS {@link PropertyProxyRegistry}. * @param proxy the property proxy to register */ protected void registerPropertyProxy(SpringPropertyProxy proxy) { PropertyProxyRegistry.getRegistry().register(proxy.getBeanType(), proxy); } /** * Returns the set of types for which {@link SpringPropertyProxy} instances should be registered. * @return the set of types to register */ protected abstract Set<Class<?>> findTypesToRegister(); /** * Template method to allow subclasses to configure their own set of {@link Converter} instances. This is a * convenient alternative to supplying a completely custom-configured {@link ConversionService} instance. * * <p> * The default implementation does not register any additional {@link Converter Converters}, thus subclasses do not need to delegate to it. * * @param registry - the converter registry used by the {@link ConversionService} */ protected void configureConverters(ConverterRegistry registry) { //default no-op } private ConversionService getDefaultConversionService() { GenericConversionService conversionService = new GenericConversionService(); configureConverters(conversionService); conversionService.addConverter(new NumberConverter()); return conversionService; } }