001    /**
002     * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
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                    InvokerFilterChain invokerFilterChain = getInvokerFilterChain(
065                            request, uri, filterChain);
066    
067                    Thread currentThread = Thread.currentThread();
068    
069                    ClassLoader contextClassLoader = currentThread.getContextClassLoader();
070    
071                    invokerFilterChain.setContextClassLoader(contextClassLoader);
072    
073                    invokerFilterChain.doFilter(servletRequest, servletResponse);
074            }
075    
076            public void init(FilterConfig filterConfig) throws ServletException {
077                    _filterConfig = filterConfig;
078    
079                    ServletContext servletContext = _filterConfig.getServletContext();
080    
081                    _contextPath = ContextPathUtil.getContextPath(servletContext);
082    
083                    boolean registerPortalLifecycle = GetterUtil.getBoolean(
084                            _filterConfig.getInitParameter("register-portal-lifecycle"), true);
085    
086                    if (registerPortalLifecycle) {
087                            registerPortalLifecycle();
088                    }
089                    else {
090                            try {
091                                    doPortalInit();
092                            }
093                            catch (Exception e) {
094                                    _log.error(e, e);
095    
096                                    throw new ServletException(e);
097                            }
098                    }
099            }
100    
101            protected void clearFilterChainsCache() {
102                    if (_filterChains != null) {
103                            _filterChains.clear();
104                    }
105            }
106    
107            @Override
108            protected void doPortalDestroy() {
109                    ServletContext servletContext = _filterConfig.getServletContext();
110    
111                    InvokerFilterHelper invokerFilterHelper =
112                            (InvokerFilterHelper)servletContext.getAttribute(
113                                    InvokerFilterHelper.class.getName());
114    
115                    if (invokerFilterHelper != null) {
116                            servletContext.removeAttribute(InvokerFilterHelper.class.getName());
117    
118                            invokerFilterHelper.destroy();
119                    }
120            }
121    
122            @Override
123            protected void doPortalInit() throws Exception {
124                    _invokerFilterChainSize = GetterUtil.getInteger(
125                            PropsUtil.get(PropsKeys.INVOKER_FILTER_CHAIN_SIZE));
126    
127                    if (_invokerFilterChainSize > 0) {
128                            _filterChains = new ConcurrentLFUCache<String, InvokerFilterChain>(
129                                    _invokerFilterChainSize);
130                    }
131    
132                    ServletContext servletContext = _filterConfig.getServletContext();
133    
134                    InvokerFilterHelper invokerFilterHelper =
135                            (InvokerFilterHelper)servletContext.getAttribute(
136                                    InvokerFilterHelper.class.getName());
137    
138                    if (invokerFilterHelper == null) {
139                            invokerFilterHelper = new InvokerFilterHelper();
140    
141                            servletContext.setAttribute(
142                                    InvokerFilterHelper.class.getName(), invokerFilterHelper);
143    
144                            invokerFilterHelper.readLiferayFilterWebXML(
145                                    servletContext, "/WEB-INF/liferay-web.xml");
146                    }
147    
148                    _invokerFilterHelper = invokerFilterHelper;
149    
150                    _invokerFilterHelper.addInvokerFilter(this);
151    
152                    String dispatcher = GetterUtil.getString(
153                            _filterConfig.getInitParameter("dispatcher"));
154    
155                    if (dispatcher.equals("ERROR")) {
156                            _dispatcher = Dispatcher.ERROR;
157                    }
158                    else if (dispatcher.equals("FORWARD")) {
159                            _dispatcher = Dispatcher.FORWARD;
160                    }
161                    else if (dispatcher.equals("INCLUDE")) {
162                            _dispatcher = Dispatcher.INCLUDE;
163                    }
164                    else if (dispatcher.equals("REQUEST")) {
165                            _dispatcher = Dispatcher.REQUEST;
166                    }
167                    else {
168                            throw new IllegalArgumentException(
169                                    "Invalid dispatcher " + dispatcher);
170                    }
171            }
172    
173            protected InvokerFilterChain getInvokerFilterChain(
174                    HttpServletRequest request, String uri, FilterChain filterChain) {
175    
176                    if (_filterChains == null) {
177                            return _invokerFilterHelper.createInvokerFilterChain(
178                                    request, _dispatcher, uri, filterChain);
179                    }
180    
181                    CacheKeyGenerator cacheKeyGenerator =
182                            CacheKeyGeneratorUtil.getCacheKeyGenerator(
183                                    InvokerFilter.class.getName());
184    
185                    String key = String.valueOf(cacheKeyGenerator.getCacheKey(uri));
186    
187                    InvokerFilterChain invokerFilterChain = _filterChains.get(key);
188    
189                    if (invokerFilterChain == null) {
190                            invokerFilterChain = _invokerFilterHelper.createInvokerFilterChain(
191                                    request, _dispatcher, uri, filterChain);
192    
193                            _filterChains.put(key, invokerFilterChain);
194                    }
195    
196                    return invokerFilterChain.clone(filterChain);
197            }
198    
199            protected String getURI(HttpServletRequest request) {
200                    String uri = null;
201    
202                    if (_dispatcher == Dispatcher.ERROR) {
203                            uri = (String)request.getAttribute(
204                                    JavaConstants.JAVAX_SERVLET_ERROR_REQUEST_URI);
205                    }
206                    else if (_dispatcher == Dispatcher.INCLUDE) {
207                            uri = (String)request.getAttribute(
208                                    JavaConstants.JAVAX_SERVLET_INCLUDE_REQUEST_URI);
209                    }
210                    else {
211                            uri = request.getRequestURI();
212                    }
213    
214                    if (Validator.isNotNull(_contextPath) &&
215                            !_contextPath.equals(StringPool.SLASH) &&
216                            uri.startsWith(_contextPath)) {
217    
218                            uri = uri.substring(_contextPath.length());
219                    }
220    
221                    return uri;
222            }
223    
224            private static Log _log = LogFactoryUtil.getLog(InvokerFilter.class);
225    
226            private String _contextPath;
227            private Dispatcher _dispatcher;
228            private ConcurrentLFUCache<String, InvokerFilterChain> _filterChains;
229            private FilterConfig _filterConfig;
230            private int _invokerFilterChainSize;
231            private InvokerFilterHelper _invokerFilterHelper;
232    
233    }