JSF Best Practice

I do developing with Java Server Pages (JSF) since the early beginning with version 1.0. Today , 17 years later,  we have version 2.3 and thus a lot of improvements and new features.  I’ve made many mistakes in using this standard web framework in my own applications. And therefore I would like to show some best practice rules in this Blog. And I hope this will simplify the work with JSF – for you and also for me – during refactoring my own applications. Most of which I write here comes from the great book ‘ The Definitive Guide to JSF in Java EE 8’ written by Bauke Scholtz (BalusC) and Arjan Tijms. I recommend you to buy this book if you have had already made experience with JSF.  So let’s start… Continue reading “JSF Best Practice”

JSF, f:ajax and render…..

Designing JSF pages with the usage of the <f:ajax> tag can be a pretty frustrating affair.  For example, if you’re trying to build a table with Ajax behavior, it often won’t work the way you expect it to. For example imaging a table with a delete-button which changes the content of your table:

<h:panelGroup layout="block" 
   id="artikel_table_id" 
   binding="#{artikelTableContainer}">
	<table>
	<ui:repeat var="bookingItem" value="#{childItemController.childItems}">
		<tr>
			<td>....</td>
			<td><h:commandLink value="delete"
				actionListener="#{childItemController.remove(bookingItem.item['numpos'])}">
				<f:ajax render="artikel_table_id"/>
			    </h:commandLink>
			</td>
		</tr>
	</ui:repeat>
	</table>
....

This example won’t work even if it looks logical. The problem here is the render attribute pointing to the id of an outer h:panelGroup. This UI component tree is created during the initial build of the view.  If You’re manipulating the component references after building the view, the changes will not be reflected in the UI component tree during a ajax event life-cycle if you do not care to also execute the compete tree.

To solve this you can change the render attribute in the following way:

<f:ajax render="#{artikelTableContainer.clientId}" 
        execute="#{artikelTableContainer.clientId}"/>

In this way now you have a binding to a component instance which forces jsf to execute and to rebuild the complete UI component tree. Note:  the execution is necessary to update input fields placed within a table row.

ui:repeat versus c:forEach

At a first look it seems that between ui:repeat and c:forEach there is not big difference. This is true if only want to visualize a data set. But if you want to manipulate the entries too – e.g in a table with an embedded edit-mode than you can run in trouble if you are working with an ui:repeat. As explained in the example before, the elements inside a ui:repeat are not part of the component tree. This becomes an issue if your entries are editable. It will work on the first look if you simply submit the outer component. But in case of a JSF validation error, which is initiating the JSF-Life-Cycle the component tree will lost your entered values.

For that reason it is recommended to use a c:forEach tag instead of a ui:repeat if your data set is editable.

Enclosing Ajax Tags

If you use an enclosing ajax tag like in the following example, please note that you need to use a c:foreach instead of ui:repeat :

<h:panelGroup binding="#{artikelTableContainer}"> 
  <f:ajax onevent="updateOrderItems">
  <table>
    <c:forEach var="orderitem" items="#{childItemController.childItems}">        
     <tr> 
       <td>....</td>
       <td><h:commandLink value="delete"
        actionListener="#{childItemController.remove(bookingItem.item['numpos'])}">
      <f:ajax render="#{artikelTableContainer.clientId}" 
          execute="#{artikelTableContainer.clientId}"/>
      </h:commandLink> 
   </td> 
  </tr> 
 </c:forEach> 
</table>
</f:ajax>
</h:panelGroup>

In this case you should not call the ‘execute’ in the enclosing ajax!

Maven on Debian failed with JDK 1.9 – ClassFormatError

Today I ran into a problem with Maven under Debian GNU/Linux 9 (stretch). My Debian has OpenJDK 8 as also OpenJDK 9 installed. OpenJDK 9 is my default java version. My Maven version is 3.3.9.

mvn -version
Apache Maven 3.3.9
Maven home: /usr/share/maven
Java version: 9-Debian, vendor: Oracle Corporation
Java home: /usr/lib/jvm/java-9-openjdk-amd64
Default locale: de_DE, platform encoding: UTF-8
OS name: "linux", version: "4.9.0-6-amd64", arch: "amd64", family: "unix"

The problem is, that building one of my projects results in the following ClassFormat Error:

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.17:test (default-test) on project imixs-workflow-core: Execution default-test of goal org.apache.maven.plugins:maven-surefire-plugin:2.17:test failed: There was an error in the forked process
[ERROR] java.lang.ClassFormatError: Absent Code attribute in method that is not native or abstract in class file javax/xml/bind/JAXBException
[ERROR] at java.base/java.lang.ClassLoader.defineClass1(Native Method)
[ERROR] at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1007)
[ERROR] at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:174)
[ERROR] at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:801)
[ERROR] at java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.java:699)
[ERROR] at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:622)
[ERROR] at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:580)
[ERROR] at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:185)
[ERROR] at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:496)
[ERROR] at java.base/java.lang.Class.getDeclaredMethods0(Native Method)
[ERROR] at java.base/java.lang.Class.privateGetDeclaredMethods(Class.java:3139)
[ERROR] at java.base/java.lang.Class.getMethodsRecursive(Class.java:3280)
[ERROR] at java.base/java.lang.Class.getMethod0(Class.java:3266)
[ERROR] at java.base/java.lang.Class.getMethod(Class.java:2063)
[ERROR] at org.apache.maven.surefire.util.ReflectionUtils.tryGetMethod(ReflectionUtils.java:57)
[ERROR] at org.apache.maven.surefire.common.junit3.JUnit3TestChecker.isSuiteOnly(JUnit3TestChecker.java:64)
[ERROR] at org.apache.maven.surefire.common.junit3.JUnit3TestChecker.isValidJUnit3Test(JUnit3TestChecker.java:59)
[ERROR] at org.apache.maven.surefire.common.junit3.JUnit3TestChecker.accept(JUnit3TestChecker.java:54)
[ERROR] at org.apache.maven.surefire.common.junit4.JUnit4TestChecker.accept(JUnit4TestChecker.java:52)
[ERROR] at org.apache.maven.surefire.util.DefaultScanResult.applyFilter(DefaultScanResult.java:97)
[ERROR] at org.apache.maven.surefire.junit4.JUnit4Provider.scanClassPath(JUnit4Provider.java:206)
[ERROR] at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:103)
[ERROR] at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:200)
[ERROR] at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:153)
[ERROR] at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:103)
[ERROR] -> [Help 1]

