001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.kernel.servlet.filters.invoker;
016    
017    import com.liferay.portal.kernel.cache.key.CacheKeyGenerator;
018    import com.liferay.portal.kernel.cache.key.CacheKeyGeneratorUtil;
019    import com.liferay.portal.kernel.concurrent.ConcurrentLFUCache;
020    import com.liferay.portal.kernel.log.Log;
021    import com.liferay.portal.kernel.log.LogFactoryUtil;
022    import com.liferay.portal.kernel.servlet.NonSerializableObjectRequestWrapper;
023    import com.liferay.portal.kernel.util.BasePortalLifecycle;
024    import com.liferay.portal.kernel.util.ContextPathUtil;
025    import com.liferay.portal.kernel.util.GetterUtil;
026    import com.liferay.portal.kernel.util.JavaConstants;
027    import com.liferay.portal.kernel.util.PropsKeys;
028    import com.liferay.portal.kernel.util.PropsUtil;
029    import com.liferay.portal.kernel.util.ServerDetector;
030    import com.liferay.portal.kernel.util.StringPool;
031    import com.liferay.portal.kernel.util.Validator;
032    import com.liferay.portal.kernel.util.WebKeys;
033    
034    import java.io.IOException;
035    
036    import javax.servlet.Filter;
037    import javax.servlet.FilterChain;
038    import javax.servlet.FilterConfig;
039    import javax.servlet.ServletContext;
040    import javax.servlet.ServletException;
041    import javax.servlet.ServletRequest;
042    import javax.servlet.ServletResponse;
043    import javax.servlet.http.HttpServletRequest;
044    
045    /**
046     * @author Mika Koivisto
047     * @author Brian Wing Shun Chan
048     */
049    public class InvokerFilter extends BasePortalLifecycle implements Filter {
050    
051            public void destroy() {
052                    portalDestroy();
053            }
054    
055            public void doFilter(
056                            ServletRequest servletRequest, ServletResponse servletResponse,
057                            FilterChain filterChain)
058                    throws IOException, ServletException {
059    
060                    HttpServletRequest request = (HttpServletRequest)servletRequest;
061    
062                    String uri = getURI(request);
063    
064                    request = handleNonSerializableRequest(request);
065    
066                    request.setAttribute(WebKeys.INVOKER_FILTER_URI, uri);
067    
068                    try {
069                            InvokerFilterChain invokerFilterChain = getInvokerFilterChain(
070                                    request, uri, filterChain);
071    
072                            Thread currentThread = Thread.currentThread();
073    
074                            ClassLoader contextClassLoader =
075                                    currentThread.getContextClassLoader();
076    
077                            invokerFilterChain.setContextClassLoader(contextClassLoader);
078    
079                            invokerFilterChain.doFilter(request, servletResponse);
080                    }
081                    finally {
082                            request.removeAttribute(WebKeys.INVOKER_FILTER_URI);
083                    }
084            }
085    
086            public void init(FilterConfig filterConfig) throws ServletException {
087                    _filterConfig = filterConfig;
088    
089                    ServletContext servletContext = _filterConfig.getServletContext();
090    
091                    _contextPath = ContextPathUtil.getContextPath(servletContext);
092    
093                    boolean registerPortalLifecycle = GetterUtil.getBoolean(
094                            _filterConfig.getInitParameter("register-portal-lifecycle"), true);
095    
096                    if (registerPortalLifecycle) {
097                            registerPortalLifecycle();
098                    }
099                    else {
100                            try {
101                                    doPortalInit();
102                            }
103                            catch (Exception e) {
104                                    _log.error(e, e);
105    
106                                    throw new ServletException(e);
107                            }
108                    }
109            }
110    
111            protected void clearFilterChainsCache() {
112                    if (_filterChains != null) {
113                            _filterChains.clear();
114                    }
115            }
116    
117            @Override
118            protected void doPortalDestroy() {
119                    ServletContext servletContext = _filterConfig.getServletContext();
120    
121                    InvokerFilterHelper invokerFilterHelper =
122                            (InvokerFilterHelper)servletContext.getAttribute(
123                                    InvokerFilterHelper.class.getName());
124    
125                    if (invokerFilterHelper != null) {
126                            servletContext.removeAttribute(InvokerFilterHelper.class.getName());
127    
128                            invokerFilterHelper.destroy();
129                    }
130            }
131    
132            @Override
133            protected void doPortalInit() throws Exception {
134                    _invokerFilterChainSize = GetterUtil.getInteger(
135                            PropsUtil.get(PropsKeys.INVOKER_FILTER_CHAIN_SIZE));
136    
137                    if (_invokerFilterChainSize > 0) {
138                            _filterChains = new ConcurrentLFUCache<String, InvokerFilterChain>(
139                                    _invokerFilterChainSize);
140                    }
141    
142                    ServletContext servletContext = _filterConfig.getServletContext();
143    
144                    InvokerFilterHelper invokerFilterHelper =
145                            (InvokerFilterHelper)servletContext.getAttribute(
146                                    InvokerFilterHelper.class.getName());
147    
148                    if (invokerFilterHelper == null) {
149                            invokerFilterHelper = new InvokerFilterHelper();
150    
151                            servletContext.setAttribute(
152                                    InvokerFilterHelper.class.getName(), invokerFilterHelper);
153    
154                            invokerFilterHelper.readLiferayFilterWebXML(
155                                    servletContext, "/WEB-INF/liferay-web.xml");
156                    }
157    
158                    _invokerFilterHelper = invokerFilterHelper;
159    
160                    _invokerFilterHelper.addInvokerFilter(this);
161    
162                    String dispatcher = GetterUtil.getString(
163                            _filterConfig.getInitParameter("dispatcher"));
164    
165                    if (dispatcher.equals("ERROR")) {
166                            _dispatcher = Dispatcher.ERROR;
167                    }
168                    else if (dispatcher.equals("FORWARD")) {
169                            _dispatcher = Dispatcher.FORWARD;
170                    }
171                    else if (dispatcher.equals("INCLUDE")) {
172                            _dispatcher = Dispatcher.INCLUDE;
173                    }
174                    else if (dispatcher.equals("REQUEST")) {
175                            _dispatcher = Dispatcher.REQUEST;
176                    }
177                    else {
178                            throw new IllegalArgumentException(
179                                    "Invalid dispatcher " + dispatcher);
180                    }
181            }
182    
183            protected InvokerFilterChain getInvokerFilterChain(
184                    HttpServletRequest request, String uri, FilterChain filterChain) {
185    
186                    if (_filterChains == null) {
187                            return _invokerFilterHelper.createInvokerFilterChain(
188                                    request, _dispatcher, uri, filterChain);
189                    }
190    
191                    CacheKeyGenerator cacheKeyGenerator =
192                            CacheKeyGeneratorUtil.getCacheKeyGenerator(
193                                    InvokerFilter.class.getName());
194    
195                    String key = String.valueOf(cacheKeyGenerator.getCacheKey(uri));
196    
197                    InvokerFilterChain invokerFilterChain = _filterChains.get(key);
198    
199                    if (invokerFilterChain == null) {
200                            invokerFilterChain = _invokerFilterHelper.createInvokerFilterChain(
201                                    request, _dispatcher, uri, filterChain);
202    
203                            _filterChains.put(key, invokerFilterChain);
204                    }
205    
206                    return invokerFilterChain.clone(filterChain);
207            }
208    
209            protected String getURI(HttpServletRequest request) {
210                    String uri = null;
211    
212                    if (_dispatcher == Dispatcher.ERROR) {
213                            uri = (String)request.getAttribute(
214                                    JavaConstants.JAVAX_SERVLET_ERROR_REQUEST_URI);
215                    }
216                    else if (_dispatcher == Dispatcher.INCLUDE) {
217                            uri = (String)request.getAttribute(
218                                    JavaConstants.JAVAX_SERVLET_INCLUDE_REQUEST_URI);
219                    }
220                    else {
221                            uri = request.getRequestURI();
222                    }
223    
224                    if (Validator.isNotNull(_contextPath) &&
225                            !_contextPath.equals(StringPool.SLASH) &&
226                            uri.startsWith(_contextPath)) {
227    
228                            uri = uri.substring(_contextPath.length());
229                    }
230    
231                    return uri;
232            }
233    
234            protected HttpServletRequest handleNonSerializableRequest(
235                    HttpServletRequest request) {
236    
237                    if (ServerDetector.isWebLogic()) {
238                            if (!NonSerializableObjectRequestWrapper.isWrapped(request)) {
239                                    request = new NonSerializableObjectRequestWrapper(request);
240                            }
241                    }
242    
243                    return request;
244            }
245    
246            private static Log _log = LogFactoryUtil.getLog(InvokerFilter.class);
247    
248            private String _contextPath;
249            private Dispatcher _dispatcher;
250            private ConcurrentLFUCache<String, InvokerFilterChain> _filterChains;
251            private FilterConfig _filterConfig;
252            private int _invokerFilterChainSize;
253            private InvokerFilterHelper _invokerFilterHelper;
254    
255    }