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    }