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.io.convert.Converter;
041 import org.granite.messaging.amf.process.AMF3MessageInterceptor;
042 import org.granite.messaging.service.ExceptionConverter;
043 import org.granite.messaging.service.security.RemotingDestinationSecurizer;
044 import org.granite.messaging.service.security.SecurityService;
045 import org.granite.messaging.service.tide.TideComponentAnnotatedWithMatcher;
046 import org.granite.messaging.service.tide.TideComponentInstanceOfMatcher;
047 import org.granite.messaging.service.tide.TideComponentNameMatcher;
048 import org.granite.messaging.service.tide.TideComponentTypeMatcher;
049 import org.granite.messaging.webapp.AMFEndpoint;
050 import org.granite.util.TypeUtil;
051 import org.granite.util.XMap;
052 import org.springframework.beans.BeansException;
053 import org.springframework.beans.factory.DisposableBean;
054 import org.springframework.beans.factory.InitializingBean;
055 import org.springframework.beans.factory.annotation.Autowired;
056 import org.springframework.context.ApplicationContext;
057 import org.springframework.context.ApplicationContextAware;
058 import org.springframework.web.context.ServletContextAware;
059 import org.springframework.web.servlet.HandlerAdapter;
060 import org.springframework.web.servlet.ModelAndView;
061
062
063 public 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 }