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.seam21;
023
024import java.io.IOException;
025import java.util.ArrayList;
026import java.util.HashMap;
027import java.util.List;
028
029import javax.servlet.FilterChain;
030import javax.servlet.FilterConfig;
031import javax.servlet.ServletException;
032import javax.servlet.ServletRequest;
033import javax.servlet.ServletResponse;
034import javax.servlet.http.HttpServletRequest;
035import javax.servlet.http.HttpServletResponse;
036
037import org.granite.config.GraniteConfig;
038import org.granite.config.flex.Channel;
039import org.granite.config.flex.Destination;
040import org.granite.config.flex.EndPoint;
041import org.granite.config.flex.Factory;
042import org.granite.config.flex.Service;
043import org.granite.config.flex.ServicesConfig;
044import org.granite.logging.Logger;
045import org.granite.messaging.amf.process.AMF3MessageInterceptor;
046import org.granite.messaging.service.ExceptionConverter;
047import org.granite.messaging.service.tide.TideComponentAnnotatedWithMatcher;
048import org.granite.messaging.service.tide.TideComponentInstanceOfMatcher;
049import org.granite.messaging.service.tide.TideComponentNameMatcher;
050import org.granite.messaging.service.tide.TideComponentTypeMatcher;
051import org.granite.messaging.webapp.AMFEndpoint;
052import org.granite.util.XMap;
053import org.jboss.seam.Component;
054import org.jboss.seam.ScopeType;
055import org.jboss.seam.annotations.Create;
056import org.jboss.seam.annotations.Install;
057import org.jboss.seam.annotations.Name;
058import org.jboss.seam.annotations.Scope;
059import org.jboss.seam.annotations.Startup;
060import org.jboss.seam.annotations.intercept.BypassInterceptors;
061import org.jboss.seam.web.AbstractFilter;
062
063
064@Scope(ScopeType.APPLICATION)
065@Name("org.granite.seam.serverFilter")
066@Startup
067@Install(precedence=Install.BUILT_IN, value=false, classDependencies={"org.granite.seam21.Seam21GraniteConfig"})
068@BypassInterceptors
069@org.jboss.seam.annotations.web.Filter
070public class ServerFilter extends AbstractFilter {
071        
072    private static final Logger log = Logger.getLogger(ServerFilter.class);
073        
074    private FilterConfig config = null;
075    private GraniteConfig graniteConfig = null;
076    private ServicesConfig servicesConfig = null;
077    
078    private List<String> tideRoles = null;
079    private List<String> tideAnnotations = null;
080    private List<String> tideInterfaces = null;
081    private List<String> tideNames = null;
082    private List<String> tideTypes = null;
083    private List<Class<? extends ExceptionConverter>> exceptionConverters = null;
084    private AMF3MessageInterceptor amf3MessageInterceptor = null;
085    private boolean tide = false;
086    private String type = "server";
087    
088    private AMFEndpoint amfEndpoint = null;
089
090    
091    public ServerFilter() {
092        super();
093        setUrlPattern("/graniteamf/*");
094    }
095    
096    
097    @Override
098    public void init(FilterConfig config) throws ServletException {
099        super.init(config);
100        
101        this.config = config;
102        
103        this.amfEndpoint = new AMFEndpoint();
104        this.amfEndpoint.init(config.getServletContext());
105    }
106        
107    
108        @Override
109        public void destroy() {
110                super.destroy();
111                
112                this.config = null;
113                
114                this.amfEndpoint.destroy();
115                this.amfEndpoint = null;
116        }
117
118
119        @Create
120        public void seamInit() {
121                Seam21GraniteConfig seam21GraniteConfig = (Seam21GraniteConfig)Component.getInstance(Seam21GraniteConfig.class, true);
122                
123        this.graniteConfig = seam21GraniteConfig.getGraniteConfig();
124        if (tideAnnotations != null) {
125                for (String ta : tideAnnotations) {
126                        try {
127                                this.graniteConfig.getTideComponentMatchers().add(new TideComponentAnnotatedWithMatcher(ta, false));
128                                log.debug("Enabled components annotated with %s for Tide remoting", ta);
129                        }
130                        catch (Exception e) {
131                                log.error(e, "Could not add tide-component annotation %s", ta);
132                        }
133                }
134        }
135        if (tideInterfaces != null) {
136                for (String ti : tideInterfaces) {
137                        try {
138                                this.graniteConfig.getTideComponentMatchers().add(new TideComponentInstanceOfMatcher(ti, false));
139                                log.debug("Enabled components extending %s for Tide remoting", ti);
140                        }
141                        catch (Exception e) {
142                                log.error(e, "Could not add tide-component interface %s", ti);
143                        }
144                }
145        }
146        if (tideNames != null) {
147                for (String tn : tideNames) {
148                        try {
149                                this.graniteConfig.getTideComponentMatchers().add(new TideComponentNameMatcher(tn, false));
150                                log.debug("Enabled components named like %s for Tide remoting", tn);
151                        }
152                        catch (Exception e) {
153                                log.error(e, "Could not add tide-component name %s", tn);
154                        }
155                }
156        }
157        if (tideTypes != null) {
158                for (String tt : tideTypes) {
159                        try {
160                                this.graniteConfig.getTideComponentMatchers().add(new TideComponentTypeMatcher(tt, false));
161                                log.debug("Enabled components with type %s for Tide remoting", tt);
162                        }
163                        catch (Exception e) {
164                                log.error(e, "Could not add tide-component type %s", tt);
165                        }
166                }
167        }
168        if (exceptionConverters != null) {
169                for (Class<? extends ExceptionConverter> ec : exceptionConverters) {
170                        this.graniteConfig.registerExceptionConverter(ec);
171                        log.debug("Registered exception converter %s", ec);
172                }
173        }
174        if (amf3MessageInterceptor != null)
175                this.graniteConfig.setAmf3MessageInterceptor(amf3MessageInterceptor);
176        
177        servicesConfig = seam21GraniteConfig.getServicesConfig();
178        
179        Channel channel = servicesConfig.findChannelById("graniteamf");
180        if (channel == null) {
181                channel = new Channel("graniteamf", "mx.messaging.channels.AMFChannel", 
182                        new EndPoint("http://{server.name}:{server.port}/{context.root}/graniteamf/amf", "flex.messaging.endpoints.AMFEndpoint"), 
183                        new XMap());
184                servicesConfig.addChannel(channel);
185        }
186        
187        if (tide) {
188                Factory factory = servicesConfig.findFactoryById("tide-seam-factory");
189                if (factory == null) {
190                        factory = new Factory("tide-seam-factory", "org.granite.tide.seam.SeamServiceFactory", new XMap());
191                        servicesConfig.addFactory(factory);
192                }
193                
194                Service service = servicesConfig.findServiceById("granite-service");
195                if (service == null) {
196                        service = new Service("granite-service", "flex.messaging.services.RemotingService", 
197                                "flex.messaging.messages.RemotingMessage", null, null, new HashMap<String, Destination>());
198                }
199                Destination destination = servicesConfig.findDestinationById("flex.messaging.messages.RemotingMessage", type);
200                if (destination == null) {
201                        List<String> channelIds = new ArrayList<String>();
202                        channelIds.add("graniteamf");
203                        destination = new Destination(type, channelIds, new XMap(), tideRoles, null, null);
204                        destination.getProperties().put("factory", factory.getId());
205                        destination.getProperties().put("validator-name", "tideValidator");
206                        service.getDestinations().put(destination.getId(), destination);
207                        servicesConfig.addService(service);
208                }
209                
210                log.info("Registered Tide/Seam service factory and destination");
211        }
212        else {
213                Factory factory = new Factory("seam-factory", "org.granite.seam.SeamServiceFactory", new XMap());
214                servicesConfig.addFactory(factory);
215                
216                Service service = new Service("granite-service", "flex.messaging.services.RemotingService", 
217                        "flex.messaging.messages.RemotingMessage", null, null, new HashMap<String, Destination>());
218                servicesConfig.addService(service);
219            
220            servicesConfig.scan(null);
221                
222                log.info("Registered Seam service factory");
223        }
224        }
225        
226        public void setTideRoles(List<String> tideRoles) {
227                this.tideRoles = tideRoles;
228        }
229        
230        public void setTideAnnotations(List<String> tideAnnotations) {
231                this.tideAnnotations = tideAnnotations;
232        }
233        
234        public void setTideInterfaces(List<String> tideInterfaces) {
235                this.tideInterfaces = tideInterfaces;
236        }
237        
238        public void setTideNames(List<String> tideNames) {
239                this.tideNames = tideNames;
240        }
241        
242        public void setTideTypes(List<String> tideTypes) {
243                this.tideTypes = tideTypes;
244        }
245        
246        public void setExceptionConverters(List<Class<? extends ExceptionConverter>> exceptionConverters) {
247                this.exceptionConverters = exceptionConverters;
248        }
249        
250        public void setAmf3MessageInterceptor(AMF3MessageInterceptor amf3MessageInterceptor) {
251                this.amf3MessageInterceptor = amf3MessageInterceptor;
252        }
253        
254        public void setTide(boolean tide) {
255                this.tide = tide;
256        }
257        
258        public void setType(String type) {
259                this.type = type;
260        }
261        
262        
263        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
264        throws IOException, ServletException {
265                if (isMappedToCurrentRequestPath(request)) {         
266                        amfEndpoint.service(
267                                graniteConfig, servicesConfig, config.getServletContext(), 
268                                (HttpServletRequest)request, (HttpServletResponse)response
269                        );
270                }
271                else { 
272                        chain.doFilter(request, response);
273                }
274        }
275}