001/** 002 * GRANITE DATA SERVICES 003 * Copyright (C) 2006-2013 GRANITE DATA SERVICES S.A.S. 004 * 005 * This file is part of the Granite Data Services Platform. 006 * 007 * Granite Data Services is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * Granite Data Services is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 015 * General Public License for more details. 016 * 017 * You should have received a copy of the GNU Lesser General Public 018 * License along with this library; if not, write to the Free Software 019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 020 * USA, or see <http://www.gnu.org/licenses/>. 021 */ 022package org.granite.spring; 023 024import java.math.BigDecimal; 025import java.math.BigInteger; 026import java.util.ArrayList; 027import java.util.HashMap; 028import java.util.List; 029import java.util.Map; 030 031import javax.servlet.ServletContext; 032import javax.servlet.http.HttpServletRequest; 033import javax.servlet.http.HttpServletResponse; 034 035import org.granite.config.GraniteConfig; 036import org.granite.config.flex.Channel; 037import org.granite.config.flex.Destination; 038import org.granite.config.flex.EndPoint; 039import org.granite.config.flex.Factory; 040import org.granite.config.flex.Service; 041import org.granite.config.flex.ServicesConfig; 042import org.granite.logging.Logger; 043import org.granite.messaging.amf.io.convert.Converter; 044import org.granite.messaging.amf.io.util.externalizer.BigDecimalExternalizer; 045import org.granite.messaging.amf.io.util.externalizer.BigIntegerExternalizer; 046import org.granite.messaging.amf.io.util.externalizer.Externalizer; 047import org.granite.messaging.amf.io.util.externalizer.LongExternalizer; 048import org.granite.messaging.amf.process.AMF3MessageInterceptor; 049import org.granite.messaging.service.ExceptionConverter; 050import org.granite.messaging.service.security.RemotingDestinationSecurizer; 051import org.granite.messaging.service.security.SecurityService; 052import org.granite.messaging.service.tide.TideComponentAnnotatedWithMatcher; 053import org.granite.messaging.service.tide.TideComponentInstanceOfMatcher; 054import org.granite.messaging.service.tide.TideComponentNameMatcher; 055import org.granite.messaging.service.tide.TideComponentTypeMatcher; 056import org.granite.messaging.webapp.AMFEndpoint; 057import org.granite.util.TypeUtil; 058import org.granite.util.XMap; 059import org.springframework.beans.BeansException; 060import org.springframework.beans.factory.DisposableBean; 061import org.springframework.beans.factory.InitializingBean; 062import org.springframework.beans.factory.annotation.Autowired; 063import org.springframework.context.ApplicationContext; 064import org.springframework.context.ApplicationContextAware; 065import org.springframework.web.context.ServletContextAware; 066import org.springframework.web.servlet.HandlerAdapter; 067import org.springframework.web.servlet.ModelAndView; 068 069 070public class ServerFilter implements InitializingBean, DisposableBean, ApplicationContextAware, ServletContextAware, HandlerAdapter { 071 072 private static final Logger log = Logger.getLogger(ServerFilter.class); 073 074 @Autowired(required=false) 075 private ServletContext servletContext = null; 076 private ApplicationContext context = null; 077 078 private GraniteConfig graniteConfig = null; 079 private ServicesConfig servicesConfig = null; 080 081 private List<String> tideRoles = null; 082 private List<String> tideAnnotations = null; 083 private List<String> tideInterfaces = null; 084 private List<String> tideNames = null; 085 private List<String> tideTypes = null; 086 private List<Class<? extends ExceptionConverter>> exceptionConverters = null; 087 private AMF3MessageInterceptor amf3MessageInterceptor; 088 private boolean useLong = false; 089 private boolean useBigInteger = false; 090 private boolean useBigDecimal = false; 091 private boolean tide = false; 092 private String type = "server"; 093 094 private AMFEndpoint amfEndpoint = null; 095 096 public void setApplicationContext(ApplicationContext context) throws BeansException { 097 this.context = context; 098 } 099 100 public void setServletContext(ServletContext servletContext) throws BeansException { 101 this.servletContext = servletContext; 102 } 103 104 public void afterPropertiesSet() { 105 SpringGraniteConfig springGraniteConfig = context.getBeansOfType(SpringGraniteConfig.class).values().iterator().next(); 106 107 this.graniteConfig = springGraniteConfig.getGraniteConfig(); 108 109 Map<String, SecurityService> securityServices = context.getBeansOfType(SecurityService.class); 110 if (securityServices.size() > 1) 111 log.error("More than one Security Service bean defined"); 112 else if (!securityServices.isEmpty()) { 113 log.debug("Security Service bean " + securityServices.keySet().iterator().next() + " selected"); 114 SecurityService securityService = securityServices.values().iterator().next(); 115 this.graniteConfig.setSecurityService(securityService); 116 } 117 118 Map<String, Externalizer> externalizers = context.getBeansOfType(Externalizer.class); 119 for (Externalizer externalizer : externalizers.values()) 120 this.graniteConfig.registerExternalizer(externalizer); 121 122 if (useBigDecimal) 123 graniteConfig.setExternalizersByType(BigDecimal.class.getName(), BigDecimalExternalizer.class.getName()); 124 125 if (useBigInteger) 126 graniteConfig.setExternalizersByType(BigInteger.class.getName(), BigIntegerExternalizer.class.getName()); 127 128 if (useLong) 129 graniteConfig.setExternalizersByType(Long.class.getName(), LongExternalizer.class.getName()); 130 131 if (tideAnnotations != null) { 132 for (String ta : tideAnnotations) { 133 try { 134 this.graniteConfig.getTideComponentMatchers().add(new TideComponentAnnotatedWithMatcher(ta, false)); 135 log.debug("Enabled components annotated with %s for Tide remoting", ta); 136 } 137 catch (Exception e) { 138 log.error(e, "Could not add tide-component annotation %s", ta); 139 } 140 } 141 } 142 if (tideInterfaces != null) { 143 for (String ti : tideInterfaces) { 144 try { 145 this.graniteConfig.getTideComponentMatchers().add(new TideComponentInstanceOfMatcher(ti, false)); 146 log.debug("Enabled components extending %s for Tide remoting", ti); 147 } 148 catch (Exception e) { 149 log.error(e, "Could not add tide-component interface %s", ti); 150 } 151 } 152 } 153 if (tideNames != null) { 154 for (String tn : tideNames) { 155 try { 156 this.graniteConfig.getTideComponentMatchers().add(new TideComponentNameMatcher(tn, false)); 157 log.debug("Enabled components named like %s for Tide remoting", tn); 158 } 159 catch (Exception e) { 160 log.error(e, "Could not add tide-component name %s", tn); 161 } 162 } 163 } 164 if (tideTypes != null) { 165 for (String tt : tideTypes) { 166 try { 167 this.graniteConfig.getTideComponentMatchers().add(new TideComponentTypeMatcher(tt, false)); 168 log.debug("Enabled components with type %s for Tide remoting", tt); 169 } 170 catch (Exception e) { 171 log.error(e, "Could not add tide-component type %s", tt); 172 } 173 } 174 } 175 if (exceptionConverters != null) { 176 for (Class<? extends ExceptionConverter> ec : exceptionConverters) { 177 this.graniteConfig.registerExceptionConverter(ec); 178 log.debug("Registered exception converter %s", ec); 179 } 180 } 181 if (amf3MessageInterceptor != null) 182 this.graniteConfig.setAmf3MessageInterceptor(amf3MessageInterceptor); 183 184 // If Spring Data available, automatically enable Page/Pageable converter 185 try { 186 TypeUtil.forName("org.springframework.data.domain.Page"); 187 Class<Converter> converterClass = TypeUtil.forName("org.granite.spring.data.PageableConverter", Converter.class); 188 this.graniteConfig.getConverters().addConverter(converterClass); 189 } 190 catch (Exception e) { 191 // Spring Data not present, ignore 192 } 193 194 servicesConfig = springGraniteConfig.getServicesConfig(); 195 196 Channel channel = servicesConfig.findChannelById("graniteamf"); 197 if (channel == null) { 198 channel = new Channel("graniteamf", "mx.messaging.channels.AMFChannel", 199 new EndPoint("http://{server.name}:{server.port}/{context.root}/graniteamf/amf", "flex.messaging.endpoints.AMFEndpoint"), 200 new XMap()); 201 servicesConfig.addChannel(channel); 202 } 203 204 if (tide) { 205 Factory factory = servicesConfig.findFactoryById("tide-spring-factory"); 206 if (factory == null) { 207 factory = new Factory("tide-spring-factory", "org.granite.tide.spring.SpringServiceFactory", new XMap()); 208 servicesConfig.addFactory(factory); 209 } 210 211 Service service = servicesConfig.findServiceById("granite-service"); 212 if (service == null) { 213 service = new Service("granite-service", "flex.messaging.services.RemotingService", 214 "flex.messaging.messages.RemotingMessage", null, null, new HashMap<String, Destination>()); 215 } 216 Destination destination = servicesConfig.findDestinationById("flex.messaging.messages.RemotingMessage", type); 217 if (destination == null) { 218 List<String> channelIds = new ArrayList<String>(); 219 channelIds.add("graniteamf"); 220 destination = new Destination(type, channelIds, new XMap(), tideRoles, null, null); 221 destination.getProperties().put("factory", factory.getId()); 222 destination.getProperties().put("validator-name", "tideValidator"); 223 service.getDestinations().put(destination.getId(), destination); 224 servicesConfig.addService(service); 225 } 226 227 if (destination.getSecurizer() == null) { 228 Map<String, RemotingDestinationSecurizer> securizers = context.getBeansOfType(RemotingDestinationSecurizer.class); 229 if (securizers.size() > 1) 230 log.error("More than one Remoting Destination Securizer bean defined"); 231 else if (!securizers.isEmpty()) { 232 log.debug("Remoting Destination Securizer bean " + securizers.keySet().iterator().next() + " selected"); 233 RemotingDestinationSecurizer securizer = securizers.values().iterator().next(); 234 destination.setSecurizer(securizer); 235 } 236 } 237 238 log.info("Registered Tide/Spring service factory and destination %s", type); 239 } 240 else { 241 Factory factory = servicesConfig.findFactoryById("spring-factory"); 242 if (factory == null) { 243 factory = new Factory("spring-factory", "org.granite.spring.SpringServiceFactory", new XMap()); 244 servicesConfig.addFactory(factory); 245 } 246 247 Service service = servicesConfig.findServiceById("granite-service"); 248 if (service == null) { 249 service = new Service("granite-service", "flex.messaging.services.RemotingService", 250 "flex.messaging.messages.RemotingMessage", null, null, new HashMap<String, Destination>()); 251 servicesConfig.addService(service); 252 } 253 254 servicesConfig.scan(null); 255 256 log.info("Registered Spring service factory"); 257 } 258 259 amfEndpoint = new AMFEndpoint(); 260 amfEndpoint.init(servletContext); 261 } 262 263 public void destroy() throws Exception { 264 amfEndpoint.destroy(); 265 amfEndpoint = null; 266 } 267 268 public void setTideRoles(List<String> tideRoles) { 269 this.tideRoles = tideRoles; 270 } 271 272 public void setTideAnnotations(List<String> tideAnnotations) { 273 this.tideAnnotations = tideAnnotations; 274 } 275 276 public void setTideInterfaces(List<String> tideInterfaces) { 277 this.tideInterfaces = tideInterfaces; 278 } 279 280 public void setTideNames(List<String> tideNames) { 281 this.tideNames = tideNames; 282 } 283 284 public void setTideTypes(List<String> tideTypes) { 285 this.tideTypes = tideTypes; 286 } 287 288 public void setExceptionConverters(List<Class<? extends ExceptionConverter>> exceptionConverters) { 289 this.exceptionConverters = exceptionConverters; 290 } 291 292 public void setAmf3MessageInterceptor(AMF3MessageInterceptor amf3MessageInterceptor) { 293 this.amf3MessageInterceptor = amf3MessageInterceptor; 294 } 295 296 public void setUseLong(boolean useLong) { 297 this.useLong = useLong; 298 } 299 300 public void setUseBigInteger(boolean useBigInteger) { 301 this.useBigInteger = useBigInteger; 302 } 303 304 public void setUseBigDecimal(boolean useBigDecimal) { 305 this.useBigDecimal = useBigDecimal; 306 } 307 308 public void setTide(boolean tide) { 309 this.tide = tide; 310 } 311 312 public void setType(String type) { 313 this.type = type; 314 } 315 316 317 public long getLastModified(HttpServletRequest request, Object handler) { 318 return -1; 319 } 320 321 public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { 322 amfEndpoint.service(graniteConfig, servicesConfig, servletContext, request, response); 323 return null; 324 } 325 326 public boolean supports(Object handler) { 327 return handler instanceof ServerFilter; 328 } 329}