Friday, 31 August 2012

CSS3 ellipsis functionality with PrimeFaces (Client side and server side)

Introduction

If you have a certain user UI requirement, you have basically 2 options when using JSF.
Since the output of the JSF system is in most cases just plain HTML, you can mixing the required CSS and javaScript to have your UI feature. Or you can have some server component that does most of the work and generates the required HTML from their renderers.
An example makes this situation clear.  In a project I had the requirement that on a screen there were a lot of long descriptions of codes that needed to be displayed.
In fact there were so much of them that the screen was very crowded when the full description of all codes was shown. The solution was that only a part of it was shown on the screen and when the mouse hoovered over, the complete description was shown

Server side solution

As I'm much more experienced in writing Custom JSF components, I created a new PrimeFaces component that is capable of showing some truncated text. It is almost identical to the outputText component and has only one additional attribute called truncateAt.
You can define with it the maximum number of characters it shows before three dots are generated.  In the case the text has more characters then specified in the truncateAt attribute, the complete text is placed in the title property of the span element surrounding the shortened text.
This custom PrimeFaces component is quit easy and the important parts of the code responsible for the rendering is shown below:

        writer.startElement("span", null);
        writer.writeAttribute("id", clientId, null);
        String value = outputText.getValue().toString();
        Integer truncateAt = outputText.getTruncateAt();
        if (truncateAt != null && value.length() > truncateAt) {
            writer.writeAttribute("title", value, null);
            value = value.substring(0, truncateAt-1)+"...";
        }

        writer.writeText(value, null);
        writer.endElement("span");
You can improve the above code by searching the words in the description and not slash words in two.

After creating a simple POJO for the component itself (extending HtmlOutputText) and registering your work in the faces-config.xml
<facelet-taglib xmlns="http://java.sun.com/xml/ns/javaee"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facelettaglibrary_2_0.xsd"
                version="2.0">
    <namespace>http://www.c4j.be/primefaces</namespace>

    <tag>
        <tag-name>outputText</tag-name>
        <component>
            <component-type>be.c4j.jsf.primefaces.outputtext.OutputText</component-type>
            <renderer-type>be.c4j.jsf.primefaces.outputtext.OutputTextRenderer</renderer-type>
        </component>
        <attribute>
        ....
    </tag>


You have your required functionality.

Cient side solution


Afterwards, some people pointed me to the CSS3 ellipsis (text-overflow attribute) as an alternative solution.  With some standard PrimeFaces components and the use of a proper css style definition, you can achieve the same effect.

The css style class looks like this
.ellipsis {
    display: inline-block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    width: 400px;
    vertical-align: bottom;
}


where the width property can be varied to your convenience.  The central element here is the text-overflow: ellipsis line.  Since you can only specify the size of a html element in block mode, you have to specify the display: inline-block to allow more information on the same 'line'

Within the JSF view we can use the tooltip PrimeFaces component to show us the long description when we hoover over the truncated area.
<h:panelGroup styleClass="ellipsis" id="longText">${bean.text}</h:panelGroup>
<p:tooltip for="longText" value="#{bean.text}"></p:tooltip>

Differences of solutions


Both solutions are resulting in more or less the same visual and functional result in the browser but there are a few small differences.
  • With the client side solution, the truncation of the description is performed based on the size it takes on the screen.  When the user changes the font size, there are a different number of characters displayed. With the server side solution, the number of characters is always the same, despite of the user font settings.
  • The tooltip is only shown when some truncation of the description occurs in the server side solution in contract to always for the client side solution.  This can be changed by adapting the rendering code and always add the description to the title property.  However showing the same text in the tooltip isn't common practice.

Comparison of solution


As said, both solutions are resulting in more or less the same visual and functional result in the browser but each has his pro and contra. An overview of them

pro server side
  • Works on all browsers, no CSS3 support required
  • No CSS required, good for CSS/JavaScript newbies (I'm one of them)
  • Advanced algorithm determining the ... position easy to implement.

contra server side
  • Custom JSF component required (you need to use another tag in the JSF view if you want the functionality)
  • Less skinnable (look and feel changes by just changing CSS and JavaScript)

For the client side solution, the pro and contras are basically switched.

pro client side
  • No special/custom JSF component required, only the tooltip component of PrimeFaces
  • Skinnable
  • Screen layout is better preserved when user changes font size in browser.

contra client side
  • CSS3 browser support required.  This time Firefox was very late to include support for it and it is only available since version 7.
  • Positioning of the ... is difficult to align with the word boundaries.

Conclusion


I still prefer the server side solution, the one I used in the project.  I find it easy to create a simple JSF custom component where I'm in control of the result in Java and don't need any CSS3 or other client side solution to have the functionality that I need.
But for all the other people that like playing with those things, you can see how easy it is to do it with PrimeFaces.

You can find an example demo here.

Thursday, 26 July 2012

Trial with some Java generics

Introduction

It has been a while that I was able to post anything on this blog.  Due to various reasons, I didn't had any time to post an entry.
But things are slowly changing again, in the positive direction, and thus I found some time to create the following entry.  However, it is slightly off topic because it is not directly related to JSF or JEE but has to do with Java generics.

In the project, I needed the current date (system date) but in various 'formats', as a String, a java.util.Date and org.joda.time.LocalDate version. And I didn't want to use a method that returned the current date in the JodaTime version and call utility methods to convert it in the other formats if I needed them.  I went for the elegant solution like this.
 
String today = DateUtil.today();

Date todayAsDate = DateUtil.today();

Type erasure


I thought the solution was easy, I should have know that this kind of problem can't be solved, and created the following method
 
public static T today() {

   T result = null;

   // Logic goes here 

   return result; 

}

But the problem is that there is no way at runtime to determine what the return type should be. I started with reflection and used the method getGenericReturnType(). But other information than that the method should return Object and I defined something like T, wasn't available.
And then I realized that the kind of method I would like to write, isn't possible. Generics are used by the java compiler, but at runtime, there is no information about them available (there are some exceptions).  The processed is referred to as 'type erasure' and allowed backward binary compatible code.

So if we write code like this
        List myList = new ArrayList();
        myList.add("test");
        String value = myList.get(0);

The compiler converts it to this pre-5 compatible version
        List myList = new ArrayList();

        myList.add("test");

        String value = (String) myList.get(0);

And in the mean time, it is able to verify if we don't add anything else then a string to the collection.

Solution


I had to define a parameter which can be used to determine the return type like this
public static T today(Class returnType) {

   T result = null;

   // Logic goes here

   return result; 

}

This results in more code to type, but still quit elegant and type safe.
So something like
 
long time = DateUtil.today(Long.class);

won't compile.

On the other hand, using the class parameter leads to some ugly if statements which can be avoided by defining an Enum. But then we loose the type safety again and we need to introduce casting again.

Conclusion


In many situation, I love the possibilities that generics can offer.  And I don't know the impact of course, but having the extra generics information at runtime, maybe only when a compiler argument is specified, could be very handy in this situation.

Friday, 13 January 2012

PrimeFaces 3 on non CSS3 compliant browsers

PrimeFaces 3

PrimeFaces 3, final release at the beginning of this year, is using CSS3 features to have some nice features and functionality.  And although there is a fair amount of CSS3 in the latest versions of the browser, also in IE9, their are a lot of people that uses a browser which isn’t capable of handling these nice things like rounded corners.
And for most of the widgets, like input field, it is no problem for the end user that he doesn’t have a rounded corner.  But for some, like a radio button, it is confusing that the user sees a rectangular shape instead of the, for him familiar, circle.
As an example, go to the showcase of PrimeFaces and look how the radio buttons are displayed.  Do you see a circle, then you have a CSS3 compliant (at least for the rounded corners feature) browser.  For those that have Internet Explorer 9, they can see how it is displayed for users having IE7 or IE8.  Go to the developers tools (or press F12) and select there the option ‘Browser mode: IE7’. The radio buttons become squared and I can understand the reaction of the end user that filed an issue on my last project.

Find a solution

On the internet, there are plenty solutions that provide you the possibility to have something like rounded corners in Internet Explorer 8 or older. You can split them up in 2 groups.

JavaScript

Here you have to include a JavaScript on your page and in the windows.onload function you have to pass the id’s of the elements that you like to decorate with a rounded corner. The problem with this approach, in combination with PrimeFaces, is that the DOM elements that are responsible for the presentation don’t contain an id attribute.  (Yes, there isn’t any input tag for the radio button so that it can be made styleable)

<div class="ui-radiobutton-box ui-widget ui-corner-all ui-radiobutton-relative ui-state-default">
   <span class="ui-radiobutton-icon"></span>
</div>

VML


The other solution is based on Vector Markup Language (or VML in short), a specification of Microsoft and others that lost the battle against SVG.  However, it was integrated in some of Microsoft products, like the browser.  With VML, it is possible to have rounded corners and a good site where everything is explained, with the inevitable pitfalls, is here.

So I added the script and updated the css file of the project to include the property behaviour in the style classes .ui-radiobutton .ui-radiobutton-box.  It worked like a charm on my computer (emulating IE7 with the help of the developer tools) and on a lot of the computers of other testers. But on another machine it crashed IE completely. Since it isn’t a reliable solution for a public website, I had to find something else.

Adapt skinning


Since PrimeFaces is using themes, there had to be a solution to fix the problem that way.  If I can just place the image of radio button on the area where the user expects it, there couldn’t be any problem like the VML not supported or browser incompatibilities.

And after trying a few scenarios, I’m not a css expert you know, I came to a solution which is quit simple.  I even didn’t need two images, one for the selected and one for the deselected situation.  This is what I added to the css file of the project.

.ui-radiobutton-box {
    background: url("../javax.faces.resource/radio_button.png.jsf?ln=images") no-repeat !important;
    border-style: none !important;
}

.ui-radiobutton .ui-radiobutton-box {
    width: 18px !important;
    height: 18px !important;
}

Some words of explanation:
  • All the properties need the !important marker to overrule the values that comes from the theme css file.

  • The background property defines the image that needs to be displayed.  I’m using the JSF resource notation to reference the image.

  • The border style is there to remove the square of the div element.

  • The size is maybe strange at first glance. The original size of the div element is 16 and then you have to add the border size (1 pixel) to it.  The image contains the complete radio button and needs to be 18 pixels wide.

And to my surprise, the default behaviour of PrimeFaces was providing me a dot in the center of the circle when the radio button is selected.

The easiest way to create the image is to take a snapshot of the screen area in a browser that is capable of rendering CSS3 rounded corners.

Disadvantage


The solution described above has a one major disadvantage, it isn’t compatible with the theme support.  To formulate it maybe a bit more correct, whenever you change the theme, you have to change the image that is used for the radio button whenever you want the background colour to match with the rest of the colours in the PrimeFaces theme.

Conclusion


Since the PrimeFaces 3 JSF component library uses CSS3 features, the representation on browsers that doesn’t support it, like IE7 and IE8, can be a little bit awkward.  A solution for the squared representation of radio buttons can be found in this text.  I uploaded also a test project on Google code for those that want to play with it.

Friday, 6 January 2012

CODI on Oracle WebLogic server 12c

Introduction

Oracle released recently their EE6 compliant version of the WebLogic server. It is a full EE6 profile, so everything you need is at your disposal.  Adam Bien did a smoke test and I made a small demo application where some CDI beans are defined inside a jar file placed in the WEB-INF\lib directory of the war file.
All these tests passed so we are ready to test some real world like application.  Just as JSF is an open system (it is build with extensibility in mind), CDI (Contexts and dependency injection, JSR-299) adhere to the same philosophy. And thus any real world application should use one of the extensions that make the life of the developer easy.
One of the popular CDI extensions is Apache MyFaces CODI, which brings you some goodies that you can use in your project.  You can read about the project on the wiki page.

 

Testing CODI

Testing CODI was done with the scope testing program that you can find here. I made the required adjustments in dependency scopes so that it works on any EE6 server. After deploying it on the Oracle WebLogic Server, I received the following error:
java.lang.IllegalStateException: No bean found for type:
org.apache.myfaces.extensions.cdi.core.api.config.CodiCoreConfig at
org.apache.myfaces.extensions.cdi.core.impl.util.CodiUtils.getOrCreateBeanByClass(CodiUtils.java:198)
Apparently this kind of error occurred also on older Glassfish v3 versions. So someone posting this issue on the mailing list received a solution very rapidly.

 

How to package a CODI application for WebLogic 12c?

So I tried the suggestions in the mailing list and the scope testing program works, except for one small issue. And it is not related to WebLogic only, in fact all containers running on Weld have the same problem. A method annotated with @PostConstruct isn’t executed when it is defined on a method in a super class of a bean with a custom scope.
This is the contents of the pom.xml file:
<dependency>
    <groupId>org.apache.myfaces.extensions.cdi.bundles</groupId>
    <artifactId>myfaces-extcdi-bundle-jsf20</artifactId>
    <version>${myfaces_codi.version}</version>
    <scope>provided</scope>
</dependency>
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <version>2.2</version>
    <executions>
        <execution>
            <id>unpack-codi</id>
            <phase>process-test-resources</phase>
            <goals>
                <goal>unpack-dependencies</goal>
            </goals>
            <configuration>
               <includeGroupIds>org.apache.myfaces.extensions.cdi.bundles</includeGroupIds>
                <includeArtifactIds>myfaces-extcdi-bundle-jsf20</includeArtifactIds>
                <outputDirectory>
                    ${project.build.directory}/classes
                </outputDirectory>
            </configuration>
        </execution>
    </executions>
</plugin>
Some words of explanation:

Defining the CODI dependency as provided, means that it isn’t included in the packaged war, but you can use the classes in you code.

The maven-dependency-plugin is used to unpack the contents of the CODI jar into the classes directory so that the required classes are available in the war file.

The last thing that needs to be done is to copy the contents of the beans.xml found in the CODI jar file, into the beans.xml file of your web application.

This way, you can use CODI, on the Oracle WebLogic Server 12c.

UPDATE: Seems that there is also a problem when the 'autodeploy' directory is used.  So for the moment only regular deployed WAR files can be used as described above.

Thursday, 1 December 2011

PrimeFaces plugin for Jboss Forge

Introduction

For those who creates many small web applications, like proof of concepts, know how much time you can loose by setting up the project structure.  Creating the pom file, web application file, faces configuration etc.  And although there exists maven archetypes, they doesn't allows suite your needs. For a lot of tests, you need slightly different options and required dependencies.
And this is where JBoss Forge can help you.  It is a command line driven tool that helps you in those repetitive tasks. And, a very important aspect for me, is the fact that it doesn't place any marker in your files or project.  In fact, it can be used on a project which isn't created with JBoss Forge by interpreting the files it find.

My goal

I came to this tool in my search for something that could help me in creating a project setup according to our company standards for JEE6 projects.  By default, JBoss Forge has the capability of creating a project that uses the JEE6 technology stack.  But it doesn't go far enough, or we have requirements that goes much further.  We want to be able to setup multiple projects for quality control (PMD, Findbugs, etc), model and services project, view project, functional testing project and so on.
The basic building blocks, but sometimes quit sophisticated, are already available.  And creating plugins is very easy.  So, everyone has to start with some easy things and thus I started by creating a plugin that is able to add the PrimeFaces component library.

Not from scratch

You can learn a lot by looking at some example code.  And in my case, there was already someone that started with such a plugin (see https://github.com/kukel/forge-plugin-primefaces.git, by Ronald van Kuijk)  Trying his code, there where some compilation problems, due to the fact that JBoss Forge is still in beta and his code was coded against a previous version, and things like scaffolding that I never use.  With scaffolding, you can create default screens that are able to view, insert and update from a database table.  They can be very handy in prototyping but in real world applications, they are never needed.
So I took his code, removed the scaffolding, made it compatible with the latest API (beta 3), added support for the latest PrimeFaces 3 release (with the new namespace declaration) and detection of CDI capabilities in the project.

Status

By just typing 'primefaces' at the JBoss Forge command prompt, you get information about the status of the project.  When PrimeFaces is installed, it specifies which version (2 or 3) and otherwise you get information about how it can be added to the project.

Setup

Adding some kind of functionality is mostly done in JBoss Forge by specifying the setup command.  With the PrimeFaces plugin you can achieve it by issuing the command 'primefaces setup'.  This will convert your project to a war artifact, installs the other required dependencies like servlet (the web.xml) and JSF (the faces-config.xml), and adds the maven dependencies after you have selected the version of PrimeFaces you want.
Before you execute this command, you should always verify if you are in the correct project.  The standard JSF setup adds also some files related to the error handling and they can overwrite some files which already exists in your project.  But with a good version control system, you don't have to worry about this.

Example

The last command I describe here, is to add an example to the project, by issuing the command 'primefaces install-example-facelet'.  It replaces the current index.xhtml file, so your are warned again, with an XHTML JSF file that uses a template and shows a value from a property from a managed bean.  When the plugin detects CDI artifacts in the project, the managed bean is defined with the javax.inject and javax.enterprise annotations.  Otherwise plain JSF2 annotations are used.

To discover

There are other command which are supported by the plugin. They are created by Ronald and kept in the code base.  But they aren't very well tested so you can use them if you want to try them out.
And in fact, the plugin is also in some kind of beta phase. It should work but there are probably situations where it will fail.  In that case you can contact me and I'll have a look at your problem and try to solve it or you can follow the git philosophy and fork it and implement the solution yourselve.

May the forge be with you ;-)

Oh, before I forget it, here you can find the code https://github.com/rdebusscher/forge-plugin-primefaces.

Wednesday, 9 November 2011

Custom reference resolver tutorial : creating a grammar


Introduction

In my previous blog entry, I presented an example on the new reference resolver add-on of ExtVal. It was able to read from a property from a MBean and use that value for validation.
As it was designed as a Reference Resolver, you had to specify a parameter at the cross field validation annotation of ExtVal where you needed the resolver. This is not friendly if you have designed some kind of resolver that you would use on a lot of locations.  Therefore the add-on has foreseen the option to create a new Reference Grammar. In this text I'll explain you how you can convert a reference resolver to a reference grammar.

Coding it

Basically, there are 2 small differences between a Reference Resolver and a Reference Grammar and you can use almost the same code in both situations. You only need to structure it a bit different.  Besides the registration of your grammar with the ExtVal add-on, see further, you should extend from the AbstractReferenceGrammar class. This class has a type parameter that needs to be specified.  In our case, it is just a simple object that holds the bean and property name. If you remember from my previous text, we invented a new grammar 'mbean@property' and the object just holds the 2 parts of the grammar (before and after the @-sign).
Your grammar has to implement 4 methods, so the empty grammar looks like this

@InvocationOrder(100)
public class MBeanGrammar extends AbstractReferenceGrammar
{

    @Override
    public void initGrammar()
    {
    }

    @Override
    protected boolean targetNotCompatibleWithGrammar(String targetValue)
    {
    }

    @Override
    protected MBeanGrammarData determineReference(String targetValue, MetaDataEntry metadataEntry)
    {
    }

    @Override
    public ReferencedValue resolveReference(MBeanGrammarData targetValue, MetaDataEntry metadataEntry)
    {
    }
}

where the (MBeanGrammarData object holds the bean and property name the user specified.

The initGrammar method is called when you register the grammar with the add-on.  You can use this interception point to do any initialization required to have a proper function of the grammar.  In our case we grab a reference to the MBean server we will be using for the resolving of the value.  Important thing to remember is that this method is just executed once.
When the ExtVal add-on encounters an annotation related to the cross field validation feature, it will ask to all the grammars if it can handle the specified reference.  Our implementation should return false for the targetNotCompatibleWithGrammar method when it contains the @-sign (our grammar can handle the reference) and true when we don't know it (like some EL-reference).  The first grammar that says that it can handle, will be used by the add-on.  How is the order determined? Grammars can be annotated with @InvocationOrder and the value you specify determines the order.  The default grammars (JavaBean and EL) have values of 950 and 1000.  So when we specify a value of 100, our new grammar is the first to be contacted to resolve the reference.
If we have a reference that we should handle, the add-on calls the determineReference method next. There we have the opportunity to parse the reference according to the grammar.  In our case it is just splitting the reference around the @-sign and put it into the MBeanGrammarData instance.

As a last step, the resolveReference method is called where we get the MBeanGrammarData instance we prepared in the previous step and we need to resolve the reference.  In our case we contact the MBean server, ask for the correct bean and extract the value of the property.  That value is wrapped nicely into the ReferencedValue and returned.

So the main difference is that the reference resolver contained all the logic in the resolveReference method and in the grammar version, we have the functionality split into 4 methods. You can find the code here.

Configuration

This is an additional step we need to do to integrate our grammar in the ExtVal add-on.  With the following 2 lines, placed in a startupListener, the Reference Grammar is registered and ready to use.

 ExtValContext extValContext = ExtValContext.getContext();
        extValContext.getModuleConfiguration(AdvancedCrossValidationAddonConfiguration.class).addReferenceGrammar(new MBeanGrammar());


Testing it

This version behaves exactly the same as our previous example, so I refer to the other text on how you can test it.

Conclusion

As easy it was to create a Reference Resolver, as easy it is to create a reference Grammar.  The grammar has the advantage that you don’t have to specify a parameter at the cross field validation annotation. But on the other side, if you only using it on a few locations, the add-on will ask your code for every reference, if you understand it.  So based on the concrete situation you have to decide what you need, a resolver or a reference.

Thursday, 20 October 2011

Custom reference resolver tutorial

Introduction


In the previous blog text, I described the cross field validation feature of ExtVal. In the meantime, the reference resolver add-on is released and this text shows how you can write your custom reference resolver.
And since the usage of the add-on API is easy, we are aiming a little bit higher with our example as a simple hello world. I'll explain you how you can write a resolver that checks a value stored in an MBean object.

Coding it

The reference resolver api is described here in the project documentation. There is just one method that you need to implement, resolveReference. The first parameter contains the string defined in the value attribute of the annotation (or method is repeatedly called for each string defined in the case of multiple values)


ReferencedValue resolveReference(final String targetValue, final MetaDataEntry metadataEntry);
So, first we have to 'invent' our indication how we will describe the property of the MBean where the value is stored. A possibility is using mbean@property where mbean is just the name in a certain node of our MBean server.

Our implementation of the method needs to do 3 things

  1. Get a reference to the MBean server of our environment
  2. Split the parameter in 2 parts (around the @ sign)
  3. Lookup the MBean and retrieve the value of the specified property.
If you aren't familiar with accessing JMX beans, you can find various documents on internet which explain it in detail. For this example, you can have a look at the source code placed in an apache extra repository (link). The implementation of our resolver is in the class org.os890.extval.addon.demo.resolver.MBeanReferenceResolver.

Before we can use this new resolver, we have to define a validationParameter so that we are able to use it in the cross field annotations of ExtVal. It is described in the add-on documentation on the referenceResolver page.

In our case, it results in:

public class MBeanReferenceResolver implements ReferenceResolver
{
    public interface MBeanReferenceResolverParameter extends ValidationParameter
    {
       @ParameterKey
       public Class KEY = ReferenceResolver.class;

       @ParameterValue
        public Class referenceResolverClass = MBeanReferenceResolver.class;
    }

     @Override
      public ReferencedValue resolveReference(String targetValue, MetaDataEntry metadataEntry)
      {
         // Implementation details omitted
       }
}
Now we can use this resolver in all cross field annotations like @Equals. In the example you can find a usage in the class org.os890.extval.addon.demo.view.BackingBean.

@Equals(value = "demo@TargetValue", parameters = MBeanReferenceResolver.MBeanReferenceResolverParameter.class)
private String source;
This property is linked to an inputField on a screen in the example.

Testing it

Now we are ready to run the example. If we press the 'Submit' button, a comparison will be made between the entered value and the value which is by default set in the MBean, which is 'ExtVal'. If they don't match, you see the message that the input is different.

This default value is set by the class org.os890.extval.addon.demo.startup.MBeanResolverStartupListener which is defined as JSF PhaseListener in the faces config file.

The following steps makes this example interesting. You can start up the default JMX console of your environment (look for the JConsole program) or any other JMX console that is able to connect to your (application) server. You will find between all the other MBeans, the one created by the demo application in the org.os890.extval.reference.addon node. It is called demo. The property TargetValue can be changed to another value, let's say 'Test'. If you now go back to your browser you will see that the comparison now only succeed with the new value 'Test' that you have entered in the JMX bean.

Conclusion
 This example shows how easy it is to create a new reference resolver and integrate it in ExtVal.  With the add-on you can create any reference you like that needs to be used by the cross field validation feature of ExtVal.