/**
* jetbrick-template
* http://subchen.github.io/jetbrick-template/
*
* Copyright 2010-2014 Guoqiang Chen. All rights reserved.
* Email: subchen@gmail.com
*
* 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.
*/
package jetbrick.template.web;
import java.util.*;
import javax.servlet.ServletContext;
import javax.servlet.http.*;
import jetbrick.template.JetContext;
/**
* 提供默认的 Servlet 对象.
*/
public class JetWebContext extends JetContext {
public static final String SERVLET_CONTEXT = "servletContext";
public static final String SESSION = "session";
public static final String REQUEST = "request";
public static final String RESPONSE = "response";
public static final String SERVLET_CONTEXT_SCOPE = "applicationScope";
public static final String SESSION_SCOPE = "sessionScope";
public static final String REQUEST_SCOPE = "requestScope";
public static final String PARAMETER = "parameter";
public static final String PARAMETER_VALUES = "parameterValues";
public static final String CONTEXT_PATH_LEGACY = "ctxpath";
public static final String WEBROOT_PATH_LEGACY = "webroot";
public static final String CONTEXT_PATH = "CONTEXT_PATH";
public static final String WEBROOT_PATH = "WEBROOT_PATH";
public static final String BASE_PATH = "BASE_PATH";
private final ServletContext servletContext;
private final HttpSession session;
private final HttpServletRequest request;
//@formatter:off
private enum TYPE {
REQUEST_SCOPE, SESSION_SCOPE, APPLICATION_SCOPE,
PARAMETER, PARAMETER_VALUES,
HEADER, HEADER_VALUES,
COOKIE,
INIT_PARAMETER,
WEBROOT_PATH,
BASE_PATH,
}
//@formatter:on
public JetWebContext(HttpServletRequest request, HttpServletResponse response) {
this(request, response, null);
}
public JetWebContext(HttpServletRequest request, HttpServletResponse response, Map<String, Object> context) {
super(context);
this.request = request;
this.session = request.getSession();
this.servletContext = session.getServletContext();
put(SERVLET_CONTEXT, servletContext);
put(SESSION, session);
put(REQUEST, request);
put(RESPONSE, response);
put(SERVLET_CONTEXT_SCOPE, TYPE.APPLICATION_SCOPE);
put(SESSION_SCOPE, TYPE.SESSION_SCOPE);
put(REQUEST_SCOPE, TYPE.REQUEST_SCOPE);
put(PARAMETER, TYPE.PARAMETER);
put(PARAMETER_VALUES, TYPE.PARAMETER_VALUES);
put(CONTEXT_PATH_LEGACY, request.getContextPath());
put(CONTEXT_PATH, request.getContextPath());
put(WEBROOT_PATH_LEGACY, TYPE.WEBROOT_PATH);
put(WEBROOT_PATH, TYPE.WEBROOT_PATH);
put(BASE_PATH, TYPE.BASE_PATH);
}
@Override
protected boolean isSimpleModel() {
return false;
}
@Override
public Object get(String name) {
if (name == null) return null;
Object value = super.get(name);
if (value != null) {
if (value instanceof TYPE) {
value = createImplicitWebObject((TYPE) value);
put(name, value); // resolved
}
return value;
}
value = request.getAttribute(name);
if (value != null) {
return value;
}
if (session != null) {
value = session.getAttribute(name);
if (value != null) {
return value;
}
}
return servletContext.getAttribute(name);
}
@SuppressWarnings("unchecked")
private Object createImplicitWebObject(TYPE type) {
switch (type) {
case REQUEST_SCOPE: {
return new EnumeratedMap<String, Object>() {
@Override
public Enumeration<String> enumerateKeys() {
return request.getAttributeNames();
}
@Override
public Object getValue(Object key) {
if (key instanceof String) {
return request.getAttribute((String) key);
}
return null;
}
};
}
case SESSION_SCOPE: {
return new EnumeratedMap<String, Object>() {
@Override
public Enumeration<String> enumerateKeys() {
return session.getAttributeNames();
}
@Override
public Object getValue(Object key) {
if (key instanceof String) {
return session.getAttribute((String) key);
}
return null;
}
};
}
case APPLICATION_SCOPE: {
return new EnumeratedMap<String, Object>() {
@Override
public Enumeration<String> enumerateKeys() {
return servletContext.getAttributeNames();
}
@Override
public Object getValue(Object key) {
if (key instanceof String) {
return servletContext.getAttribute((String) key);
}
return null;
}
};
}
case PARAMETER: {
return new EnumeratedMap<String, Object>() {
@Override
public Enumeration<String> enumerateKeys() {
return request.getParameterNames();
}
@Override
public Object getValue(Object key) {
if (key instanceof String) {
return request.getParameter((String) key);
}
return null;
}
};
}
case PARAMETER_VALUES: {
return new EnumeratedMap<String, Object>() {
@Override
public Enumeration<String> enumerateKeys() {
return request.getParameterNames();
}
@Override
public Object getValue(Object key) {
if (key instanceof String) {
return request.getParameterValues((String) key);
}
return null;
}
};
}
case HEADER: {
return new EnumeratedMap<String, Object>() {
@Override
public Enumeration<String> enumerateKeys() {
return request.getHeaderNames();
}
@Override
public Object getValue(Object key) {
if (key instanceof String) {
return request.getHeader((String) key);
}
return null;
}
};
}
case HEADER_VALUES: {
return new EnumeratedMap<String, Object>() {
@Override
public Enumeration<String> enumerateKeys() {
return request.getHeaderNames();
}
@Override
public Object getValue(Object key) {
if (key instanceof String) {
List<String> list = new ArrayList<String>();
Enumeration<String> e = request.getHeaders((String) key);
if (e != null) {
while (e.hasMoreElements()) {
list.add(e.nextElement());
}
}
return list.toArray(new String[list.size()]);
}
return null;
}
};
}
case COOKIE: {
Cookie[] cookies = request.getCookies();
Map<String, Object> map = new HashMap<String, Object>();
for (int i = 0; (cookies != null) && (i < cookies.length); i++) {
Cookie cookie = cookies[i];
if (cookie != null) {
String name = cookie.getName();
if (!map.containsKey(name)) {
map.put(name, cookie);
}
}
}
return map;
}
case INIT_PARAMETER: {
return new EnumeratedMap<String, Object>() {
@Override
public Enumeration<String> enumerateKeys() {
return servletContext.getInitParameterNames();
}
@Override
public Object getValue(Object key) {
if (key instanceof String) {
return servletContext.getInitParameter((String) key);
}
return null;
}
};
}
case WEBROOT_PATH: {
StringBuilder sb = new StringBuilder();
String schema = request.getScheme();
int port = request.getServerPort();
sb.append(schema);
sb.append("://");
sb.append(request.getServerName());
if (!(port == 80 && "http".equals(schema)) && !(port == 443 && "https".equals(schema))) {
sb.append(':').append(request.getServerPort());
}
sb.append(request.getContextPath());
return sb.toString();
}
case BASE_PATH: {
// 比 WEBROOT_PATH 后面多了一个 "/",
// 主要用于 <base href="${BASE_PATH}" />
StringBuilder sb = new StringBuilder();
String schema = request.getScheme();
int port = request.getServerPort();
sb.append(schema);
sb.append("://");
sb.append(request.getServerName());
if (!(port == 80 && "http".equals(schema)) && !(port == 443 && "https".equals(schema))) {
sb.append(':').append(request.getServerPort());
}
sb.append(request.getContextPath());
sb.append('/');
return sb.toString();
}
default:
return null;
}
}
private static abstract class EnumeratedMap<K, V> implements Map<K, V> {
private Map<K, V> map;
@Override
public boolean containsKey(Object key) {
return getValue(key) != null;
}
@Override
public boolean containsValue(Object value) {
return getAsMap().containsValue(value);
}
@Override
public V get(Object key) {
return getValue(key);
}
@Override
public boolean isEmpty() {
return getAsMap().isEmpty();
}
@Override
public int size() {
return getAsMap().size();
}
@Override
public Set<Map.Entry<K, V>> entrySet() {
return getAsMap().entrySet();
}
@Override
public Set<K> keySet() {
return getAsMap().keySet();
}
@Override
public Collection<V> values() {
return getAsMap().values();
}
@Override
public V put(K key, V value) {
throw new UnsupportedOperationException();
}
@Override
public void putAll(Map<? extends K, ? extends V> map) {
throw new UnsupportedOperationException();
}
@Override
public V remove(Object key) {
throw new UnsupportedOperationException();
}
@Override
public void clear() {
throw new UnsupportedOperationException();
}
public abstract Enumeration<K> enumerateKeys();
public abstract V getValue(Object key);
public Map<K, V> getAsMap() {
if (map == null) {
synchronized (this) {
if (map == null) {
Map<K, V> result = new HashMap<K, V>();
for (Enumeration<K> e = enumerateKeys(); e.hasMoreElements();) {
K key = e.nextElement();
V value = getValue(key);
result.put(key, value);
}
map = result;
}
}
}
return map;
}
}
}