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