/*******************************************************************************
* Copyright 2009, 2010 Innovation Gate GmbH. All Rights Reserved.
*
* This file is part of the OpenWGA server platform.
*
* OpenWGA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* In addition, a special exception is granted by the copyright holders
* of OpenWGA called "OpenWGA plugin exception". You should have received
* a copy of this exception along with OpenWGA in file COPYING.
* If not, see <http://www.openwga.com/gpl-plugin-exception>.
*
* OpenWGA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenWGA in file COPYING.
* If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
package de.innovationgate.wgpublisher;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.WeakHashMap;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import org.apache.commons.lang.ArrayUtils;
import de.innovationgate.utils.WGUtils;
import de.innovationgate.webgate.api.WGFactory;
import de.innovationgate.wgpublisher.WGPDispatcher.RequestInformation;
import de.innovationgate.wgpublisher.log.WGALoggerWrapper;
import de.innovationgate.wgpublisher.log.WGARequestInformation;
import de.innovationgate.wgpublisher.lucene.LuceneManager;
public class WGAFilter implements Filter {
private WGACore _core;
private WGAFilterChain _wgaFilterChain;
private ServletContext _servletContext;
private Map<ServletRequest, WGARequestInformation> _currentRequests = new WeakHashMap<ServletRequest, WGARequestInformation>();
/**
* wrapper for HttpServletResponse
* - ignores all calls to setCharacterEncoding
* - replace parameter charset=<XY> during setContentType with <wrappedResponse>.getCharacterEncoding()
* Therefore the output encoding can be final set on the original response.
*
*/
private class FinalCharacterEncodingResponseWrapper extends HttpServletResponseWrapper {
public static final String SYSPROP_ENCODING_ON_CONTENTTYPE = "de.innovationgate.wga.encoding.oncontenttype";
private boolean _encodingOnContentType = false;
private int _statusCode = HttpServletResponse.SC_OK;
private String _statusMessage;
public FinalCharacterEncodingResponseWrapper(HttpServletResponse arg0) {
super(arg0);
_encodingOnContentType = Boolean.getBoolean(SYSPROP_ENCODING_ON_CONTENTTYPE);
}
public void setCharacterEncoding(String arg0) {
// ignore
}
public void setContentType(String arg0) {
String contentType = arg0;
if (contentType != null) {
if (contentType.indexOf(";") != -1) {
List parameters = WGUtils.deserializeCollection(contentType, ";");
boolean charsetParamSet = false;
for (int i=1; i < parameters.size(); i++) {
String parameter = (String) parameters.get(i);
parameter = parameter.trim();
if (parameter.toLowerCase().startsWith("charset")) {
parameters.set(i, "charset=" + getResponse().getCharacterEncoding());
charsetParamSet = true;
}
}
if (_encodingOnContentType && !charsetParamSet && contentType.toLowerCase().trim().startsWith("text/")) {
// this is for a websphere bug
// if character encoding is set before content type and content type
// is given without charset websphere resets the charset to platform default
// therefore we ensure here that all of our content types have the correct
// charset parameter
parameters.add("charset=" + getResponse().getCharacterEncoding());
}
contentType = WGUtils.serializeCollection(parameters, ";");
} else if (_encodingOnContentType && contentType.toLowerCase().trim().startsWith("text/")) {
// see above about websphere bug
contentType += ";charset=" + getResponse().getCharacterEncoding();
}
}
getResponse().setContentType(contentType);
}
@Override
public void sendError(int sc, String msg) throws IOException {
super.sendError(sc, msg);
_statusCode = sc;
_statusMessage = msg;
}
@Override
public void sendError(int sc) throws IOException {
super.sendError(sc);
_statusCode = sc;
_statusMessage = null;
}
@Override
public void setStatus(int sc, String sm) {
super.setStatus(sc, sm);
_statusCode = sc;
_statusMessage = sm;
}
@Override
public void setStatus(int sc) {
super.setStatus(sc);
_statusCode = sc;
_statusMessage = null;
}
public int getStatusCode() {
return _statusCode;
}
public String getStatusMessage() {
return _statusMessage;
}
@Override
public void sendRedirect(String location) throws IOException {
super.sendRedirect(location);
setStatus(SC_MOVED_TEMPORARILY);
}
}
/**
* a wrapper for WGA GET requests
* - supports decoding of url parameters (parameters of the querystring) in the correct encoding
* - supports setting defaults for url parameters if they are empty (not submitted)
*
*/
public class GETRequestWrapper extends HttpServletRequestWrapper {
private Map _parameters = new HashMap();
private ServletRequest _wrappedRequest;
public GETRequestWrapper(HttpServletRequest request, String encoding) {
super(request);
_wrappedRequest = request;
if (encoding != null) {
String queryString = request.getQueryString();
// decode query string parameters with wga character encoding
if (queryString != null) {
StringTokenizer keyValuePairs = new StringTokenizer(queryString, "&");
while (keyValuePairs.hasMoreTokens()) {
String keyValuePair = keyValuePairs.nextToken();
String key = null;
String value = null;
int pos = keyValuePair.indexOf("=");
if (pos != -1) {
key = keyValuePair.substring(0, pos);
if (pos < keyValuePair.length() - 1) {
value = keyValuePair.substring(pos + 1);
} else {
value = "";
}
try {
String keyDecoded = URLDecoder.decode(key, encoding);
String valueDecoded = URLDecoder.decode(value, encoding);
String values[] = (String[]) _parameters.get(keyDecoded);
values = (String[])ArrayUtils.add(values, valueDecoded);
_parameters.put(keyDecoded, values);
} catch (UnsupportedEncodingException e) {
WGFactory.getLogger().warn("Unable to decode request parameter '" + key + "'.", e);
}
}
}
}
} else {
// no encoding given - rely on default container encoding and request parsing
_parameters = request.getParameterMap();
}
}
public String getParameter(String name) {
copyNoneExistingParams(_wrappedRequest.getParameterMap());
String values[] = (String[]) _parameters.get(name);
if (values == null || values.length == 0) {
return null;
} else {
return values[0];
}
}
public Map getParameterMap() {
copyNoneExistingParams(_wrappedRequest.getParameterMap());
return new HashMap(_parameters);
}
public String[] getParameterValues(String name) {
copyNoneExistingParams(_wrappedRequest.getParameterMap());
return (String[]) _parameters.get(name);
}
public Enumeration getParameterNames() {
copyNoneExistingParams(_wrappedRequest.getParameterMap());
return Collections.enumeration(_parameters.keySet());
}
public void setParameterIfEmpty(String name, String value) {
String[] values = getParameterValues(name);
if (values == null || values.length == 0 || (values.length == 1 && values[0].equals(""))) {
String valueArr[] = new String[1];
valueArr[0] = value;
_parameters.put(name, valueArr);
}
}
public void setParameterIfEmpty(String name, String[] values) {
String[] existingValues = getParameterValues(name);
if (existingValues == null || existingValues.length == 0 || (existingValues.length == 1 && existingValues[0].equals(""))) {
_parameters.put(name, values);
}
}
public void setRequest(ServletRequest request) {
super.setRequest(request);
_wrappedRequest = request;
}
private void copyNoneExistingParams(Map from) {
// add all parameters from the request to local map, which where not already parsed from querystring or added via setParameterIfEmpty
// necessary for jsp-param parsing
HashMap temp = new HashMap(from);
Iterator localParams = _parameters.keySet().iterator();
while (localParams.hasNext()) {
String localParam = (String) localParams.next();
temp.remove(localParam);
}
_parameters.putAll(temp);
}
}
/* (Kein Javadoc)
* @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
*/
public void init(FilterConfig arg0) throws ServletException {
_servletContext = arg0.getServletContext();
_core = WGACore.retrieve(_servletContext);
if (_core != null) {
_core.setFilter(this);
}
initFilterChain();
}
public void initFilterChain() {
_core.getLog().info("Initializing filter chain");
_wgaFilterChain = new WGAFilterChain(_core, _servletContext);
}
/* (Kein Javadoc)
* @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 {
WGARequestInformation info = new WGARequestInformation();
try {
info.setStartTime(System.currentTimeMillis());
request.setAttribute(WGARequestInformation.REQUEST_ATTRIBUTENAME, info);
_wgaFilterChain.init(request, chain);
_currentRequests.put(request, info);
// F000037B2
if (_core.getCharacterEncoding() != null) {
request.setCharacterEncoding(_core.getCharacterEncoding());
// B000041DA
response.setCharacterEncoding(_core.getCharacterEncoding());
}
HttpServletResponse wrappedResponse = new FinalCharacterEncodingResponseWrapper((HttpServletResponse)response);
if (((HttpServletRequest)request).getMethod().equalsIgnoreCase("GET")) {
HttpServletRequest wrappedRequest = new GETRequestWrapper((HttpServletRequest)request, _core.getCharacterEncoding());
_wgaFilterChain.doFilter(wrappedRequest, wrappedResponse);
} else {
_wgaFilterChain.doFilter(request, wrappedResponse);
}
info.setStatusCode(((FinalCharacterEncodingResponseWrapper)wrappedResponse).getStatusCode());
info.setStatusMessage(((FinalCharacterEncodingResponseWrapper)wrappedResponse).getStatusMessage());
}
catch (ServletException e) {
info.setStatusCode(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
info.setStatusMessage(e.getMessage());
throw e;
}
finally {
info.setEndTime(System.currentTimeMillis());
try {
WGALoggerWrapper logger = _core.getAccessLogger();
if (logger != null) {
logger.logRequest(request);
}
} catch (Exception e) {
_core.getLog().error("Unable to log request.", e);
}
WGFactory.getInstance().closeSessions();
// close opened lucene-resultsets
LuceneManager luceneManager = _core.getLuceneManager();
if (luceneManager != null) {
luceneManager.closeOpenedResultSets();
}
_currentRequests.remove(request);
}
}
/* (Kein Javadoc)
* @see javax.servlet.Filter#destroy()
*/
public void destroy() {}
}