Blog Archives

March 22nd, 2011
8:42 pm
Facelets executes EL expressions in HTML comments by default

Posted under JSF
Tags , , , ,

This one caught me out when I was relying on <!– –> to comment out debug code when developing a facelets page. I found that methods in my Java code were being called seemingly from nowhere!

According to the specification, Facelets should honour (i.e. skip) comments by default, but in my case it did not appear to do so.

This can be enforced by adding the following context parameter to web.xml. Once done, you can safely rely on the use of commenting out when debugging. You can also use ui:remove to tell facelets to ignore sections of markup. This post here gives the details.

Note that the linked post from the above post uses the deprecated parameter name facelets.SKIP_COMMENTS. The correct parameter is as below, as you will be warned about in your server log file if you use the deprecated one!

 

<context-param>
  <param-name>javax.faces.FACELETS_SKIP_COMMENTS</param-name>
  <param-value>true</param-value>
</context-param> 

No Comments »

March 22nd, 2011
8:35 pm
JSF rendered attribute calls the getter multiple times

Posted under JSF
Tags , , ,

Initially when I saw this I thought it was a strange bug – the getter for the value expression referenced in a rendered attribute on a JSF2.0 facelets page was called 7 (yes seven) times when I would have expected one call only!

There are logical and historical reasons for this which are detailed in this post here.

The moral of the tale would seem to be that you should not make any assumptions about how often getters for value expressions are called, nor when exactly they are called. If you are doing for example database access you should never do this in a getter, but should use system events (JSF2) or Phase events (JSF1) for the database access as these give fully predictable behaviour as to when the calls happen and give you full control.

No Comments »

March 22nd, 2011
8:27 pm
Using the Browser Resize Event in jQuery

Posted under JSF
Tags , , , ,

jQuery ties into this event in a browser independant way. The following code fragment illustrates the use of this. Note tha following points:-

  • Different browsers implement resize differently. Most fire continual events during the resize, but some browsers (e.g. I believe older versions of Firefox) just fire the resize at the end of the drag. You therefore cannot predict how often and when the resize is called.
  • You need to place the code in the body section – I placed it in the head initially and it was never called.
  • When referring to a function defined in the head section as I have here, you need to prefix the call with “document.” otherwise the target function appears out of scope. The example assumes that yourFunctionName is a Javascript function defined elsewhere, e.g. in the header section of the page.

 

        <script type=”text/javascript”>
                /*
                 * This script block executes the target function on a resize.
                 * Note that jQuery has a browser independant means to hook into the event.
                 */
                jQuery(window).resize(function() {
                //alert(‘resize called’);
                document.yourFunctionName(args);
            });
        </script>

No Comments »

March 22nd, 2011
8:11 pm
Fixing Primefaces scrolling table header width issues using jQuery

Posted under JSF
Tags , , , , , , , ,

This has been very much an ongoing chestnut with Primefaces, mainly due to the tricks you have to use in order to get fixed table column headers and a scrolling table. Primefaces does this with a pair of tables – one for the header row and another for the data. The problems which often arise are mismatching columns between the header and the data, incorrectly sized table header above the column headers, and an incorrectly sized header row which does not appear to size properly dynamically when scrollbars are present/absent.

These issues can often be fixed, but it does appear that there is no overall silver bullet which makes everything work in every use case. The best approach I have found is to have a selection of approaches to try, and to apply the appropriate ones to solve problems which arise in particular use cases. The following details the different approaches I have used in various cases to solve width and alignment problems.

The following commented code sample shows how to use jQuery to correct table header width and column header width problems for scrolling tables. These problems are typically triggered by the dynamic appearance/removal of scrollbars, which will depend on table height and row count. Note that the function described, ss_FixTableHeaderWidth, would either be called in an inline script block placed immediately after a table definition in a facelets page (for a static table) or would be triggered as part of an Ajax call (for a dynamically rendered Ajax table). The example shows the static case. Note the following points about the code:-

  • The code may be found in the repository here.
  • The jQuery selectors should be optimised for performance. In general, ID selectors are the most efficient, so  narrow down with an ID selector first if you can (as below). Element selectors are also efficient, but classes can be really slow depending on what the browser supports – jQuery may end up doing a full DOM tree scan for every class selector, which is highly undesirable!. To avoid this below, I have prefixed class selectors with an element type which then makes use of the faster element searching, e.g. div.ui-scrollable-datatable.
  • Avoid duplicating selector searches where possible – in the example below a reuse them where I can, by using previous selector results as the context for subsequent lower level selectors, for example jQuery(‘div.ui-scrollable-datatable-container’, mainDiv) makes use of the jQuery result mainDiv from a previous selector when selecting its descendant scrollable container div.
  • You need to keep track of the difference between DOM elements returned by some calls, and jQuery objects which can be returned by others. You can always wrap a DOM element with a jQuery object using jQuery(element), but this is not always necessary. Avoid the overhead of doing it when you already have a jQuery object as it is redundant. The jQuery documentation makes all this clear.
  • The jQuery online docs are available here.  You cannot directly download the docs from the jQuery site, but it does link to some unofficial PDF downloads. However, the best and most searchable option seems to be an unofficial windows help file/CHM version download linked from StackOverflow (not fully up to date but still very useful). This is available here.
  • The RH header column size is set to auto to accommodate header row size changes, the idea being that this RH column will expand to fill the row, and the browser will not mess with other column sizes. Note that the column widths are just a guide to the browser and it is free to mess with them. This can be really awkward as we rely on the header table and data table being rendered exactly the same way to line up. This auto approach seems to work.
  • Firefox (3.6 and 4) has a problem whereby when setting an element width (in this case with jQuery), the actual value set is often 1px less than the requested value (particularly a problem when setting header table width). This can easily be seen by reading back the element width immediately after setting it. The fix I use for this is to do all width setting in a function (ss_setWidth) which checks the width afterwards and calculates the value of the mismatch. If there is a mismatch, the mismatch is then added to the width to set, and the element width is set a second time. This function is safe to use for all browsers.

 

Function definition, placed in page header section

    <script type=”text/javascript”>
    //<![CDATA[

        function ss_FixTableHeaderWidth(formId, tableId) {
           
            /*
             *Fix incorrect table header width due to scrollbars
             */
           
            var fullTableId = ‘#’ + formId + ‘\\3A’ + tableId;
            var topHeader = jQuery(fullTableId + ‘ > div.ui-datatable-header’);
            var mainDiv = jQuery(fullTableId + ‘ > div.ui-scrollable-datatable’);
            var headerTable = jQuery(‘table.ui-scrollable-datatable-header’, mainDiv);
            var dataContainer = jQuery(‘div.ui-scrollable-datatable-container’, mainDiv);           
            var dataTable = jQuery(‘table.ui-scrollable-datatable-body’, dataContainer);           
            var lastColumnHeader = jQuery(‘thead > tr:eq(0) > th:last’, headerTable);

/*           
            alert (‘TableId=’+fullTableId + ‘\n’ +
                   ‘topHeader=’+topHeader.attr(‘class’) + ‘\n’ +
                   ‘mainDiv=’+mainDiv.attr(‘class’) + ‘\n’ +
                   ‘headerTable=’+headerTable.attr(‘class’) + ‘\n’ +
                   ‘dataContainer=’+dataContainer.attr(‘class’) + ‘\n’ +
                   ‘dataTable=’+dataTable.attr(‘class’) + ‘\n’ +
                   ‘lastColumnHeader=’+topHeader.attr(‘class’));
*/           
            /*
             * Set the RH header column width to auto to prevent header table width adjustments
             *  from messing up column alignments
             */
            lastColumnHeader.css(‘width’, ‘auto’);

            /*
             * For some themes (pepper-grinder, overcast, ui-lightness), the width is incorrectly set for a scroll bar
             * even when there isn’t one. Detect whether scroll bars are actually present and fix the width if required.
             */
            if (dataContainer.outerHeight() >= dataContainer.get(0).scrollHeight) {
                //alert(‘Scroll bars not present’);
                //dataContainer.width(dataTable.outerWidth());
                ss_setWidth(dataContainer, dataTable.outerWidth());
            }       

            //Now set the width of the column headers table correctly and then finally the table header to match.
            var newHeaderTableWidth = headerTable.width() + dataContainer.outerWidth() – headerTable.outerWidth();
            var newTopHeaderWidth = topHeader.width() + dataContainer.outerWidth() – topHeader.outerWidth();

            //headerTable.width(newHeaderTableWidth);
            ss_setWidth(headerTable, newHeaderTableWidth);
            //topHeader.width(newTopHeaderWidth);
            ss_setWidth(topHeader, newTopHeaderWidth);
        }
       
        function ss_setWidth(element, value) {
           /*
            * This function overcomes an issue with Firefox (3.6 and 4), whereby the actual width set for an element
            * (particularly the header table) is sometimes less (typically 1px less) than the passed width to be set.
            * We read back the width after setting it, and if it differs from what we set,
            * we adjust our original value by the mismatch and set the width again.
            */           
            element.width(value);
            mismatch = value – element.width();
            if (mismatch != 0) {
                //alert(‘mismatch=’+mismatch+’ fixed’)
                element.width(value + mismatch);
            }
        }       
    //]]>
    </script>

Function call, placed inline immediately following table

<p:dataTable …>

</p:dataTable>
<script type=”text/javascript”>ss_FixTableHeaderWidth(‘frmTest’, ‘tblTable’);</script>

Iterating columns to set the width for each one individually

The following code sample uses the jQuery .each loop to iterate the header columns and set the width of each one to its matching data column (along with setting the table/row widths correctly). This sounds ideal for solving the header problems, but in practice it did not work well. The main issue is that jQuery reported a different value for the header column widths to that reported by the browser (via Firebug). The values were out by 1px, which caused an incremental mismatch in the column alignment as you go left to right. This approach was therefore abandoned in favour of just setting the RH header column size to auto to accommodate row size changes, as explained above. However, I reproduce the code here as it is a useful example of how to iterate a returned  jQuery object collection from a selector.

Function definition, column iteration version

    <script type=”text/javascript”>
    //<![CDATA[

        function ss_FixTableHeaderWidth(formId, tableId) {

            /*
             *Fix incorrect table header width due to scrollbars
             */
            
            var fullTableId = ‘#’ + formId + ‘\\3A’ + tableId;
            var topHeader = jQuery(fullTableId + ‘ > div.ui-datatable-header’);
            var mainDiv = jQuery(fullTableId + ‘ > div.ui-scrollable-datatable’);
            var headerTable = jQuery(‘table.ui-scrollable-datatable-header’, mainDiv);
            var dataContainer = jQuery(‘div.ui-scrollable-datatable-container’, mainDiv);           
            var dataTable = jQuery(‘table.ui-scrollable-datatable-body’, dataContainer);           
           
            /*
             * For some themes (pepper-grinder, overcast, ui-lightness), the width is incorrectly set for a scroll bar
             * even when there isn’t one. Detect whether scroll bars are actually present and fix the width if required.
             */
            if (dataContainer.outerHeight() >= dataContainer.get(0).scrollHeight) {
                //alert(‘Scroll bars not present’);
                //dataContainer.width(dataTable.outerWidth());
                ss_setWidth(dataContainer, dataTable.outerWidth());
            }                       

            /*
             * Now iterate the columns with a jQuery each loop and set the header column width
             * to be the same as its corresponding data column width.
             * This is for illustration – the idea has been abandoned, as I found that Javascript/jQuery
             * reports a different value for the header widths to firebug on the final rendered page (out by 1px).
             * This causes an increasing mismatch between data columns and header columns as you go from left to right.
             * The column widths are only a suggestion and the browser may modify them anyway.
             * Therefore the final version, in SortTable.xhtml just sets the RH column width to auto
             * to take up the slack when the row width is changed, and leaves the others alone.
             * This appears to work much better.
             * However the iteration technique here is a useful working jQuery example.
             */
            var columnHeaders = jQuery(‘thead > tr:eq(0) > th’, headerTable);
            var firstRowCells = jQuery(‘tbody > tr:eq(0) > td’, dataTable);
            var columnCount = columnHeaders.size()
           
            columnHeaders.each(function(idx){
                    var columnHeader = jQuery(this);
                    if (idx < columnCount – 1) {
                       
                        var firstRowCell = jQuery(firstRowCells.get(idx));
/*
                        alert(‘idx=’+idx+’\n’+
                              ‘header width=’+columnHeader.width()+’\n’ +
                              ‘header csswidth=’+columnHeader.css(‘width’)+’\n’ +
                              ‘header innerWidth=’+columnHeader.innerWidth()+’\n’ +
                              ‘header outerWidth=’+columnHeader.outerWidth()+’\n’ +
                              ‘data width=’+firstRowCell.width()+’\n’ +
                              ‘data csswidth=’+firstRowCell.css(‘width’)+’\n’ +
                              ‘data innerWidth=’+firstRowCell.innerWidth()+’\n’ +
                              ‘data outerWidth=’+firstRowCell.outerWidth());
*/
                        var newWidth = columnHeader.width() + firstRowCell.outerWidth() – columnHeader.outerWidth();
                        //alert(‘idx=’+idx+’,width=’+columnHeader.width()+’, newWidth=’+newWidth);
                        //columnHeader.width(newWidth);
                        ss_setWidth(columnHeader, newWidth);
                    }
                    else {
                        columnHeader.css(‘width’, ‘auto’);
                    }
              });

            //Now set the width of the column headers table correctly and then finally the table header to match.
            var newHeaderTableWidth = headerTable.width() + dataContainer.outerWidth() – headerTable.outerWidth();
            var newTopHeaderWidth = topHeader.width() + dataContainer.outerWidth() – topHeader.outerWidth();

            //headerTable.width(newHeaderTableWidth);
            ss_setWidth(headerTable, newHeaderTableWidth);

            //topHeader.width(newTopHeaderWidth);
            ss_setWidth(topHeader, newTopHeaderWidth);
        }
       
        function ss_setWidth(element, value) {
            /*
             * This function overcomes an issue with Firefox (3.6 and 4), whereby the actual width set for an element
             * (particularly the header table) is sometimes less (typically 1px less) than the passed width to be set.
             * We read back the width after setting it, and if it differs from what we set,
             * we adjust our original value by the mismatch and set the width again.
             */                       
            element.width(value);
            mismatch = value – element.width();
            if (mismatch != 0) {
                //alert(‘mismatch=’+mismatch+’ fixed’)
                element.width(value + mismatch);
            }
        }       
    //]]>
    </script>

No Comments »

March 9th, 2011
12:49 pm
Problems updating a checkbox in a Primefaces Table header

Posted under JSF
Tags , , , ,

With reference to my previous post, I found that a checkbox in a row cell in a Primefaces Table could not (from its value change listener) update a checkbox in the header. Per the previous post I was using component binding and calling UIInput.setValue() to update the value.

Strangely, another checkbox (checkbox B) outside the table was able to (again from its value change listener) update the checkbox in the table header.

More strangely, I then just moved checkbox B into a table row cell, and then found that it would not update the header checkbox.

I noticed that the checkbox row selection feature in the Primefaces showcase has the same issue – if you select all via the checkbox in the header, then all the rows become correctly selected. If however you then deselect a row, you would expect the header check box to deselect itself – however it does not.

As a further test, I tried it with Ajax, and was still unable to update the header checkbox from a row checkbox listener.

This Primefaces forum post may points to some possible causes, but its not clear cut. It certainly appears to be an internal issue to do with the Primefaces Table.

Workaround

One workaround to this would be to link the checkboxes client side with Javascript or jQuery. I resisted this because I will need to perform immediate actions elsewhere on the form based on a select click, so originally decided to do it all server side with listeners and (in the final solution) Ajax. However I may end up doing both – doing the at least some of linked selecting client side, but still using server side listeners for the other requirements.

Doubtless I will need to be careful that my own Javascript/jQuery does not interact negatively with the Ajax Javascript when implementing this. This post here points out that programmatic update of components via javascript does not fire events – only user actions cause events. In my case this need not be an issue – I could used javascript to cause row check box clicks to update the header check box. For example, if all rows were selected manually, I would tick the header box via script. Similarly, if then a row was deselected, I would untick the header check box. In each of those cases, I would not want or need any events to fire due to the header check box change. However, if the user explicitly clicked the header check box either way, I could use its listener to update all the row boxes (as I know this works) and to take any other action needed. whether in this latter case I allow the Javascript to update all the row boxes or not I am not sure – it is more consistent as then all the interlocking is in Javascript, but it will not cause row checkbox events to fire, so the header checkbox listener will still need to update all the selected properties for each row checkbox. If Javascript updates all the row boxes, then at least I don’t need to do any re-render of them which is more efficient. However, it is more complex as it involves iterating all the rows in script, although I expect this can be done pretty easily via jQuery.

No Comments »

March 8th, 2011
6:47 pm
JSF – changing input component values in a value change listener

Posted under JSF
Tags , , , , ,

My requirement on this one was to have some linked logic between select checkboxes on table rows and a ‘select all’ checkbox in the column header. Checking ‘select all’ should check all the row boxes. Then, unchecking one or more of the row boxes should uncheck ‘select all’ as the rows are no longer all checked.

Initially I had decided to get a whole test form working without Ajax, then apply the desired Ajax to all of it consistently. I had previously hit event timing issues due to mixing Ajax and HTTP submits on the same form. This gave rise to strange behaviour such as old queued events seeming to fire from nowhere, and events containing null arguments in method expressions. The basic wisdom on this is don’t mix Ajax and traditional HTTP submits on the same form – bad things will happen! I therefore decided to get the code logic working first with plain submits, by adding “onclick=’submit();’” to the checkboxes to force submits temporarily. The idea behind this was to avoid getting a mix of problems due to Ajax and problems due to other coding bugs, by eliminating the other coding bugs first.

The approach when doing this kind of thing is typically to set the components to immediate=”true” and call FacesContext.getCurrentInstance().renderResponse(); at the end of the value change listener to force an immediate rendering.

The problem I hit however, was that although I was correctly setting bean values for other checkboxes from the listener, the values were not being read again prior to renderResponse(),so the new values were not being displayed on the page. This is in fact standard behaviour. The way to update the values being rendered is to call setValue()  on the actual UIInput Component as well as writing the backing bean. To do this you need to get at the component instance, and the best way to achieve this is to use the binding attribute in the JSF page. For example, the following code fragments could be used in the JSF page and the managed bean:-

 

JSF Page

<h:selectBooleanCheckbox value=”#{mainBean.selectedB}”
                         valueChangeListener=”#{mainBean.selectedListenerB}”
                         binding=”#{mainBean.selectBoxBBinding}”
                         id=”chkSelectB” immediate=”true” onclick=”submit();”>
</h:selectBooleanCheckbox>

 

Managed Bean

private UIInput selectBoxBBinding;

public UIInput getSelectBoxBBinding() {
    return selectBoxBBinding;
}
public void setSelectBoxBBinding(UIInput selectBoxBBinding) {
    this.selectBoxBBinding = selectBoxBBinding;
}

 

Value Change Listener

public void selectedListenerA(ValueChangeEvent event) {
    boolean newValue = (Boolean)event.getNewValue();
    setSelectedA(newValue);

   //SelectedB is set to the same value as selectedA
    setSelectedB(newValue);
    selectBoxBBinding.setValue(newValue);
    FacesContext.getCurrentInstance().renderResponse();
}

This causes the new value to be displayed in the updated checkbox.  Binding to a component allows access to a number of other properties and methods as well, so gives a lot of flexibility. However, in most normal cases straightforward value binding is enough.

 

Using Ajax to achieve the same result

Ironically, if I had used Ajax on this issue, I would not have hit the problem. When Ajax is used, setting the new values in the managed bean is enough to allow them to be displayed directly on screen. The following JSF fragment shows how to use Ajax in check box SelectA in order to directly update check box SelectB without using a form submit. execute=@this causes the server side processing for SelectA to be performed (@this means the current component and is the default). render=”chkSelectB” causes the rendering to be peformed for SelectB, which displays the new value. Both execute and render take a space delimited list of client Ids, or special keywords such as @this, @form, @all, @non etc. The Ids can be prefixed with “:” to force Id scanning from the root where there are naming container issues etc. I am not covering any of this here. 

