My JSF Books/Videos My JSF Tutorials OmniFaces/JSF PPTs
JSF 2.3 Tutorial
JSF Caching Tutorial
JSF Navigation Tutorial
JSF Scopes Tutorial
JSF Page Author Beginner's Guide
OmniFaces 2.3 Tutorial Examples
OmniFaces 2.2 Tutorial Examples
JSF Events Tutorial
OmniFaces Callbacks Usages
JSF State Tutorial
JSF and Design Patterns
JSF 2.3 New Features (2.3-m04)
Introduction to OmniFaces
25+ Reasons to use OmniFaces in JSF
OmniFaces Validators
OmniFaces Converters
JSF Design Patterns
Mastering OmniFaces
Reusable and less-verbose JSF code

My JSF Resources ...

Java EE Guardian
Member of JCG Program
Member MVB DZone
Blog curated on ZEEF
OmniFaces is an utility library for JSF, including PrimeFaces, RichFaces, ICEfaces ...

[OmniFaces Utilities] - Find the right JSF OmniFaces 2 utilities methods/functions

Search on blog

Petition by Java EE Guardians

Twitter

marți, 20 octombrie 2015

JSF ELContext and ELResolver for Novices

ELContext, ELResolver, FunctionMapper and VariableMapper are NOT specific to JSF!
An expression ${foo.buzz.bizz} describes a base object foo with a property buzz that has a property bizz

The EL (Expression Language) or (Unified Expression Language) is just a set of conventions used to write expressions like, #{foo}, #{foo.buzz},#{foo.buzz.bizz}, etc. Obviously, these strings doesn't mean anything as long as a parser will not break them down to pieces and interpret them via a set of rules. So, an application (named parser) uses a grammar defined by EL to check if a string is well-formed and represents an expression (the EL unit of work). Basically, EL recognizes two kind of expressions: value expressions and method expressions (invoke a method) . Fortunately, it isn't necessary to write an EL parser, because there are at least two open source implementations available under the relatively permissive Apache License: el-api.jar jasper-el.jar and juel-xxx.jar.

