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.spring; 022 023import java.util.ArrayList; 024import java.util.HashMap; 025import java.util.List; 026import java.util.Map; 027 028import javax.servlet.ServletContext; 029import javax.servlet.http.HttpServletRequest; 030import javax.servlet.http.HttpServletResponse; 031 032import org.granite.config.GraniteConfig; 033import org.granite.config.flex.Channel; 034import org.granite.config.flex.Destination; 035import org.granite.config.flex.EndPoint; 036import org.granite.config.flex.Factory; 037import org.granite.config.flex.Service; 038import org.granite.config.flex.ServicesConfig; 039import org.granite.logging.Logger; 040import org.granite.messaging.amf.io.convert.Converter; 041import org.granite.messaging.amf.process.AMF3MessageInterceptor; 042import org.granite.messaging.service.ExceptionConverter; 043import org.granite.messaging.service.security.RemotingDestinationSecurizer; 044import org.granite.messaging.service.security.SecurityService; 045import org.granite.messaging.service.tide.TideComponentAnnotatedWithMatcher; 046import org.granite.messaging.service.tide.TideComponentInstanceOfMatcher; 047import org.granite.messaging.service.tide.TideComponentNameMatcher; 048import org.granite.messaging.service.tide.TideComponentTypeMatcher; 049import org.granite.messaging.webapp.AMFEndpoint; 050import org.granite.util.TypeUtil; 051import org.granite.util.XMap; 052import org.springframework.beans.BeansException; 053import org.springframework.beans.factory.DisposableBean; 054import org.springframework.beans.factory.InitializingBean; 055import org.springframework.beans.factory.annotation.Autowired; 056import org.springframework.context.ApplicationContext; 057import org.springframework.context.ApplicationContextAware; 058import org.springframework.web.context.ServletContextAware; 059import org.springframework.web.servlet.HandlerAdapter; 060import org.springframework.web.servlet.ModelAndView; 061 062 063public class ServerFilter implements InitializingBean, DisposableBean, ApplicationContextAware, ServletContextAware, HandlerAdapter { 064 065 private static final Logger log = Logger.getLogger(ServerFilter.class); 066 067 @Autowired(required=false) 068 private ServletContext servletContext = null; 069 private ApplicationContext context = null; 070 071 private GraniteConfig graniteConfig = null; 072 private ServicesConfig servicesConfig = null; 073 074 private List<String> tideRoles = null; 075 private List<String> tideAnnotations = null; 076 private List<String> tideInterfaces = null; 077 private List<String> tideNames = null; 078 private List<String> tideTypes = null; 079 private List<Class<? extends ExceptionConverter>> exceptionConverters = null; 080 private AMF3MessageInterceptor amf3MessageInterceptor; 081 private boolean tide = false; 082 private String type = "server"; 083 084 private AMFEndpoint amfEndpoint = null; 085 086 public void setApplicationContext(ApplicationContext context) throws BeansException { 087 this.context = context; 088 } 089 090 public void setServletContext(ServletContext servletContext) throws BeansException { 091 this.servletContext = servletContext; 092 } 093 094 public void afterPropertiesSet() { 095 SpringGraniteConfig springGraniteConfig = context.getBeansOfType(SpringGraniteConfig.class).values().iterator().next(); 096 097 this.graniteConfig = springGraniteConfig.getGraniteConfig(); 098 099 Map<String, SecurityService> securityServices = context.getBeansOfType(SecurityService.class); 100 if (securityServices.size() > 1) 101 log.error("More than one Security Service bean defined"); 102 else if (!securityServices.isEmpty()) { 103 log.debug("Security Service bean " + securityServices.keySet().iterator().next() + " selected"); 104 SecurityService securityService = securityServices.values().iterator().next(); 105 this.graniteConfig.setSecurityService(securityService); 106 } 107 108 if (tideAnnotations != null) { 109 for (String ta : tideAnnotations) { 110 try { 111 this.graniteConfig.getTideComponentMatchers().add(new TideComponentAnnotatedWithMatcher(ta, false)); 112 log.debug("Enabled components annotated with %s for Tide remoting", ta); 113 } 114 catch (Exception e) { 115 log.error(e, "Could not add tide-component annotation %s", ta); 116 } 117 } 118 } 119 if (tideInterfaces != null) { 120 for (String ti : tideInterfaces) { 121 try { 122 this.graniteConfig.getTideComponentMatchers().add(new TideComponentInstanceOfMatcher(ti, false)); 123 log.debug("Enabled components extending %s for Tide remoting", ti); 124 } 125 catch (Exception e) { 126 log.error(e, "Could not add tide-component interface %s", ti); 127 } 128 } 129 } 130 if (tideNames != null) { 131 for (String tn : tideNames) { 132 try { 133 this.graniteConfig.getTideComponentMatchers().add(new TideComponentNameMatcher(tn, false)); 134 log.debug("Enabled components named like %s for Tide remoting", tn); 135 } 136 catch (Exception e) { 137 log.error(e, "Could not add tide-component name %s", tn); 138 } 139 } 140 } 141 if (tideTypes != null) { 142 for (String tt : tideTypes) { 143 try { 144 this.graniteConfig.getTideComponentMatchers().add(new TideComponentTypeMatcher(tt, false)); 145 log.debug("Enabled components with type %s for Tide remoting", tt); 146 } 147 catch (Exception e) { 148 log.error(e, "Could not add tide-component type %s", tt); 149 } 150 } 151 } 152 if (exceptionConverters != null) { 153 for (Class<? extends ExceptionConverter> ec : exceptionConverters) { 154 this.graniteConfig.registerExceptionConverter(ec); 155 log.debug("Registered exception converter %s", ec); 156 } 157 } 158 if (amf3MessageInterceptor != null) 159 this.graniteConfig.setAmf3MessageInterceptor(amf3MessageInterceptor); 160 161 // If Spring Data available, automatically enable Page/Pageable converter 162 try { 163 TypeUtil.forName("org.springframework.data.domain.Page"); 164 Class<Converter> converterClass = TypeUtil.forName("org.granite.spring.data.PageableConverter", Converter.class); 165 this.graniteConfig.getConverters().addConverter(converterClass); 166 } 167 catch (Exception e) { 168 // Spring Data not present, ignore 169 } 170 171 servicesConfig = springGraniteConfig.getServicesConfig(); 172 173 Channel channel = servicesConfig.findChannelById("graniteamf"); 174 if (channel == null) { 175 channel = new Channel("graniteamf", "mx.messaging.channels.AMFChannel", 176 new EndPoint("http://{server.name}:{server.port}/{context.root}/graniteamf/amf", "flex.messaging.endpoints.AMFEndpoint"), 177 new XMap()); 178 servicesConfig.addChannel(channel); 179 } 180 181 if (tide) { 182 Factory factory = servicesConfig.findFactoryById("tide-spring-factory"); 183 if (factory == null) { 184 factory = new Factory("tide-spring-factory", "org.granite.tide.spring.SpringServiceFactory", new XMap()); 185 servicesConfig.addFactory(factory); 186 } 187 188 Service service = servicesConfig.findServiceById("granite-service"); 189 if (service == null) { 190 service = new Service("granite-service", "flex.messaging.services.RemotingService", 191 "flex.messaging.messages.RemotingMessage", null, null, new HashMap<String, Destination>()); 192 } 193 Destination destination = servicesConfig.findDestinationById("flex.messaging.messages.RemotingMessage", type); 194 if (destination == null) { 195 List<String> channelIds = new ArrayList<String>(); 196 channelIds.add("graniteamf"); 197 destination = new Destination(type, channelIds, new XMap(), tideRoles, null, null); 198 destination.getProperties().put("factory", factory.getId()); 199 destination.getProperties().put("validator-name", "tideValidator"); 200 service.getDestinations().put(destination.getId(), destination); 201 servicesConfig.addService(service); 202 } 203 204 if (destination.getSecurizer() == null) { 205 Map<String, RemotingDestinationSecurizer> securizers = context.getBeansOfType(RemotingDestinationSecurizer.class); 206 if (securizers.size() > 1) 207 log.error("More than one Remoting Destination Securizer bean defined"); 208 else if (!securizers.isEmpty()) { 209 log.debug("Remoting Destination Securizer bean " + securizers.keySet().iterator().next() + " selected"); 210 RemotingDestinationSecurizer securizer = securizers.values().iterator().next(); 211 destination.setSecurizer(securizer); 212 } 213 } 214 215 log.info("Registered Tide/Spring service factory and destination %s", type); 216 } 217 else { 218 Factory factory = servicesConfig.findFactoryById("spring-factory"); 219 if (factory == null) { 220 factory = new Factory("spring-factory", "org.granite.spring.SpringServiceFactory", new XMap()); 221 servicesConfig.addFactory(factory); 222 } 223 224 Service service = servicesConfig.findServiceById("granite-service"); 225 if (service == null) { 226 service = new Service("granite-service", "flex.messaging.services.RemotingService", 227 "flex.messaging.messages.RemotingMessage", null, null, new HashMap<String, Destination>()); 228 servicesConfig.addService(service); 229 } 230 231 servicesConfig.scan(null); 232 233 log.info("Registered Spring service factory"); 234 } 235 236 amfEndpoint = new AMFEndpoint(); 237 amfEndpoint.init(servletContext); 238 } 239 240 public void destroy() throws Exception { 241 amfEndpoint.destroy(); 242 amfEndpoint = null; 243 } 244 245 public void setTideRoles(List<String> tideRoles) { 246 this.tideRoles = tideRoles; 247 } 248 249 public void setTideAnnotations(List<String> tideAnnotations) { 250 this.tideAnnotations = tideAnnotations; 251 } 252 253 public void setTideInterfaces(List<String> tideInterfaces) { 254 this.tideInterfaces = tideInterfaces; 255 } 256 257 public void setTideNames(List<String> tideNames) { 258 this.tideNames = tideNames; 259 } 260 261 public void setTideTypes(List<String> tideTypes) { 262 this.tideTypes = tideTypes; 263 } 264 265 public void setExceptionConverters(List<Class<? extends ExceptionConverter>> exceptionConverters) { 266 this.exceptionConverters = exceptionConverters; 267 } 268 269 public void setAmf3MessageInterceptor(AMF3MessageInterceptor amf3MessageInterceptor) { 270 this.amf3MessageInterceptor = amf3MessageInterceptor; 271 } 272 273 public void setTide(boolean tide) { 274 this.tide = tide; 275 } 276 277 public void setType(String type) { 278 this.type = type; 279 } 280 281 282 public long getLastModified(HttpServletRequest request, Object handler) { 283 return -1; 284 } 285 286 public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { 287 amfEndpoint.service(graniteConfig, servicesConfig, servletContext, request, response); 288 return null; 289 } 290 291 public boolean supports(Object handler) { 292 return handler instanceof ServerFilter; 293 } 294}