<h:outputText value=”Select Box A”/>
    <h:selectBooleanCheckbox value=”#{mainBean.selectedA}”
                             valueChangeListener=”#{mainBean.selectedListenerA}”
                             id=”chkSelectA”>
    <f:ajax execute=”@this” render=”chkSelectB”/>
    </h:selectBooleanCheckbox>
<br/><br/>
<h:outputText value=”Select Box B”/>
    <h:selectBooleanCheckbox value=”#{mainBean.selectedB}”
                             valueChangeListener=”#{mainBean.selectedListenerB}”
                             binding=”#{mainBean.selectBoxBBinding}”
                             id=”chkSelectB”>
    </h:selectBooleanCheckbox>

No Comments »

March 6th, 2011
7:47 pm
Adding jsf view state to domain objects–part II

Posted under JSF
Tags , , , , , , ,

My original post on this is here.  It links to an Icefaces post which discusses using a decorator to do this. The fundamental problem is that you often want view state such as (but certainly not limited to) a selected flag on objects e.g. in tables. However, you do not want to pollute domain classes with view state, so it would not be desirable to add a selected flag to your domain objects as this blurs the layers (especially as you may have multiple different UI layers on the same domain, such as JSF browser clients, smart phone web clients, web services etc. all with different needs). Other examples of view state might be style classes to be used on different table rows in response to use actions etc.

Since my original post I have looked at other ways of achieving this, and summarize various approaches below which could be used to add view state to rows of a table.

In each case, assume initially we have a JSF table of the form <h:dataTable var=”row” value=”#{mainBean.rows}”>, where each row object has the properties firstName and surname, plus the need for a selected boolean flag to be maintained separately from the row.

 

1/ Using a row decorator

My original post discusses using a decorator to add the extra state, as per the icefaces post. This involves wrapping every row, but is transparent to the code. The downside of the decorator is that each domain class requiring the extra state needs its own decorator even though each case might require the same extra state. This potentially means a lot of extra classes just to add a selected flag.

 

2/ Using a generic row wrapper class composed with the row

A second alternative which is similar to the decorator would be just to use a wrapper class which holds the extra state plus the domain class instance, and explicitly make the calls to the domain class methods and properties. Thus, the following code might be used to read our table row properties and the selected flag (all the examples use direct instantiation for simplicity) :-

//wrap a row. rowWrappers is the list containing the wrapped rows
rowWrappers.add(new RowWrapper<Row>(row));

// read properties on a facelets page – note that the table now contains wrapped rows:-

<h:dataTable var=”rowWrapper” value=”#{mainBean.rowWrappers}”>,
<h:outputText value=”#{rowWrapper.row.firstName}”>
<h:outputText value=”#{rowWrapper.row.surname}”>

//read the selected flag on a facelets page
<h:outputText styleClass=”#{rowWrapper.selected ? ‘style1’ : ‘style2’}” value=”…”/>

The pros and cons of this approach are:-

  • All the rows need to be wrapped as before.
  • All the ‘delegation’ to access row properties is explicit in all the expressions.
  • The upside however is that to add a given set of view state properties, only a single class is needed and this can wrap any number of domain classes generically, which can be a significant advantage.

 

3/ Using a Map to hold the additional row state objects

A third approach makes use of the fact that JSF EL value expressions can transparently read Map entries just like properties. Therefore where object m is a map or object that implements java.util.Map, the equivalent expressions m.property1 and m[‘property1’] when reading a value (i.e. on the right hand side of an expression, or rvalue mode) both result in

m.get(‘property1’)

being executed. When writing a value (i.e. on the left hand side of an expression, or in lvalue mode), as in m.property1 = rhsexpression, the statement

m.put(‘property1’, rhsexpression)

will be executed, assigning rhsexpression as the value of property1.

This technique allows us to use the row object itself as a key to the map containing the additional row state:-

//add row state object to map
rowFlagsMap.add(row, new RowFlags());

// read properties on a facelets page :-

<h:dataTable var=”row” value=”#{mainBean.rows}”>,
<h:outputText value=”#{row.firstName}”>
<h:outputText value=”#{row.surname}”>

//read the selected flag on a facelets page using the current row as a map key
<h:outputText styleClass=”#{mainBean.rowFlagsMap[row].selected ? ‘style1’ : ‘style2’}” value=”…”/>

Note that the nested expression evaluation works correctly with the map as the ‘man in the middle’ and that the expression mainBean.rowFlagsMap[row].selected could be used equally to fetch any other property from the rowflags object instead of the selected  property. The expression works as we would expect in both lvalue and rvalue modes, such that if for example the above property value was written to as true from the jsf page (e.g. from the value property of an updated check box we had just ticked), the expression would execute correctly as

mainBean.rowFlagsMap.get(row).selected=true;

The pros and cons of this approach are:-

  • We need an extra map access to get the row state, but for typical table sizes a hashmap would give very efficient access and should not be an issue.
  • We need to use the more complex expression mainBean.rowFlagsMap[row].selected  to fetch the additional row state. However, the plus is that we do not have to wrap each row in the code, and assuming that there are more table properties than additional state, we do not have to explicitly use a nested expression for them as we would in the previous approach.
  • When using this approach, it must be born in mind that you are using an object as a Map key. This should not be an issue, but if you override the hashCode function such that the hash value could change during the lifetime of a row object (for example if a row property changed) you would need to take account of this. Note also that rows in the map will only correctly match the exact same objects. If you refetch the same domain objects again from your entity manager you cannot expect them to match any existing objects in the map. Again, this should not normally be an issue as you would expect to rebuild the map from scratch when refetching domain objects from persistent storage.

 

