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