
com.britesnow.snow.web.RequestContext Maven / Gradle / Ivy
/* Copyright 2009 Jeremy Chone - Licensed under the Apache License, Version 2.0
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.britesnow.snow.web;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.lang.reflect.Array;
import java.net.URLDecoder;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Deque;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.britesnow.snow.util.HttpRequestUtil;
import com.britesnow.snow.util.MapUtil;
import com.britesnow.snow.util.ObjectUtil;
import com.britesnow.snow.web.auth.AuthToken;
import com.google.common.base.Throwables;
public class RequestContext {
static private Logger logger = LoggerFactory.getLogger(RequestContext.class);
HttpServletRequest req;
HttpServletResponse res;
ServletContext servletContext;
private ServletFileUpload fileUploader;
private boolean isParamInitialized = false;
private boolean isMultipart = false;
private List> fileItems;
// built on demand
private Map paramMap = null;
// built on demand
private Map cookieMap;
private String resourcePath;
private Deque framePathsStack;
// this is the HashMap for the "m" model map
private Map webModel = new HashMap();
// usually set by the WebController.service
private WebActionResponse webActionResponse;
// optional
private String pathInfo;
// set by AuthService.authRequest
private AuthToken> authToken;
public RequestContext(HttpServletRequest req, HttpServletResponse res, ServletContext servletContext,
ServletFileUpload fileUploader) {
this.req = req;
this.res = res;
this.servletContext = servletContext;
this.fileUploader = fileUploader;
init();
}
protected void init() {
}
/*--------- Auth Methods ---------*/
public AuthToken> getAuthToken() {
return authToken;
}
public void setAuthToken(AuthToken> auth) {
this.authToken = auth;
}
@SuppressWarnings("unchecked")
public T getUser(Class userClass) {
if (authToken != null && userClass.isInstance(authToken.getUser())) {
return (T) authToken.getUser();
} else {
return null;
}
}
/*--------- /Auth Methods ---------*/
// --------- Attribute Access --------- //
public void setAttribute(String name, Object obj) {
req.setAttribute(name, obj);
}
public void removeAttribute(String name) {
req.removeAttribute(name);
}
public Object getAttribute(String name) {
return req.getAttribute(name);
}
public T getAttributeAs(String name, Class cls) {
return getAttributeAs(name, cls, null);
}
public T getAttributeAs(String name, Class cls, T defaultValue) {
Object value = req.getAttribute(name);
if (value != null) {
if (cls.isInstance(value)) {
return (T) value;
} else {
// otherwise, get get the toString and try to get it with the ObjectUtil.
return ObjectUtil.getValue(value.toString(), cls, defaultValue);
}
} else {
return defaultValue;
}
}
// --------- /Attribute Access --------- //
/*--------- Param Methods ---------*/
// mostly for Mock objects
protected void setParamMap(Map paramMap) {
this.paramMap = paramMap;
isParamInitialized = true;
}
public Map getParamMap() {
initParamsIfNeeded();
return paramMap;
}
/**
* A map of all the param starting with the prefix.
*
* @param prefix
* @return The key is the string after the prefix, and the value, is the value itself. Return null if no param
* started with the prefix.
*/
public Map getParamMap(String prefix) {
Map allParamMap = getParamMap();
Map prefixParamMap = null;
if (allParamMap != null && prefix != null) {
for (String paramName : allParamMap.keySet()) {
if (paramName.startsWith(prefix)) {
if (prefixParamMap == null) {
prefixParamMap = new HashMap();
}
Object value = allParamMap.get(paramName);
prefixParamMap.put(paramName.substring(prefix.length()), value);
}
}
}
return prefixParamMap;
}
/**
* @param
* @param prefix
* @param cls
* @return The list of values given a param prefix
*/
public List getParamMapValues(String prefix, Class cls) {
List list = new ArrayList();
Map prefixParamMap = getParamMap(prefix);
if (prefixParamMap != null) {
for (Object valueObj : prefixParamMap.values()) {
if (valueObj instanceof String) {
T value = ObjectUtil.getValue((String) valueObj, cls, null);
if (value != null) {
list.add(value);
}
}
}
}
return list;
}
/**
* Simple method to get the Request value for a given parameter name. Return null if the value is null or empty.
*
* @param name
* parameter value
* @return
*/
public String getParam(String name) {
return getParamAs(name, String.class, null);
}
/**
* Return the param value as "cls" class object. If the value is null (or empty string) return null.
*
* @param
* @param name
* @param cls
* @return the http param value if exist or valid, otherwise, null.
*/
public T getParamAs(String name, Class cls) {
return getParamAs(name, cls, null);
}
/**
* Return the param value as "cls" class object. If the value is null (or empty string) return the defaultValue.
*
* Note: For the first call, this method will parse the request (in case of a multipart).
*
* Issues
*
* - FIXME: Need to fix the multipart handling. Can be simplified
*
*
*
* @param
* Class of the return element
* @param name
* of the parameter
* @param cls
* Class of the return element
* @param defaultValue
* Default value in case of an error or null/empty value
* @return
*/
@SuppressWarnings("unchecked")
public T getParamAs(String name, Class cls, T defaultValue) {
Map paramMap = getParamMap();
if (paramMap == null) {
return defaultValue;
}
// if we have a primitive type or array, then, just get the single value and convert it to the appropriate type
if (ObjectUtil.isPrimitive(cls) || cls.isArray() || cls == FileItem.class || cls.isEnum()) {
// first, try to get it from the paramMap
Object valueObject = paramMap.get(name);
if (isMultipart) {
// HACK
// if not found, try to get it from the regular HttpServletRequest
// (in the case of a multiPart post,
// HttpServletRequest.getParameter still have the URL params)
if (valueObject == null) {
valueObject = getReq().getParameter(name);
}
}
if (valueObject == null) {
return defaultValue;
} else if (valueObject instanceof String) {
return (T) ObjectUtil.getValue((String) valueObject, cls, defaultValue);
} else if (valueObject instanceof String[]) {
return (T) ObjectUtil.getValue((String[]) valueObject, cls, defaultValue);
} else {
// hope for the best (should be a fileItem)
return (T) valueObject;
}
}
// otherwise, if it is not a primitive type, attempt to create the targeted object with the corresponding
// paramMap
else {
Map subParamMap = getParamMap(name + "."); // i.e., "product."
if (subParamMap != null) {
try {
T value = cls.newInstance();
ObjectUtil.populate(value, subParamMap);
return value;
} catch (Exception e) {
logger.warn(e.getMessage());
return defaultValue;
}
} else {
return defaultValue;
}
}
}
private void initParamsIfNeeded() {
if (!isParamInitialized) {
isMultipart = ServletFileUpload.isMultipartContent(getReq());
if (isMultipart) {
try {
fileItems = fileUploader.parseRequest(getReq());
paramMap = new HashMap();
Map paramBaseClasses = new HashMap();
boolean hasMultivalues = false;
for (Object item : fileItems) {
FileItem fileItem = (FileItem) item;
String paramName = fileItem.getFieldName();
// in case of normal fields, take the string value. otherwise
// put the whole file item into the map.
Object value;
Class paramBaseClass;
if (fileItem.isFormField()) {
try {
value = fileItem.getString("UTF-8");
} catch (UnsupportedEncodingException e) {
value = fileItem.getString();
}
paramBaseClass = String.class;
} else {
value = fileItem;
paramBaseClass = FileItem.class;
}
// make sure that the client isn't calling something that is mixing and
// matching parameter types...
// todo - could support this as Object arrays or arrays of most specific shared super class.
Class prevBaseClass = paramBaseClasses.put(paramName, paramBaseClass);
if (prevBaseClass != null && !prevBaseClass.equals(paramBaseClass)) {
throw new IllegalArgumentException("parameter " + paramName
+ " has mixed parameter types (expected all file or all string)");
}
// if there is already a value, then, create a list
if (paramMap.containsKey(paramName)) {
hasMultivalues = true;
Object prevValue = paramMap.get(paramName);
if (prevValue instanceof List) {
((List) prevValue).add(value);
} else {
List values = new ArrayList(2);
values.add(prevValue);
values.add(value);
paramMap.put(paramName, values);
}
} else {
paramMap.put(paramName, value);
}
}
// if we had multivalues, need to change the list to arrays
if (hasMultivalues) {
for (String name : paramMap.keySet()) {
Object value = paramMap.get(name);
if (value instanceof List) {
List valueList = (List) value;
Object[] valueArray = (Object[]) Array.newInstance(paramBaseClasses.get(name), valueList.size());
valueList.toArray(valueArray);
paramMap.put(name, valueArray);
}
}
}
} catch (FileUploadException e) {
// TODO Auto-generated catch block
logger.error(e.getMessage());
}
} else {
paramMap = new HashMap();
// By the httpServletRequest spect, we can assume the type of
// the return Map (name and values)
Map reqMap = getReq().getParameterMap();
// now, simplify the map, by replacing single string array to
// the string itself.
for (String paramName : reqMap.keySet()) {
String[] values = reqMap.get(paramName);
if (values.length == 1) {
paramMap.put(paramName, values[0]);
} else {
paramMap.put(paramName, values);
}
}
}
isParamInitialized = true;
}
}
/*--------- /Param Methods ---------*/
/*--------- Cookie Methods ---------*/
public Map getCookieMap() {
if (cookieMap == null) {
cookieMap = new HashMap();
Cookie[] cookies = getReq().getCookies();
if (cookies != null) {
for (Cookie c : cookies) {
String value = c.getValue();
try {
value = URLDecoder.decode(value, "UTF-8");
} catch (Exception e) {
// YES, ignore for now. If failed, the raw value will be in the cookie.
}
cookieMap.put(c.getName(), value);
}
}
}
return cookieMap;
}
public String getCookie(String name) {
return getCookieMap().get(name);
}
public T getCookie(String name, Class cls, T defaultValue) {
return ObjectUtil.getValue(getCookie(name), cls, defaultValue);
}
public void setCookie(String name, Object value) {
// update the response
HttpRequestUtil.setCookieValue(getRes(), name, value, true);
// update the cookieMap (making sure that the template gets what we send to the browser)
if (value != null) {
getCookieMap().put(name, value.toString());
} else {
removeCookie(name);
}
}
public void removeCookie(String name) {
// update the response
HttpRequestUtil.removeCookie(getReq(), getRes(), name);
// update the cookieMap
getCookieMap().remove(name);
}
/*--------- /Cookie Methods ---------*/
// --------- WebState Methods --------- //
/**
* @param stateContext
* @return return a WebState for a given uiContext. Never return null.
*/
/*
* TODO: needs to implement WebStateHandler public WebStateHandle getWebState(String stateContext){ if (webStateMap
* == null){ webStateMap = new HashMap(); } WebStateHandle webState =
* webStateMap.get(stateContext); if (webState == null){ webState =
* getWebStateHandleFactory().constructWebStateHandle(stateContext, this); webStateMap.put(stateContext, webState);
* } return webState; }
*/
// --------- /WebState Methods --------- //
// --------- Paths --------- //
public String[] getResourcePaths() {
return splitPath(getResourcePath());
}
public String getResourcePathAt(int i) {
return pathAt(getResourcePaths(), i);
}
public T getResourcePathAt(int i, Class cls) {
return pathAt(getResourcePaths(), i, cls, null);
}
public T getResourcePathAt(int i, Class cls, T defaultValue) {
return pathAt(getResourcePaths(), i, cls, defaultValue);
}
public String getResourcePath() {
return resourcePath;
}
public void setResourcePath(String resourcePath) {
this.resourcePath = resourcePath;
}
public void setFramePaths(String[] framePaths) {
if (framePaths != null) {
ArrayDeque stack = new ArrayDeque();
stack.addAll(Arrays.asList(framePaths));
framePathsStack = stack;
}
}
public String popFramePath() {
if (framePathsStack != null && !framePathsStack.isEmpty()) {
return framePathsStack.pop();
} else {
return null;
}
}
// --------- /Paths --------- //
// --------- Utilities for Paths --------- //
// TODO: probably does not need to be that complicated. Might want to use Guava here.
static private String[] splitPath(String path) {
String[] paths = null;
String[] tmpPaths = path.split("/");
// remove the first element (always empty since the currentPri
// start starts with "/")
if (tmpPaths.length > 1) {
paths = new String[tmpPaths.length - 1];
if (tmpPaths.length > 1) {
System.arraycopy(tmpPaths, 1, paths, 0, paths.length);
}
} else {
paths = new String[0];
}
return paths;
}
static private String pathAt(String[] paths, int i) {
if (paths.length > i) {
return paths[i];
} else {
return null;
}
}
public T pathAt(String[] paths, int i, Class cls, T defaultValue) {
String valueStr = pathAt(paths, i);
return ObjectUtil.getValue(valueStr, cls, defaultValue);
}
// --------- /Utilities for Paths --------- //
/*--------- Writer ---------*/
public Writer getWriter() {
try {
return res.getWriter();
} catch (IOException e) {
throw Throwables.propagate(e);
}
}
/*--------- /Writer ---------*/
/*--------- RootModel ---------*/
/**
* Return the value in the model map (the m.**) with the appropriate type or null if not found.
*
* @see #getModelValue(String, Class, Object)
*/
public T getModelValue(String namePath, Class cls) {
return getModelValue(namePath, cls, null);
}
/**
* Return the value in the model map (the m.**) with the appropriate type and fall back value.
*
* @param
* @param namePath
* path deliminated with the ".". Note that the "m." should not be in this namePath.
* @param cls
* The type of the value to be casted to
* @param defaultValue
* The fall back value
* @return
*/
public T getModelValue(String namePath, Class cls, T defaultValue) {
return MapUtil.getDeepValue(webModel, namePath, cls, defaultValue);
}
/**
* @return the Model M (use for the page model "m")
*/
public Map getWebModel() {
return webModel;
}
/*--------- /RootModel ---------*/
public WebActionResponse getWebActionResponse() {
return webActionResponse;
}
public void setWebActionResponse(WebActionResponse webActionResponse) {
this.webActionResponse = webActionResponse;
}
/*--------- HttpServlet ---------*/
public HttpServletRequest getReq() {
return req;
}
public HttpServletResponse getRes() {
return res;
}
public ServletContext getServletContext() {
return servletContext;
}
public String getContextPath() {
HttpServletRequest request = getReq();
if (request != null) {
return request.getContextPath();
}
return null;
}
public String getPathInfo() {
if (pathInfo == null) {
if (req != null) {
// first try the traditional way
pathInfo = req.getPathInfo();
// otherwise build it from the requestURI
if (pathInfo == null) {
// remove the contextPath
pathInfo = req.getRequestURI().substring(req.getContextPath().length());
try {
pathInfo = URLDecoder.decode(pathInfo, "UTF-8");
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
logger.error(e.getMessage());
}
}
}
}
return pathInfo;
}
/*--------- /HttpServlet ---------*/
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy