All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.shale.tiger.faces.VariableResolverImpl Maven / Gradle / Ivy

The newest version!
/*
 * 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.shale.tiger.faces;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.el.EvaluationException;
import javax.faces.el.PropertyNotFoundException;
import javax.faces.el.ValueBinding;
import javax.faces.el.VariableResolver;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.shale.tiger.config.FacesConfigConfig;
import org.apache.shale.tiger.managed.Bean;
import org.apache.shale.tiger.managed.Value;
import org.apache.shale.tiger.managed.config.ListEntriesConfig;
import org.apache.shale.tiger.managed.config.ListEntryConfig;
import org.apache.shale.tiger.managed.config.ManagedBeanConfig;
import org.apache.shale.tiger.managed.config.ManagedPropertyConfig;
import org.apache.shale.tiger.managed.config.MapEntriesConfig;
import org.apache.shale.tiger.managed.config.MapEntryConfig;
import org.apache.shale.tiger.view.faces.LifecycleListener2;
import org.apache.shale.util.ConverterHelper;
import org.apache.shale.util.Messages;
import org.apache.shale.util.PropertyHelper;

/**
 * 

Implementation of VariableResolver that delegates * to the original handler under these circumstances:

*
    *
  • There is bean already in existence with the specified name.
  • *
  • There is no managed beans definition for the specified name.
  • *
* *

If control is not delegated, implement the standard functionality * for creating managed beans (this is necessary because JSF does not * expose any direct API to access these capabilities), with the following * additions:

*
    *
  • If the specified managed bean class includes the * {@link Bean} annotation, the type and scope properties * will have been preconfigured from the corresponding * attribute values. (These default settings can be * overridden by specifying an actual managed bean element * in a faces-config.xml resource.)
  • *
  • If a field of the specified bean class includes the * {@link Value} annotation, the property initialization * will be preconfigured to the literal or expression * specified by the value attribute of the * annotation. (These default settings can be overridden * by specifiying an actual managed bean element, and * including a property definition that sets the value.
  • *
* *

FIXME - Incomplete implemetnation of standard managed beans * functionality in the following areas:

*
    *
  • Partial support for list entries on managed beans and managed properties. * It currently works for lists, but not for arrays.
  • *
* *

IMPLEMENTATION NOTE - There is no faces-config.xml * resource that registers this variable resolver, since we could end up with * ordering issues with the standard Shale variable resolver. Therefore, the * standard implementation will dynamically insert an instance of this * resolver (below the standard instance, but above the implementation * provided instance) in the standard decorator chain that is implemented * as the JavaServer Faces runtime parses configuration resources.

*/ public class VariableResolverImpl extends VariableResolver { /** *

Create a new VariableResolverImpl wrapping the * specified VariableResolver.

* * @param original Original VariableResolver to wrap */ public VariableResolverImpl(VariableResolver original) { this.original = original; if (log().isInfoEnabled()) { log().info(messages().getMessage("variable.resolver", new Object[] { original })); } } // ----------------------------------------------------- Instance Variables /** *

Helper bean for performing conversions.

*/ private ConverterHelper convHelper = new ConverterHelper(); /** *

Log instance for this class.

*/ private transient Log log = null; /** *

Messages instance for this class.

*/ private transient Messages messages = null; /** *

The original VariableResolver to which we should * delegate when necessary.

*/ private VariableResolver original = null; /** *

Helper bean for accessing properties.

*/ private PropertyHelper propHelper = new PropertyHelper(); // ----------------------------------------------- VariableResolver Methods /** *

Resolve the specified variable name, creating and initializing * a new managed bean if necessary.

* * @param context FacesContext used to resolve variables * @param name Name of the variable to be resolved * * @exception EvaluationException if an evaluation error occurs */ public Object resolveVariable(FacesContext context, String name) throws EvaluationException { if (log().isDebugEnabled()) { log().debug("resolveVariable(" + name + ")"); } // Is there an existing bean by this name? If so, delegate Object value = context.getExternalContext().getRequestMap().get(name); if (value == null) { value = context.getExternalContext().getSessionMap().get(name); } if (value == null) { value = context.getExternalContext().getApplicationMap().get(name); } if (value != null) { if (log().isTraceEnabled()) { log().trace("resolveVariable(" + name + ") --> existing bean, so delegate"); } return original.resolveVariable(context, name); } // Do we have a managed bean definition for this name? If not, delegate FacesConfigConfig config = config(context); if (config == null) { if (log().isTraceEnabled()) { log().trace("resolveVariable(" + name + ") --> no FacesConfigConfig, so delegate"); } return original.resolveVariable(context, name); } ManagedBeanConfig mb = config.getManagedBean(name); if (mb == null) { if (log().isTraceEnabled()) { log().trace("resolveVariable(" + name + ") --> no ManagedBeanConfig, so delegate"); } return original.resolveVariable(context, name); } // Configure and return a new managed bean Object created = create(context, mb); return created; } // -------------------------------------------------------- Private Methods /** *

The {@link FacesConfigConfig} entry containing our managed bean * definitions, lazily instantiated.

*/ private FacesConfigConfig config = null; /** *

Return the {@link FacesConfigConfig} bean describing the * configuration information for this applicaiton, if any.

* * @param context FacesContext for the current request */ private FacesConfigConfig config(FacesContext context) { if (config == null) { config = (FacesConfigConfig) context.getExternalContext().getApplicationMap(). get(LifecycleListener2.FACES_CONFIG_CONFIG); } return config; } /** *

Create, configure, and return a new instance based on the * specified managed bean, after storing it in the configured * scope (if any).

* * @param context FacesContext for the current request * @param mb ManagedBeanConfig describing the bean to be created * * @exception EvaluationException if an evaluation error occurs */ private Object create(FacesContext context, ManagedBeanConfig mb) throws EvaluationException { if (log().isDebugEnabled()) { log().debug("create(" + mb.getName() + ")"); } // Instantiate a new instance of the appropriate bean class Object instance = instance(context, mb); // Configure properties as necessary for (ManagedPropertyConfig mp : mb.getProperties().values()) { property(context, mb, mp, instance); } // Configure list entries as necessary ListEntriesConfig listEntries = mb.getListEntries(); if (listEntries != null) { // FIXME - arrays are not yet supported if (!List.class.isAssignableFrom(instance.getClass())) { throw new EvaluationException(messages(). getMessage("list.list", context.getViewRoot().getLocale(), new Object[] { instance.getClass().getName() })); } list(context, listEntries, (List) instance); } // Configure map entries as necessary MapEntriesConfig mapEntries = mb.getMapEntries(); if (mapEntries != null) { if (!Map.class.isAssignableFrom(instance.getClass())) { throw new EvaluationException(messages(). getMessage("map.map", context.getViewRoot().getLocale(), new Object[] { instance.getClass().getName() })); } map(context, mapEntries, (Map) instance); } // Place the bean into a scope, if necessary scope(context, mb, instance); return instance; } /** *

Create and return an instance of the class named by the * specified managed bean configuration bean. * * @param context FacesContext for the current request * @param mb {@link ManagedBeanConfig} defining the bean to create * * @exception EvaluationException if an evaluation error occurs */ private Object instance(FacesContext context, ManagedBeanConfig mb) throws EvaluationException { // Is there actually a class name available for us to use? if (mb.getType() == null) { throw new EvaluationException(messages(). getMessage("variable.type", context.getViewRoot().getLocale(), new Object[] { mb.getName() })); } // Instantiate an instance of the appropriate class ClassLoader cl = Thread.currentThread().getContextClassLoader(); Class clazz = null; Object instance = null; try { clazz = cl.loadClass(mb.getType()); instance = clazz.newInstance(); } catch (ClassNotFoundException e) { throw new EvaluationException(messages(). getMessage("variable.class", context.getViewRoot().getLocale(), new Object[] { mb.getName(), mb.getType() }), e); } catch (IllegalAccessException e) { throw new EvaluationException(messages(). getMessage("variable.access", context.getViewRoot().getLocale(), new Object[] { mb.getName(), mb.getType() }), e); } catch (InstantiationException e) { throw new EvaluationException(messages(). getMessage("variable.instantiate", context.getViewRoot().getLocale(), new Object[] { mb.getName(), mb.getType() }), e); } return instance; } /** *

Populate the contents of the specified List from the * specified list entries configuration information.

* * @param context FacesContext for the current request * @param config {@link ListEntriesConfig} describing this list * @param list List instance to have entries appended * * @exception EvaluationException if an evaluation error occurs */ private void list(FacesContext context, ListEntriesConfig config, List list) { // Determine the type to which list entries should be conveted, if any String valueType = config.getValueType(); ClassLoader cl = Thread.currentThread().getContextClassLoader(); Class type = null; try { if (valueType != null) { type = cl.loadClass(valueType); } } catch (ClassNotFoundException e) { throw new EvaluationException(messages(). getMessage("list.class", context.getViewRoot().getLocale(), new Object[] { valueType }), e); } // Add a list entry for each configuration element that is present for (ListEntryConfig entry : config.getEntries()) { if (entry.isNullValue()) { list.add(null); } else if (entry.isExpression()) { // Evaluate the specified value binding expression ValueBinding vb = context.getApplication().createValueBinding(entry.getValue()); list.add(vb.getValue(context)); } else { if (type != null) { list.add(convHelper.asObject(context, type, entry.getValue())); } else { list.add(entry.getValue()); } } } } /** *

Return the Log instance to be used for this class, * instantiating a new one if necessary.

*/ private Log log() { if (log == null) { log = LogFactory.getLog(VariableResolverImpl.class); } return log; } /** *

Populate the contents of the specified Map from the * specified map entries configuration information.

* * @param context FacesContext for the current request * @param config {@link MapEntriesConfig} describing this list * @param map Map instance to have entries appended * * @exception EvaluationException if an evaluation error occurs */ private void map(FacesContext context, MapEntriesConfig config, Map map) { ClassLoader cl = Thread.currentThread().getContextClassLoader(); // Determine the type to which map keys should be conveted, if any String keyType = config.getKeyType(); Class keyClass = null; try { if (keyType != null) { keyClass = cl.loadClass(keyType); } } catch (ClassNotFoundException e) { throw new EvaluationException(messages(). getMessage("map.keyClass", context.getViewRoot().getLocale(), new Object[] { keyType }), e); } // Determine the type to which map values should be conveted, if any String valueType = config.getValueType(); Class valueClass = null; try { if (valueType != null) { valueClass = cl.loadClass(valueType); } } catch (ClassNotFoundException e) { throw new EvaluationException(messages(). getMessage("map.valueClass", context.getViewRoot().getLocale(), new Object[] { valueType }), e); } // Add a map key/value pair for each configuration element that is present for (MapEntryConfig entry : config.getEntries()) { Object key = null; if (keyClass != null) { key = convHelper.asObject(context, keyClass, entry.getKey()); } else { key = entry.getKey(); } if (entry.isNullValue()) { map.put(key, null); } else if (entry.isExpression()) { // Evaluate the specified value binding expression ValueBinding vb = context.getApplication().createValueBinding(entry.getValue()); map.put(key, vb.getValue(context)); } else { if (valueClass != null) { map.put(key, convHelper.asObject(context, valueClass, entry.getValue())); } else { map.put(key, entry.getValue()); } } } } /** *

Return the Messages instance to be used for this class, * instantiating a new one if necessary.

*/ private Messages messages() { if (messages == null) { messages = new Messages("org.apache.shale.tiger.faces.Bundle", Thread.currentThread().getContextClassLoader()); } return messages; } /** *

Configure the specified property of the specified bean instance, * based on information from the specified managed property entry.

* * @param context FacesContext for the current request * @param mb {@link ManagedBeanConfig} for the bean being scoped * @param mp {@link ManagedPropertyConfig} for the property being configured * @param instance Bean instance to be potentially placed in scope * * @exception EvaluationException if an evaluation error occurs */ private void property(FacesContext context, ManagedBeanConfig mb, ManagedPropertyConfig mp, Object instance) throws EvaluationException { // Configure list entries as necessary ListEntriesConfig listEntries = mp.getListEntries(); if (listEntries != null) { // Acquire the value of the specified property from the // specified instance, if it exists Object property = null; try { property = propHelper.getValue(instance, mp.getName()); // property = PropertyUtils.getProperty(instance, mp.getName()); } catch (PropertyNotFoundException e) { ; // Fall through to creating our own list } catch (Exception e) { throw new EvaluationException(messages(). getMessage("list.get", context.getViewRoot().getLocale(), new Object[] { mp.getName(), mb.getName()}), e); } if (property == null) { property = new ArrayList(); } // FIXME - arrays are not yet supported if (!List.class.isAssignableFrom(property.getClass())) { throw new EvaluationException(messages(). getMessage("list.listProperty", context.getViewRoot().getLocale(), new Object[] { mp.getName(), mb.getName(), property.getClass().getName() })); } // Accumulate the new values for the list list(context, listEntries, (List) property); // Store the value of the property try { propHelper.setValue(instance, mp.getName(), property); // BeanUtils.setProperty(instance, mp.getName(), property); } catch (Exception e) { throw new EvaluationException(messages(). getMessage("list.set", context.getViewRoot().getLocale(), new Object[] { mp.getName(), mb.getName()}), e); } // We are through with this property, so return return; } // Configure map entries as necessary MapEntriesConfig mapEntries = mp.getMapEntries(); if (mapEntries != null) { // Acquire the value of the specified property from the // specified instance, if it exists Object property = null; try { property = propHelper.getValue(instance, mp.getName()); // property = PropertyUtils.getProperty(instance, mp.getName()); } catch (PropertyNotFoundException e) { ; // Fall through to creating our own map } catch (Exception e) { throw new EvaluationException(messages(). getMessage("map.get", context.getViewRoot().getLocale(), new Object[] { mp.getName(), mb.getName()}), e); } if (property == null) { property = new HashMap(); } if (!Map.class.isAssignableFrom(property.getClass())) { throw new EvaluationException(messages(). getMessage("map.mapProperty", context.getViewRoot().getLocale(), new Object[] { mp.getName(), mb.getName(), property.getClass().getName() })); } // Accumulate the new values for the list map(context, mapEntries, (Map) property); // Store the value of the property try { propHelper.setValue(instance, mp.getName(), property); // BeanUtils.setProperty(instance, mp.getName(), property); } catch (Exception e) { throw new EvaluationException(messages(). getMessage("map.set", context.getViewRoot().getLocale(), new Object[] { mp.getName(), mb.getName()}), e); } // We are through with this property, so return return; } // Does this managed property specify initialization? if ((mp.getValue() == null) && !mp.isNullValue()) { return; } // Acquire the value to be set (possibly requiring conversion) Object value = null; if (!mp.isNullValue()) { if (mp.isExpression()) { // Evaluate the specified value binding expression ValueBinding vb = context.getApplication().createValueBinding(mp.getValue()); value = vb.getValue(context); } else { // Grab the string literal version of the value to set value = mp.getValue(); } } // Assign the acquired value to the specified bean property try { Class type = propHelper.getType(instance, mp.getName()); if ((value != null) && (value instanceof String)) { value = convHelper.asObject(context, type, (String) value); } propHelper.setValue(instance, mp.getName(), value); } catch (Exception e) { throw new EvaluationException(messages(). getMessage("variable.evaluate", context.getViewRoot().getLocale(), new Object[] { mb.getName(), mp.getName(), mp.getValue() }), e); } } /** *

Install the specified bean instance in the specified scope (if any). *

* * @param context FacesContext for the current request * @param mb {@link ManagedBeanConfig} for the bean being scoped * @param instance Bean instance to be potentially placed in scope * * @exception EvaluationException if an evaluation error occurs */ private void scope(FacesContext context, ManagedBeanConfig mb, Object instance) throws EvaluationException { if (log().isTraceEnabled()) { log().trace("Store bean " + mb.getName() + " in scope " + mb.getScope()); } ExternalContext econtext = context.getExternalContext(); String scope = mb.getScope(); if ("request".equalsIgnoreCase(scope)) { econtext.getRequestMap().put(mb.getName(), instance); } else if ("session".equalsIgnoreCase(scope)) { econtext.getSessionMap().put(mb.getName(), instance); } else if ("application".equalsIgnoreCase(scope)) { econtext.getApplicationMap().put(mb.getName(), instance); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy