/*
* #%L
* carewebframework
* %%
* Copyright (C) 2008 - 2016 Regenstrief Institute, Inc.
* %%
* Licensed 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.
*
* This Source Code Form is also subject to the terms of the Health-Related
* Additional Disclaimer of Warranty and Limitation of Liability available at
*
* http://www.carewebframework.org/licensing/disclaimer.
*
* #L%
*/
package org.carewebframework.ui;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.Validate;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;
import org.carewebframework.api.FrameworkUtil;
import org.carewebframework.api.property.PropertyUtil;
import org.carewebframework.common.StrUtil;
import org.carewebframework.ui.util.RequestUtil;
import org.zkoss.zk.ui.Desktop;
import org.zkoss.zk.ui.Execution;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.Session;
/**
* Class to manage instantiation of framework containers.
*/
public class FrameworkWebSupport {
private static final String REQUEST_PARAMS = "_CWFRequestParams";
private static final String REQUEST_URL = "_CWFRequestUrl";
private static final ThreadLocal<Desktop> _desktops = new ThreadLocal<>();
/**
* Converts the queryString to a map.
*
* @param queryString The query string (leading "?" is optional)
* @return A map containing the parameters from the query string. This may return null if the
* queryString is empty. Multiple values for a parameter are separated by commas.
*/
public static Map<String, String> queryStringToMap(String queryString) {
return queryStringToMap(queryString, ",");
}
/**
* Converts the queryString to a map.
*
* @param queryString The query string (leading "?" is optional)
* @param valueDelimiter String to use to delimit multiple values for a parameter. May be null.
* @return A map containing the arguments from the query string. This may return null if the
* queryString is empty.
*/
public static Map<String, String> queryStringToMap(String queryString, String valueDelimiter) {
if (queryString == null || queryString.isEmpty()) {
return null;
}
try {
valueDelimiter = valueDelimiter == null ? "" : valueDelimiter;
URI uri = new URI(queryString.startsWith("?") ? queryString : ("?" + queryString));
List<NameValuePair> params = URLEncodedUtils.parse(uri, StrUtil.CHARSET);
Map<String, String> result = new HashMap<>();
for (NameValuePair nvp : params) {
String value = result.get(nvp.getName());
result.put(nvp.getName(), (value == null ? "" : value + valueDelimiter) + nvp.getValue());
}
return result;
} catch (URISyntaxException e) {
return null;
}
}
/**
* Returns the current desktop. Returns null if the current thread has not been associated with
* a desktop..
*
* @return Current desktop or null.
*/
public static Desktop getDesktop() {
Execution exec = Executions.getCurrent();
return exec == null ? _desktops.get() : exec.getDesktop();
}
/**
* Return current Desktop ID or null if unavailable.
*
* @return Desktop ID or null if unavailable.
*/
public static String getDesktopId() {
Desktop desktop = getDesktop();
return desktop == null ? null : desktop.getId();
}
/**
* Associates the specified desktop with the current thread. Used for background threads that
* need to reference the desktop.
*
* @param desktop If not null, associates this desktop with the current thread. If null, removes
* any existing association.
*/
public static void associateDesktop(Desktop desktop) {
if (desktop != null) {
_desktops.set(desktop);
} else {
_desktops.remove();
}
}
/**
* Adds the specified query string to the url.
*
* @param url url to receive the query string.
* @param queryString Query string to add.
* @return The updated url.
* @throws IllegalArgumentException if url is null
*/
public static String addQueryString(String url, String queryString) {
Validate.notNull(url, "The url must not be null");
if (!StringUtils.isEmpty(queryString)) {
if (url.endsWith("?")) {
url += queryString;
} else if (url.contains("?")) {
url += "&" + queryString;
} else {
url += "?" + queryString;
}
}
return url;
}
/**
* Returns the original request parameters from the current request.
*
* @return the String value for key represented by constant {@link #REQUEST_PARAMS}.
*/
public static String getRequestParams() {
return (String) FrameworkUtil.getAttribute(REQUEST_PARAMS);
}
/**
* Save the request parameters as an attribute of the framework
*
* @param value String value to set for key represented by constant {@link #REQUEST_PARAMS}.
*/
public static void setRequestParams(String value) {
FrameworkUtil.setAttribute(REQUEST_PARAMS, value);
}
/**
* Returns the original request url from the current request.
*
* @return the String value for key represented by constant {@link #REQUEST_URL}
*/
public static String getRequestUrl() {
return (String) FrameworkUtil.getAttribute(REQUEST_URL);
}
/**
* Save the request url.
*
* @param value String value to set for key represented by constant {@link #REQUEST_URL}.
*/
public static void setRequestUrl(String value) {
FrameworkUtil.setAttribute(REQUEST_URL, value);
}
/**
* Returns the HttpServletRequest object for the current execution.
*
* @return the HttpServletRequest
*/
public static HttpServletRequest getHttpServletRequest() {
return RequestUtil.getRequest();
}
/**
* Returns the HttpServletResponse object for the current execution.
*
* @return the HttpServletResponse
*/
public static HttpServletResponse getHttpServletResponse() {
Execution exec = Executions.getCurrent();
return exec == null ? null : (HttpServletResponse) exec.getNativeResponse();
}
/**
* Returns the named cookie from the current request.
*
* @param cookieName Name of cookie.
* @see #getCookie(String, HttpServletRequest)
* @return A cookie, or null if not found.
* @throws IllegalArgumentException if argument is null or {@link #getHttpServletRequest()}
* returns null
*/
public static Cookie getCookie(String cookieName) {
return getCookie(cookieName, getHttpServletRequest());
}
/**
* Returns the named cookie from the specified request. When values are retrieved, they should
* be decoded.
*
* @see #decodeCookieValue(String)
* @param cookieName Name of cookie
* @param httpRequest Request containing cookie.
* @return A cookie, or null if not found.
* @throws IllegalArgumentException if arguments are null
*/
public static Cookie getCookie(String cookieName, HttpServletRequest httpRequest) {
Validate.notNull(cookieName, "The cookieName must not be null");
Validate.notNull(httpRequest, "The httpRequest must not be null");
Cookie[] cookies = httpRequest.getCookies();
if (cookies != null) {
for (Cookie cookie : httpRequest.getCookies()) {
if (cookieName.equals(cookie.getName())) {
return cookie;
}
}
}
return null;
}
/**
* Returns the value from the named cookie from the specified request. The value is decoded with
* for security and consistency (Version 0+ of Cookies and web containers)
*
* @see #getCookie(String, HttpServletRequest)
* @see #decodeCookieValue(String)
* @param cookieName Name of cookie
* @param httpRequest Request containing cookie. If null, it will check
* {@link Execution#getNativeRequest()}
* @return A cookie value, or null if not found.
* @throws IllegalArgumentException if arguments are null
*/
public static String getCookieValue(String cookieName, HttpServletRequest httpRequest) {
Cookie cookie = getCookie(cookieName, httpRequest);
return cookie == null ? null : decodeCookieValue(cookie.getValue());
}
/**
* <p>
* Encodes a plain text cookie value.
* </p>
* <i>Note: The direction to use a two-phase encode/decode process (i.e. instead of the Base64
* class URL_SAFE option) was intentional</i>
*
* @see URLEncoder#encode(String, String)
* @see Base64#encodeBase64String(byte[])
* @param cookieValuePlainText The plain text to encode
* @return encoded cookie value
* @throws IllegalArgumentException If the argument is null
*/
public static String encodeCookieValue(String cookieValuePlainText) {
Validate.notNull(cookieValuePlainText, "The cookieValuePlainText must not be null");
try {
return URLEncoder.encode(Base64.encodeBase64String(cookieValuePlainText.getBytes()), StrUtil.CHARSET);
} catch (Exception e) {
throw new RuntimeException("Unexpected exception occurred encoding cookie value", e);
}
}
/**
* <p>
* Decodes an encoded cookie value
* </p>
* <i>Note: The direction to use a two-phase encode/decode process (i.e. instead of the Base64
* class URL_SAFE option) was intentional</i>
*
* @see URLDecoder#decode(String, String)
* @see Base64#decode(String)
* @param encodedCookieValue The encoded cookie value
* @return decoded cookie value
* @throws IllegalArgumentException If the argument is null
*/
public static String decodeCookieValue(String encodedCookieValue) {
Validate.notNull(encodedCookieValue, "The encodedCookieValue must not be null");
try {
return new String(Base64.decodeBase64(URLDecoder.decode(encodedCookieValue, StrUtil.CHARSET)));
} catch (Exception e) {
throw new RuntimeException("Unexpected exception occurred decoding cookie value", e);
}
}
/**
* Returns the value from the named cookie from the specified request. The value is decoded.
*
* @see #getCookieValue(String, HttpServletRequest)
* @param cookieName Name of cookie
* @return A cookie value, or null if not found.
* @throws IllegalArgumentException if argument is null or if underlying HttpServletRequest is
* null
*/
public static String getCookieValue(String cookieName) {
return getCookieValue(cookieName, getHttpServletRequest());
}
/**
* Sets a cookie into the current response.
*
* @see #setCookie(String, String, HttpServletResponse, HttpServletRequest)
* @param cookieName Name of cookie.
* @param value Value of cookie.
* @return Newly created cookie.
* @throws IllegalArgumentException if {@link #getHttpServletResponse()} is null
*/
public static Cookie setCookie(String cookieName, String value) {
return setCookie(cookieName, value, getHttpServletResponse(), getHttpServletRequest());
}
/**
* Sets a cookie into the response. Cookies are URLEncoded for consistency (Version 0+ of
* Cookies)
*
* @param cookieName Name of cookie.
* @param value Value of cookie. If null, the cookie is removed from the client if it exists.
* @param httpResponse Response object.
* @param httpRequest Request object.
* @return Newly created cookie.
* @throws IllegalArgumentException if cookieName, httpResponse, or httpRequest arguments are
* null
*/
public static Cookie setCookie(String cookieName, String value, HttpServletResponse httpResponse,
HttpServletRequest httpRequest) {
Validate.notNull(httpResponse, "The httpResponse must not be null");
Cookie cookie = getCookie(cookieName, httpRequest);
if (value != null) {
value = encodeCookieValue(value);
}
if (cookie == null) {
if (value == null) {
return null;
}
cookie = new Cookie(cookieName, value);
} else if (value == null) {
cookie.setMaxAge(0);
} else {
cookie.setValue(value);
}
if (httpRequest.isSecure()) {
cookie.setSecure(true);
}
httpResponse.addCookie(cookie);
return cookie;
}
/**
* Returns a session attribute value, removing it from the session.
*
* @param session Session containing attributes of interest.
* @param name Name of attribute to retrieve.
* @return Value of attribute or null if it does not exist.
*/
public static Object extractSessionAttribute(Session session, String name) {
return extractSessionAttribute(session, name, null);
}
/**
* Returns a session attribute value, removing it from the session.
*
* @param session Session containing attributes of interest.
* @param name Name of attribute to retrieve.
* @param dflt Default value if none exists.
* @return Value of attribute.
*/
public static Object extractSessionAttribute(Session session, String name, Object dflt) {
Object value = session.removeAttribute(name);
return value == null ? dflt : value;
}
/**
* Returns framework property first by looking for an HTTP request parameter and then by looking
* at the property store. Assumes the property and the request parameter names are the same.
*
* @param propertyName Property name.
* @return Property value.
*/
public static String getFrameworkProperty(String propertyName) {
return getFrameworkProperty(propertyName, propertyName);
}
/**
* Returns framework property first by looking for an HTTP request parameter and then by looking
* at the property store.
*
* @param parameterName Name of parameter in execution.
* @param propertyName Name of property in property store.
* @return Property value.
*/
public static String getFrameworkProperty(String parameterName, String propertyName) {
Execution exec = Executions.getCurrent();
String value = exec == null ? null : exec.getParameter(parameterName);
return value == null ? PropertyUtil.getValue(propertyName, null) : value;
}
/**
* Enforce static class.
*/
private FrameworkWebSupport() {
};
}