/* 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.apache.myfaces.portlet.faces.el;
import java.beans.FeatureDescriptor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.el.ELContext;
import javax.el.ELException;
import javax.el.ELResolver;
import javax.el.PropertyNotFoundException;
import javax.el.PropertyNotWritableException;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
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.faces.BridgeUtil;
import javax.portlet.faces.preference.Preference;
import org.apache.myfaces.portlet.faces.util.map.PortletSessionMap;
import org.apache.myfaces.portlet.faces.preference.PreferenceImpl;
public class PortletELResolver extends ELResolver
{
// Important preserve index (order) between array and constants
// Just as important -- we binary search this array
// So it must be in alphabetic order
public static final String[] IMPLICIT_OBJECTS = new String[] {"portletConfig",
"portletPreferences",
"renderRequest", "renderResponse",
"sessionApplicationScope", "sessionPortletScope"};
public static final int PORTLET_CONFIG = 0;
public static final int PORTLET_PREFERENCES = 1;
public static final int RENDER_REQUEST = 2;
public static final int RENDER_RESPONSE = 3;
public static final int SESSION_APPLICATION_SCOPE = 4;
public static final int SESSION_PORTLET_SCOPE = 5;
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 (property == null)
{
throw new PropertyNotFoundException("Null property");
}
FacesContext facesContext = (FacesContext) context.getContext(FacesContext.class);
ExternalContext extCtx = facesContext.getExternalContext();
// only process if running in a portlet request
if (!BridgeUtil.isPortletRequest() || base != null)
{
return null;
}
int index = -1;
if (property instanceof String)
{
index = Arrays.binarySearch(IMPLICIT_OBJECTS, property);
}
switch (index)
{
case RENDER_REQUEST:
context.setPropertyResolved(true);
return extCtx.getRequest();
case RENDER_RESPONSE:
context.setPropertyResolved(true);
return extCtx.getResponse();
case PORTLET_CONFIG:
context.setPropertyResolved(true);
return context.getContext(PortletConfig.class);
case SESSION_APPLICATION_SCOPE:
context.setPropertyResolved(true);
Map m = (Map) extCtx.getRequestMap().get("javax.portlet.faces.SessionApplicationScopeMap");
if (m == null)
{
m = new PortletSessionMap(extCtx.getRequest(), PortletSession.APPLICATION_SCOPE);
extCtx.getRequestMap().put("javax.portlet.faces.SessionApplicationScopeMap", m);
}
return m;
case SESSION_PORTLET_SCOPE:
context.setPropertyResolved(true);
return extCtx.getSessionMap();
case PORTLET_PREFERENCES:
context.setPropertyResolved(true);
m = (Map) extCtx.getRequestMap().get("javax.portlet.faces.PreferenceMap");
if (m == null)
{
m = getPreferenceMap(((PortletRequest) extCtx.getRequest()).getPreferences());
extCtx.getRequestMap().put("javax.portlet.faces.SessionApplicationScopeMap", m);
}
return m;
default:
return null;
}
}
@Override
public void setValue(ELContext context, Object base, Object property, Object val)
throws ELException
{
// only process if running in a portlet request
if (!BridgeUtil.isPortletRequest() || base != null)
{
return;
}
if (property == null)
{
throw new PropertyNotFoundException("Null property");
}
int index = -1;
if (property instanceof String)
{
index = Arrays.binarySearch(IMPLICIT_OBJECTS, property);
}
if (index >= 0)
{
throw new PropertyNotWritableException((String) property);
}
}
@Override
public boolean isReadOnly(ELContext context, Object base, Object property) throws ELException
{
// only process if running in a portlet request
if (!BridgeUtil.isPortletRequest() || base != null)
{
return false;
}
if (property == null)
{
throw new PropertyNotFoundException("Null property");
}
int index = -1;
if (property instanceof String)
{
index = Arrays.binarySearch(IMPLICIT_OBJECTS, property);
}
if (index >= 0)
{
context.setPropertyResolved(true);
return true;
}
return false;
}
@Override
public Class<?> getType(ELContext context, Object base, Object property) throws ELException
{
if (property == null)
{
throw new PropertyNotFoundException("Null property");
}
// only process if running in a portlet request
if (!BridgeUtil.isPortletRequest() || base != null)
{
return null;
}
int index = -1;
if (property instanceof String)
{
index = Arrays.binarySearch(IMPLICIT_OBJECTS, property);
}
switch (index)
{
case RENDER_REQUEST:
case RENDER_RESPONSE:
case PORTLET_CONFIG:
case SESSION_APPLICATION_SCOPE:
case SESSION_PORTLET_SCOPE:
case PORTLET_PREFERENCES:
context.setPropertyResolved(true);
}
return null;
}
@Override
public Iterator<FeatureDescriptor> getFeatureDescriptors(ELContext context, Object base)
{
if (base != null)
{
return null;
}
ArrayList<FeatureDescriptor> list = new ArrayList<FeatureDescriptor>(14);
list.add(getFeatureDescriptor("renderRequest", "renderRequest", "renderRequest", false, false,
true, RenderRequest.class, Boolean.TRUE));
list.add(getFeatureDescriptor("renderResponse", "renderResponse", "renderResponse", false, false,
true, RenderResponse.class, Boolean.TRUE));
list.add(getFeatureDescriptor("portletConfig", "portletConfig", "portletConfig", false, false,
true, PortletConfig.class, Boolean.TRUE));
list.add(getFeatureDescriptor("sessionApplicationScope", "sessionApplicationScope",
"sessionApplicationScope", false, false, true, Map.class,
Boolean.TRUE));
list.add(getFeatureDescriptor("sessionPortletScope", "sessionPortletScope",
"sessionPortletScope", false, false, true, Map.class,
Boolean.TRUE));
list.add(getFeatureDescriptor("portletPreferences", "portletPreferences",
"portletPreferences", false, false, true, Map.class,
Boolean.TRUE));
return list.iterator();
}
@Override
public Class<?> getCommonPropertyType(ELContext context, Object base)
{
if (base != null)
{
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;
}
@SuppressWarnings("unchecked")
private Map<String, String> getPreferencesValueMap(ExternalContext extCtx)
{
Map<String, String> m;
PortletRequest portletRequest = (PortletRequest) extCtx.getRequest();
Enumeration<String> e = portletRequest.getPreferences().getNames();
if (e.hasMoreElements())
{
m = new HashMap<String, String>();
while (e.hasMoreElements())
{
String name = e.nextElement();
String value = portletRequest.getPreferences().getValue(name, null);
if (value != null)
{
m.put(name, value);
}
}
}
else
{
m = Collections.emptyMap();
}
return m;
}
private Map<String, Preference> getPreferenceMap(PortletPreferences prefs)
{
Map <String, Preference> m;
// construct a Map of Preference 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;
}
}