But, in order to use these libraries in a new context (environment), we need to provide a javax.el.ELContext (the context/environment required to evaluate the expression). By its nature, EL can be used in any environment (e.g. in/out Java EE environment). So, these value/method expressions (e.g. #{foo.buzz}) and the environment should be somehow connected or linked or, with other words, they should be mutually aware. This is the main job of ELContext! ELContext is responsible to provide the mechanism through which all relevant context for creating or evaluating an expression is specified. How ELContext is created depends on the underlying technology. For example:

·         in JSP we have JspContext.getELContext()
·         in JSF (and other technologies) the ELContext creation is controlled via ELContextListener so that applications and frameworks can ensure their own context objects are attached to any newly created ELContext. For example, if you check the source code of Oracle Mojarra (main JSF implementation), then you can notice the com.sun.faces.el.ELContextListenerImpl, which is the implementation of the contract defined by javax.el.ELContextListener.

Now, the ELContext is materialized via three objects, as follows (in Mojarra, the concrete implementation of ELContext is com.sun.faces.el.ELContextImpl):

·         javax.el.ELResolver - This is responsible to resolve the parts (variables and properties) of an expression. For an expression #{foo.buzz} the ELResolver would need to resolve foo to an object and then decide what buzz represented on that object. For example, in JSF, the ELResolver is used to interact with the model (managed beans, implicit objects, etc).
·         javax.el.FunctionMapper - This is responsible to resolve functions of the form ${someprefix:somefunction()} to a public, static method encapsulated by the type java.lang.reflect.Method. OmniFaces has a nice implementation of a custom FunctionMapper, but this is another discussion.
·         javax.el.VariableMapper - Basically, the variable mapper is a simple class required only to store ValueExpression instances in a map. Via VariableMapper elements operating in different contexts that uses the same ELContext can share value expressions. For example, JSP can set an expression and JSF to use it.

Now, let's focus on ELResolver. As its name suggest, the ELResolver is responsible to resolve expressions, or, with other words to turn expressions into Object references. For example, when a ELResolver gets an expression of type ${foo.buzz.bizz} (describes a base object foo with a property buzz that has a property bizz), it will have to resolve:

base: null
property: foo

base: foo (as resolved above)
property: buzz

base: buzz (as resolved above)
property: bizz 

So, the resolver is asked to resolve the expression conforming to javax.el API (not related to JSF) which provides classes for resolving several common types (arrays, beans, maps and lists - JSF novices tend to believe that EL expressions and ELResolver are useful only in conjunction with beans, which is not true). These are further aggregated via javax.el.CompositeELResolver (this is another topic).
Each time an expression needs to be resolved, JSF will call the default expression language resolver implementation. Each value expression is evaluated behind the scenes by the getValue() method.
When the <el-resolver> tag is present, the pointed custom resolver is added in the chain of responsibility (next to the existing resolvers). The EL implementation manages a chain of resolver instances for different types of expression elements. For each part of an expression, EL will traverse the chain until it finds a resolver capable to resolve that part - a single expression is totally resolved by a single resolver or after a "team work" of several resolvers. The resolver capable of dealing with that part will pass true to the setPropertyResolved() method; this method acts as a flag at the ELContext level. Furthermore, EL implementation checks, after each resolver call, the value of this flag via the getPropertyResolved() method. When the flag is true, EL implementation will repeat the process for the next part of the expression.

So, the chain of responsibility contains a set of ELResolvers which are applied sequentially for each part of an expression until one of the resolvers is capable to resolve that part. For example, Oracle Mojarra comes among others with the following ELResolvers:

·         com.sun.faces.el.ImplicitObjectELResolver - as its name suggest, this resolver is capable to deal with JSF implicit objects (check them here). For example, the FacesContext can be programmatically accessed as:

       FacesContext fc = FacesContext.getCurrentInstance();

But, FacesContext is available in page also via the implicit object #{facesContext} which is an EL expression. Being an EL expression means that it must be resolved by an ELResolver, and, in this case, that resolver is ImplicitObjectELResolver. Let's see the relevant code for accomplish this:

// Mojarra 2.2.9 source code - com.sun.faces.el.ImplicitObjectELResolver
public class ImplicitObjectELResolver extends ELResolver implements ELConstants{

 // a map that holds the implicit objects names
 protected static final Map<String, Integer> IMPLICIT_OBJECTS;

 static {
  // the strings that can be used in expressions to indicate a certain implicit
  // object, e.g. #{facesContext}
  String[] implictNames = new String[]{
  "application", "applicationScope", "cc",
  "component", "cookie", "facesContext",
  ...
  };
 ...
 }

 public Object getValue(ELContext context,Object base, Object property)                             
                                                      throws ELException {
  // there is no base needed (e.g. #{foo.facesContext} is wrong !
  // if foo was resolved that it become base, and now this resolver will return
  if (base != null) {
      return null;
  }
    
  if (property == null) {
      String message = MessageUtils.getExceptionMessageString
       (MessageUtils.NULL_PARAMETERS_ERROR_MESSAGE_ID, "property");
        throw new PropertyNotFoundException(message);
  }

  Integer index = IMPLICIT_OBJECTS.get(property.toString());

  if (index == null) {
      return null;
  } else {
      // the FacesContext and ExternalContext are needed to resolve most of implicit 
      // objects, so they are obtained here to avoid code duplication
      FacesContext facesContext =(FacesContext)context.getContext(FacesContext.class);
      ExternalContext extCtx = facesContext.getExternalContext();
      switch (index) {
              ...
              case FACES_CONTEXT:
                   context.setPropertyResolved(true);
                   return facesContext;
              ...
              default:
               return null;
      }
  }
 }

 // other methods
}

So, the most important method of an ELResolver is the getValue(). Basically, this method is responsible:

- to identify the part of the expression that it can resolve;
- invoke the ELContext#setPropertyResolved() to signal that it can resolve or not the part of the expression;
- if it can resolve the part of the expression, then resolve it (practically, perform the programmatic steps necessary to obtain the result expected by the expression author)!

·         com.sun.faces.el.ManagedBeanELResolver - as its name suggest, this is responsible to resolve the part of an expression that points a managed bean. So, in an expression as #{foo.buzz}, this resolver expects to identify the foo as the name of a managed bean. Of course, it doesn't know that, so it has to perform certain searches (e.g. try to find the bean name in request/session/application scope - these are basically maps, and managed beans names are keys in these maps).

·         com.sun.faces.el.ResourceELResolver - this is responsible to resolve expression that indicates resources (e.g. CSS, JS, images) via expressions of type #{resource['library:resource']} and  #{resource['resource']}. Basically, it will identify the resource and uses the ResourceHandler#createResource() to create it and return its request path.

There are more ELResolvers, but I believe you understood the idea (as an exercise, you can also check com.sun.faces.el.FacesResourceBundleELResolver). Practically, in JSF, most expressions are linked to managed beans, implicit objects and resources, but this is not mandatory. Per example, in a dummy case, we may want to link the #{atp} expression to a static method:

public class ATPSinglesRankings {
 public static List<String> getSinglesRankings(){
  List<String> atp_ranking= new ArrayList<>();
  atp_ranking.add("1 Nadal, Rafael (ESP)");
  ...
  return atp_ranking;
 }
}

For this, our custom ELResolver (named ATPVarResolver) will override among others the getValue() method.

1  private static final String PLAYERS = "atp";
2  ...
3  @Override
4  public Object getValue(ELContext ctx, Object base, Object property) {
5
6   if ((base == null) && property.equals(PLAYERS)) {
7       ctx.setPropertyResolved(true);
8       List<String> values = ATPSinglesRankings.getSinglesRankings();
9       return values;
10  }
11  return null;
12 }

Let's inspect this code:

Line 6: The #{atp} expression doesn't need a base, so we ensure that the base is null - with other words, we don't accept something like, #{foo.atp} (tip: null base should always be resolved as a value expression).  The atp string acts as a "reserved" word... think that only #{atp} expression can be resolved by this ELResolver, not #{ATP}, or #{aTp}, or #{ATPlayers}, etc. Basically, JSF will apply the chain of available resolvers until it hits the ATPVarResolver... no other resolver will be able to link the #{atp} expression with the static getSinglesRankings(). So, notice that the atp variable is matched in a simple manner, via String#equals() method. The third argument  passed by JSF in getValue() should be exactly the atp string. In a expression of type #{foo.buzz}, first the property will be foo, afterwards, buzz. For the foo , the ELResolver class acts as a VariableResolver, while for the buzz (since there is the base foo) the ELResolver class acts as a PropertyResolver.

Line 7: If the base is null and the third argument of getValue()  is atp then this resolver is capable to resolve this expression. It must signal this to ELContext, so the chain of resolvers can be interrupted for this part of the expression, and the next part of the expression (if any; none in our case) will enter in the chain. For signaling that the #{atp} expression can be resolved by this resolver we need to invoke the ELContext#setPropertyResolved(true). As long as this flag is false, JSF will try to apply the next resolver from chain.

Line 8-9: So, is time for the ATPVarResolver to accomplish its main goal, which consist in resolving the #{atp} expression, or, with other words, to turn expressions into Object references - in this case, to turn #{atp} into List<String>. Practically, at this point, we invoke the getSinglesRankings() method and return the result. Generally speaking, here we place the code necessary to link that part of the expression with an object (constant, collection, primitive, object, managed bean, resource, etc). This code is basically the programmatic approach of accessing that artifact.

Line 11: Think that other expressions may pass through this resolver, not just #{atp}. Obviously, the ATPVarResolver will not be able to resolve them. In such cases we return null.

The getValue() is the most important method of an  ELResolver, but there a few more methods to discuss:

·         public abstract Class<?> getType(ELContext context,
                                 Object base,Object property)
This method identifies the most general acceptable type for our property. The scope of this method is to determine if a call of the setValue() method is safe without causing a ClassCastException to be thrown. Since we return a collection, we can say that the general acceptable type is List. The implementation of the getType() method is as follows:

private final Class<?> CONTENT = List.class;
...
@Override
public Class<?> getType(ELContext ctx, Object base, Object property) {

 if (base != null)
     return null;
 }

 if (property == null) {
     throw new PropertyNotFoundException(error_message);
 }

 if ((base == null) && property.equals(PLAYERS)) {
      ctx.setPropertyResolved(true);
      return CONTENT;
 }
 return null;
}

In our case, the most general acceptable type for #{atp} is java.util.List. This means that if setValue() method will allow us to set a value to this expression then that value must be of type List.

·         public abstract void setValue(ELContext context, Object base,
                                     Object property, Object value)
This method tries to set the value for a given property and base. For read-only variables, such as atp, you need to throw an exception of type PropertyNotWritableException. The implementation of the setValue() method is as follows:

private static final String PLAYERS = "atp";
...
@Override
public void setValue(ELContext ctx, Object base, Object property, Object value) {

 if (base != null) {
     return;
 }

 ctx.setPropertyResolved(false);

 if (property == null) {
     throw new PropertyNotFoundException(error_message);
 }

 if (PLAYERS.equals(property)) {
     // In case of a writable base-property you have to check here the type of the
     // passed values, and if they are ok, then set them. Since we have a read-only
     // variable, there is no need to do that, we just signal that this is a read-only
     // variable via an exception. Normally, before calling setValue(), the developer    
     // should check if this is a read-only resolver via isReadOnly() method.

     throw new PropertyNotWritableException(error_message);
 }
}

·         public abstract boolean isReadOnly(ELContext context,
                                   Object base, Object property)
This method returns true if the resolver is read-only and false otherwise. Since the atp variable is read-only, the implementation is obvious. This method is directly related to the setValue() method, meaning that it signals whether it is safe or not to call the setValue() method without getting PropertyNotWritableException as a response. The implementation of the isReadOnly() method is as follows:

@Override
public boolean isReadOnly(ELContext ctx, Object base, Object property) {
 return true;
}

·         public abstract Iterator<FeatureDescriptor> getFeatureDescriptors(ELContext context, Object base)
This method returns a set of information about the variables or properties that can be resolved (commonly it is used by a design time tool (for example, JDeveloper has such a tool) to allow code completion of expressions). In this case, you can return null. The implementation of the getFeatureDescriptors() method is as follows:

@Override
public Iterator<FeatureDescriptor>
               getFeatureDescriptors(ELContext ctx, Object base) {
 return null;
}

·         public abstract Class<?> getCommonPropertyType(ELContext context, Object base)
This method returns the most general type that this resolver accepts. The implementation of the getCommonPropertyType() method is as follows:

@Override
public Class<?> getCommonPropertyType(ELContext ctx, Object base) {
 if (base != null) {
     return null;
 }
 return String.class;
}

So, our custom ELResolver is ready, but we have to instruct JSF to use it. By default, JSF will try to resolve the #{atp} expression via the current chain of resolvers, and it not aware of ATPVarResolver resolver. In order to add our resolver in the chain of resolvers, we need to add the below configuration in faces-config.xml:

<application>
 <el-resolver>beans.ATPVarResolver</el-resolver>
</application>

When JSF will find this configuration it will add the ATPVarResolver resolver next to the existing ones. So, when #{atp} need to be resolved, JSF will "traverse" the chain of resolvers, and, at some moment, it will find the ATPVarResolver as the proper resolver for the atp variable.

So, do not forget to register your custom ELResolver class in faces-config.xml using the <el-resolver> tag and specifying the fully qualified name (FQN) of the corresponding class. In other words, you add the ELResolver class in the chain of responsibility, which represents the pattern used by JSF to deal with ELResolvers.

Done! Next, you can simply output the collection items in a data table, as shown in
the following code:

<h:dataTable id="atpTableId" value="#{atp}" var="t">
 <h:column>
  #{t}
 </h:column>
</h:dataTable>

!Pay attention to cases when an expression can be correctly evaluated by multiple resolvers. For example, if you had in the application a managed bean of like below:

@Named
@RequestScoped
public class Atp {
 ...  
}

Then #{atp} can be resolved to an instance of Atp bean also. Is like you are creating an instance of Atp. So, depending on which resolver will resolve first the #{atp} you can obtain the list of players or something like beans.Atp@b98ce3, which represents an instance of Atp class exposed via toString() method.

How do you know if the ELResolver class acts as a VariableResolver class (these two classes are deprecated in JSF 2.2) or as a PropertyResolver class? The answer lies in the first part of the expression (known as the base argument), which in our case is null (the base is before the first dot or the square bracket, while property is after this dot or the square bracket). When the base is null, the ELResolver class acts as a VariableResolver class; otherwise, it acts as a PropertyResolver class. In Mojarra, you can study the source code of com.sun.faces.el.VariableResolverImpl and com.sun.faces.el.PropertyResolverImpl.
The complete application is available here.

Niciun comentariu :

Trimiteți un comentariu

JSF BOOKS COLLECTION

Postări populare

OmniFaces/JSF Fans

Follow by Email

Visitors Starting 4 September 2015

Locations of Site Visitors