Wednesday, March 12, 2014

Implement pagination in JSF 2.x with Primefaces

Primefaces provids LazyDataModel which you can bind with DataTable object to provide very powerful pagination functionalities in the UI, including customizable pagination buttons, sorting functions, and multiple query criteria, and so on.
The way to use it is not difficult but there's not much information about it you can find in the documentation. The best starting point is to check the Primeface showcase at http://www.primefaces.org/showcase/ui/datatableLazy.jsf .
Steps to implement the support for LazyDataModel with JSF2.x can be briefly described as follows:

  1. Implement a child class (Let's call it ChildLazyDataModel) of LazyDataModel with one @Override method List load(int first, int pagesize, String sortfield, SortOrder sortorder, Map filters). This method will be invoked whenever pagination happens. Inside the method, 2 pieces of logic should be implemented:
    • The total result count should be set on the datamodel.
    • The result should be returned from the query.
  2. Build the JSF backing bean in the way that it contains an instance of ChildLazyDataModel. Let's call it PrimeBackingBean. The getter of the lazy data model will return a new instance.
  3. Bind the ChildLazyDataModel variable from PrimeBackingBean with the Primeface datatable object in the JSF files.

You can get some examples with EJB or DAO in the internet. But I didn't find much information on how to implement it with the setup of JSF2 and JPA. The tricky part is normally people inject JPA execution logic (query, update entities) into JSF managed beans, for example, PrimeBackingBean in our case. Such injection won't work for ChildLazyDataModel, as ChildLazyDataModel is not a container-manageable yet. I didn't try the option to make it container-manageable object yet. Instead, I used an easier alternative:

  • Inject the JPA execution bean into PrimeBackingBean.
  • Implement the constructor for ChildLazyDataModel with the parameter of JPA execution bean. The JPA execution bean instance can be used to do all the required queries.
  • In the getter for the lazy data model of PrimeBackingBean, instantiate new lazy data model by passing the injected JPA execution bean using the new constructor.

Friday, March 07, 2014

Injecting EJB into JAX-RS service

Java EE 6 introduced dependency injection mechanism, which makes it extremely easy to instantiate bean objects and pass the reference to other java services.
Injecting EJB into web services, servlets or EJBs can be easily done by using @javax.ejb.EJB annotation.
However, it doesn't work in the same way for JAX-RS services. Server would report NPE if @EJB annotation is used to inject EJB instance. The reason is that JAX-RS services are not managed beans.
An easy way to fix it is to make the JAX-RS service a stateless session bean by annotating it with @javax.ejb.Stateless.
A better alternative is to make JAX-RS service a managed bean. Detailed steps are as follows:
1. Add an empty beans.xml to WEB-INF directory. The purpose of this is to indicate that the web application is JCDI enabled.
2. Add a no-argument constructor to the JAX-RS service class. This makes the service class a JCDI bean. If some properties need to be set with some values (from http headers, for example.), it can be done inside the @javax.annotation.PostConstruct method.
3. Annotate the JAX-RS service class with @javax.enterprise.context.RequestScoped. This defines the service has http request scope.
4. Inject EJB instance with @javax.inject.Inject annotation.

Monday, March 03, 2014

Handle NTLM authentication with HttpClient v4.0.1 (Websphere application server v8.5)

I tried to use Apache HttpClient v4.3.3 in one of my jax-rs service implementation, which is deployed to websphere applciation v8.5.
However, the code always reported the issue that the INSTANCE field is not present in BasicLineFormatter class. It turned out that in one of the plugin jar file of WAS (com.ibm.ws.prereq.jaxrs.jar), the old version of HttpClient is included. According to the version properties file, the version is 4.0.1.
The problem came because HttpClient v4.0.1 doesn't support NTLM authentication, which is required for my service. I had to find a way to change the order of class loading of the web application. I tried a few options such as making the class loading using "parent last", adding the library to JRE path, and so on. None of them worked out.
Eventually I had to go with the v4.0.1 version which is shipped with WAS v8.5. Information provided on http://hc.apache.org/httpcomponents-client-4.3.x/ntlm.html is mostly correct, except that it applies with v4.3.3. Here's the instruction for using SAMBA JCIFS with v4.0.1:
1. Create NTLMEngine with the instructions on http://hc.apache.org/httpcomponents-client-4.3.x/ntlm.html .
2. Implement AuthSchemeFactory instead of AuthSchemeProvider for v4.3.3.
public class JCIFSNTLMSchemeFactory implements AuthSchemeFactory {@Override
public AuthScheme newInstance(HttpParams arg0) {
return new NTLMScheme(new JCIFSEngine());
}
}
3. Use the following code as an example to register the AuthSchemeFactory and create NTLM credential :
DefaultHttpClient httpclient = new DefaultHttpClient();
httpclient.getAuthSchemes().register("ntlm",new JCIFSNTLMSchemeFactory());
CredentialsProvider credsProvider = new BasicCredentialsProvider();
NTCredentials ntcred = new NTCredentials(username, password,
InetAddress.getLocalHost().getHostName(), domain);
credsProvider.setCredentials(new AuthScope(hostname, port,
AuthScope.ANY_REALM, "NTLM"), ntcred);
httpclient.setCredentialsProvider(credsProvider);
In this way, the NTLM support is done on WAS v8.5.
Normally sharepoint site use SSL for communication. The client certificate needs to be imported into the truststore of WAS. Otherwise, "SSL HANDSHAKE FAILURE" will be reported.