Archive for the 'JSF' Category

February 14th, 2012
3:11 pm
Using a Message Bundle to make Dialog sizes locale dependant

Posted under JSF
Tags , , , , ,

A common issue I have found is setting confirmation dialog widths correctly to hold the target message neatly.

With a Primefaces p:confirmDialog for example, the height auto adjusts but the width defaults to 300 pixels, and is set via an integer width attribute.

When supporting multiple languages, message sizes and sentence structure obviously differ, and it can be desirable to change the dialog width for example. Whilst a large width could be chosen which is likely to support any language, this can look less than perfect due to the extra unwanted space.

One simple solution which I came up with is just to store the dialog width in the Message Bundle along with the message. This way, the dialog width will automatically adjust to the value set for the target locale when switching locales. The same idea could be used to set a width etc. via CSS as well.

Whilst I am in no way suggesting turning a message bundle into a style sheet, this is a clean solution for this particular simple case and others like it, especially as the width is set as a component attribute and not in CSS, so style sheet localisation is not a possibility. Style sheet/resource localisation is available in JSF 2, but is somewhat non-intuitive. (Core JSF 3 p113-114 opines that it is an unappealing solution, and hopes for a better implementation in a future JSF release.)

No Comments »

January 27th, 2012
7:01 pm
JSF session sharing across multiple Browser Windows

Posted under JSF
Tags , , ,

It is a design feature of servlet sessions that if you open the same application in multiple windows in the same browser type, the session data is shared across them all. This post on Stack Overflow discusses the issue.

Therefore, if for example you need multiple sessions present in order to test Optimistic Lock collisions, you need a way around this. There are 2 solutions :-

  1. Use a different browser type in each window. For example, if you use Firefox and Chrome as a pair, or Firefox and Opera for example, you will in fact get separate sessions as there is no sharing of cookies and other related data across different browser types.
  2. Log in from another computer, for example by using an RDP session to another computer on the same desktop and running the application from there. In this case, both browser types can be the same.

No Comments »

January 27th, 2012
6:09 pm
h:link navigation fails when Javascript confirm function called in click event

Posted under JSF
Tags , , , ,

I use the click event to validate a navigation, returning true to allow it and false to cancel it.
On some occasions, the toolbar buttons (which are based internally on h:link with pre-emptive Get style navigation based on an outcome) do not navigate event when the click event correctly returns true.

Some toolbar buttons always did this, others always worked. No explanation could be found for the failure to navigate, even after extensive testing and online searching for answers.

The solution to this was to return cancel in the click event, but to have the click event explicitly do the navigation itself via Javascript. The following code fragment illustrates the problem:-

<h:link id="link" disabled="#{disabled}" outcome="#{outcome}" href="#{href}" title="#{title}" tabindex="#{tabIndex}"
      onclick="if (#{empty onNavigate ? ‘true’ : el:format1(onNavigate, el:concat3(‘\”, component.clientId, ‘\”))})
      window.location.href=this.href; return false;">

The if test checks if the navigation is require, then if so, window.location.href is set to the target href in the component. False is always returned so that standard navigation is disabled.

This solved the problem consistently. (This has also been logged as Mantis issue 104).

No Comments »

January 27th, 2012
11:30 am
Controlling CDI conversation propagation

Posted under JSF
Tags , , , , ,

This is a tricky issue to control correctly. The following points have been found during testing (Mojarra 2.0.4 FCS / Primefaces 2.2.1 / Glassfish 3.0.1)

  1. One key issue is that to start a new conversation on a page, the navigation to that page must not propagate any previously active conversation. This will then start a new transient (i.e. not long-running/not started) conversation on the new page, and conversation.begin() can be used to make it long-running (i.e. start it).
  2. When doing a standard JSF Ajax postback, the current conversation is always propagated, and it does not appear to be possible to prevent this/start a new conversation from a postback. JSF always adds the current CID as a querystring parameter
  3. To prevent propagation and to allow a new page to start a new conversation, GET navigation needs to be performed. This fits in well with my main toolbar options – I use pre-emptive GET navigation for the main pages with full page refreshes.
  4. Primefaces p:button allows the new JSF 2 outcome style GET navigation but cannot be stopped from propagating a conversation – it always adds a CID parameter. If you add one with an empty or null value, you still get a “cid=” attribute which CDI then spits out as an invalid conversation on the new page.
  5. h:link can be stopped from propagating by using an explicit f:param for the cid, providing the param has no value or an explicit null value (an empty string will not work).
  6. Trying to refer to another inactive conversation, e.g. by storing conversation scoped bean references in a session level map and looking them up, seriously screws up CDI with an extremely long/possibly recursive stack trace. (See Mantis issue xxx for the stack dump). This is likely to be due to the proxying mechanism used for conversations.
  7. Therefore, it is not possible to invent say a ‘onPageLeave’ event for a previous page and call it after a new page has started and had its conversation activated.
  8. If therefore I need to refresh all pages for the application, for example if an OptimisticLockException occurred, I use a central workspace session bean to manage all the pages. I set a refresh pending flag in a map for each page, and then when the page is next visited, the workspace bean calls a refresh event of my own for the page, and then clears the pending flag. When processing the current page after an OptimisticLockException, I can refresh directly if the user requests it from a lock dialog.
  9. My workspace bean holds the CID for each page against the page name in a map, and uses this when rendering the Toolbar, adding the appropriate cid= parameter for each toolbar option. In fact I use an outer map keyed on page group name (where the page group corresponds to a top level toolbar option), with an inner map containing all the cids and refresh pending flags for the individual pages in that group. This allows for example a report toolbar option to be a menu of currently active reports, and allows new reports to be created dynamically as new conversations and added to the list under the report menu on the toolbar.
  10. Conversations are started and ended via calls to the workspace bean, which can then add/remove entries from the maps to keep track of what pages/cids are currently active.
  11. Regarding navigation and cid propagation, another option is to call JSF directly to obtain the navigation case for an outcome. ConfigurableNavigationHandler allows you to pass an outcome and get the actual navigation case, from which you can then get the URL. This should allow full control of the cid= propagation parameter on the querystring, and allow control for components which do not support JSF 2.0 style GET pre-emptive navigation directly from an outcome. The url can be passed to any component which accepts a url, and should then still perform the correct navigation and conversation control. See CoreJSF 3 page 333 for a code example on this. This method could prove useful for example with a Primefaces MenuItem, which does either JSF postback style navigation, or URL navigation, but does not directly do pre-emptive GET navigation by giving it an outcome.

No Comments »

January 27th, 2012
10:16 am
Method call in rendered attribute is called again after navigating to new form

Posted under JSF
Tags , , ,

Initially this looked very strange. When navigating to a new form, the rendered= methods for the old form were being called again, and were failing due to scoping issues – a new request scope bean was being created causing a null pointer exception in the method as required state had been lost.

This post and also this post on StackOverflow explain the problem. Apparently JSF rechecks the rendered conditions after the submit as part of an attack safeguard. This is what caused recreation of a new bean and the failure.

This behaviour was certainly unexpected, and I have not seen it documented ‘up front’ previously – so it is certainly one to be aware of! This is not the first time I have had issues with the render= attribute.

In my case, resolving issues in creation of conversations solved the problem – once I had conversations propagating properly, everything worked correctly and the state was present for the extra calls to the rendered= methods.

No Comments »

January 20th, 2012
4:08 pm
Using EL expressions to specify custom Validators and Converters

Posted under JSF
Tags , , , , ,

This post here discusses using an EL reference to specify a converter. This gets around the fact that you cannot use CDI beans in a converter class.

You can also do this in a validator, for example using the validator attribute on h:inputText. This is useful if you need access to other instance variables in order to do the validation. In my case, I needed access to a list for a table to verify uniqueness on string names in the list.

This is mentioned in Core JSF 3 on page 294:-

In the preceding section, you saw how to implement a validation class. However, you can also add the validation method to an existing class and invoke it through a method expression, like this:
<h:inputText id=”card” value=”#{payment.card}”
required=”true” validator=”#{payment.luhnCheck}”/>
The payment bean must then have a method with the exact same signature as the validate method of the Validator interface:

public class PaymentBean {

public void luhnCheck(FacesContext context, UIComponent component, Object value) {
… // same code as in the preceding example
}
}

Why would you want to do this? There is one major advantage. The validation method can access other instance variables of the class. You saw an example in the section, “Supplying Attributes to Converters” on page 289.

No Comments »

September 23rd, 2011
3:17 pm
Preventing Overflow with long strings in table cells

Posted under JSF
Tags , , , , , , ,

I hit this issue when displaying email addresses in a p:dataTable.

The problem is that for long strings without spaces, the browser tries to enlarge the table cell width, causing the table to stretch beyond the correct bounds and messing up the layout. A column will wrap and enlarge vertically, but this will only be done when it can break on a space. Setting the widths for the columns is technically just advisory on the browser and may be overriden if needed.

There are various solutions to this, and this post here in Stack Overflow discusses them.

