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     */
022    package org.granite.seam21;
023    
024    import java.io.IOException;
025    import java.util.ArrayList;
026    import java.util.HashMap;
027    import java.util.List;
028    
029    import javax.servlet.FilterChain;
030    import javax.servlet.FilterConfig;
031    import javax.servlet.ServletException;
032    import javax.servlet.ServletRequest;
033    import javax.servlet.ServletResponse;
034    import javax.servlet.http.HttpServletRequest;
035    import javax.servlet.http.HttpServletResponse;
036    
037    import org.granite.config.GraniteConfig;
038    import org.granite.config.flex.Channel;
039    import org.granite.config.flex.Destination;
040    import org.granite.config.flex.EndPoint;
041    import org.granite.config.flex.Factory;
042    import org.granite.config.flex.Service;
043    import org.granite.config.flex.ServicesConfig;
044    import org.granite.logging.Logger;
045    import org.granite.messaging.amf.process.AMF3MessageInterceptor;
046    import org.granite.messaging.service.ExceptionConverter;
047    import org.granite.messaging.service.tide.TideComponentAnnotatedWithMatcher;
048    import org.granite.messaging.service.tide.TideComponentInstanceOfMatcher;
049    import org.granite.messaging.service.tide.TideComponentNameMatcher;
050    import org.granite.messaging.service.tide.TideComponentTypeMatcher;
051    import org.granite.messaging.webapp.AMFEndpoint;
052    import org.granite.util.XMap;
053    import org.jboss.seam.Component;
054    import org.jboss.seam.ScopeType;
055    import org.jboss.seam.annotations.Create;
056    import org.jboss.seam.annotations.Install;
057    import org.jboss.seam.annotations.Name;
058    import org.jboss.seam.annotations.Scope;
059    import org.jboss.seam.annotations.Startup;
060    import org.jboss.seam.annotations.intercept.BypassInterceptors;
061    import 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
070    public 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    }