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            @Override
052            public void destroy() {
053                    portalDestroy();
054            }
055    
056            @Override
057            public void doFilter(
058                            ServletRequest servletRequest, ServletResponse servletResponse,
059                            FilterChain filterChain)
060                    throws IOException, ServletException {
061    
062                    HttpServletRequest request = (HttpServletRequest)servletRequest;
063    
064                    String uri = getURI(request);
065    
066                    request = handleNonSerializableRequest(request);
067    
068                    request.setAttribute(WebKeys.INVOKER_FILTER_URI, uri);
069    
070                    InvokerFilterChain invokerFilterChain = getInvokerFilterChain(
071                            request, uri, filterChain);
072    
073                    Thread currentThread = Thread.currentThread();
074    
075                    ClassLoader contextClassLoader = currentThread.getContextClassLoader();
076    
077                    invokerFilterChain.setContextClassLoader(contextClassLoader);
078    
079                    invokerFilterChain.doFilter(request, servletResponse);
080            }
081    
082            @Override
083            public void init(FilterConfig filterConfig) throws ServletException {
084                    _filterConfig = filterConfig;
085    
086                    ServletContext servletContext = _filterConfig.getServletContext();
087    
088                    _contextPath = ContextPathUtil.getContextPath(servletContext);
089    
090                    boolean registerPortalLifecycle = GetterUtil.getBoolean(
091                            _filterConfig.getInitParameter("register-portal-lifecycle"), true);
092    
093                    if (registerPortalLifecycle) {
094                            registerPortalLifecycle();
095                    }
096                    else {
097                            try {
098                                    doPortalInit();
099                            }
100                            catch (Exception e) {
101                                    _log.error(e, e);
102    
103                                    throw new ServletException(e);
104                            }
105                    }
106            }
107    
108            protected void clearFilterChainsCache() {
109                    if (_filterChains != null) {
110                            _filterChains.clear();
111                    }
112            }
113    
114            @Override
115            protected void doPortalDestroy() {
116                    ServletContext servletContext = _filterConfig.getServletContext();
117    
118                    InvokerFilterHelper invokerFilterHelper =
119                            (InvokerFilterHelper)servletContext.getAttribute(
120                                    InvokerFilterHelper.class.getName());
121    
122                    if (invokerFilterHelper != null) {
123                            servletContext.removeAttribute(InvokerFilterHelper.class.getName());
124    
125                            invokerFilterHelper.destroy();
126                    }
127            }
128    
129            @Override
130            protected void doPortalInit() throws Exception {
131                    _invokerFilterChainSize = GetterUtil.getInteger(
132                            PropsUtil.get(PropsKeys.INVOKER_FILTER_CHAIN_SIZE));
133    
134                    if (_invokerFilterChainSize > 0) {
135                            _filterChains = new ConcurrentLFUCache<String, InvokerFilterChain>(
136                                    _invokerFilterChainSize);
137                    }
138    
139                    ServletContext servletContext = _filterConfig.getServletContext();
140    
141                    InvokerFilterHelper invokerFilterHelper =
142                            (InvokerFilterHelper)servletContext.getAttribute(
143                                    InvokerFilterHelper.class.getName());
144    
145                    if (invokerFilterHelper == null) {
146                            invokerFilterHelper = new InvokerFilterHelper();
147    
148                            servletContext.setAttribute(
149                                    InvokerFilterHelper.class.getName(), invokerFilterHelper);
150    
151                            invokerFilterHelper.readLiferayFilterWebXML(
152                                    servletContext, "/WEB-INF/liferay-web.xml");
153                    }
154    
155                    _invokerFilterHelper = invokerFilterHelper;
156    
157                    _invokerFilterHelper.addInvokerFilter(this);
158    
159                    String dispatcher = GetterUtil.getString(
160                            _filterConfig.getInitParameter("dispatcher"));
161    
162                    if (dispatcher.equals("ERROR")) {
163                            _dispatcher = Dispatcher.ERROR;
164                    }
165                    else if (dispatcher.equals("FORWARD")) {
166                            _dispatcher = Dispatcher.FORWARD;
167                    }
168                    else if (dispatcher.equals("INCLUDE")) {
169                            _dispatcher = Dispatcher.INCLUDE;
170                    }
171                    else if (dispatcher.equals("REQUEST")) {
172                            _dispatcher = Dispatcher.REQUEST;
173                    }
174                    else {
175                            throw new IllegalArgumentException(
176                                    "Invalid dispatcher " + dispatcher);
177                    }
178            }
179    
180            protected InvokerFilterChain getInvokerFilterChain(
181                    HttpServletRequest request, String uri, FilterChain filterChain) {
182    
183                    if (_filterChains == null) {
184                            return _invokerFilterHelper.createInvokerFilterChain(
185                                    request, _dispatcher, uri, filterChain);
186                    }
187    
188                    CacheKeyGenerator cacheKeyGenerator =
189                            CacheKeyGeneratorUtil.getCacheKeyGenerator(
190                                    InvokerFilter.class.getName());
191    
192                    String key = String.valueOf(cacheKeyGenerator.getCacheKey(uri));
193    
194                    InvokerFilterChain invokerFilterChain = _filterChains.get(key);
195    
196                    if (invokerFilterChain == null) {
197                            invokerFilterChain = _invokerFilterHelper.createInvokerFilterChain(
198                                    request, _dispatcher, uri, filterChain);
199    
200                            _filterChains.put(key, invokerFilterChain);
201                    }
202    
203                    return invokerFilterChain.clone(filterChain);
204            }
205    
206            protected String getURI(HttpServletRequest request) {
207                    String uri = null;
208    
209                    if (_dispatcher == Dispatcher.ERROR) {
210                            uri = (String)request.getAttribute(
211                                    JavaConstants.JAVAX_SERVLET_ERROR_REQUEST_URI);
212                    }
213                    else if (_dispatcher == Dispatcher.INCLUDE) {
214                            uri = (String)request.getAttribute(
215                                    JavaConstants.JAVAX_SERVLET_INCLUDE_REQUEST_URI);
216                    }
217                    else {
218                            uri = request.getRequestURI();
219                    }
220    
221                    if (Validator.isNotNull(_contextPath) &&
222                            !_contextPath.equals(StringPool.SLASH) &&
223                            uri.startsWith(_contextPath)) {
224    
225                            uri = uri.substring(_contextPath.length());
226                    }
227    
228                    return uri;
229            }
230    
231            protected HttpServletRequest handleNonSerializableRequest(
232                    HttpServletRequest request) {
233    
234                    if (ServerDetector.isWebLogic()) {
235                            if (!NonSerializableObjectRequestWrapper.isWrapped(request)) {
236                                    request = new NonSerializableObjectRequestWrapper(request);
237                            }
238                    }
239    
240                    return request;
241            }
242    
243            private static Log _log = LogFactoryUtil.getLog(InvokerFilter.class);
244    
245            private String _contextPath;
246            private Dispatcher _dispatcher;
247            private ConcurrentLFUCache<String, InvokerFilterChain> _filterChains;
248            private FilterConfig _filterConfig;
249            private int _invokerFilterChainSize;
250            private InvokerFilterHelper _invokerFilterHelper;
251    
252    }