4/ Using a Smart Map Interface to implement a selected property by storing the selected row objects

This approach is similar to the previous one, in that it uses a Map interface to hold a selected flag. The difference is that we implement our own class implementing  the Map interface and hide a map behind it. Our Map class simply stores each selected row in a ‘real’ map. When the caller reads the selected flag for a row by calling map.get on our map class, we perform a contains call on the ‘real’ map and return true if the row is present, or false if it is not. Similarly, when asked to set selected =true for a row, we just add the row to the ‘real’ map. When asked to set selected=false for a row, we remove it from the ‘real’ map. The pros and cons of this approach are:-

  • We only need to store the selected rows in the map, so we are storing less map entries.
  • The expressions to check the selected flag are a bit simpler, requiring something of the form mainBean.selectedMap[row]
  • Conversely, we need to implement the smart map – this needs quite a number of dummy methods when implementing the Map interface. When implementing this, I typically create an abstract base class which dummies out most of the java.util.Map methods which I don’t need, and then extend this for a desired implementation. This project in the repository makes use of this technique – see the classes uk.co.salientsoft.view.JSFValueMap and uk.co.salientsoft.view.SelectedMap.
  • The other downside is that this method only allows storage of a simple boolean based on the presence or absence of a row. If we need more additional row state, we need to look to one of the other methods.
  • As with the previous method, we are using a row object itself as a map key, so the same caveats apply as in the previous case.

 

Conclusion

As is often the case, there is no clear winner – you take your pick depending on individual requirements and the various pros and cons. Overall, my current favourite in general is to use the additional Map. It is simple to implement (you don’t need to dummy a load of Map methods like you do with the smart Map). Unlike the smart Map, you can add any number of additional properties to a row. The domain row properties can be accessed exactly as before, and you don’t need to wrap every row (however you do need to create the row state object and add it to the map for every row). Whilst the access to the additional state requires a slightly more complex expression, this is likely to be needed less often than expressions to read the domain properties.

No Comments »

March 4th, 2011
5:48 pm
Breadcrumb Composite Component using ui:repeat

Posted under JSF
Tags , , , , , , ,

Update 16/1/2012

A bug was found in the crumb styling. max-width was correctly set on the crumbs to truncate them, but when white space is present in a crumb, the default is to wrap at the max-width. This causes the breadcrumb to increase in height and add a second line. The fix was to turn off the wrapping by setting “white-space:nowrap” in the css for the crumb anchor tags (see Mantis issue 99 for details) :-

.ss-breadcrumb ul li,
.ss-breadcrumb ul li a {
    overflow:hidden!important;
    display:inline-block;
    white-space:nowrap;
    text-decoration: none;
}

 

Original Post

This follows on from my previous posts on the Primefaces breadcrumb here  and here.

I found a couple of further important issues I hit when using the standard breadcrumb:-

  1. In order to add and remove crumbs dynamically, it uses the Primefaces MenuModel. Methods of the MenuItem class are used to add actions and listeners.
  2. The mechanism seems somewhat cumbersome. In particular, it does not appear to be easy to pass a particular target object as an argument to an action or listener method, as the binding appears to be created as a string. Ideally what I would want is for the breadcrumb entries to be created by iterating a list using a var attribute like a table, and then to pass the var object containing the current crumb in the list as an argument in a method call to an action when that crumb was clicked.
  3. The only way I could see to do it involved passing an identifier for an object (such as the primary key for an entity). Whilst I certainly did not bottom it out completely, the mechanism seemed somewhat complex to use and lacking in flexibility.

Adding these issues to the ones already highlighted in the other posts (in particular the slowness of the jQuery operations when initially collapsing a breadcrumb in preview mode), I decided to take the step of rolling my own custom breadcrumb. The following approach was taken:-

  1. I decided to use a composite component rather than create a full blown custom component in code, as this looked more straightforward, and I had experience of composite component creation.
  2. The key factor which made this possible was that I could use ui:repeat to build the breadcrumbs dynamically from a list.
  3. Conditionally rendered xhtml tags could be handled using ui:fragment within the ui:repeat loop. This allowed the use of the rendered attribute on ui:fragment to optionally render sections even when standard non-jsf html tags such as <li> were used. For example, the root crumb of the component is rendered differently to the others, using an icon only. Also, full width crumbs are rendered differently to truncated crumbs (when truncating the component to fit a target width)

