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