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