My chosen solution in this case was the following:-

  • Place the text in the cells in <spans>, to allow them to be styled with CSS. You could also style the column <td> cells by applying style/styleClass attributes to the p:column tag, but this will limit your flexibility – for example if you do this p:column does not expose the title attribute on the <td> (see below)
  • Style the <spans>  with display:inline-block;overflow:hidden. This allows a width to be set for the span (I used the same width as set for the column), and hides any overflow (which would otherwise bleed into the next column).
  • Text will still wrap on spaces if they are present, but long strings without spaces, such as email addresses or file paths, do not cause a problem, but they will truncate and so will not be fully visible by default.
  • I include a title attribute on the span to include the full text. This allows the full text to be displayed on hover for any long strings that are truncated in the cell.

This neatly solves the problem, and prevents the table layout messing up.

No Comments »

September 23rd, 2011
12:18 pm
Re-queuing JSF Events

Posted under JSF
Tags , , , ,

This is a very simple and powerful technique which can provide an easy solution to a number of event issues.

The case in point was where I wanted a value change event on an input component (a check box) to behave like an action event.

The value change event will normally fire after validation (after the Process validations phase). In my case, I wanted the event to be fired at the Invoke Application phase, as would happen with a button click. In other words, I wanted my checkbox to behave more like a button.

Whilst there are other ways around this  kind of issue, they often involve messing with the JSF life cycle by using immediate components/calling render response early etc. and typically have other side effects. For example, in a Value change event you will not see the results of the bean setters being called as this has not happened yet, so you end up having to make JSF calls to manually update values early etc.

Instead, a value change event can easily be re-queued to occur in the Invoke Application phase. The beauty of this is that you are relocating the event rather than messing with the JSF lifecycle, which means that the event happens in the context you want it to, and everything is set up correctly.

To requeue an event, you must detect when it fires the first time, and then requeue it. When it fires the second time, you detect this again and perform the action that you desire.

Here is a code sample which does this:-

    public void showInheritedListener(ValueChangeEvent event) {

        /*
         * Requeue this event to the Invoke Application phase so it behaves like an action
         * This ensures that all the model values have been updated.
         */
        if (event.getPhaseId() == PhaseId.INVOKE_APPLICATION) {
               log.fine(this+":showInheritedListener: oldValue="+event.getOldValue()+", newvalue="+event.getNewValue());       
            boolean newValue = (Boolean)event.getNewValue();
            changeInherited(newValue);
        }
        else {
            event.setPhaseId(PhaseId.INVOKE_APPLICATION);
            event.queue();
        }       
    }   

An important point to note is the use of event.getPhaseId() to detect which phase the event is currently being called in. In particular, when it is first called after the Process Validations phase, it is important to note that event.getPhaseId() will return PhaseId.ANY_PHASE, which is not expected or intuitive. You will see from the above code that by handling the first call to the event in the else clause of the if, we only have to test for the second call, when event.getPhaseId() will return PhaseId.INVOKE_APPLICATION as you would expect.

This technique is clean and simple to use, and does not suffer from unwanted side effects that other solutions have. It is well worth taking note of.

No Comments »

July 27th, 2011
9:05 am
f:selectItem error – java.lang.String cannot be cast to javax.faces.model.SelectItem

Posted under JSF
Tags , ,

I received this error when using <f: selectItem> on a prototype of a page:-

java.lang.ClassCastException: java.lang.String cannot be cast to javax.faces.model.SelectItem

It turns out that the error was trivial, but easy to miss at first glance.

My initial code was as follows:-

<f:selectItem value=”1″ itemLabel=”&lt;default&gt;”/>

The mistake was to use the value attribute instead of the itemValue  attribute. The following is the corrected code:-

<f:selectItem itemValue=”1″ itemLabel=”&lt;default&gt;”/>

 This solves the problem.

No Comments »

July 27th, 2011
7:34 am
Primefaces p:panel–main panel bar/title bar does not render at all

Posted under JSF
Tags , , , ,

This issue was encountered under Primefaces 2.2.1 – other versions have not been tested for this. In certain cases it is possible for the panel component to not render the title bar at all.

When this happens, the content is rendered assuming the panel is expanded, but the panel bar itself does not render, and crucially, there is therefore no access to the expand/collapse icon as it is not rendered. Other components can expand/collapse the panel via its widget however.

This is caused when there is neither a header attribute present nor a header facet present. If one or other (or both) are present, the panel title bar does render. Note that the behaviour occurs even if toggleable is set to true.

This behaviour is undocumented and is rather a gotcha when you hit it, as it seems indicative of something more serious.

The solution is straightforward however – you must provide either the header attribute or a header facet in order for the panel component itself to render correctly.

No Comments »