Java tutorial
/******************************************************************************* * 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.noerp.base.util; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.FileNameMap; import java.net.URLConnection; import java.nio.ByteBuffer; import java.sql.Timestamp; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Currency; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; import java.util.TimeZone; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.apache.commons.lang.RandomStringUtils; import org.apache.oro.text.regex.MalformedPatternException; import org.apache.oro.text.regex.Pattern; import org.apache.oro.text.regex.PatternMatcher; import org.apache.oro.text.regex.Perl5Matcher; import com.ibm.icu.util.Calendar; /** * HttpUtil - Misc HTTP Utility Functions */ public class UtilHttp { public static final String module = UtilHttp.class.getName(); public static final String MULTI_ROW_DELIMITER = "_o_"; public static final String ROW_SUBMIT_PREFIX = "_rowSubmit_o_"; public static final String COMPOSITE_DELIMITER = "_c_"; public static final int MULTI_ROW_DELIMITER_LENGTH = MULTI_ROW_DELIMITER.length(); public static final int ROW_SUBMIT_PREFIX_LENGTH = ROW_SUBMIT_PREFIX.length(); public static final int COMPOSITE_DELIMITER_LENGTH = COMPOSITE_DELIMITER.length(); /** * Create a combined map from servlet context, session, attributes and parameters * @return The resulting Map */ public static Map<String, Object> getCombinedMap(HttpServletRequest request) { return getCombinedMap(request, null); } /** * Create a combined map from servlet context, session, attributes and parameters * -- this method will only use the skip names for session and servlet context attributes * @return The resulting Map */ public static Map<String, Object> getCombinedMap(HttpServletRequest request, Set<? extends String> namesToSkip) { Map<String, Object> combinedMap = new HashMap<String, Object>(); combinedMap.putAll(getParameterMap(request)); // parameters override nothing combinedMap.putAll(getServletContextMap(request, namesToSkip)); // bottom level application attributes combinedMap.putAll(getSessionMap(request, namesToSkip)); // session overrides application combinedMap.putAll(getAttributeMap(request)); // attributes trump them all return combinedMap; } /** * Create a map from a HttpServletRequest (parameters) object * @return The resulting Map */ public static Map<String, Object> getParameterMap(HttpServletRequest request) { return getParameterMap(request, null, null); } public static Map<String, Object> getParameterMap(HttpServletRequest request, Set<? extends String> nameSet) { return getParameterMap(request, nameSet, null); } /** * Create a map from a HttpServletRequest (parameters) object * @param onlyIncludeOrSkip If true only include, if false skip, the named parameters in the nameSet. If this is null and nameSet is not null, default to skip. * @return The resulting Map */ public static Map<String, Object> getParameterMap(HttpServletRequest request, Set<? extends String> nameSet, Boolean onlyIncludeOrSkip) { boolean onlyIncludeOrSkipPrim = onlyIncludeOrSkip == null ? true : onlyIncludeOrSkip.booleanValue(); Map<String, Object> paramMap = new HashMap<String, Object>(); // add all the actual HTTP request parameters Enumeration<String> e = UtilGenerics.cast(request.getParameterNames()); while (e.hasMoreElements()) { String name = e.nextElement(); if (nameSet != null && (onlyIncludeOrSkipPrim ^ nameSet.contains(name))) { continue; } Object value = null; String[] paramArr = request.getParameterValues(name); if (paramArr != null) { if (paramArr.length > 1) { value = Arrays.asList(paramArr); } else { value = paramArr[0]; // does the same thing basically, nothing better about it as far as I can see: value = request.getParameter(name); } } paramMap.put(name, value); } paramMap.putAll(getPathInfoOnlyParameterMap(request, nameSet, onlyIncludeOrSkip)); if (paramMap.size() == 0) { // nothing found in the parameters; maybe we read the stream instead Map<String, Object> multiPartMap = UtilGenerics.checkMap(request.getAttribute("multiPartMap")); if (UtilValidate.isNotEmpty(multiPartMap)) { paramMap.putAll(multiPartMap); } } if (Debug.verboseOn()) { Debug.logVerbose("Made Request Parameter Map with [" + paramMap.size() + "] Entries", module); Debug.logVerbose("Request Parameter Map Entries: " + System.getProperty("line.separator") + UtilMisc.printMap(paramMap), module); } return canonicalizeParameterMap(paramMap); } public static Map<String, Object> getQueryStringOnlyParameterMap(String queryString) { Map<String, Object> paramMap = new HashMap<String, Object>(); if (UtilValidate.isNotEmpty(queryString)) { StringTokenizer queryTokens = new StringTokenizer(queryString, "&"); while (queryTokens.hasMoreTokens()) { String token = queryTokens.nextToken(); if (token.startsWith("amp;")) { // this is most likely a split value that had an & in it, so don't consider this a name; note that some old code just stripped the "amp;" and went with it //token = token.substring(4); continue; } int equalsIndex = token.indexOf("="); String name = token; if (equalsIndex > 0) { name = token.substring(0, equalsIndex); paramMap.put(name, token.substring(equalsIndex + 1)); } } } return canonicalizeParameterMap(paramMap); } public static Map<String, Object> getPathInfoOnlyParameterMap(HttpServletRequest request, Set<? extends String> nameSet, Boolean onlyIncludeOrSkip) { return getPathInfoOnlyParameterMap(request.getPathInfo(), nameSet, onlyIncludeOrSkip); } public static Map<String, Object> getPathInfoOnlyParameterMap(String pathInfoStr, Set<? extends String> nameSet, Boolean onlyIncludeOrSkip) { boolean onlyIncludeOrSkipPrim = onlyIncludeOrSkip == null ? true : onlyIncludeOrSkip.booleanValue(); Map<String, Object> paramMap = new HashMap<String, Object>(); // now add in all path info parameters /~name1=value1/~name2=value2/ // note that if a parameter with a given name already exists it will be put into a list with all values if (UtilValidate.isNotEmpty(pathInfoStr)) { // make sure string ends with a trailing '/' so we get all values if (!pathInfoStr.endsWith("/")) pathInfoStr += "/"; int current = pathInfoStr.indexOf('/'); int last = current; while ((current = pathInfoStr.indexOf('/', last + 1)) != -1) { String element = pathInfoStr.substring(last + 1, current); last = current; if (element.charAt(0) == '~' && element.indexOf('=') > -1) { String name = element.substring(1, element.indexOf('=')); if (nameSet != null && (onlyIncludeOrSkipPrim ^ nameSet.contains(name))) { continue; } String value = element.substring(element.indexOf('=') + 1); Object curValue = paramMap.get(name); if (curValue != null) { List<String> paramList = null; if (curValue instanceof List<?>) { paramList = UtilGenerics.checkList(curValue); paramList.add(value); } else { String paramString = (String) curValue; paramList = new LinkedList<String>(); paramList.add(paramString); paramList.add(value); } paramMap.put(name, paramList); } else { paramMap.put(name, value); } } } } return canonicalizeParameterMap(paramMap); } public static Map<String, Object> getUrlOnlyParameterMap(HttpServletRequest request) { // NOTE: these have already been through canonicalizeParameterMap, so not doing it again here Map<String, Object> paramMap = getQueryStringOnlyParameterMap(request.getQueryString()); paramMap.putAll(getPathInfoOnlyParameterMap(request.getPathInfo(), null, null)); return paramMap; } public static Map<String, Object> canonicalizeParameterMap(Map<String, Object> paramMap) { for (Map.Entry<String, Object> paramEntry : paramMap.entrySet()) { if (paramEntry.getValue() instanceof String) { paramEntry.setValue(canonicalizeParameter((String) paramEntry.getValue())); } else if (paramEntry.getValue() instanceof Collection<?>) { List<String> newList = new LinkedList<String>(); for (String listEntry : UtilGenerics.<String>checkCollection(paramEntry.getValue())) { newList.add(canonicalizeParameter(listEntry)); } paramEntry.setValue(newList); } } return paramMap; } public static String canonicalizeParameter(String paramValue) { try { /** calling canonicalize with strict flag set to false so we only get warnings about double encoding, etc; can be set to true for exceptions and more security */ String cannedStr = UtilCodec.canonicalize(paramValue, false); if (Debug.verboseOn()) Debug.logVerbose("Canonicalized parameter with " + (cannedStr.equals(paramValue) ? "no " : "") + "change: original [" + paramValue + "] canned [" + cannedStr + "]", module); return cannedStr; } catch (Exception e) { Debug.logError(e, "Error in canonicalize parameter value [" + paramValue + "]: " + e.toString(), module); return paramValue; } } /** * Create a map from a HttpRequest (attributes) object used in JSON requests * @return The resulting Map */ public static Map<String, Object> getJSONAttributeMap(HttpServletRequest request) { Map<String, Object> returnMap = new HashMap<String, Object>(); Map<String, Object> attrMap = getAttributeMap(request); for (Map.Entry<String, Object> entry : attrMap.entrySet()) { String key = entry.getKey(); Object val = entry.getValue(); if (val instanceof java.sql.Timestamp) { val = val.toString(); } if (val instanceof String || val instanceof Number || val instanceof Map<?, ?> || val instanceof List<?> || val instanceof Boolean) { if (Debug.verboseOn()) Debug.logVerbose("Adding attribute to JSON output: " + key, module); returnMap.put(key, val); } } return returnMap; } /** * Create a map from a HttpRequest (attributes) object * @return The resulting Map */ public static Map<String, Object> getAttributeMap(HttpServletRequest request) { return getAttributeMap(request, null); } /** * Create a map from a HttpRequest (attributes) object * @return The resulting Map */ public static Map<String, Object> getAttributeMap(HttpServletRequest request, Set<? extends String> namesToSkip) { Map<String, Object> attributeMap = new HashMap<String, Object>(); // look at all request attributes Enumeration<String> requestAttrNames = UtilGenerics.cast(request.getAttributeNames()); while (requestAttrNames.hasMoreElements()) { String attrName = requestAttrNames.nextElement(); if (namesToSkip != null && namesToSkip.contains(attrName)) continue; Object attrValue = request.getAttribute(attrName); attributeMap.put(attrName, attrValue); } if (Debug.verboseOn()) { Debug.logVerbose("Made Request Attribute Map with [" + attributeMap.size() + "] Entries", module); Debug.logVerbose("Request Attribute Map Entries: " + System.getProperty("line.separator") + UtilMisc.printMap(attributeMap), module); } return attributeMap; } /** * Create a map from a HttpSession object * @return The resulting Map */ public static Map<String, Object> getSessionMap(HttpServletRequest request) { return getSessionMap(request, null); } /** * Create a map from a HttpSession object * @return The resulting Map */ public static Map<String, Object> getSessionMap(HttpServletRequest request, Set<? extends String> namesToSkip) { Map<String, Object> sessionMap = new HashMap<String, Object>(); HttpSession session = request.getSession(); // look at all the session attributes Enumeration<String> sessionAttrNames = UtilGenerics.cast(session.getAttributeNames()); while (sessionAttrNames.hasMoreElements()) { String attrName = sessionAttrNames.nextElement(); if (namesToSkip != null && namesToSkip.contains(attrName)) continue; Object attrValue = session.getAttribute(attrName); sessionMap.put(attrName, attrValue); } if (Debug.verboseOn()) { Debug.logVerbose("Made Session Attribute Map with [" + sessionMap.size() + "] Entries", module); Debug.logVerbose("Session Attribute Map Entries: " + System.getProperty("line.separator") + UtilMisc.printMap(sessionMap), module); } return sessionMap; } /** * Create a map from a ServletContext object * @return The resulting Map */ public static Map<String, Object> getServletContextMap(HttpServletRequest request) { return getServletContextMap(request, null); } /** * Create a map from a ServletContext object * @return The resulting Map */ public static Map<String, Object> getServletContextMap(HttpServletRequest request, Set<? extends String> namesToSkip) { Map<String, Object> servletCtxMap = new HashMap<String, Object>(); // look at all servlet context attributes ServletContext servletContext = (ServletContext) request.getAttribute("servletContext"); Enumeration<String> applicationAttrNames = UtilGenerics.cast(servletContext.getAttributeNames()); while (applicationAttrNames.hasMoreElements()) { String attrName = applicationAttrNames.nextElement(); if (namesToSkip != null && namesToSkip.contains(attrName)) continue; Object attrValue = servletContext.getAttribute(attrName); servletCtxMap.put(attrName, attrValue); } if (Debug.verboseOn()) { Debug.logVerbose("Made ServletContext Attribute Map with [" + servletCtxMap.size() + "] Entries", module); Debug.logVerbose("ServletContext Attribute Map Entries: " + System.getProperty("line.separator") + UtilMisc.printMap(servletCtxMap), module); } return servletCtxMap; } public static Map<String, Object> makeParamMapWithPrefix(HttpServletRequest request, String prefix, String suffix) { return makeParamMapWithPrefix(request, null, prefix, suffix); } public static Map<String, Object> makeParamMapWithPrefix(HttpServletRequest request, Map<String, ? extends Object> additionalFields, String prefix, String suffix) { return makeParamMapWithPrefix(getCombinedMap(request), additionalFields, prefix, suffix); } public static Map<String, Object> makeParamMapWithPrefix(Map<String, ? extends Object> context, Map<String, ? extends Object> additionalFields, String prefix, String suffix) { Map<String, Object> paramMap = new HashMap<String, Object>(); for (Map.Entry<String, ? extends Object> entry : context.entrySet()) { String parameterName = entry.getKey(); if (parameterName.startsWith(prefix)) { if (UtilValidate.isNotEmpty(suffix)) { if (parameterName.endsWith(suffix)) { String key = parameterName.substring(prefix.length(), parameterName.length() - (suffix.length())); if (entry.getValue() instanceof ByteBuffer) { ByteBuffer value = (ByteBuffer) entry.getValue(); paramMap.put(key, value); } else { String value = (String) entry.getValue(); paramMap.put(key, value); } } } else { String key = parameterName.substring(prefix.length()); if (context.get(parameterName) instanceof ByteBuffer) { ByteBuffer value = (ByteBuffer) entry.getValue(); paramMap.put(key, value); } else { String value = (String) entry.getValue(); paramMap.put(key, value); } } } } if (additionalFields != null) { for (Map.Entry<String, ? extends Object> entry : additionalFields.entrySet()) { String fieldName = entry.getKey(); if (fieldName.startsWith(prefix)) { if (UtilValidate.isNotEmpty(suffix)) { if (fieldName.endsWith(suffix)) { String key = fieldName.substring(prefix.length(), fieldName.length() - (suffix.length() - 1)); Object value = entry.getValue(); paramMap.put(key, value); // check for image upload data if (!(value instanceof String)) { String nameKey = "_" + key + "_fileName"; Object nameVal = additionalFields.get("_" + fieldName + "_fileName"); if (nameVal != null) { paramMap.put(nameKey, nameVal); } String typeKey = "_" + key + "_contentType"; Object typeVal = additionalFields.get("_" + fieldName + "_contentType"); if (typeVal != null) { paramMap.put(typeKey, typeVal); } String sizeKey = "_" + key + "_size"; Object sizeVal = additionalFields.get("_" + fieldName + "_size"); if (sizeVal != null) { paramMap.put(sizeKey, sizeVal); } } } } else { String key = fieldName.substring(prefix.length()); Object value = entry.getValue(); paramMap.put(key, value); // check for image upload data if (!(value instanceof String)) { String nameKey = "_" + key + "_fileName"; Object nameVal = additionalFields.get("_" + fieldName + "_fileName"); if (nameVal != null) { paramMap.put(nameKey, nameVal); } String typeKey = "_" + key + "_contentType"; Object typeVal = additionalFields.get("_" + fieldName + "_contentType"); if (typeVal != null) { paramMap.put(typeKey, typeVal); } String sizeKey = "_" + key + "_size"; Object sizeVal = additionalFields.get("_" + fieldName + "_size"); if (sizeVal != null) { paramMap.put(sizeKey, sizeVal); } } } } } } return paramMap; } public static List<Object> makeParamListWithSuffix(HttpServletRequest request, String suffix, String prefix) { return makeParamListWithSuffix(request, null, suffix, prefix); } public static List<Object> makeParamListWithSuffix(HttpServletRequest request, Map<String, ? extends Object> additionalFields, String suffix, String prefix) { List<Object> paramList = new ArrayList<Object>(); Enumeration<String> parameterNames = UtilGenerics.cast(request.getParameterNames()); while (parameterNames.hasMoreElements()) { String parameterName = parameterNames.nextElement(); if (parameterName.endsWith(suffix)) { if (UtilValidate.isNotEmpty(prefix)) { if (parameterName.startsWith(prefix)) { String value = request.getParameter(parameterName); paramList.add(value); } } else { String value = request.getParameter(parameterName); paramList.add(value); } } } if (additionalFields != null) { for (Map.Entry<String, ? extends Object> entry : additionalFields.entrySet()) { String fieldName = entry.getKey(); if (fieldName.endsWith(suffix)) { if (UtilValidate.isNotEmpty(prefix)) { if (fieldName.startsWith(prefix)) { paramList.add(entry.getValue()); } } else { paramList.add(entry.getValue()); } } } } return paramList; } /** * Given a request, returns the application name or "root" if deployed on root * @param request An HttpServletRequest to get the name info from * @return String */ public static String getApplicationName(HttpServletRequest request) { String appName = "root"; if (request.getContextPath().length() > 1) { appName = request.getContextPath().substring(1); } return appName; } public static void setInitialRequestInfo(HttpServletRequest request) { HttpSession session = request.getSession(); if (UtilValidate.isNotEmpty(session.getAttribute("_WEBAPP_NAME_"))) { // oops, info already in place... return; } String fullRequestUrl = getFullRequestUrl(request); session.setAttribute("_WEBAPP_NAME_", getApplicationName(request)); session.setAttribute("_CLIENT_LOCALE_", request.getLocale()); session.setAttribute("_CLIENT_REQUEST_", fullRequestUrl); session.setAttribute("_CLIENT_USER_AGENT_", request.getHeader("User-Agent") != null ? request.getHeader("User-Agent") : ""); session.setAttribute("_CLIENT_REFERER_", request.getHeader("Referer") != null ? request.getHeader("Referer") : ""); session.setAttribute("_CLIENT_FORWARDED_FOR_", request.getHeader("X-Forwarded-For")); session.setAttribute("_CLIENT_REMOTE_ADDR_", request.getRemoteAddr()); session.setAttribute("_CLIENT_REMOTE_HOST_", request.getRemoteHost()); session.setAttribute("_CLIENT_REMOTE_USER_", request.getRemoteUser()); } /** * Put request parameters in request object as attributes. * @param request */ public static void parametersToAttributes(HttpServletRequest request) { java.util.Enumeration<String> e = UtilGenerics.cast(request.getParameterNames()); while (e.hasMoreElements()) { String name = e.nextElement(); request.setAttribute(name, request.getParameter(name)); } } private static StringBuilder prepareServerRootUrl(HttpServletRequest request) { StringBuilder requestUrl = new StringBuilder(); requestUrl.append(request.getScheme()); requestUrl.append("://" + request.getServerName()); if (request.getServerPort() != 80 && request.getServerPort() != 443) requestUrl.append(":" + request.getServerPort()); return requestUrl; } public static String getServerRootUrl(HttpServletRequest request) { return prepareServerRootUrl(request).toString(); } public static String getFullRequestUrl(HttpServletRequest request) { StringBuilder requestUrl = prepareServerRootUrl(request); requestUrl.append(request.getRequestURI()); if (request.getQueryString() != null) { requestUrl.append("?" + request.getQueryString()); } return requestUrl.toString(); } public static Locale getLocale(HttpServletRequest request, HttpSession session, Object appDefaultLocale) { // check session first, should override all if anything set there Object localeObject = session != null ? session.getAttribute("locale") : null; // next see if the userLogin has a value if (localeObject == null) { Map<?, ?> userLogin = (Map<?, ?>) session.getAttribute("userLogin"); if (userLogin == null) { userLogin = (Map<?, ?>) session.getAttribute("autoUserLogin"); } if (userLogin != null) { localeObject = userLogin.get("lastLocale"); } } // no user locale? before global default try appDefaultLocale if specified if (localeObject == null && !UtilValidate.isEmpty(appDefaultLocale)) { localeObject = appDefaultLocale; } // finally request (w/ a fall back to default) if (localeObject == null) { localeObject = request != null ? request.getLocale() : null; } return UtilMisc.ensureLocale(localeObject); } /** * Get the Locale object from a session variable; if not found use the browser's default * @param request HttpServletRequest object to use for lookup * @return Locale The current Locale to use */ public static Locale getLocale(HttpServletRequest request) { if (request == null) return Locale.getDefault(); return getLocale(request, request.getSession(), null); } /** * Get the Locale object from a session variable; if not found use the system's default. * NOTE: This method is not recommended because it ignores the Locale from the browser not having the request object. * @param session HttpSession object to use for lookup * @return Locale The current Locale to use */ public static Locale getLocale(HttpSession session) { if (session == null) return Locale.getDefault(); return getLocale(null, session, null); } public static void setLocale(HttpServletRequest request, String localeString) { setLocale(request.getSession(), UtilMisc.parseLocale(localeString)); } public static void setLocale(HttpSession session, Locale locale) { session.setAttribute("locale", locale); } public static void setLocaleIfNone(HttpSession session, String localeString) { if (UtilValidate.isNotEmpty(localeString) && session.getAttribute("locale") == null) { setLocale(session, UtilMisc.parseLocale(localeString)); } } public static void setTimeZone(HttpServletRequest request, String tzId) { setTimeZone(request.getSession(), UtilDateTime.toTimeZone(tzId)); } public static void setTimeZone(HttpSession session, TimeZone timeZone) { session.setAttribute("timeZone", timeZone); } public static TimeZone getTimeZone(HttpServletRequest request) { HttpSession session = request.getSession(); TimeZone timeZone = null; Map<String, String> userLogin = UtilGenerics.cast(session.getAttribute("userLogin")); if (userLogin != null) { String tzId = userLogin.get("lastTimeZone"); if (tzId != null) { timeZone = TimeZone.getTimeZone(tzId); } } if (timeZone == null) { timeZone = TimeZone.getDefault(); } session.setAttribute("timeZone", timeZone); return timeZone; } /** * Get the currency string from the session. * @param session HttpSession object to use for lookup * @return String The ISO currency code */ public static String getCurrencyUom(HttpSession session, String appDefaultCurrencyUom) { // session, should override all if set there String iso = (String) session.getAttribute("currencyUom"); // check userLogin next, ie if nothing to override in the session if (iso == null) { Map<String, ?> userLogin = UtilGenerics.cast(session.getAttribute("userLogin")); if (userLogin == null) { userLogin = UtilGenerics.cast(session.getAttribute("autoUserLogin")); } if (userLogin != null) { iso = (String) userLogin.get("lastCurrencyUom"); } } // no user currency? before global default try appDefaultCurrencyUom if specified if (iso == null && !UtilValidate.isEmpty(appDefaultCurrencyUom)) { iso = appDefaultCurrencyUom; } // if none is set we will use the configured default if (iso == null) { try { iso = UtilProperties.getPropertyValue("general", "currency.uom.id.default", "USD"); } catch (Exception e) { Debug.logWarning("Error getting the general:currency.uom.id.default value: " + e.toString(), module); } } // if still none we will use the default for whatever locale we can get... if (iso == null) { Currency cur = Currency.getInstance(getLocale(session)); iso = cur.getCurrencyCode(); } return iso; } /** * Get the currency string from the session. * @param request HttpServletRequest object to use for lookup * @return String The ISO currency code */ public static String getCurrencyUom(HttpServletRequest request) { return getCurrencyUom(request.getSession(), null); } /** Simple event to set the users per-session currency uom value */ public static void setCurrencyUom(HttpSession session, String currencyUom) { session.setAttribute("currencyUom", currencyUom); } public static void setCurrencyUomIfNone(HttpSession session, String currencyUom) { if (UtilValidate.isNotEmpty(currencyUom) && session.getAttribute("currencyUom") == null) { session.setAttribute("currencyUom", currencyUom); } } /** URL Encodes a Map of arguements */ public static String urlEncodeArgs(Map<String, ? extends Object> args) { return urlEncodeArgs(args, true); } /** URL Encodes a Map of arguements */ public static String urlEncodeArgs(Map<String, ? extends Object> args, boolean useExpandedEntites) { StringBuilder buf = new StringBuilder(); if (args != null) { for (Map.Entry<String, ? extends Object> entry : args.entrySet()) { String name = entry.getKey(); Object value = entry.getValue(); String valueStr = null; if (name == null || value == null) { continue; } Collection<?> col; if (value instanceof String) { col = Arrays.asList(value); } else if (value instanceof Collection) { col = UtilGenerics.cast(value); } else if (value.getClass().isArray()) { col = Arrays.asList((Object[]) value); } else { col = Arrays.asList(value); } for (Object colValue : col) { if (colValue instanceof String) { valueStr = (String) colValue; } else if (colValue == null) { continue; } else { valueStr = colValue.toString(); } if (UtilValidate.isNotEmpty(valueStr)) { if (buf.length() > 0) { if (useExpandedEntites) { buf.append("&"); } else { buf.append("&"); } } buf.append(UtilCodec.getEncoder("url").encode(name)); /* the old way: try { buf.append(URLEncoder.encode(name, "UTF-8")); } catch (UnsupportedEncodingException e) { Debug.logError(e, module); } */ buf.append('='); buf.append(UtilCodec.getEncoder("url").encode(valueStr)); /* the old way: try { buf.append(URLEncoder.encode(valueStr, "UTF-8")); } catch (UnsupportedEncodingException e) { Debug.logError(e, module); } */ } } } } return buf.toString(); } public static String getRequestUriFromTarget(String target) { if (UtilValidate.isEmpty(target)) return null; int endOfRequestUri = target.length(); if (target.indexOf('?') > 0) { endOfRequestUri = target.indexOf('?'); } int slashBeforeRequestUri = target.lastIndexOf('/', endOfRequestUri); String requestUri = null; if (slashBeforeRequestUri < 0) { requestUri = target.substring(0, endOfRequestUri); } else { requestUri = target.substring(slashBeforeRequestUri, endOfRequestUri); } return requestUri; } /** Returns the query string contained in a request target - basically everything * after and including the ? character. * @param target The request target * @return The query string */ public static String getQueryStringFromTarget(String target) { if (UtilValidate.isEmpty(target)) return ""; int queryStart = target.indexOf('?'); if (queryStart != -1) { return target.substring(queryStart); } return ""; } /** Removes the query string from a request target - basically everything * after and including the ? character. * @param target The request target * @return The request target string */ public static String removeQueryStringFromTarget(String target) { if (UtilValidate.isEmpty(target)) return null; int queryStart = target.indexOf('?'); if (queryStart < 0) { return target; } return target.substring(0, queryStart); } public static String getWebappMountPointFromTarget(String target) { int firstChar = 0; if (UtilValidate.isEmpty(target)) return null; if (target.charAt(0) == '/') firstChar = 1; int pathSep = target.indexOf('/', 1); String webappMountPoint = null; if (pathSep > 0) { // if not then no good, supposed to be a inter-app, but there is no path sep! will do general search with null and treat like an intra-app webappMountPoint = target.substring(firstChar, pathSep); } return webappMountPoint; } public static String encodeAmpersands(String htmlString) { StringBuilder htmlBuffer = new StringBuilder(htmlString); int ampLoc = -1; while ((ampLoc = htmlBuffer.indexOf("&", ampLoc + 1)) != -1) { //NOTE: this should work fine, but if it doesn't could try making sure all characters between & and ; are letters, that would qualify as an entity // found ampersand, is it already and entity? if not change it to & int semiLoc = htmlBuffer.indexOf(";", ampLoc); if (semiLoc != -1) { // found a semi colon, if it has another & or an = before it, don't count it as an entity, otherwise it may be an entity, so skip it int eqLoc = htmlBuffer.indexOf("=", ampLoc); int amp2Loc = htmlBuffer.indexOf("&", ampLoc + 1); if ((eqLoc == -1 || eqLoc > semiLoc) && (amp2Loc == -1 || amp2Loc > semiLoc)) { continue; } } // at this point not an entity, no substitute with a & htmlBuffer.insert(ampLoc + 1, "amp;"); } return htmlBuffer.toString(); } public static String encodeBlanks(String htmlString) { return htmlString.replaceAll(" ", "%20"); } public static String setResponseBrowserProxyNoCache(HttpServletRequest request, HttpServletResponse response) { setResponseBrowserProxyNoCache(response); return "success"; } public static void setResponseBrowserProxyNoCache(HttpServletResponse response) { long nowMillis = System.currentTimeMillis(); response.setDateHeader("Expires", nowMillis); response.setDateHeader("Last-Modified", nowMillis); // always modified response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate"); // HTTP/1.1 response.addHeader("Cache-Control", "post-check=0, pre-check=0, false"); response.setHeader("Pragma", "no-cache"); // HTTP/1.0 } public static String getContentTypeByFileName(String fileName) { FileNameMap mime = URLConnection.getFileNameMap(); return mime.getContentTypeFor(fileName); } /** * Stream an array of bytes to the browser * This method will close the ServletOutputStream when finished * * @param response HttpServletResponse object to get OutputStream from * @param bytes Byte array of content to stream * @param contentType The content type to pass to the browser * @param fileName the fileName to tell the browser we are downloading * @throws IOException */ public static void streamContentToBrowser(HttpServletResponse response, byte[] bytes, String contentType, String fileName) throws IOException { // tell the browser not the cache setResponseBrowserProxyNoCache(response); // set the response info response.setContentLength(bytes.length); if (contentType != null) { response.setContentType(contentType); } if (fileName != null) { response.setHeader("Content-Disposition", "attachment;filename=\"" + fileName + "\""); } // create the streams OutputStream out = response.getOutputStream(); InputStream in = new ByteArrayInputStream(bytes); // stream the content try { streamContent(out, in, bytes.length); } catch (IOException e) { in.close(); out.close(); // should we close the ServletOutputStream on error?? throw e; } // close the input stream in.close(); // close the servlet output stream out.flush(); out.close(); } public static void streamContentToBrowser(HttpServletResponse response, byte[] bytes, String contentType) throws IOException { streamContentToBrowser(response, bytes, contentType, null); } /** * Streams content from InputStream to the ServletOutputStream * This method will close the ServletOutputStream when finished * This method does not close the InputSteam passed * * @param response HttpServletResponse object to get OutputStream from * @param in InputStream of the actual content * @param length Size (in bytes) of the content * @param contentType The content type to pass to the browser * @throws IOException */ public static void streamContentToBrowser(HttpServletResponse response, InputStream in, int length, String contentType, String fileName) throws IOException { // tell the browser not the cache setResponseBrowserProxyNoCache(response); // set the response info response.setContentLength(length); if (contentType != null) { response.setContentType(contentType); } if (fileName != null) { response.setHeader("Content-Disposition", "attachment;filename=\"" + fileName + "\""); } // stream the content OutputStream out = response.getOutputStream(); try { streamContent(out, in, length); } catch (IOException e) { out.close(); throw e; } // close the servlet output stream out.flush(); out.close(); } public static void streamContentToBrowser(HttpServletResponse response, InputStream in, int length, String contentType) throws IOException { streamContentToBrowser(response, in, length, contentType, null); } /** * Stream binary content from InputStream to OutputStream * This method does not close the streams passed * * @param out OutputStream content should go to * @param in InputStream of the actual content * @param length Size (in bytes) of the content * @throws IOException */ public static void streamContent(OutputStream out, InputStream in, int length) throws IOException { int bufferSize = 512; // same as the default buffer size; change as needed // make sure we have something to write to if (out == null) { throw new IOException("Attempt to write to null output stream"); } // make sure we have something to read from if (in == null) { throw new IOException("Attempt to read from null input stream"); } // make sure we have some content if (length == 0) { throw new IOException("Attempt to write 0 bytes of content to output stream"); } // initialize the buffered streams BufferedOutputStream bos = new BufferedOutputStream(out, bufferSize); BufferedInputStream bis = new BufferedInputStream(in, bufferSize); byte[] buffer = new byte[length]; int read = 0; try { while ((read = bis.read(buffer, 0, buffer.length)) != -1) { bos.write(buffer, 0, read); } } catch (IOException e) { Debug.logError(e, "Problem reading/writing buffers", module); bis.close(); bos.close(); throw e; } finally { if (bis != null) { bis.close(); } if (bos != null) { bos.flush(); bos.close(); } } } public static String stripViewParamsFromQueryString(String queryString) { return stripViewParamsFromQueryString(queryString, null); } public static String stripViewParamsFromQueryString(String queryString, String paginatorNumber) { Set<String> paramNames = new HashSet<String>(); if (UtilValidate.isNotEmpty(paginatorNumber)) { paginatorNumber = "_" + paginatorNumber; } paramNames.add("VIEW_INDEX" + paginatorNumber); paramNames.add("VIEW_SIZE" + paginatorNumber); paramNames.add("viewIndex" + paginatorNumber); paramNames.add("viewSize" + paginatorNumber); return stripNamedParamsFromQueryString(queryString, paramNames); } public static String stripNamedParamsFromQueryString(String queryString, Collection<String> paramNames) { String retStr = null; if (UtilValidate.isNotEmpty(queryString)) { StringTokenizer queryTokens = new StringTokenizer(queryString, "&"); StringBuilder cleanQuery = new StringBuilder(); while (queryTokens.hasMoreTokens()) { String token = queryTokens.nextToken(); if (token.startsWith("amp;")) { token = token.substring(4); } int equalsIndex = token.indexOf("="); String name = token; if (equalsIndex > 0) { name = token.substring(0, equalsIndex); } if (!paramNames.contains(name)) { if (cleanQuery.length() > 0) { cleanQuery.append("&"); } cleanQuery.append(token); } } retStr = cleanQuery.toString(); } return retStr; } /** * Given multi form data with the ${param}_o_N notation, creates a Collection * of Maps for the submitted rows. Each Map contains the key/value pairs * of a particular row. The keys will be stripped of the _o_N suffix. * There is an additionaly key "row" for each Map that holds the * index of the row. */ public static Collection<Map<String, Object>> parseMultiFormData(Map<String, Object> parameters) { Map<Integer, Map<String, Object>> rows = new HashMap<Integer, Map<String, Object>>(); // stores the rows keyed by row number // first loop through all the keys and create a hashmap for each ${ROW_SUBMIT_PREFIX}${N} = Y for (String key : parameters.keySet()) { // skip everything that is not ${ROW_SUBMIT_PREFIX}N if (key == null || key.length() <= ROW_SUBMIT_PREFIX_LENGTH) continue; if (key.indexOf(MULTI_ROW_DELIMITER) <= 0) continue; if (!key.substring(0, ROW_SUBMIT_PREFIX_LENGTH).equals(ROW_SUBMIT_PREFIX)) continue; if (!parameters.get(key).equals("Y")) continue; // decode the value of N and create a new map for it Integer n = Integer.decode(key.substring(ROW_SUBMIT_PREFIX_LENGTH, key.length())); Map<String, Object> m = new HashMap<String, Object>(); m.put("row", n); // special "row" = N tuple rows.put(n, m); // key it to N } // next put all parameters with matching N in the right map for (Map.Entry<String, Object> entry : parameters.entrySet()) { String key = entry.getKey(); // skip keys without DELIMITER and skip ROW_SUBMIT_PREFIX if (key == null) continue; int index = key.indexOf(MULTI_ROW_DELIMITER); if (index <= 0) continue; if (key.length() > ROW_SUBMIT_PREFIX_LENGTH && key.substring(0, ROW_SUBMIT_PREFIX_LENGTH).equals(ROW_SUBMIT_PREFIX)) continue; // get the map with index N Integer n = Integer.decode(key.substring(index + MULTI_ROW_DELIMITER_LENGTH, key.length())); // N from ${param}${DELIMITER}${N} Map<String, Object> map = rows.get(n); if (map == null) continue; // get the key without the <DELIMITER>N suffix and store it and its value String newKey = key.substring(0, index); map.put(newKey, entry.getValue()); } // return only the values, which is the list of maps return rows.values(); } /** * Returns a new map containing all the parameters from the input map except for the * multi form parameters (usually named according to the ${param}_o_N notation). */ public static <V> Map<String, V> removeMultiFormParameters(Map<String, V> parameters) { Map<String, V> filteredParameters = new HashMap<String, V>(); for (Map.Entry<String, V> entry : parameters.entrySet()) { String key = entry.getKey(); if (key != null && (key.indexOf(MULTI_ROW_DELIMITER) != -1 || key.indexOf("_useRowSubmit") != -1 || key.indexOf("_rowCount") != -1)) { continue; } filteredParameters.put(key, entry.getValue()); } return filteredParameters; } /** * Utility to make a composite parameter from the given prefix and suffix. * The prefix should be a regular paramter name such as meetingDate. The * suffix is the composite field, such as the hour of the meeting. The * result would be meetingDate_${COMPOSITE_DELIMITER}_hour. * * @param prefix * @param suffix * @return the composite parameter */ public static String makeCompositeParam(String prefix, String suffix) { return prefix + COMPOSITE_DELIMITER + suffix; } /** * Given the prefix of a composite parameter, recomposes a single Object from * the composite according to compositeType. For example, consider the following * form widget field, * * <field name="meetingDate"> * <date-time type="timestamp" input-method="time-dropdown"> * </field> * * The result in HTML is three input boxes to input the date, hour and minutes separately. * The parameter names are named meetingDate_c_date, meetingDate_c_hour, meetingDate_c_minutes. * Additionally, there will be a field named meetingDate_c_compositeType with a value of "Timestamp". * where _c_ is the COMPOSITE_DELIMITER. These parameters will then be recomposed into a Timestamp * object from the composite fields. * * @param request * @param prefix * @return Composite object from data or null if not supported or a parsing error occurred. */ public static Object makeParamValueFromComposite(HttpServletRequest request, String prefix, Locale locale) { String compositeType = request.getParameter(makeCompositeParam(prefix, "compositeType")); if (UtilValidate.isEmpty(compositeType)) return null; // collect the composite fields into a map Map<String, String> data = new HashMap<String, String>(); for (Enumeration<String> names = UtilGenerics.cast(request.getParameterNames()); names.hasMoreElements();) { String name = names.nextElement(); if (!name.startsWith(prefix + COMPOSITE_DELIMITER)) continue; // extract the suffix of the composite name String suffix = name.substring(name.indexOf(COMPOSITE_DELIMITER) + COMPOSITE_DELIMITER_LENGTH); // and the value of this parameter String value = request.getParameter(name); // key = suffix, value = parameter data data.put(suffix, value); } if (Debug.verboseOn()) { Debug.logVerbose("Creating composite type with parameter data: " + data.toString(), module); } // handle recomposition of data into the compositeType if ("Timestamp".equals(compositeType)) { String date = data.get("date"); String hour = data.get("hour"); String minutes = data.get("minutes"); String ampm = data.get("ampm"); if (date == null || date.length() < 10) return null; if (UtilValidate.isEmpty(hour)) return null; if (UtilValidate.isEmpty(minutes)) return null; boolean isTwelveHour = UtilValidate.isNotEmpty(ampm); // create the timestamp from the data try { int h = Integer.parseInt(hour); Timestamp timestamp = Timestamp.valueOf(date.substring(0, 10) + " 00:00:00.000"); Calendar cal = Calendar.getInstance(locale); cal.setTime(timestamp); if (isTwelveHour) { boolean isAM = ("AM".equals(ampm) ? true : false); if (isAM && h == 12) h = 0; if (!isAM && h < 12) h += 12; } cal.set(Calendar.HOUR_OF_DAY, h); cal.set(Calendar.MINUTE, Integer.parseInt(minutes)); return new Timestamp(cal.getTimeInMillis()); } catch (IllegalArgumentException e) { Debug.logWarning("User input for composite timestamp was invalid: " + e.getMessage(), module); return null; } } // we don't support any other compositeTypes (yet) return null; } /** Obtains the session ID from the request, or "unknown" if no session pressent. */ public static String getSessionId(HttpServletRequest request) { HttpSession session = request.getSession(); return (session == null ? "unknown" : session.getId()); } /** * checks, if the current request comes from a searchbot * * @param request * @return whether the request is from a web searchbot */ public static boolean checkURLforSpiders(HttpServletRequest request) { boolean result = false; String spiderRequest = (String) request.getAttribute("_REQUEST_FROM_SPIDER_"); if (UtilValidate.isNotEmpty(spiderRequest)) { if ("Y".equals(spiderRequest)) { return true; } else { return false; } } else { String initialUserAgent = request.getHeader("User-Agent") != null ? request.getHeader("User-Agent") : ""; List<String> spiderList = StringUtil .split(UtilProperties.getPropertyValue("url", "link.remove_lsessionid.user_agent_list"), ","); if (UtilValidate.isNotEmpty(spiderList)) { for (String spiderNameElement : spiderList) { Pattern pattern = null; try { pattern = PatternFactory.createOrGetPerl5CompiledPattern(spiderNameElement, false); } catch (MalformedPatternException e) { Debug.logError(e, module); } PatternMatcher matcher = new Perl5Matcher(); if (matcher.contains(initialUserAgent, pattern)) { request.setAttribute("_REQUEST_FROM_SPIDER_", "Y"); result = true; break; } } } } if (!result) { request.setAttribute("_REQUEST_FROM_SPIDER_", "N"); } return result; } /** Returns true if the user has JavaScript enabled. * @param request * @return whether javascript is enabled */ public static boolean isJavaScriptEnabled(HttpServletRequest request) { HttpSession session = request.getSession(); Boolean javaScriptEnabled = (Boolean) session.getAttribute("javaScriptEnabled"); if (javaScriptEnabled != null) { return javaScriptEnabled.booleanValue(); } return false; } /** Returns the number or rows submitted by a multi form. */ public static int getMultiFormRowCount(HttpServletRequest request) { return getMultiFormRowCount(getParameterMap(request)); } /** Returns the number or rows submitted by a multi form. */ public static int getMultiFormRowCount(Map<String, ?> requestMap) { // The number of multi form rows is computed selecting the maximum index int rowCount = 0; String maxRowIndex = ""; int rowDelimiterLength = MULTI_ROW_DELIMITER.length(); for (String parameterName : requestMap.keySet()) { int rowDelimiterIndex = (parameterName != null ? parameterName.indexOf(MULTI_ROW_DELIMITER) : -1); if (rowDelimiterIndex > 0) { String thisRowIndex = parameterName.substring(rowDelimiterIndex + rowDelimiterLength); if (thisRowIndex.indexOf("_") > -1) { thisRowIndex = thisRowIndex.substring(0, thisRowIndex.indexOf("_")); } if (maxRowIndex.length() < thisRowIndex.length()) { maxRowIndex = thisRowIndex; } else if (maxRowIndex.length() == thisRowIndex.length() && maxRowIndex.compareTo(thisRowIndex) < 0) { maxRowIndex = thisRowIndex; } } } if (UtilValidate.isNotEmpty(maxRowIndex)) { try { rowCount = Integer.parseInt(maxRowIndex); rowCount++; // row indexes are zero based } catch (NumberFormatException e) { Debug.logWarning("Invalid value for row index found: " + maxRowIndex, module); } } return rowCount; } public static String stashParameterMap(HttpServletRequest request) { HttpSession session = request.getSession(); Map<String, Map<String, Object>> paramMapStore = UtilGenerics .checkMap(session.getAttribute("_PARAM_MAP_STORE_")); if (paramMapStore == null) { paramMapStore = new HashMap<String, Map<String, Object>>(); session.setAttribute("_PARAM_MAP_STORE_", paramMapStore); } Map<String, Object> parameters = getParameterMap(request); String paramMapId = RandomStringUtils.randomAlphanumeric(10); paramMapStore.put(paramMapId, parameters); return paramMapId; } public static void restoreStashedParameterMap(HttpServletRequest request, String paramMapId) { HttpSession session = request.getSession(); Map<String, Map<String, Object>> paramMapStore = UtilGenerics .checkMap(session.getAttribute("_PARAM_MAP_STORE_")); if (paramMapStore != null) { Map<String, Object> paramMap = paramMapStore.get(paramMapId); if (paramMap != null) { paramMapStore.remove(paramMapId); for (Map.Entry<String, Object> paramEntry : paramMap.entrySet()) { if (request.getAttribute(paramEntry.getKey()) != null) { Debug.logWarning("Skipped loading parameter [" + paramEntry.getKey() + "] because it would have overwritten a request attribute", module); continue; } request.setAttribute(paramEntry.getKey(), paramEntry.getValue()); } } } } /** * Returns a unique Id for the current request * @param request An HttpServletRequest to get the name info from * @return String */ public static String getNextUniqueId(HttpServletRequest request) { Integer uniqueIdNumber = (Integer) request.getAttribute("UNIQUE_ID"); if (uniqueIdNumber == null) { uniqueIdNumber = Integer.valueOf(1); } request.setAttribute("UNIQUE_ID", Integer.valueOf(uniqueIdNumber.intValue() + 1)); return "autoId_" + uniqueIdNumber; } }