The following are the key features and design points for the breadcrumb:-

  1. The component is designed specifically for dynamic use, being driven from a list much like a table. It is not possible to build it statically on the facelets page (static use is covered by the standard control so this was specifically a non-goal/non-requirement).
  2. It is rendered entirely statically, so there is no (potentially slow) javascript/jQuery stuff going on at render time or during use.
  3. Compression to fit a target width is done by passing the desired target width in to the control. This is then used to set max-width css properties on the crumbs. This allows the crumbs to take the width they need and to only be truncated when they hit the max value. The max value is calculated on the server at render time by dividing the max target width by the number of crumbs to be rendered (allowing for the root crumb as a special case).
  4. The full text for a crumb can be viewed at any time by hovering over the crumb – it is displayed using the HTML title attribute. This is one annoyance with the standard Primefaces control – it does not allow use of the title attribute. Using the title  attribute allows the control to be static on the page for speed but still allows truncated crumbs to be easily read.
  5. The component supports the concept of stale crumbs. The idea is that when moving back up the crumb path (leftwards, or navigating up a tree path), the crumbs to the right which were previously visited are not immediately removed. They are highlighted differently as non bold and italic to make them less important compared to the ‘fresh’ crumbs on the path. In addition, the current crumb is underlined in order to make it completely clear where the current position is. Without stale crumbs present, this would normally be the rightmost crumb, but this will now no longer be the case if stale crumbs are present.
  6. Stale crumbs are only removed if the user navigates down a different tree path which invalidates them, in which case they disappear. Provided the user remains on the same tree path, the crumbs will be left in place.
  7. The stale crumbs may be clicked for navigation just like the fresh ones, to allow the user to revisit old ‘stale’ locations. When a stale crumb is revisited, it changes back to a fresh crumb again (as do all other stale crumbs to its left) and it becomes the current crumb – it is therefore rendered in bold, non-italic, and is underlined. The crumbs to the right of it if any still remain stale as they were before.
  8. To assist navigation up a tree structured hierarchy, it is common to include an ‘up’ button somewhere. This is taken a step further by including both up (= left pointing) and down (=right pointing)buttons on the left hand side of the breadcrumb component. When combined with stale crumb support, this feature allows easy navigation both up and down a given tree path. The right button is only enabled when stale crumbs are present, and clicking it moves down the stale crumb list just as if the next stale crumb was clicked. Navigating to the root of the tree (leftmost crumb) disables the left button.
  9. The component is styled in a similar way to the standard Primefaces component, and uses the same CSS classes for the styling.
  10. Styling may be modified, and features such as up/down support turned on or off.
  11. The component is styled using an inner div which holds the component itself – this can be floating if desired in which case it resizes the width to hold its contents. The inner div is contained in an outer div which is typically fixed in size to suit the page, allowing the inner div to scale up to that size. The width used for crumb truncation calculation is passed separately into the control – this will normally be slightly less than the max width set for the divs.
  12. The component is backed by a controller backing bean, BreadcrumbCtrl/BreadcrumbCtrlImpl, which may be subclassed to allow further customisation. The crumbs are passed into the bean as a simple generic list, and a property name used for the crumb text display is passed as a string attribute to the composite component. The controller fields action and listener events from the component, and passes them on using a BreadcrumbEvent interface – an object implementing this interface is passed into the controller bean at init time. When the user clicks on a crumb, the actual crumb in the list plus its list index are simply passed to its action method. When multiple components are used on a page, each will have their own controller object. These will typically be injected into the page backing bean e.g. by CDI as dependent beans. When the action and listener events are called, the actual controller object is also passed. This would allow for example the page backing bean to implement BreadcrumbEvent and manage actions for a number of dependent breadcrumb controllers, using the passed controller object to determine which one was clicked.

The following are some of the key technical issues which arose during development of the component:-

  • ui:repeat is used for iterative xhtml generation of the crumbs. This uses a var attribute like a table to represent the current object (crumb) in the list. It also supports a varstatus attribute which allows access to various loop properties within the loop, such as the current loop index, first and last boolean properties and others. The index property in particular is used to determine styling for the current crumb and stale crumbs etc.
  • In addition, the varstatus object (com.sun.faces.facelets.tag.jstl.core.IterationStatus) can be accessed from the controller bean using code similar to the following, where varStatusKey is the name given in the varstatus attribute to ui:repeat:-

Map<String, Object> requestMap = FacesContext.getCurrentInstance().getExternalContext().getRequestMap();
IterationStatus varStatus = IterationStatus) requestMap.get(varStatusKey);

  • It is important to note that whilst it is tempting to cache the varstatus object in the controller bean, this does not work – a new object must be obtained each time using the above code.
  • ui:fragment can be used directly in the ui:repeat loop within the composite component implementation – it is not immediately obvious from the documentation that this is the case.
  • When declaring the attributes for the composite component using <composite:attribute>, note that the type attribute allows specification of a particular object type, the required attribute makes an attribute mandatory, and the default attribute sets a default.

The source code and a usage example of the breadcrumb control may be found in the repository here.

No Comments »

February 11th, 2011
5:49 pm
Further h:outputStylesheet issues

Posted under JSF
Tags , , , , , , ,

I needed to load a custom style sheet for a composite component.

Primefaces has problems loading theme images correctly when using h:outputStylesheet as per here, but using a raw link tag was no good as I wanted to develop a custom component which loaded its own styles, i.e. it had no <head> section.

This post here indicates that if you don’t use the library attribute you can get h:outputStylesheet to work even with Primefaces themes.

In my case, I was not loading themes/images etc. so this was not an issue, but I still used the following directive and avoided use of the library attribute for simplicity:-

