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