The problem is a incompatibility of maven 3.3.9 with JDK 1.9. To solve this problem I switch to my OpenJDK 8 by setting the JAVA_HOME variable explicitly to JDK8 :

export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64/

After this change maven install works fine again in my projects.

To make the JAVA_HOME setting permanent follow this stepts.

1. find your preferred java version

ls -la /usr/lib/jvm/

2. edit the file /etc/profile and add the following line with the path to the JDK 8 you find before:

export JAVA_HOME="path to jdk8 that you found"

3. verify you maven installation

mvn -version

You maven should now be set to JDK8.

I hope this post will become obsolete in near future.

Cassandra – How to Handle Large Media Files

Using Apache Cassandra as an highly available  Big Data Platform is in my eyes a good choice as Cassandra Cluster is easy to handle. We are using Apache Cassandra as an archive platform for our human centric worklfow engine Imixs-Workflow. But how does Cassandra perform with large files?

If you start with Cassandra you have to change the way how you use databases, especially when you come from the SQL direction.  Although Cassandra can handle very large amounts of data easily, you have to consider the concept of the partition size. This means in short that the data within a partition (defined by the Partitionkey) should not exceed 100 MB. If you plan to store large files (e.g media files) you need to split up your data into smaller chunks. In the following I will explain in short how this can be done. Continue reading “Cassandra – How to Handle Large Media Files”

MVC 1.0 – Binding Input Values

MVC 1.0 is the new action based web framework for Jakarta EE. One advantage of the new technology is that you can work with plain html. With the expression language (EL) provided by JSP and Facelets you can easily bind values form a CDI controler to an input field:

<dl>
  <dt>Name:</dt>
  <dd>
    <input type="text" value="#{dataController.name}" name="name" />
   </dd>
</dl>

This works also for Textareas:

<dl>
  <dt>Description:</dt>
  <dd>
    <textarea name="descripton">#{dataController.description}</textarea>
  </dd>
</dl>

A little bit more tricky in this szeanrio is the handling of select options (Combobox). As the selected Item is defined by an attribute within the option tag a combination with EL is clumsy. But with the help of jQuery this can also be archived easily. See my following example:

<dl>
  <dt>Sort Order:</dt>
  <dd>
      <select name="sortOrder" id="sortOrder">
        <option value="DESC">Descanding</option>
        <option value="ASC">Ascanding</option>
      </select>
  </dd>
</dl>

<script type="text/javascript">
$(document).ready(function() {
  // update the select option....
  $("#sortOrder").val("#{dataController.sortOrder}");
});
</script>

See also the tutorial “MVC 1.0 in Java EE 8 – Handling Form Submits” to learn how you can submit you form inputs with MVC 1.0.

javax.ws.rs.client.Client and Form Based Authentication

Today I implemented a javax.ws.rs.client.ClientRequestFilter for a form based authentication. The FormAuthenticator class can be used in combination with a javax.ws.rs.client.Client  to interact, for example, with a rest api secured by a login form. Such a login form in Java EE typically uses the request URI ‘/j_security_check‘ with the form input fields ‘j_username’ and ‘j_password‘. As a result of a successful login the browser stores a cookie named “JSESSIONID” which need to be send with every request.

The request filter can be added to a javax.ws.rs.Client like this:

....
// create a javax.ws.rs.client
client = ClientBuilder.newClient();
// create new formAuthenticator
FormAuthenticator formAuthFilter = new FormAuthenticator(rest_api_url, 
     userid, password);
// register the filter...
client.register(formAuthFilter);
// now you can GET, POST, ....
....

You cam find the source code of this filter class on GitHub.

If you have any ideas for improvements your comments are welcome!

Imixs-Workflow 4.2.6 released

Today I released version 4.2.6 of Imixs-Workflow. The new release is prepared for the Imixs-Archive feature which is the next big thing in Imixs-Workflow. The new version also includes some improvements of the Rest API and several bug fixes. The release notes can be seen on GitHub.

New Version of Open Source Workflow Engine

In these days I released the latest version 4.2.0 of the human-centric open source workflow engine Imixs-Workflow.

With version 4.2.0, the second minor release of Imixs-Workflow version 4 is now available. After the stability and performance improvements of version 4 were confirmed with the minor update 4.1, now the first feature update has been released. Imixs-Workflow 4.2 offers a number of additional features and technical improvements. You can join the project on GitHub.

Read more here.