<h:outputStylesheet name=”uk.co.salientsoft/util/SSBreadcrumb.css”/>

This version worked. My initial attempts (which failed with a resource loading error) were as follows :-

<h:outputStylesheet name=”resources/uk.co.salientsoft/util/SSBreadcrumb.css”/>

<h:outputStylesheet name=”#{request.contextPath}/resources/uk.co.salientsoft/util/SSBreadcrumb.css”/>

In other words, with a css file stored in Eclipse under WebContent/resources/uk.co.salientsoft/util/SSBreadcrumb.css,  the above working example was correct, i.e. to load correctly, omit the context root and the resources level and use a relative reference without the preceding slash.

I did try to debug this by visiting the logger settings in Glassfish admin, then under the Log Levels tab, setting everything with JSF in it to finest! This did display an error when trying to load the resource:-

[#|2011-02-11T17:21:13.331+0000|FINE|glassfish3.0.1|javax.enterprise.resource.webcontainer.jsf.application|_ThreadID=31;_ThreadName=Thread-1;
ClassName=com.sun.faces.application.resource.ResourceHandlerImpl;MethodName=logMissingResource;
|JSF1064: Unable to find or serve resource, /SSBreadcrumb/resources/uk.co.salientsoft/util/SSBreadcrumb.css.|#]

However the error was not particularly informative as it just spat back to me the path I gave it to load. It would have been nice for it to tell me how it was mapping the path as then I could have seen the problem more easily.

Note however that using this page in Glassfish is a very convenient way to turn on logging in Glassfish, as it lists the common logger paths for you and gives a combo to select the level for each. You don’t have to go googling for the logger paths and edit a log properties file yourself. Note also that when you do this you must restart Glassfish for the log level changes to actually take effect.

No Comments »

December 18th, 2010
10:33 pm
Using the Integrated Tomcat Server Adapter in Eclipse

Posted under Eclipse
Tags , , , ,

Update

Another post here describes how to enable and control logging when using the Tomcat Server Adapter, as it is not enabled by default. As a result, I changed my thinking and have switched to using the Workspace Metadata to store the server configuration (as detailed below). This allows more convenient editing of the logging.properties file in Eclipse, and also allows a separate Tomcat configuration for each Eclipse Workspace. I have not experienced any corruption/pollution issues from working this way.

Original Post

I use this a lot for prototyping as it is significantly faster for deployment and has less overhead than Glassfish. I run JSF/ICEfaces/JPA applications by running JPA outside the container – see here for more details.

When running Tomcat inside Eclipse, it runs within its own context, i.e. separately from the installed Tomcat Server. Therefore, you should stop Tomcat externally when using it internally via Eclipse’s Tomcat Server Adapter.

You can use the adapter by right clicking in the Server view and clicking on New, then choosing the appropriate version of the Apache Tomcat adapter, browsing for the installation directory for Tomcat in the process.

When using this, you have 3 choices as to where the applications deployed to Tomcat are stored, all of which may be chosen by opening the Server Window for your Tomcat Server in Eclipse. As I point out here, there is often some ambiguity between which properties you change from the properties context menu option (resulting in a popup), and which are from the Server view via the Open option (also obtained by double clicking the server entry in the server view). In this case, the 3 choices are listed under the Server view (Open/double click option), but they are typically shown disabled and it is not always consistent as to how to enable the selections. Firstly stop all running applications on the server, and stop the server. Secondly, clear out any applications from the server by using the Clean context menu option, and/or visiting the Modules tab in the Server view and removing all applications there. You can also click the Switch Location button on the properties context menu popup. You will also need to refresh/reopen the Server view window to ensure that changes are picked up. Once you have reached the point where the the server locations are modifiable, you have the following choices :-

  1. Workspace Metadata (does not modify Tomcat Installation)
  2. Use Tomcat Installation (takes control of Tomcat Installation)
  3. Use Custom Location (does not modify Tomcat Installation) :-
    Server Path: Top level location for all the deployed apps and other Tomcat metadata
    Deploy Path: Subfolder under the Server Path, where the apps sit – defaults to wtpwebapps

My preference is 3. – I like to avoid polluting the main Tomcat installation with Eclipse development stuff, as I can then use it for other purposes. Also, I like to avoid storing the Tomcat applications in the Eclipse workspace metadata. The metadata is cluttered enough as it is, and is sometimes prone to pollution and problems with Eclipse not starting (see here). I therefore like to keep this data in a custom location separate from both the Metadata and the Tomcat installation, but as part of a folder structure which includes the workspaces. I also include any libraries which are shared between workspaces (e.g. JSF/ICEfaces plugins) in the same structure. See here for details about sharing downloaded plugin libraries across multiple workspaces by exporting/importing Eclipse preferences.

My typical folder structure might be as follows :-

Dev (top level (sub)folder somewhere)
Tomcat (custom Tomcat apps location as above)
webapps (my preferred setting for the Deploy Path: above)
Libraries (Top level for libraries shared between workspaces, such as JSF/ICEfaces plugin libraries)
Workspaces (All Eclipse workspaces live under here)
Workspace 1
Project 1
Project 2
Project 3

Workspace 2
Project 4
Project 5

No Comments »