/**
* 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.spring;
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 javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.granite.config.GraniteConfig;
import org.granite.config.flex.Channel;
import org.granite.config.flex.Destination;
import org.granite.config.flex.EndPoint;
import org.granite.config.flex.Factory;
import org.granite.config.flex.Service;
import org.granite.config.flex.ServicesConfig;
import org.granite.logging.Logger;
import org.granite.messaging.amf.io.convert.Converter;
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.process.AMF3MessageInterceptor;
import org.granite.messaging.service.ExceptionConverter;
import org.granite.messaging.service.security.RemotingDestinationSecurizer;
import org.granite.messaging.service.security.SecurityService;
import org.granite.messaging.service.tide.TideComponentAnnotatedWithMatcher;
import org.granite.messaging.service.tide.TideComponentInstanceOfMatcher;
import org.granite.messaging.service.tide.TideComponentNameMatcher;
import org.granite.messaging.service.tide.TideComponentTypeMatcher;
import org.granite.messaging.webapp.AMFEndpoint;
import org.granite.util.TypeUtil;
import org.granite.util.XMap;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.web.context.ServletContextAware;
import org.springframework.web.servlet.HandlerAdapter;
import org.springframework.web.servlet.ModelAndView;
public class ServerFilter implements InitializingBean, DisposableBean, ApplicationContextAware, ServletContextAware, HandlerAdapter {
private static final Logger log = Logger.getLogger(ServerFilter.class);
@Autowired(required=false)
private ServletContext servletContext = null;
private ApplicationContext context = null;
private GraniteConfig graniteConfig = null;
private ServicesConfig servicesConfig = null;
private List<String> tideRoles = null;
private List<String> tideAnnotations = null;
private List<String> tideInterfaces = null;
private List<String> tideNames = null;
private List<String> tideTypes = null;
private List<Class<? extends ExceptionConverter>> exceptionConverters = null;
private AMF3MessageInterceptor amf3MessageInterceptor;
private boolean useLong = false;
private boolean useBigInteger = false;
private boolean useBigDecimal = false;
private boolean enableExceptionLogging = true;
private boolean tide = false;
private String type = "server";
private AMFEndpoint amfEndpoint = null;
public void setApplicationContext(ApplicationContext context) throws BeansException {
this.context = context;
}
public void setServletContext(ServletContext servletContext) throws BeansException {
this.servletContext = servletContext;
}
public void afterPropertiesSet() {
SpringGraniteConfig springGraniteConfig = context.getBeansOfType(SpringGraniteConfig.class).values().iterator().next();
this.graniteConfig = springGraniteConfig.getGraniteConfig();
Map<String, SecurityService> securityServices = context.getBeansOfType(SecurityService.class);
if (securityServices.size() > 1)
log.error("More than one Security Service bean defined");
else if (!securityServices.isEmpty()) {
log.debug("Security Service bean " + securityServices.keySet().iterator().next() + " selected");
SecurityService securityService = securityServices.values().iterator().next();
this.graniteConfig.setSecurityService(securityService);
}
Map<String, Externalizer> externalizers = context.getBeansOfType(Externalizer.class);
for (Externalizer externalizer : externalizers.values())
this.graniteConfig.registerExternalizer(externalizer);
if (useBigDecimal)
graniteConfig.setExternalizersByType(BigDecimal.class.getName(), BigDecimalExternalizer.class.getName());
if (useBigInteger)
graniteConfig.setExternalizersByType(BigInteger.class.getName(), BigIntegerExternalizer.class.getName());
if (useLong)
graniteConfig.setExternalizersByType(Long.class.getName(), LongExternalizer.class.getName());
if (tideAnnotations != null) {
for (String ta : tideAnnotations) {
try {
this.graniteConfig.getTideComponentMatchers().add(new TideComponentAnnotatedWithMatcher(ta, false));
log.debug("Enabled components annotated with %s for Tide remoting", ta);
}
catch (Exception e) {
log.error(e, "Could not add tide-component annotation %s", ta);
}
}
}
if (tideInterfaces != null) {
for (String ti : tideInterfaces) {
try {
this.graniteConfig.getTideComponentMatchers().add(new TideComponentInstanceOfMatcher(ti, false));
log.debug("Enabled components extending %s for Tide remoting", ti);
}
catch (Exception e) {
log.error(e, "Could not add tide-component interface %s", ti);
}
}
}
if (tideNames != null) {
for (String tn : tideNames) {
try {
this.graniteConfig.getTideComponentMatchers().add(new TideComponentNameMatcher(tn, false));
log.debug("Enabled components named like %s for Tide remoting", tn);
}
catch (Exception e) {
log.error(e, "Could not add tide-component name %s", tn);
}
}
}
if (tideTypes != null) {
for (String tt : tideTypes) {
try {
this.graniteConfig.getTideComponentMatchers().add(new TideComponentTypeMatcher(tt, false));
log.debug("Enabled components with type %s for Tide remoting", tt);
}
catch (Exception e) {
log.error(e, "Could not add tide-component type %s", tt);
}
}
}
if (exceptionConverters != null) {
for (Class<? extends ExceptionConverter> ec : exceptionConverters) {
this.graniteConfig.registerExceptionConverter(ec);
log.debug("Registered exception converter %s", ec);
}
}
if (amf3MessageInterceptor != null)
this.graniteConfig.setAmf3MessageInterceptor(amf3MessageInterceptor);
// If Spring Data available, automatically enable Page/Pageable converter
try {
TypeUtil.forName("org.springframework.data.domain.Page");
Class<Converter> converterClass = TypeUtil.forName("org.granite.spring.data.PageableConverter", Converter.class);
this.graniteConfig.getConverters().addConverter(converterClass);
}
catch (Exception e) {
// Spring Data not present, ignore
}
servicesConfig = springGraniteConfig.getServicesConfig();
Channel channel = servicesConfig.findChannelById("graniteamf");
if (channel == null) {
channel = new Channel("graniteamf", "mx.messaging.channels.AMFChannel",
new EndPoint("http://{server.name}:{server.port}/{context.root}/graniteamf/amf", "flex.messaging.endpoints.AMFEndpoint"),
new XMap());
servicesConfig.addChannel(channel);
}
if (tide) {
Factory factory = servicesConfig.findFactoryById("tide-spring-factory");
if (factory == null) {
XMap factoryProperties = new XMap();
factoryProperties.put("enable-exception-logging", String.valueOf(enableExceptionLogging));
factory = new Factory("tide-spring-factory", "org.granite.tide.spring.SpringServiceFactory", factoryProperties);
servicesConfig.addFactory(factory);
}
Service service = servicesConfig.findServiceById("granite-service");
if (service == null) {
service = new Service("granite-service", "flex.messaging.services.RemotingService",
"flex.messaging.messages.RemotingMessage", null, null, new HashMap<String, Destination>());
}
Destination destination = servicesConfig.findDestinationById("flex.messaging.messages.RemotingMessage", type);
if (destination == null) {
List<String> channelIds = new ArrayList<String>();
channelIds.add("graniteamf");
destination = new Destination(type, channelIds, new XMap(), tideRoles, null, null);
destination.getProperties().put("factory", factory.getId());
destination.getProperties().put("validator-name", "tideValidator");
service.getDestinations().put(destination.getId(), destination);
servicesConfig.addService(service);
}
if (destination.getSecurizer() == null) {
Map<String, RemotingDestinationSecurizer> securizers = context.getBeansOfType(RemotingDestinationSecurizer.class);
if (securizers.size() > 1)
log.error("More than one Remoting Destination Securizer bean defined");
else if (!securizers.isEmpty()) {
log.debug("Remoting Destination Securizer bean " + securizers.keySet().iterator().next() + " selected");
RemotingDestinationSecurizer securizer = securizers.values().iterator().next();
destination.setSecurizer(securizer);
}
}
log.info("Registered Tide/Spring service factory and destination %s", type);
}
else {
Factory factory = servicesConfig.findFactoryById("spring-factory");
if (factory == null) {
XMap factoryProperties = new XMap();
factoryProperties.put("enable-exception-logging", String.valueOf(enableExceptionLogging));
factory = new Factory("spring-factory", "org.granite.spring.SpringServiceFactory", factoryProperties);
servicesConfig.addFactory(factory);
}
Service service = servicesConfig.findServiceById("granite-service");
if (service == null) {
service = new Service("granite-service", "flex.messaging.services.RemotingService",
"flex.messaging.messages.RemotingMessage", null, null, new HashMap<String, Destination>());
servicesConfig.addService(service);
}
servicesConfig.scan(null);
log.info("Registered Spring service factory");
}
amfEndpoint = new AMFEndpoint();
amfEndpoint.init(servletContext);
}
public void destroy() throws Exception {
amfEndpoint.destroy();
amfEndpoint = null;
}
public void setTideRoles(List<String> tideRoles) {
this.tideRoles = tideRoles;
}
public void setTideAnnotations(List<String> tideAnnotations) {
this.tideAnnotations = tideAnnotations;
}
public void setTideInterfaces(List<String> tideInterfaces) {
this.tideInterfaces = tideInterfaces;
}
public void setTideNames(List<String> tideNames) {
this.tideNames = tideNames;
}
public void setTideTypes(List<String> tideTypes) {
this.tideTypes = tideTypes;
}
public void setExceptionConverters(List<Class<? extends ExceptionConverter>> exceptionConverters) {
this.exceptionConverters = exceptionConverters;
}
public void setAmf3MessageInterceptor(AMF3MessageInterceptor amf3MessageInterceptor) {
this.amf3MessageInterceptor = amf3MessageInterceptor;
}
public void setUseLong(boolean useLong) {
this.useLong = useLong;
}
public void setUseBigInteger(boolean useBigInteger) {
this.useBigInteger = useBigInteger;
}
public void setUseBigDecimal(boolean useBigDecimal) {
this.useBigDecimal = useBigDecimal;
}
public void setEnableExceptionLogging(boolean enableLogging) {
this.enableExceptionLogging = enableLogging;
}
public void setTide(boolean tide) {
this.tide = tide;
}
public void setType(String type) {
this.type = type;
}
public long getLastModified(HttpServletRequest request, Object handler) {
return -1;
}
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
amfEndpoint.service(graniteConfig, servicesConfig, servletContext, request, response);
return null;
}
public boolean supports(Object handler) {
return handler instanceof ServerFilter;
}
}