/*
* JBoss, Home of Professional Open Source.
* Copyright 2012, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.portletbridge.el;
import java.beans.FeatureDescriptor;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import javax.el.ELContext;
import javax.el.ELException;
import javax.el.ELResolver;
import javax.el.PropertyNotFoundException;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.EventRequest;
import javax.portlet.EventResponse;
import javax.portlet.PortletConfig;
import javax.portlet.PortletPreferences;
import javax.portlet.PortletRequest;
import javax.portlet.PortletSession;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.ResourceRequest;
import javax.portlet.ResourceResponse;
import javax.portlet.faces.Bridge;
import javax.portlet.faces.BridgeUtil;
import javax.portlet.faces.preference.Preference;
import org.jboss.portletbridge.context.map.PortletApplicationScopeSessionMap;
import org.jboss.portletbridge.preference.PreferenceImpl;
public class PortletELResolver extends ELResolver {
public static final String PORTLET_CONFIG = "portletConfig";
public static final String ACTION_REQUEST = "actionRequest";
public static final String ACTION_RESPONSE = "actionResponse";
public static final String EVENT_REQUEST = "eventRequest";
public static final String EVENT_RESPONSE = "eventResponse";
public static final String RENDER_REQUEST = "renderRequest";
public static final String RENDER_RESPONSE = "renderResponse";
public static final String RESOURCE_REQUEST = "resourceRequest";
public static final String RESOURCE_RESPONSE = "resourceResponse";
public static final String PORTLET_SESSION = "portletSession";
public static final String PORTLET_SESSION_SCOPE = "portletSessionScope";
public static final String HTTP_SESSION_SCOPE = "httpSessionScope";
public static final String PORTLET_PREFERENCES = "portletPreferences";
public static final String PORTLET_PREFERENCES_VALUES = "portletPreferencesValues";
public static final String MUTABLE_PORTLET_PREFERENCES_VALUES = "mutablePortletPreferencesValues";
// old portlet bridge 1.0 - leave for backwards compatibility in 2.0 GA
public static final String SESSION_APPLICATION_SCOPE = "sessionApplicationScope";
public static final String SESSION_PORTLET_SCOPE = "sessionPortletScope";
public static final String PORTLET_PREFERENCE_VALUE = "portletPreferenceValue";
public static final String PORTLET_PREFERENCE_VALUES = "portletPreferenceValues";
// vendor specific
public static final String AJAX_CONTEXT = "ajaxContext";
private Map<String, Object> appScopeSessionMap = null;
public PortletELResolver() {
}
@Override
public Object getValue(ELContext context, Object base, Object property) throws ELException {
// variable resolution is a special case of property resolution
// where the base is null.
if (!BridgeUtil.isPortletRequest() || null != base) {
return null;
}
if (null == property) {
throw new PropertyNotFoundException("Null property");
}
if (null == context) {
throw new IllegalArgumentException("PortletELResolver.getValue was passed a null ELContext");
}
ELContextImpl portletELContext = (ELContextImpl) context.getContext(ELContextImpl.class);
if (null == portletELContext) {
return null;
}
if (portletELContext.isFacesResolved()) {
return getValueWithFacesResolution(context, portletELContext, base, property);
} else {
return getValueWithJSPResolution(context, portletELContext, base, property);
}
}
private Object getValueWithJSPResolution(ELContext context, ELContextImpl portletELContext, Object base, Object property) {
if (property instanceof String) {
FacesContext facesContext = (FacesContext) context.getContext(FacesContext.class);
ExternalContext externalContext = facesContext.getExternalContext();
try {
if (HTTP_SESSION_SCOPE.equals(property)) {
context.setPropertyResolved(true);
return getHttpSessionMap(externalContext, portletELContext);
} else if (MUTABLE_PORTLET_PREFERENCES_VALUES.equals(property)) {
context.setPropertyResolved(true);
return getMutablePortletPreferencesValues(externalContext, portletELContext);
} else {
return null;
}
} catch (IllegalArgumentException e) {
// Faces defers to the implicit object resolver when evaluating
// in a JSP context. Alas, this means that Faces doesn't resolve
// session scoped ManagedBeans in a JSP context if the managed bean
// is already created rather it defers to the JSP Implicit resolver
// which accesses the http session not the protlet session. I.e.
// though the managed bean resolver sees that the session scoped bean
// exists it can't be retrieved because its in the portlet session
// not the http session.
// So its up to us to see if the bean is in the session
if (externalContext.getSessionMap().containsKey(property)) {
context.setPropertyResolved(true);
return externalContext.getSessionMap().get(property);
} else {
return null;
}
}
} else {
return null;
}
}
private Object getValueWithFacesResolution(ELContext context, ELContextImpl portletELContext, Object base, Object property) {
FacesContext facesContext = (FacesContext) context.getContext(FacesContext.class);
ExternalContext externalContext = facesContext.getExternalContext();
if (PORTLET_CONFIG.equals(property)) {
PortletConfig config = portletELContext.getPortletConfig();
if (null != config) {
context.setPropertyResolved(true);
return config;
} else {
throw new ELException(
"EL Resolve failed: can't resolve portletConfig because its not set on this Faces EL Resolver.");
}
} else if (ACTION_REQUEST.equals(property) && (BridgeUtil.getPortletRequestPhase() == Bridge.PortletPhase.ACTION_PHASE)) {
context.setPropertyResolved(true);
return externalContext.getRequest();
} else if (ACTION_RESPONSE.equals(property)
&& (BridgeUtil.getPortletRequestPhase() == Bridge.PortletPhase.ACTION_PHASE)) {
context.setPropertyResolved(true);
return externalContext.getResponse();
} else if (RENDER_REQUEST.equals(property) && (BridgeUtil.getPortletRequestPhase() == Bridge.PortletPhase.RENDER_PHASE)) {
context.setPropertyResolved(true);
return externalContext.getRequest();
} else if (RENDER_RESPONSE.equals(property)
&& (BridgeUtil.getPortletRequestPhase() == Bridge.PortletPhase.RENDER_PHASE)) {
context.setPropertyResolved(true);
return externalContext.getResponse();
} else if (EVENT_REQUEST.equals(property) && (BridgeUtil.getPortletRequestPhase() == Bridge.PortletPhase.EVENT_PHASE)) {
context.setPropertyResolved(true);
return externalContext.getRequest();
} else if (EVENT_RESPONSE.equals(property) && (BridgeUtil.getPortletRequestPhase() == Bridge.PortletPhase.EVENT_PHASE)) {
context.setPropertyResolved(true);
return externalContext.getResponse();
} else if (RESOURCE_REQUEST.equals(property)
&& (BridgeUtil.getPortletRequestPhase() == Bridge.PortletPhase.RESOURCE_PHASE)) {
context.setPropertyResolved(true);
return externalContext.getRequest();
} else if (RESOURCE_RESPONSE.equals(property)
&& (BridgeUtil.getPortletRequestPhase() == Bridge.PortletPhase.RESOURCE_PHASE)) {
context.setPropertyResolved(true);
return externalContext.getResponse();
} else if (SESSION_APPLICATION_SCOPE.equals(property) || HTTP_SESSION_SCOPE.equals(property)) {
context.setPropertyResolved(true);
if (null == appScopeSessionMap) {
Object request = externalContext.getRequest();
if (BridgeUtil.isPortletRequest()) {
appScopeSessionMap = new PortletApplicationScopeSessionMap((PortletRequest) request);
}
}
return appScopeSessionMap;
} else if (SESSION_PORTLET_SCOPE.equals(property) || PORTLET_SESSION_SCOPE.equals(property)) {
context.setPropertyResolved(true);
return externalContext.getSessionMap();
} else if (PORTLET_SESSION.equals(property)) {
context.setPropertyResolved(true);
return externalContext.getSession(false);
} else if (PORTLET_PREFERENCE_VALUE.equals(property)) {
context.setPropertyResolved(true);
return getPreferencesValueMap(facesContext);
} else if (PORTLET_PREFERENCES.equals(property)) {
context.setPropertyResolved(true);
return ((PortletRequest) externalContext.getRequest()).getPreferences();
} else if (MUTABLE_PORTLET_PREFERENCES_VALUES.equals(property)) {
context.setPropertyResolved(true);
return getPreferenceMap(((PortletRequest) externalContext.getRequest()).getPreferences());
} else if (PORTLET_PREFERENCES_VALUES.equals(property)) {
context.setPropertyResolved(true);
return ((PortletRequest) externalContext.getRequest()).getPreferences().getMap();
} else {
return null;
}
}
@Override
public void setValue(ELContext context, Object base, Object property, Object val) throws ELException {
if (null != base) {
return;
}
if (null == property) {
throw new PropertyNotFoundException("Null property");
}
}
@Override
public boolean isReadOnly(ELContext context, Object base, Object property) throws ELException {
if (null != base) {
return false;
}
if (null == property) {
throw new PropertyNotFoundException("Null property");
}
return false;
}
@Override
public Class<?> getType(ELContext context, Object base, Object property) throws ELException {
if (null != base) {
return null;
}
if (null == property) {
throw new PropertyNotFoundException("Null property");
}
return null;
}
@Override
public Iterator<FeatureDescriptor> getFeatureDescriptors(ELContext context, Object base) {
if (null != base) {
return null;
}
ArrayList<FeatureDescriptor> list = new ArrayList<FeatureDescriptor>(20);
list.add(getFeatureDescriptor(ACTION_REQUEST, ACTION_REQUEST, ACTION_REQUEST, false, false, true,
ActionRequest.class, Boolean.TRUE));
list.add(getFeatureDescriptor(ACTION_RESPONSE, ACTION_RESPONSE, ACTION_RESPONSE, false, false, true,
ActionResponse.class, Boolean.TRUE));
list.add(getFeatureDescriptor(EVENT_REQUEST, EVENT_REQUEST, EVENT_REQUEST, false, false, true, EventRequest.class,
Boolean.TRUE));
list.add(getFeatureDescriptor(EVENT_RESPONSE, EVENT_RESPONSE, EVENT_RESPONSE, false, false, true,
EventResponse.class, Boolean.TRUE));
list.add(getFeatureDescriptor(HTTP_SESSION_SCOPE, HTTP_SESSION_SCOPE, HTTP_SESSION_SCOPE, false, false, true,
Map.class, Boolean.TRUE));
list.add(getFeatureDescriptor("mutablePortletPreferences", "mutablePortletPreferences", "mutablePortletPreferences",
false, false, true, Map.class, Boolean.TRUE));
list.add(getFeatureDescriptor(PORTLET_CONFIG, PORTLET_CONFIG, PORTLET_CONFIG, false, false, true,
PortletConfig.class, Boolean.TRUE));
list.add(getFeatureDescriptor(PORTLET_PREFERENCES, PORTLET_PREFERENCES, PORTLET_PREFERENCES, false, false, true,
PortletPreferences.class, Boolean.TRUE));
list.add(getFeatureDescriptor(PORTLET_PREFERENCES_VALUES, PORTLET_PREFERENCES_VALUES, PORTLET_PREFERENCES_VALUES,
false, false, true, Map.class, Boolean.TRUE));
list.add(getFeatureDescriptor(PORTLET_SESSION, PORTLET_SESSION, PORTLET_SESSION, false, false, true,
PortletSession.class, Boolean.TRUE));
list.add(getFeatureDescriptor(PORTLET_SESSION_SCOPE, PORTLET_SESSION_SCOPE, PORTLET_SESSION_SCOPE, false, false, true,
Map.class, Boolean.TRUE));
list.add(getFeatureDescriptor(RENDER_REQUEST, RENDER_REQUEST, RENDER_REQUEST, false, false, true,
RenderRequest.class, Boolean.TRUE));
list.add(getFeatureDescriptor(RENDER_RESPONSE, RENDER_RESPONSE, RENDER_RESPONSE, false, false, true,
RenderResponse.class, Boolean.TRUE));
list.add(getFeatureDescriptor(RESOURCE_REQUEST, RESOURCE_REQUEST, RESOURCE_REQUEST, false, false, true,
ResourceRequest.class, Boolean.TRUE));
list.add(getFeatureDescriptor(RESOURCE_RESPONSE, RESOURCE_RESPONSE, RESOURCE_RESPONSE, false, false, true,
ResourceResponse.class, Boolean.TRUE));
list.add(getFeatureDescriptor(SESSION_APPLICATION_SCOPE, SESSION_APPLICATION_SCOPE, SESSION_APPLICATION_SCOPE, false,
false, true, Map.class, Boolean.TRUE));
list.add(getFeatureDescriptor(SESSION_PORTLET_SCOPE, SESSION_PORTLET_SCOPE, SESSION_PORTLET_SCOPE, false, false, true,
Map.class, Boolean.TRUE));
list.add(getFeatureDescriptor(PORTLET_PREFERENCE_VALUE, PORTLET_PREFERENCE_VALUE, PORTLET_PREFERENCE_VALUE, false,
false, true, Map.class, Boolean.TRUE));
list.add(getFeatureDescriptor(PORTLET_PREFERENCE_VALUES, PORTLET_PREFERENCE_VALUES, PORTLET_PREFERENCE_VALUES, false,
false, true, Map.class, Boolean.TRUE));
list.add(getFeatureDescriptor(AJAX_CONTEXT, AJAX_CONTEXT, AJAX_CONTEXT, false, false, true, Map.class, Boolean.TRUE));
return list.iterator();
}
@Override
public Class<?> getCommonPropertyType(ELContext context, Object base) {
if (null != base) {
return null;
}
return String.class;
}
private FeatureDescriptor getFeatureDescriptor(String name, String displayName, String desc, boolean expert,
boolean hidden, boolean preferred, Object type, Boolean designTime) {
FeatureDescriptor fd = new FeatureDescriptor();
fd.setName(name);
fd.setDisplayName(displayName);
fd.setShortDescription(desc);
fd.setExpert(expert);
fd.setHidden(hidden);
fd.setPreferred(preferred);
fd.setValue(ELResolver.TYPE, type);
fd.setValue(ELResolver.RESOLVABLE_AT_DESIGN_TIME, designTime);
return fd;
}
private Map<String, String> getPreferencesValueMap(FacesContext context) {
Map<String, String> m = new HashMap<String, String>();
Map<String, String[]> preferencesValuesMap = ((PortletRequest) context.getExternalContext().getRequest())
.getPreferences().getMap();
for (Iterator<Entry<String, String[]>> entryIterator = preferencesValuesMap.entrySet().iterator(); entryIterator
.hasNext();) {
Map.Entry<String, String[]> entry = (Map.Entry<String, String[]>) entryIterator.next();
String[] preferenceValues = (String[]) entry.getValue();
if (null != preferenceValues && preferenceValues.length > 0) {
m.put((String) entry.getKey(), preferenceValues[0]);
}
}
return Collections.unmodifiableMap(m);
}
private Map<String, Preference> getPreferenceMap(PortletPreferences prefs) {
Map<String, Preference> m;
// construct a Map of PreferenceImpl objects for each preference
Enumeration<String> e = prefs.getNames();
if (e.hasMoreElements()) {
m = new HashMap<String, Preference>();
while (e.hasMoreElements()) {
String name = e.nextElement();
m.put(name, new PreferenceImpl(prefs, name));
}
} else {
m = Collections.emptyMap();
}
return m;
}
private Map<String, Object> getHttpSessionMap(ExternalContext externalContext, ELContextImpl portletELContext) {
Map<String, Object> sessionMap = portletELContext.getHttpSessionMap();
if (null == sessionMap) {
sessionMap = new PortletApplicationScopeSessionMap((PortletRequest) externalContext.getRequest());
portletELContext.setHttpSessionMap(sessionMap);
}
return sessionMap;
}
private Map getMutablePortletPreferencesValues(ExternalContext externalContext, ELContextImpl portletELContext) {
Map<String, Preference> preferencesValuesMap = portletELContext.getMutablePortletPreferencesMap();
if (null == preferencesValuesMap) {
preferencesValuesMap = getPreferenceMap(((PortletRequest) externalContext.getRequest()).getPreferences());
portletELContext.setMutablePortletPreferencesMap(preferencesValuesMap);
}
return preferencesValuesMap;
}
}