📄 wicketfilter.java
字号:
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package org.apache.wicket.protocol.http;import java.io.IOException;import java.io.InputStream;import java.io.UnsupportedEncodingException;import java.text.ParseException;import java.util.ArrayList;import java.util.Properties;import javax.servlet.Filter;import javax.servlet.FilterChain;import javax.servlet.FilterConfig;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.apache.wicket.AbortException;import org.apache.wicket.Application;import org.apache.wicket.RequestContext;import org.apache.wicket.RequestCycle;import org.apache.wicket.Resource;import org.apache.wicket.Session;import org.apache.wicket.WicketRuntimeException;import org.apache.wicket.markup.parser.XmlPullParser;import org.apache.wicket.markup.parser.XmlTag;import org.apache.wicket.protocol.http.portlet.FilterRequestContext;import org.apache.wicket.protocol.http.portlet.WicketFilterPortletContext;import org.apache.wicket.protocol.http.request.WebRequestCodingStrategy;import org.apache.wicket.session.ISessionStore;import org.apache.wicket.settings.IRequestCycleSettings;import org.apache.wicket.util.resource.IResourceStream;import org.apache.wicket.util.resource.ResourceStreamNotFoundException;import org.apache.wicket.util.string.Strings;import org.apache.wicket.util.time.Time;import org.slf4j.Logger;import org.slf4j.LoggerFactory;/** * Filter for initiating handling of Wicket requests. * * @author jcompagner */public class WicketFilter implements Filter{ /** * The name of the context parameter that specifies application factory class */ public static final String APP_FACT_PARAM = "applicationFactoryClassName"; /** * The name of the root path parameter that specifies the root dir of the app. */ public static final String FILTER_MAPPING_PARAM = "filterMappingUrlPattern"; /** Log. */ private static final Logger log = LoggerFactory.getLogger(WicketFilter.class); /** * The servlet path holder when the WicketSerlvet is used. So that the filter path will be * computed with the first request. Note: This variable is by purpose package protected. See * WicketServlet */ static final String SERVLET_PATH_HOLDER = "<servlet>"; /** See javax.servlet.FilterConfig */ private FilterConfig filterConfig; /** * This is the filter path that can be specified in the filter config. Or it is the servlet path * if the wicket servlet it used. both are without any / (start or end) */ private String filterPath; /** The Wicket Application associated with the Filter */ private WebApplication webApplication; private boolean servletMode = false; /** * The name of the optional filter parameter indicating it may/can only be accessed from within * a Portlet context. Value should be true */ private static final String PORTLET_ONLY_FILTER = "portletOnlyFilter"; /** * The name of the optional filter parameter indicating a javax.portlet.PortletContext class * should be looked up to determine if portlet support should be provided. */ private static final String DETECT_PORTLET_CONTEXT = "detectPortletContext"; /** * The name of the optional web.xml context parameter indicating if a portlet context is to be * determined by looking up the javax.portlet.PortletContext class. Default value is false. This * context parameter is only queried if the filter parameter DETECT_PORTLET_CONTEXT isn't * provided. If additionally the context parameter is not specified, a WicketPortlet.properties * resource will be looked up through the classpath which, if found, is queried for a property * with the same name. */ private static final String DETECT_PORTLET_CONTEXT_FULL_NAME = "org.apache.wicket.detectPortletContext"; /** * The classpath resource name of an optional WicketPortlet.properties file. */ private static final String WICKET_PORTLET_PROPERTIES = "org/apache/wicket/protocol/http/portlet/WicketPortlet.properties"; /* * Delegate for handling Portlet specific filtering. Not instantiated if not running in a * portlet container context */ private WicketFilterPortletContext filterPortletContext; /* * Flag if this filter may only process request from within a Portlet context. */ private boolean portletOnlyFilter; /** * Servlet cleanup. */ public void destroy() { if (webApplication != null) { webApplication.internalDestroy(); webApplication = null; } } /** * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, * javax.servlet.ServletResponse, javax.servlet.FilterChain) */ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpServletRequest; HttpServletResponse httpServletResponse; boolean inPortletContext = false; if (filterPortletContext != null) { FilterRequestContext filterRequestContext = new FilterRequestContext( (HttpServletRequest)request, (HttpServletResponse)response); inPortletContext = filterPortletContext.setupFilter(getFilterConfig(), filterRequestContext, getFilterPath((HttpServletRequest)request)); httpServletRequest = filterRequestContext.getRequest(); httpServletResponse = filterRequestContext.getResponse(); } else { httpServletRequest = (HttpServletRequest)request; httpServletResponse = (HttpServletResponse)response; } if (portletOnlyFilter && !inPortletContext) { chain.doFilter(request, response); return; } String relativePath = getRelativePath(httpServletRequest); if (isWicketRequest(relativePath)) { try { // Set the webapplication for this thread Application.set(webApplication); long lastModified = getLastModified(httpServletRequest); if (lastModified == -1) { // servlet doesn't support if-modified-since, no reason // to go through further expensive logic doGet(httpServletRequest, httpServletResponse); } else { long ifModifiedSince; try { ifModifiedSince = httpServletRequest.getDateHeader("If-Modified-Since"); } catch (IllegalArgumentException e) { log.warn("Invalid If-Modified-Since header", e); ifModifiedSince = -1; } if (ifModifiedSince < (lastModified / 1000 * 1000)) { // If the servlet mod time is later, call doGet() // Round down to the nearest second for a proper compare // A ifModifiedSince of -1 will always be less maybeSetLastModified(httpServletResponse, lastModified); doGet(httpServletRequest, httpServletResponse); } else { httpServletResponse.setStatus(HttpServletResponse.SC_NOT_MODIFIED); } } } finally { // always unset the application thread local Application.unset(); RequestContext.unset(); } } else { chain.doFilter(request, response); } } /** * Handles servlet page requests. * * @param servletRequest * Servlet request object * @param servletResponse * Servlet response object * @throws ServletException * Thrown if something goes wrong during request handling * @throws IOException */ public void doGet(final HttpServletRequest servletRequest, final HttpServletResponse servletResponse) throws ServletException, IOException { String relativePath = getRelativePath(servletRequest); // Special-case for home page - we redirect to add a trailing slash. if (relativePath.length() == 0 && !Strings.stripJSessionId(servletRequest.getRequestURI()).endsWith("/")) { final String redirectUrl = servletRequest.getRequestURI() + "/"; servletResponse.sendRedirect(servletResponse.encodeRedirectURL(redirectUrl)); return; } final ClassLoader previousClassLoader = Thread.currentThread().getContextClassLoader(); final ClassLoader newClassLoader = getClassLoader(); try { if (previousClassLoader != newClassLoader) { Thread.currentThread().setContextClassLoader(newClassLoader); } // If the request does not provide information about the encoding of // its body (which includes POST parameters), than assume the // default encoding as defined by the wicket application. Bear in // mind that the encoding of the request usually is equal to the // previous response. // However it is a known bug of IE that it does not provide this // information. Please see the wiki for more details and why all // other browser deliberately copied that bug. if (servletRequest.getCharacterEncoding() == null) { try { // The encoding defined by the wicket settings is used to // encode the responses. Thus, it is reasonable to assume // the request has the same encoding. This is especially // important for forms and form parameters. servletRequest.setCharacterEncoding(webApplication.getRequestCycleSettings() .getResponseRequestEncoding()); } catch (UnsupportedEncodingException ex) { throw new WicketRuntimeException(ex.getMessage()); } } // Create a new webrequest final WebRequest request = webApplication.newWebRequest(servletRequest); // Are we using REDIRECT_TO_BUFFER? if (webApplication.getRequestCycleSettings().getRenderStrategy() == IRequestCycleSettings.REDIRECT_TO_BUFFER) { // Try to see if there is a redirect stored ISessionStore sessionStore = webApplication.getSessionStore(); String sessionId = sessionStore.getSessionId(request, false); if (sessionId != null) { BufferedHttpServletResponse bufferedResponse = null; String queryString = servletRequest.getQueryString(); if (!Strings.isEmpty(queryString)) { bufferedResponse = webApplication.popBufferedResponse(sessionId, queryString); } else { bufferedResponse = webApplication.popBufferedResponse(sessionId, relativePath); } if (bufferedResponse != null) { bufferedResponse.writeTo(servletResponse); // redirect responses are ignored for the request // logger... return; } } } WebResponse response = null; boolean externalCall = !Application.exists(); try { // if called externally (i.e. WicketServlet) we need to set the thread local here // AND clean it up at the end of the request if (externalCall) { Application.set(webApplication); } // Create a response object and set the output encoding according to // wicket's application settings. response = webApplication.newWebResponse(servletResponse); response.setAjax(request.isAjax()); response.setCharacterEncoding(webApplication.getRequestCycleSettings() .getResponseRequestEncoding()); createRequestContext(request, response); // Create request cycle final RequestCycle cycle = webApplication.newRequestCycle(request, response); try { // Process request cycle.request(); } catch (AbortException e) { // noop } } finally { // Close response if (response != null) response.close(); // Clean up thread local session Session.unset(); if (externalCall) { // Clean up thread local application if this was an external call // (if not, doFilter will clean it up) Application.unset(); RequestContext.unset(); } } } finally { if (newClassLoader != previousClassLoader) { Thread.currentThread().setContextClassLoader(previousClassLoader); } } } /** * @return The filter config of this WicketFilter */ public FilterConfig getFilterConfig() { return filterConfig; } /** * Returns a relative path from an HttpServletRequest Use this to resolve a Wicket request. * * @param request * @return Path requested, minus query string, context path, and filterPath. Relative, no * leading '/'. */ public String getRelativePath(HttpServletRequest request) { String path = Strings.stripJSessionId(request.getRequestURI()); String contextPath = request.getContextPath(); path = path.substring(contextPath.length()); if (servletMode) { String servletPath = request.getServletPath(); path = path.substring(servletPath.length()); } filterPath = getFilterPath(request); if (path.length() > 0) { path = path.substring(1); } // We should always be under the rootPath, except // for the special case of someone landing on the // home page without a trailing slash. if (!path.startsWith(filterPath)) { if (filterPath.equals(path + "/")) { path += "/"; } } if (path.startsWith(filterPath)) { path = path.substring(filterPath.length()); } return path; } /** * * @see javax.servlet.Filter#init(javax.servlet.FilterConfig) */ public void init(FilterConfig filterConfig) throws ServletException { this.filterConfig = filterConfig; String filterMapping = filterConfig.getInitParameter(WicketFilter.FILTER_MAPPING_PARAM); if (SERVLET_PATH_HOLDER.equals(filterMapping)) { servletMode = true; } final ClassLoader previousClassLoader = Thread.currentThread().getContextClassLoader(); final ClassLoader newClassLoader = getClassLoader(); try { if (previousClassLoader != newClassLoader) { Thread.currentThread().setContextClassLoader(newClassLoader); } // Try to configure filterPath from web.xml if it's not specified as // an init-param. if (filterMapping == null) { InputStream is = filterConfig.getServletContext().getResourceAsStream( "/WEB-INF/web.xml"); if (is != null) { try { filterPath = getFilterPath(filterConfig.getFilterName(), is); } catch (ServletException e) { log.error("Error reading servlet/filter path from web.xml", e); } catch (SecurityException e) { // Swallow this at INFO. log.info("Couldn't read web.xml to automatically pick up servlet/filter path: " +
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -