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, 26 ianuarie 2016

[OmniFaces utilities (2.3)] - Check if the given CDI managed bean scope is active


[OmniFaces utilities] The isActive() returns true when the given CDI managed bean scope is active. I.e., all beans therein can be accessed without facing ContextNotActiveException.

Method:
Usage:

For example, you can test if the request scope is active like this:

import org.omnifaces.util.Beans;
...
boolean isrequestscopeactive = Beans.isActive(RequestScoped.class);
if (isrequestscopeactive){
    // do something
} else {
    // do something else

}

luni, 25 ianuarie 2016

PrimeFaces cross-field client bean validation sample

As you probably know, PrimeFaces comes with a very useful support for client side validation based on JSF validation API and Bean Validation. In this post we will focus on Bean Validation, and say that this can be successfully used as long as we don't need cross-field validation or class level validation. This means that the validation constrains placed at class level will not be recognized by PrimeFaces client side validation.

In this post, you can see a pretty custom solution, but pretty fast to implement in order to obtain a cross-field client side validation for Bean Validation using PrimeFaces. We have a user contact made of a name and an e-mail, and our validation constraint is of type: e-mail must start with name (e.g. name@domain.com):

<h:form>  
 <p:panelGrid columns="3">
  <p:outputLabel for="nameId" value="Name"/>
  <p:inputText id="nameId" value="#{contactBean.name}"/>               
  <p:message for="nameId"/>           

  <p:outputLabel for="emailId" value="E-mail"/>
  <p:inputText id="emailId" value="#{contactBean.email}"/>                     
  <p:message for="emailId"/>           

  <p:commandButton value="Contact Member" action="#{contactBean.someAction()}"
                   update="@form" validateClient="true"/>               
 </p:panelGrid>       
 <p:messages/>
</h:form>  

For accomplishing this task, we will slightly adapt the PrimeFaces custom client side validation.

First, we create ValidContact annotation:

@Documented
@Constraint(validatedBy = {ContactValidator.class})
@ClientConstraint(resolvedBy=ValidContactClientConstraint.class)
@Target({ANNOTATION_TYPE, METHOD, FIELD})
@Retention(RUNTIME)
public @interface ValidContact {

 String message() default "Invalid contact !";
 Class<?>[] groups() default {};
 Class<? extends Payload>[] payload() default {};
}

Further, in our bean we annotate the proper fields (name and email) with this annotation - we need to do this to indicate the fields that enters in cross-field validation; so, annotate each such field:

@Named
@RequestScoped
public class ContactBean implements Serializable {

 private static final long serialVersionUID = 1L;
   
 @ValidContact(message = "The name should be used in e-mail as name@domain.com!")
 private String name;
   
 @ValidContact(message = "The e-mail should be of type name@domain.com!")
 private String email;

 // getters and setters

 public void someAction() {
  Messages.addGlobalInfo("Thank you for your contacts!");
 }
}

Now, we write the validator. Here, we need to keep the name until the validator gets the e-mail also. For this, we can use the faces context attributes, as below:

public class ContactValidator implements ConstraintValidator<ValidContact, String> {

 @Override
 public void initialize(ValidContact constraintAnnotation) {
  // NOOP
 }

 @Override
 public boolean isValid(String value, ConstraintValidatorContext context) {
  if (Faces.getContextAttribute("NAME_VALUE") == null) {
      Faces.setContextAttribute("NAME_VALUE", value);
  } else {
      return value.startsWith(String.valueOf(Faces.getContextAttribute("NAME_VALUE")));
  }
  return true;
 }
}

Now, we have to accomplish the client-side validation. Again, notice that we store the name into an array (you can add here more fields) and wait for the e-mail:

<script type="text/javascript">
 var data = [];
 PrimeFaces.validator['ValidContact'] = {
  MESSAGE_ID: 'org.primefaces.examples.validate.contact.message',
  validate: function (element, value) {
   if (data.length == 0) {
       data.push(value);
   } else {
       if (!value.startsWith(data[0])) {
           var msgStr = element.data('p-contact-msg'),
           msg = msgStr ? {summary: msgStr, detail: msgStr} :
            vc.getMessage(this.MESSAGE_ID);
           throw msg;
       }
   }
  }
 };
</script>

Finally, we ensure the presence of ClientValidationConstraint implementation:

public class ValidContactClientConstraint implements ClientValidationConstraint {

 public static final String MESSAGE_METADATA = "data-p-contact-msg";

 public Map<String, Object> getMetadata(ConstraintDescriptor constraintDescriptor) {
  Map<String, Object> metadata = new HashMap<String, Object>();
  Map attrs = constraintDescriptor.getAttributes();
  Object message = attrs.get("message");

  if (message != null) {
      metadata.put(MESSAGE_METADATA, message);
  }

  return metadata;
 }

 public String getValidatorId() {
  return ValidContact.class.getSimpleName();
 }
}

Valid screenshot:
Invalid screenshot:

Done! The complete application is available here.

Read more such goodies in:

PrimeFaces & OmniFaces - Powers Combined

duminică, 24 ianuarie 2016

PrimeFaces ring with OmniFaces unique value column

As you probably know, PrimeFaces comes with a component capable to display data with a circular animation. This component is named Ring.

For example, the below snippet of code will work in conjunction with BarcelonaSquadBean to return the result from image below:

<h:form id="form">           
 <p:panel>
  <p:ring id="custom" value="#{barcelonaSquadBean.players}" var="t">
   <p:outputPanel style="text-align: center; height:90%;" layout="block">                  
    <p:inputText value="#{t.name}" required="true" style="width: 90%; height: inherit;"/>           
   </p:outputPanel>                            
  </p:ring>   
 </p:panel>

 <p:panel style="text-align: center; margin-top: 10px;">
  <p:commandButton actionListener="#{barcelonaSquadBean.someAction()}" update="@form"
                   value="Subscribe Team"/>                                   
  <p:messages id="msgs"/>
 </p:panel>
</h:form>

The issue consist in the fact that we can mistakenly provide the same player name twice and obviosuly this is not diserable. In order to fix this, we can use the OmniFaces ValidateUniqueColumn validator. This validator is exposed to page authors via <o:validateUniqueColumn/> tag. The main characteristics of this validator are:
  • It validates if the given UIInput component in an UIData component has an unique value throughout all rows.
  • It includes in validation the data that is not visible in case of using pagination, as long as it is in the data model.
  • It works directly on the data model (e.g. when lazy loading is used, the data model contains a subset of data; only this subset counts on validation).
  • It signals only the first invalid row on which the value is actually changed.
  • A faces message will be added on the client ID of the input component in this invalid row.
  • Its default message is of type (the {0} placeholder represents the label of the input component, while the {1} placeholder represents the 1‐based row index of the data model):

{0}: Please fill out an unique value for the entire column. Duplicate found in row {1} 

 If you need to a custom message then just use the message attribute:

<o:validateUniqueColumn message="custom message here" />

So, we can use <o:validateUniqueColumn/> in our case like below:

<p:panel>
 <p:ring id="custom" value="#{barcelonaSquadBean.players}" var="t">
  <p:outputPanel style="text-align: center; height:90%;" layout="block">                  
   <p:inputText value="#{t.name}" required="true" style="width: 90%; height: inherit;">           
    <o:validateUniqueColumn message="Duplicate player not allowed!"/>
   </p:inputText>                     
  </p:outputPanel>                           
 </p:ring>   
</p:panel> 

This time we cannot submit the team with duplicate players. Check figure below:

The complete application is available here.

Read more such goodies in:

PrimeFaces & OmniFaces - Powers Combined

vineri, 22 ianuarie 2016

Combining @ListenerFor with SystemEventListener

Conforming to documentation, "if the class to which @ListenerFor annotation is attached implements SystemEventListener and does not implement ComponentSystemEventListener, "target" is the Application instance".

Based on this affirmation, it is possible to believe that the below example will work and will register the TomComponent as a listener for all emitters capable to emit the PostAddToViewEvent event (not just instances of TomComponent):

@FacesComponent(value = TomComponent.COMPONENT_TYPE, createTag = true)
@ListenerFor(systemEventClass = PostAddToViewEvent.class)
public class TomComponent extends UIComponentBase implements SystemEventListener {

 public static final String COMPONENT_FAMILY = "jsf.component";
 public static final String COMPONENT_TYPE = "jsf.component.TomComponent";

 @Override
 public void processEvent(SystemEvent event) throws AbortProcessingException {
  System.out.println("EVENT EMITTED: " + event);
 }

 @Override
 public String getFamily() {
   return COMPONENT_FAMILY;
 }  

 @Override
 public boolean isListenerForSource(Object source) {
  System.out.println("EVENT SOURCE: " + source);
 return true;
 } 
 ...
}

But, remember that an custom component implements the ComponentSystemEventListener interface by inheritance from UIComponent! So, the output of the above case will be:

EVENT SOURCE:
jsf.component.TomComponent

And the processEvent(SystemEvent event) is not called! Since ComponentSystemEventListener is inherited (so implemented), and we have the @ListenerFor, the TomComponent will be registered as the listener for PostAddToViewEvent event emitted only by instances of TomComponent. But, as you notice from the above output, the flow passes through the isListenerForSource(Object source), which means that, in this particular case, we need to return true;, or return source instanceof TomComponent;, otherwise we will block the call of the processEvent(ComponentSystemEventListener event) method.
So, combining @ListenerFor with SystemEventListener and UIComponents is not a good thing, only if you really know what you are doing.

Well, the things changes in case of combining the @ListenerFor with SystemEventListener  and Renderer. Since Renderer doesn't implement the ComponentSystemEventListener, we are in the case from the documentation quoted above. Now, the reasoning is going further and "If "target" is the Application instance, inspect the value of the sourceClass() annotation attribute value. If the value is Void.class, call Application.subscribeToEvent(Class, SystemEventListener), passing the value of systemEventClass() as the first argument and the instance of the class to which this annotation is attached (which must implement SystemEventListener) as the second argument".

miercuri, 20 ianuarie 2016

Using PrimeFaces and OmniFaces to customize the PrimeFaces client-side bean validation error messages

As you probably know, PrimeFaces support Bean Validation. Actually, PrimeFaces comes with a client side validation framework integrated with Bean Validation Specification.  Basically, PrimeFaces obtains via a set of classes (located in org.primefaces.validate.bean) the server side validation constraints for each type of supported validators. These constrains will be used in a JavaScript file named beanvalidation.js to perform the validation on client side and generate the corresponding messages. For example, let's suppose that we have the following bean:

@Named
@RequestScoped
public class DataBean {

 @Size(min = 2, max = 25)
 private String name;
 @Size(min = 2, max = 10)
 private String surname;

 // getters and setters
}

PrimeFaces extracts the constraints for @Size via org.primefaces.validate.bean.SizeClientValidationConstraint, like below:

package org.primefaces.validate.bean;

import java.util.HashMap;
import java.util.Map;
import javax.validation.constraints.Size;
import javax.validation.metadata.ConstraintDescriptor;
import org.primefaces.util.HTML;

public class SizeClientValidationConstraint implements ClientValidationConstraint {

 private static final String MESSAGE_METADATA = "data-p-size-msg";
 private static final String MESSAGE_ID = "{javax.validation.constraints.Size.message}";

 public Map<String, Object> getMetadata(ConstraintDescriptor constraintDescriptor) {
       
  Map<String, Object> metadata = new HashMap<String, Object>();
  Map attrs = constraintDescriptor.getAttributes();
  Object message = attrs.get("message");

  metadata.put(HTML.VALIDATION_METADATA.MIN_LENGTH, attrs.get("min"));
  metadata.put(HTML.VALIDATION_METADATA.MAX_LENGTH, attrs.get("max"));

  if (!message.equals(MESSAGE_ID)) {
      metadata.put(MESSAGE_METADATA, message);
  }

  return metadata;
 }

 public String getValidatorId() {
  return Size.class.getSimpleName();
 }
}

Now, the extracted constrains are used in beanvalidation.js, as below:

if (window.PrimeFaces) {
    ...
    PrimeFaces.locales.en_US.messages["javax.validation.constraints.Size.message"] = "size must be between {0} and {1}";

    PrimeFaces.validator.Size = {
    MESSAGE_ID: "javax.validation.constraints.Size.message",
      validate: function(d, f) {
       if (f !== null) {
           var e = d.val().length,
           c = d.data("p-minlength"),
           a = d.data("p-maxlength"),
           b = PrimeFaces.util.ValidationContext;
           if (e < c || e > a) {
               throw b.getMessageBV(d, this.MESSAGE_ID, d.data("p-size-msg"), c, a)
           }
       }
      }
    };
    ...  
};

So, this will produce the error messages from figure below:


Now, let's suppose that we want to change this message and involve more information in it. For example, let's suppose that we want to provide in the error messages the labels of the invalid components. So, instead of the above image, we want to obtain something like this:


Note In case of server-side validation via Bean Validation, you can accomplish this task via OmniFaces JsfLabelMessageInterpolator.

In order to accomplish this task we have several approaches. One of these approaches consist in overriding the SizeClientValidationConstraint for extracting the validated input label and overriding the client-side implementation to take this label into account.

So, first we will write a new SizeClientValidationConstraint like below:

import java.util.HashMap;
import java.util.Map;
import javax.validation.constraints.Size;
import javax.validation.metadata.ConstraintDescriptor;
import static org.omnifaces.util.Components.getCurrentComponent;
import static org.omnifaces.util.Components.getLabel;
import org.primefaces.util.HTML;

public class SizeClientValidationConstraint implements ClientValidationConstraint {

 private static final String MESSAGE_METADATA = "data-p-size-msg";
 private static final String MESSAGE_ID = "{javax.validation.constraints.Size.message}";

 public Map<String, Object> getMetadata(ConstraintDescriptor constraintDescriptor) {
       
  Map<String, Object> metadata = new HashMap<String, Object>();
  Map attrs = constraintDescriptor.getAttributes();
  Object message = attrs.get("message");

  metadata.put(HTML.VALIDATION_METADATA.MIN_LENGTH, attrs.get("min"));
  metadata.put(HTML.VALIDATION_METADATA.MAX_LENGTH, attrs.get("max"));
  metadata.put(HTML.VALIDATION_METADATA.LABEL, getLabel(getCurrentComponent()));       

  if (!message.equals(MESSAGE_ID)) {
      metadata.put(MESSAGE_METADATA, message);
  }

  return metadata;
 }

 public String getValidatorId() {
  return Size.class.getSimpleName();
 }
}

Thanks to OmniFaces utilities, we can obtain the label of the current validated input component via Components#getCurrentComponent() and Components#getLabel(). This save us for writing a good chunk of code! Further, we simply add the label in the metadata under HTML.VALIDATION_METADATA.LABEL.

Now, on client-side, we adjust the JavaScript code to use this label in error validation messages for @Size:

<script type="text/javascript">
 //<![CDATA[
 PrimeFaces.locales.en_US.messages["javax.validation.constraints.Size.message"] = "The size of {0} must be between {1} and {2} characters";
 PrimeFaces.validator.Size = {
  MESSAGE_ID: "javax.validation.constraints.Size.message",
  validate: function (d, f) {
  if (f !== null) {
      var e = d.val().length,
          c = d.data("p-minlength"),
          a = d.data("p-maxlength"),
          l = d.data("p-label");
          b = PrimeFaces.util.ValidationContext;
          if (e < c || e > a) {
              throw b.getMessageBV(d, this.MESSAGE_ID, d.data("p-size-msg"), l, c, a)
          }
   }
  }
 };
 //]]>  
</script>

Done! The complete application in available here.

Read more such goodies in:

PrimeFaces & OmniFaces - Powers Combined

marți, 19 ianuarie 2016

Use a JSF built-in converter to preserve data type

Let's suppose that we have a <h:selectManyListbox> used in the classical way:

<h:form>         
 <h:selectManyListbox value="#{playerBean.selectedRanks}">              
  <f:selectItems value="#{playerBean.playersRanks}"/>
 </h:selectManyListbox>
 <h:commandButton value="Select" action="#{playerBean.selectedAction()}"/>
</h:form>
Basically, the playersRanks is a list of integers that "populates" our list, and the selectedRanks represents the user selections:

@Named
@SessionScoped
public class PlayerBean implements Serializable {

 private ArrayList<Integer> selectedRanks;
 private static final ArrayList<Integer> playersRanks;

 static {
  playersRanks = new ArrayList<>();
  playersRanks.add(1);
  playersRanks.add(2);
  playersRanks.add(3);
 }

 public ArrayList<Integer> getPlayersRanks() {
  return playersRanks;
 }

 public ArrayList<Integer> getSelectedRanks() {
  return selectedRanks;
 }

 public void setSelectedRanks(ArrayList<Integer> selectedRanks) {
  this.selectedRanks = selectedRanks;
 }

 public String selectedAction() {
  // TODO
 }
}

So, the user may select the ranks and submit them without issues/errors. Even if no error occurred, we can notice a "strange" behavior if we try to run the following snippet of code:

<ui:repeat value="#{playerBean.selectedRanks}" var="i">
 #{i}: #{i.getClass()}
</ui:repeat>

The output reveals that the selected ranks are strings, not integers as we expected to see:

1: class java.lang.String
3: class java.lang.String

The explanation relies on the fact that "the generic type information of List<Integer> is lost during runtime and therefore JSF/EL who sees only List is not able to identify that the generic type is Integer and assumes it to be default String (as that's the default type of the underlying HttpServletRequest#getParameter() call during apply request values phase) " - Bauke Scholtz (aka BalusC).

There are two approaches:

·               explicitly specify a Converter
·               use Integer[] instead

In this case, we can use the built-in javax.faces.Integer built-in converter:

<h:form>         
 <h:selectManyListbox value="#{playerBean.selectedRanks}"  
                      converter="javax.faces.Integer">             
  <f:selectItems value="#{playerBean.playersRanks}"/>
 </h:selectManyListbox>
 <h:commandButton value="Select" action="#{playerBean.selectedAction()}"/>
</h:form>

Now, we can perform the same test and the output will be:

1: class java.lang.Integer
3: class java.lang.Integer

Read further explanations here.

JSF BOOKS COLLECTION

Postări populare

Visitors Starting 4 September 2015

Locations of Site Visitors