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

vineri, 17 iulie 2015

Introducing the OmniFaces Runner Scope

This class helps in letting code run within its own scope. Such scope is defined by specific variables being available to EL within it. The request scope is used to store the variables - this is the definition of the OmniFaces utility class, ScopedRunner.

Putting the things as simple as possible, this class manages two maps, suggestively named, scopedVariables and previousVariables.  The below code is pretty straightforward:

public class ScopedRunner {

 private FacesContext context;
 private Map<String, Object> scopedVariables;
 private Map<String, Object> previousVariables = new HashMap<>();

 public ScopedRunner(FacesContext context) {
  this(context, new HashMap<String, Object>());
 }

 public ScopedRunner(FacesContext context, Map<String, Object> scopedVariables) {
  this.context = context;
  this.scopedVariables = scopedVariables;
 }
 ...

The scopedVariables holds the keys names of the variables and the values of the variables that should be available in the JSF request scope at a specific moment and for a specific period of time (let's name this period of time, the runner scope). The  spotlight is represented by the Callback.Void#invoke() - presented later.  These variables can be passed via the second constructor from above or added one by one using the ScopedRunner#with():

 public ScopedRunner with(String key, Object value) {
  scopedVariables.put(key, value);
  return this; // return this ScopedRunner, so adding variables and finally calling  invoke can be chained
 }
 ...

So, basically we have a class which allows us, at instantiation moment or later, to populate the scopedVariables map with some keys and values. These are needed in the JSF request scope at a specific moment for a limited period of time, and they will replace any exiting variables with the same name. The replaced variables (if any) should be restored in the JSF request scope at the end of this period of time (at the end of the runner scope).

For storing the original variables (if any), ScopedRunner have another map named, previousVariables. This map acts as a provisory storage for the variables extracted from request scope until they are putted back (actually, you don't even need to be aware of the existence of this map!).  

Now, remember that we just said above that the  spotlight is represented by the Callback.Void#invoke(). Well, the ScopedRunner#invoke() method is used to delimitate and define the period of time for which this scope exist (specifies the runner scope boundaries). Basically, until you explicitly call this method, the runner scope doesn't exist, or, with other words, the scopedVariables is not "published" in the JSF request scope. When this method is called, OmniFaces accomplished several main steps that actually demarcates the runner scope lifespan:

- the runner scope "is alive"
- it "publishes" the scopedVariables in the JSF request scope (check setNewScope())
- it stores the previously existing variables (if any) in the previousVariables (check setNewScope())
- it provides control to the developer by calling his Callback.Void#invoke() implementation - practically, your invoke() method represents the moment in time when you need the passed in variables (scopedVariables) to be in the request scope
- when the developer gives control back to ScopedRunner#invoke() method, the request scope content is restored via the previousVariables content (check restorePreviousScope())
- after all its content is transferred back in the request scope, this map is cleared, (check restorePreviousScope())
- the runner scope "dies"

The ScopedRunner#invoke()and the corresponding helpers are listed below:

 public void invoke(Callback.Void callback) {
  try {
       setNewScope();
       callback.invoke();
  } finally {
       restorePreviousScope();
  }
 }

 private void setNewScope() {
  previousVariables.clear();

  Map<String, Object> requestMap = context.getExternalContext().getRequestMap();
  for (Map.Entry<String, Object> entry : scopedVariables.entrySet()) {
       Object previousVariable = requestMap.put(entry.getKey(), entry.getValue());
       if (previousVariable != null) {
           previousVariables.put(entry.getKey(), previousVariable);
       }
  }
 }

 private void restorePreviousScope() {
  try {
      Map<String, Object> requestMap = context.getExternalContext().getRequestMap();
      for (Map.Entry<String, Object> entry : scopedVariables.entrySet()) {
           Object previousVariable = previousVariables.get(entry.getKey());
           if (previousVariable != null) {
               requestMap.put(entry.getKey(), previousVariable);
           } else {
               requestMap.remove(entry.getKey());
           }
      }
  } finally {
      previousVariables.clear();
  }
 }
} // end of ScopedRunner class

Here it is an use case flow diagram: 

Now, that you know what the OmniFaces ScopedRunner does, is time to think to an use case. Let's suppose that we have an iterating components (UIData/UIRepeat/ UISelectItems) which should be programmatically consulted on a per-iteration basis. For this, we are using the var attribute, which in case of UISelectItems, exposes the value from the value attribute under this request scoped key so that it may be referred to in EL for the value of other attributes. This means that at a certain moment, in request scope, we must have a key with the var attribute value and a value with the object instance of that iteration.
We can easily add this into the request map, but if the request map already contain such a key then the corresponding entry will be lost. An workaround will be to store locally the existing key-value pair, place our key-value in request scope, and restore it at the end of our job. Basically, this is what ScopedRunner does in a professional and generic approach. The main advantages of using ScopedRunner are:

- we don't have to take care of adding/restoring the request scope
- we can easily manipulate multiple variables
- we can easily reuse the ScopedRunner in multiple places
- we obtain a clean and detached code of this topic
- we can extend the ScopedRunner for accomplish more specific tasks
- we exploit OmniFaces capabilities as much as possible (it will be an waste of time to have installed OmniFaces and to not use this ScopedRunner despite other workarounds)

A skeleton of usage was inspired from the org.omnifaces.util.selectitems.SelectItemsCollector class:

UISelectItems uiSelectItems ...; // An UISelectItems instance.
Iterable<?> items ...; // The value of the uiSelectItems value attribute as Iterable 
                       // (we may suppose that these are not instances of SelectItem)

// The UISelectItems var attribute value.
Map<String, Object> attributes = uiSelectItems.getAttributes();
String var = (String) attributes.get("var");

// Helper class that's used to set the item value in (EL) scope using the name set by  
// "var" during the iteration. If during each iteration the value of this is changed,   
// any value expressions in the attribute map referring it will resolve to that
// particular instance.
ScopedRunner scopedRunner = new ScopedRunner(facesContext);

for (final Object item : items) {

     if (!isEmpty(var)) {
         scopedRunner.with(var, item);
     }

     // During each iteration, just resolve all attributes
     scopedRunner.invoke(new Callback.Void() {
      // Before calling the below invoke(), the ScopedRunner#setNewScope() has   
      // replaced in the request scope the entry that has a key equal with the var value (if 
      // any) with the one indicated above via the ScopedRunner#with() and stored it under 
      // the private previousVariables map.
      @Override
      public void invoke() {
       // Just resolve all attributes for this item.
       ...
       // Build a SelectItem instance to wrap this item or do something else.
      }
     });
     // The ScopedRunner#restorePreviousScope() will restore the original entry.
}

Now, you can exploit the ScopedRunner in different ways in your JSF projects.

joi, 16 iulie 2015

Inject CDI in JSF and vice versa

The pacifist approach will combine these two in the same application. In this case, you have two options: to avoid any interaction between the managed beans and CDI beans or, obviously, to encourage the interaction between them for better performance. If you choose the second option, then it is important to keep in mind some simple rules of injection as shown in the following figure:

miercuri, 15 iulie 2015

JSF/CDI Bean Injection Short Overview

From the following figure, you can seek some guidance for dealing with some of the most popular cases:


As a general rule in JSF, don't use objects that have shorter lifespan than the objects you are calling it from. In other words, use objects whose lifespan is the same as, or longer than, the object being injected into. Breaking this rule will end up in a JSF exception.

Common mistakes (bad practices):

- Use request objects in session objects
- Use session objects in application objects

Nevertheless, for CDI, these cases are not such a big issue. When you are using an object that has a shorter lifespan than the object you are calling it from (for example, injecting a request scoped bean into a session scoped bean), CDI classifies the use case as a mismatched injection and fixes the issue via CDI proxies. For each request, the CDI proxy re-establishes the connection to a live instance of the request scoped bean.

Keep in mind also:

- Overusing a view scoped bean for request scoped data may affect memory.
- Overusing a request scoped bean for view scoped data may cause forms with unexpected behavior.
- Overusing an application scoped bean for request/view/session scoped data may cause an undesirably wide visibility of data across users and will affect memory.
- Overusing a session scoped bean for request/view data may cause an undesirably wide visibility of data across multiple browser windows/tabs in that session.

Starting with JSF 2.0, managed beans can be injected (dependency injection) into the property of another managed bean using the @ManagedProperty annotation. Another way to inject beans is to use the @Inject annotation, which is part of the CDI powerful injection mechanism.

Read more:
JSF 2.2, CDI and OmniFaces Scopes List

marți, 14 iulie 2015

JSF 2.2, CDI and OmniFaces Scopes List

JSF 2.2, CDI and OmniFaces Scopes List:

Read more:

[OmniFaces utilities 2.2] Update the row of the given UIData component at the given zero-based row index in tables with pagination

Before reading this post is recommended to read the Update the row of the given UIData component at the given zero-based row index.
You may be also interested in: Update the row of the given UIData component at the given zero-based row index with support for nested UIData


[OmniFaces utilities] The updateRow() method updates the row of the given UIData component at the given zero-based row index. This will basically update all direct children of all UIColumn components at the given row index.

Note that the to-be-updated direct child of UIColumn must be a fullworthy JSF UI component which renders a concrete HTML element to the output, so that JS/ajax can update it. So if you have due to design restrictions for example a <h:panelGroup rendered="..."> without an ID, then you should give it an ID. This way it will render a <span id="..."> which is updateable by JS/ajax.

Method:
Usage:

Let's suppose that we have a table that supports pagination, like the following PrimeFaces Data Table:

<p:dataTable var="t" value="#{playersBean.players}"
                     binding="#{playersTable}"
                     rows="5"
                     paginator="true"
                     paginatorTemplate="{CurrentPageReport}  {FirstPageLink} {PreviousPageLink} {PageLinks} 
                                        {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
                     rowsPerPageTemplate="5,10,15">
 <p:column headerText="Player">
  <h:panelGroup id="playerId">#{t.player}</h:panelGroup>
 </p:column>

 <p:column headerText="Age">
  <h:panelGroup id="ageId">#{t.age}</h:panelGroup>
 </p:column>

 <p:column headerText="Birthplace">
  <h:panelGroup id="birthplaceId">#{t.birthplace}</h:panelGroup>
 </p:column>

 <p:column headerText="Residence">
  <h:panelGroup id="residenceId">#{t.residence}</h:panelGroup>
 </p:column>

 <p:column headerText="Height">
  <h:panelGroup id="heightId">#{t.height} cm</h:panelGroup>
 </p:column>

 <p:column headerText="Weight">
  <h:panelGroup id="weightId">#{t.weight} kg</h:panelGroup>
 </p:column>
</p:dataTable>

This will produce a table like in figure below - there are two pages and each page has 5 rows (rows with indexes from 0 to 9):


In OmniFaces 2.1, the utility method Ajax#updateRow() works only for rows from the first page, which means that if we try to update the first (or any other row from the first page) and the last (or any other row from the second page) rows, only the first row (or any other specified row from the first page) will be updated:

<f:ajax>
 <!-- this will work as expected -->
 <h:commandButton value="Update First Row"             
                  action="#{playersBean.updateRow(playersTable, 0)}" />
 <!-- this will not work as expected -->
 <h:commandButton value="Update Last Row"
                  action="#{playersBean.updateRow(playersTable, 9)}" />                          
</f:ajax>

The PlayersBean is available here.

The result of trying to update first and last rows will be:


Starting with OmniFaces 2.2, this issue was fixed and Ajax#updateRow() works for all rows in a table that have pagination. Testing the above code with OmniFaces 2.2 will reveal this:

luni, 13 iulie 2015

OmniFaces 2.1 - Inject HTTP cookie via @Cookie annotation

The CDI annotation Cookie is available starting with OmniFaces 2.1 and it allows you to inject a HTTP request cookie value from the current JSF context in a CDI managed bean. It's basically like:

@ManagedProperty("#{cookie.cookieName.value}")
private String cookieName;

in a "plain old" JSF managed bean. You can use this as:

// By default the name of the cookie is taken from the name of the variable 
// into which injection takes place. The example below injects the cookie with name foo.
@Inject @Cookie
private String foo;

// The name can be optionally specified via the name attribute. 
// The example below injects the cookie with name foo into a variable named bar.
@Inject @Cookie(name="foo")
private String bar;

The implementation of this annotation can be a source of inspiration for creating new such annotations. The Cookie annotation is declared in org.omnifaces.cdi.Cookie as:

@Qualifier
@Retention(RUNTIME)
@Target({ TYPE, METHOD, FIELD, PARAMETER })
public @interface Cookie {
 @Nonbinding  String name() default "";
}

Further, the producer for injecting a JSF request cookie as defined by the above Cookie annotation is defined in org.omnifaces.cdi.cookie.RequestCookieProducer:

public class RequestCookieProducer {

 @SuppressWarnings("unused") // Workaround for OpenWebBeans not properly passing it as produce() method argument.
 @Inject
 private InjectionPoint injectionPoint;

 @Produces
 @Cookie
 public String produce(InjectionPoint injectionPoint) {
  Cookie cookie = getQualifier(injectionPoint, Cookie.class);
  String name = cookie.name().isEmpty() ? injectionPoint.getMember().getName() : cookie.name();
  return getRequestCookie(name);
 }
}

The getQualifier() method returns the qualifier annotation of the given qualifier class from the given injection point and you can read further details here, where you can see an annotation for injecting the value of an application initialization parameter (declared in web.xml via <context-param>).

sâmbătă, 4 iulie 2015

OmniFaces 2.1 - ReadOnlyValueExpression that can be set when the "real" value is not yet available

This post presents the features brought by OmniFaces 2.1 for the ReadOnlyValueExpression artifact. If you are not familiar with ReadOnlyValueExpression then please read this post before, "OmniFaces2.0 - ReadOnlyValueExpression that can be set when the "real"value is not yet available".

In OmniFaces 2.0 we can create a ReadOnlyValueExpression via a callback which takes one argument and returns one value (the object is the "real" needed value of this ValueExpression). Starting with OmniFaces 2.1, the Callback.Returning was replaced with the serializable version of it, Callback.SerializableReturning. By the other hand, the Callback.ReturningWithArgument is still there.

So, instead of writing:

ReadOnlyValueExpression readOnlyValueExpression = new 
     ReadOnlyValueExpression(type_of_object, new Returning<Object>() {
 @Override
 public Object invoke() {
  return object;
 }
});

Now, we write:

ReadOnlyValueExpression readOnlyValueExpression = new 
     ReadOnlyValueExpression(type_of_object, new SerializableReturning<Object>() {

 private static final long serialVersionUID = 1L;

 @Override
 public Object invoke() {
  return object;
 }
});

Moreover, note that in OmniFaces 2.0, the Callback can be "attached" only via ReadOnlyValueExpression constructors, while in OmniFaces 2.1 it can be "attached" via constructors, or later, via setCallbackReturning() and setCallbackWithArgument() methods. This adds more flexibility, since we are not restricted to "attach" the Callback when we instantiate the ReadOnlyValueExpression, and we can obtain the functional Callback interface that will be called when the value expression is resolved, via getCallbackReturning() and getCallbackWithArgument(). Below you can see these methods:

·         OmniFaces 2.1 set/getCallbackReturning():

·         OmniFaces 2.1 set/getCallbackWithArgument():


So, in OmniFaces 2.1 we can write the functional Callback interface, as below:

public static class MyCallbakImpl implements SerializableReturning<Object> {

 private static final long serialVersionUID = 1L;

 public MyCallbakImpl () { // empty constructor, not mandatory!
  // NOOP
 }

 // more constructors
 ...

 @Override
 public Object invoke() {
  ...
 }
}

And, whenever we need, we can create the ReadOnlyValueExpression without "attaching" the above functional now, MyCallbakImpl:

// this is just an example, you don't have to pass the UIComponent type, rather your expected type
ReadOnlyValueExpression readOnlyValueExpression = new ReadOnlyValueExpression(UIComponent.class);

Later, at the proper moment, we use the OmniFaces 2.1 setCallbackReturning() to "attach" the readOnlyValueExpression to MyCallbakImpl:

readOnlyValueExpression.setCallbackReturning(new MyCallbakImpl());

Is pretty obvious how to use the getCallbackReturning().

joi, 2 iulie 2015

[OmniFaces utilities 2.1] Get the value of the given tag attribute as a value expression


[OmniFaces utilities] The getValueExpression() method returns the value of the given tag attribute as a value expression, so it can be carried around and evaluated at a later moment in the lifecycle without needing the Facelet context.

Method:
Usage:

The Facelets#getValueExpression() returns the value of the given tag attribute as a value expression, so it can be carried around and evaluated at a later moment in the lifecycle without needing the Facelet context. For example, the Facelet context is available in a tag handler when the component tree is build, but you may not need the values of tag attributes (e.g. attr1 and attr2) at that moment, you may need them later, for example after the validation take place (at PostValidateEvent). The problem is that the Facelet context is not available then, so you cannot simply call, FaceletContext#getAttribute() method. So, when the Facelet context is available, we can collect the value expressions of those attributes as below:

public class MyTagHander extends TagHandler {

 private ValueExpression veAttr1;
 private ValueExpression veAttr2;

 @Override
 public void apply(FaceletContext context, final UIComponent parent) throws IOException {

  veAttr1 = Facelets.getValueExpression(context, getAttribute("attr1"), String.class);
  veAttr2 = Facelets.getValueExpression(context, getAttribute("attr2"), String.class); 

  // for example, here you can subscribe to PostValidateEvent
 }
}

Later, at PostValidateEvent, we can evaluate veAttr1 and veAttr2, as below:

FacesContext context = ...;
ELContext elContext = context.getELContext();
String evaluatedAttr1 = evaluate(elContext, veAttr1, true);
String evaluatedAttr2 = evaluate(elContext, veAttr2, true);

private static String evaluate(ELContext context, ValueExpression expression, boolean required) {
 Object value = (expression != null) ? expression.getValue(context) : null;

 if (required && isEmpty(value)) { // see Utils#isEmpty()
     throw new IllegalArgumentException(...);
 }

 return (value != null) ? value.toString() : null;
}

You can see a complete example of using Facelets#getValueExpression() in OmniFaces ViewParamValidationFailed.

miercuri, 1 iulie 2015

[OmniFaces utilities 2.1] Get a string for the given key searching declared resource bundles


[OmniFaces utilities] The getBundleString() method gets a string for the given key searching declared resource bundles, order by declaration in faces-config.xml. If the string is missing, then this method returns ???key???.

Method:
Usage:

Let's suppose that we have the below two resource bundles:

The content of  msgs.UserMessages for English is:

The content of  msgs.AdminMessages for English is:
Notice that the NAME key appears in both!

Now, in faces-config.xml, we declare both resource bundles, as below (for the "user" messages we have attached the var named, user, and for the "admin" messages, the var named, admin):

<application>
 <locale-config>
  <default-locale>en</default-locale>
  <supported-locale>en</supported-locale>
  <supported-locale>fr</supported-locale>
 </locale-config>
 <resource-bundle>
  <base-name>msgs.UserMessages</base-name>
  <var>user</var>
 </resource-bundle>
 <resource-bundle>
  <base-name>msgs.AdminMessages</base-name>
  <var>admin</var>
 </resource-bundle>
</application>

Now, you can use both resource bundles in the application views by indicating the proper var. For example, a dummy usage is below:

<h:outputText value="#{admin['NAME']}"/><br/>
<h:outputText value="#{admin['ROLE']}"/><br/>
<h:outputText value="#{admin['SECURITY']}"/><br/>
<h:outputText value="#{user['NAME']}"/><br/>
<h:outputText value="#{user['SURNAME']}"/><br/>

Now, programmatically speaking, we can locate a key in the current resource bundles like below - keep in mind that OmniFaces will inspect the resource bundles in the order of their declaration in faces-config.xml, which means that in this case it will first inspect the UserMessages, and if the searched key is not present there, it will inspect the AdminMessages). The result are listed for both locales:

// 'First Name' or 'Nom', from UserMessages
Faces.getBundleString("NAME");
// 'Last Name' or ' Nom de Famille', from UserMessages
Faces.getBundleString("SURNAME");
// 'administrator' or 'administrateur', from AdminMessages
Faces.getBundleString("ROLE");
// 'low' or 'faible', from AdminMessages
Faces.getBundleString("SECURITY");

If you reverse the order of UserMessages and AdminMessages in faces-config.xml, then we will have:

// 'Complete Name' or 'nom et surnom', from AdminMessages
Faces.getBundleString("NAME");
// 'Last Name' or 'Nom de Famille', from UserMessages
Faces.getBundleString("SURNAME");
// 'administrator' or 'administrateur', from AdminMessages
Faces.getBundleString("ROLE");
// 'low' or 'faible', from AdminMessages
Faces.getBundleString("SECURITY");

JSF BOOKS COLLECTION

Postări populare

Visitors Starting 4 September 2015

Locations of Site Visitors