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