/* RequestXelResolver.java
Purpose:
Description:
History:
Tue Mar 29 18:45:46 2005, Created by tomyeh
Copyright (C) 2005 Potix Corporation. All Rights Reserved.
{{IS_RIGHT
This program is distributed under LGPL Version 2.1 in the hope that
it will be useful, but WITHOUT ANY WARRANTY.
}}IS_RIGHT
*/
package org.zkoss.web.servlet.xel;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.zkoss.xel.ExpressionFactory;
import org.zkoss.xel.VariableResolver;
import org.zkoss.xel.XelException;
/**
* A XEL variable resolver that is based on Servlet request, response,
* and EL.
*
* @author tomyeh
* @since 3.0.0
*/
public abstract class RequestXelResolver implements VariableResolver {
private final ServletContext _ctx;
private final ServletRequest _request;
private final ServletResponse _response;
private HttpSession _sess;
private Map<String, Object> _reqScope, _sessScope, _appScope;
/** A fake page context implementation. */
private PageContext _pc;
/** cached cookies. */
private Map<String, Cookie> _cookies;
/** Request-based resolver.
* @param ctx the context; which might be null
* @param request the request. It cannot be null.
* @param response the response, which might bell.
* @exception IllegalArgumentException if request is null.
*/
public RequestXelResolver(ServletContext ctx, ServletRequest request, ServletResponse response) {
_ctx = ctx;
_request = request;
_response = response;
}
public RequestXelResolver(ServletContext ctx, ServletRequest request) {
this(ctx, request, null);
}
public RequestXelResolver(ServletRequest request) {
this(null, request, null);
}
//-- extra --//
/** Returns the expression factory (never null).
* <p>The deriving class must override it.
*/
public abstract ExpressionFactory getExpressionFactory();
/** Returns the page context. */
public PageContext getPageContext() {
if (_pc == null)
_pc = new PageContextImpl();
return _pc;
}
/** Returns the request. */
public ServletRequest getRequest() {
return _request;
}
/** Returns the response. */
public ServletResponse getResponse() {
return _response;
}
/** Returns the context. */
public ServletContext getServletContext() {
return _ctx;
}
//-- VariableResovler --//
@SuppressWarnings("unchecked")
public Object resolveVariable(String name) throws XelException {
if ("pageContext".equals(name)) {
return getPageContext();
} else if ("pageScope".equals(name)) {
return Collections.EMPTY_MAP;
} else if ("requestScope".equals(name)) {
return getRequestScope();
} else if ("sessionScope".equals(name)) {
return getSessionScope();
} else if ("applicationScope".equals(name)) {
return getApplicationScope();
} else if ("param".equals(name)) {
return _request != null ? new ParameterMap(_request) : Collections.EMPTY_MAP;
} else if ("paramValues".equals(name)) {
return _request != null ? _request.getParameterMap() : Collections.EMPTY_MAP;
} else if ("header".equals(name)) {
if (!(_request instanceof HttpServletRequest))
return Collections.EMPTY_MAP;
final HttpServletRequest hreq = (HttpServletRequest) _request;
return new AttributesMap() {
protected Enumeration getKeys() {
return hreq.getHeaderNames();
}
protected Object getValue(String key) {
return hreq.getHeader(key);
}
protected void setValue(String key, Object val) {
throw new UnsupportedOperationException("readonly");
}
protected void removeValue(String key) {
throw new UnsupportedOperationException("readonly");
}
};
} else if ("headerValues".equals(name)) {
if (!(_request instanceof HttpServletRequest))
return Collections.EMPTY_MAP;
final HttpServletRequest hreq = (HttpServletRequest) _request;
return new AttributesMap() {
//It is OK to cache because it is readonly
private final Map _values = new HashMap();
protected Enumeration getKeys() {
return hreq.getHeaderNames();
}
protected Object getValue(String key) {
Object o = _values.get(key);
if (o == null) {
final Enumeration e = hreq.getHeaders(key);
if (e == null || !e.hasMoreElements())
return null;
final List l = new LinkedList();
do {
l.add(e.nextElement());
} while (e.hasMoreElements());
o = l.toArray(new String[l.size()]);
_values.put(key, o);
}
return o;
}
protected void setValue(String key, Object val) {
throw new UnsupportedOperationException("readonly");
}
protected void removeValue(String key) {
throw new UnsupportedOperationException("readonly");
}
};
} else if ("initParam".equals(name)) {
if (_ctx == null)
return Collections.EMPTY_MAP;
return new AttributesMap() {
protected Enumeration getKeys() {
return _ctx.getInitParameterNames();
}
protected Object getValue(String key) {
return _ctx.getInitParameter(key);
}
protected void setValue(String key, Object val) {
throw new UnsupportedOperationException("readonly");
}
protected void removeValue(String key) {
throw new UnsupportedOperationException("readonly");
}
};
} else if ("cookie".equals(name)) {
if (_cookies != null)
return _cookies;
final Cookie[] cookies;
if (!(_request instanceof HttpServletRequest)
|| (cookies = ((HttpServletRequest) _request).getCookies()) == null || cookies.length == 0)
return Collections.EMPTY_MAP;
_cookies = new HashMap<String, Cookie>();
for (int j = cookies.length; --j >= 0;)
_cookies.put(cookies[j].getName(), cookies[j]);
}
return findAttribute(name);
//according EL spec, we have to search attribute
}
private HttpSession getSession() {
if (_sess != null)
return _sess;
if (!(_request instanceof HttpServletRequest))
return null;
return _sess = ((HttpServletRequest) _request).getSession(false);
}
private Object findAttribute(String name) {
Object o = getRequestScope().get(name);
if (o != null)
return o;
o = getSessionScope().get(name);
return o != null ? o : getApplicationScope().get(name);
}
private Map<String, Object> getRequestScope() {
if (_reqScope != null)
return _reqScope;
if (_request == null)
return Collections.emptyMap();
return _reqScope = new RequestScope(_request);
}
private Map<String, Object> getSessionScope() {
if (_sessScope != null)
return _sessScope;
final HttpSession sess = getSession();
if (sess == null)
return _sessScope = Collections.emptyMap();
return _sessScope = new AttributesMap() {
@SuppressWarnings("unchecked")
protected Enumeration<String> getKeys() {
return sess.getAttributeNames();
}
protected Object getValue(String key) {
return sess.getAttribute(key);
}
protected void setValue(String key, Object val) {
sess.setAttribute(key, val);
}
protected void removeValue(String key) {
sess.removeAttribute(key);
}
};
}
private Map<String, Object> getApplicationScope() {
if (_appScope != null)
return _appScope;
if (_ctx == null)
return _appScope = Collections.emptyMap();
return _appScope = new AttributesMap() {
@SuppressWarnings("unchecked")
protected Enumeration<String> getKeys() {
return _ctx.getAttributeNames();
}
protected Object getValue(String key) {
return _ctx.getAttribute(key);
}
protected void setValue(String key, Object val) {
_ctx.setAttribute(key, val);
}
protected void removeValue(String key) {
_ctx.removeAttribute(key);
}
};
}
/** An implementation of PageContext. */
private class PageContextImpl implements PageContext {
public ServletRequest getRequest() {
return _request;
}
public ServletResponse getResponse() {
return _response;
}
public ServletConfig getServletConfig() {
return null;
}
public ServletContext getServletContext() {
return _ctx;
}
public HttpSession getSession() {
return RequestXelResolver.this.getSession();
}
public VariableResolver getVariableResolver() {
return RequestXelResolver.this;
}
}
}