Archive for 2011

March 23rd, 2011
2:35 pm
HTML Text string plus floated right hand icon–the order matters!

Posted under HTML
Tags , , ,

A column header consisted of a text string, plus a Primefaces icon which was to be floated right in the header, in line with the text.

My initial HTML consisted of the following :-

header text<span style=”float:right;” class=”iconclass”></span>

where iconclass was one of the standard Primefaces classes for rendering icons using CSS backgrounds.

In this case, I could not stop the icon from being dropped onto a new line below the text. It was still floated right correctly, but dropped down a line.

I compared it with another similar example (not one of mine) which did work correctly, and could see no difference at all in the technique or the CSS properties of any of the elements – I would absolutely have expected both to behave the same but they did not.

In the end, simply swapping the order of the elements made it work correctly :-

<span style=”float:right;” class=”iconclass”></span> header text

I.E. putting the floated icon first and then specifying the text worked correctly and did not drop the icon down!

I am not clear on the precise reasoning for this behaviour – it was consistent across various browsers. I suspect it has to do with some of the subtleties of floating behaviour.

However, the lesson was simple – the order of elements in cases like this matters, and may result in a solution in similar cases which ‘should’ work but don’t!

No Comments »

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 7th, 2011
10:23 am
JUnit testing EJBs with Eclipse / Glassfish 3.0.1 – EJB 3.1 embedded container

Posted under Glassfish
Tags , , , , , ,

Update – Controlling Logging with the JUnit Eclipse Plugin

Controlling logging with the Eclipse JUnit plugin is not obvious and not documented. Even a trawl of the net did not find an answer even though the question was asked on some forums. Fortunately, it is straightforward once you know. By default, JUnit under Eclipse just logs at INFO level. It uses java.util.logging by default, and therefore the way to contol it is as follows :-

1/ Make a local copy of logging.properties from the one under your JAVA_HOME/jre/lib directory – in my case I placed it under <eclipse project>/test, which was the top level test folder.

2/ Add the following VM argument to the run configuration used for JUnit testing of your project (see under Run/Run Configurations):-

-Djava.util.logging.config.file=${workspace_loc:YourEclipseProject}\\test\\logging.properties

The {} construct allows you to conveniently specify the file system path to your Eclipse project. Note that the path delimiters for Windows are escaped as per usual.

3/ Then edit the logging.properties as desired. The comments in the file are pretty comprehensive. Note that the console logger has its own limit on logging level even if you specify a more detailed level for your own package. For JUnit testing, I prefer to disable the console logger and just log to a file, as then I can just refer to the JUnit pane without it being interrupted with the scrolling console log, as a scrolling log goes against the JUnit principle of automated testing anyway. When specifying your own logging file you can use a path relative to the top level project directory, and %h in the name is your user home directory, and %u is used as a version number when successive log files are created with the same name. The following shows my sample logging.properties:-

############################################################
#      JUnit Testing Logging Configuration File – S.E. Woodley
#
# You can use a different file by specifying a filename
# with the java.util.logging.config.file system property. 
# For example java -Djava.util.logging.config.file=myfile
############################################################

############################################################
#      Global properties
############################################################

# "handlers" specifies a comma separated list of log Handler
# classes.  These handlers will be installed during VM startup.
# Note that these classes must be on the system classpath.
# By default we only configure a ConsoleHandler, which will only
# show messages at the INFO and above levels.
#handlers= java.util.logging.ConsoleHandler

# To also add the FileHandler, use the following line instead.
#handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler
#
#S.E. Woodley remove the console handler for JUnit testing.
handlers= java.util.logging.FileHandler

# Default global logging level.
# This specifies which kinds of events are logged across
# all loggers.  For any given facility this global level
# can be overriden by a facility specific level
# Note that the ConsoleHandler also has a separate level
# setting to limit messages printed to the console.
.level= INFO

############################################################
# Handler specific properties.
# Describes specific configuration info for Handlers.
############################################################

# default file output is in user’s home directory.
#java.util.logging.FileHandler.pattern = %h/java%u.log
java.util.logging.FileHandler.pattern = test\\JUnitTest%u.log
java.util.logging.FileHandler.limit = 50000
java.util.logging.FileHandler.count = 1
#java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter
java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter

# Limit the message that are printed on the console to INFO and above.
java.util.logging.ConsoleHandler.level = INFO
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter

############################################################
# Facility specific properties.
# Provides extra control for each logger.
############################################################

# For example, set the com.xyz.foo logger to only log SEVERE
# messages:
com.xyz.foo.level = SEVERE
uk.co.salientsoft.level=INFO

Using Exit Codes when running Scripts etc. for Test setup

1/ In my case I needed to run a SqlPlus script to populate a test database as part of the JUnit test setup. With SqlPlus, it is possible for a script to return an exit code which indicates success, or whether there was an SQL or operating system error such as an error finding a called script. This post here indicates how this can be done. This is obviously highly desirable for JUnit testing as successful script execution can then correctly affect the test outcome via an assert. My ScriptRunner class, mentioned below, returns the exit code from SqlPlus.

2/ I used my ScriptRunner utility class which allows simple property file based setup for running external OS programs such as SqlPlus, and which acts as a wrapper to the standard Java ProcessBuilder class. ScriptRunner will be found in the repository. The sample code at the end of this post has been modified to show the use of ScriptRunner with exit code assert handling, in the @BeforeClass method.

Original Post

The new embedded container in Java EE 6 is a good choice for unit testing of EJBs. It allows standalone testing outside of a full container, and supports CDI and CDI injected beans in EJBs, including the injection of POJOs into EJBs. The following steps explain how to set it up, as their are a  few gotchas for the unwary. There are other approaches to this – in particular there is a distinction between using the embedded API and an embedded container. However, the following approach was commonly used by a number of sites, is straightforward, and ticked all my boxes for JUnit testing of EJBs. A code sample is at the foot of this post.

1/ Add the following embedded container shell jar to your classpath. Failure to do this results in the following error :-

        javax.ejb.EJBException: No EJBContainer provider available: no provider names had been found.

I defined an Eclipse User Library for it:-

        <install-dir>\glassfish\lib\embedded\glassfish-embedded-static-shell.jar

Note that when doing this, the User Library must point to the actual jar in the glassfish instance you are using. You cannot just copy the library to another location and point to it, or you will continue to get the above provider names error. The above jar is a ‘shell jar’ explicitly designed to link an embedded container to an existing glassfish installation. The embedded container uses the shell jar location to detect the glassfish instance to use to obtain the necessary run configuration. For example, if your EJBs make calls to JPA and use a data source named in persistence.xml, then the embedded container will use the data source defined in the glassfish instance you are pointing at.

Some posts talk about having to use the default in-memory data source name when testing, but this is probably due to a difference in the way the embedded container is being configured and used. For example, there are other embedded jars you can use which are not designed to tie in to an existing glassfish installation. In my case this was not necessary and my existing Oracle data source was automatically discovered and used.

2/ Next, add a second copy of beans.xml in src/META-INF (alongside persistence.xml and orm.xml). There is a gotcha here – the full container deployment of a war file needs to see it in WEB_INF, but this will not work for the embedded container. I was unable to find a single location that would satisfy both, and I tried passing properties to the embedded container to get it to see the beans.xml in WEB_INF, but to no avail. Note that if you do not add the second copy as above, you may find that some injection works, e.g. for EJBs into other EJBs, but in my situation I sometimes had POJOs (such as the Apache Base64 encoder) injected into EJBs, and for this to work, you have to get this step right. In the end, I also added a unit test to check that POJO injection was working, with a warning to check beans.xml  if the test failed.

3/ Eclipse (helios in my case) has good support for JUnit 4, and tests and test suites can be run directly by right clicking and selecting Run as JUnit Test or Debug as JUnit test. It also has a wizard to allow creation and maintenance of test suites, but sadly this did not work due to a known bug. The code below illustrates how to create a suite using annotations (you can also do it with code). Creating stubs for unit tests is also easy via right click in the explorer and selecting New JUnit test, and selecting the class to test etc. If JUnit 4 is not already present on your build path, Eclipse will prompt you to add it.

4/ When creating the tests in Eclipse, I added a new source folder just for the tests, as test/src  to keep the tests separate from deployed code. Also, in the build path dialog (right click the project and select Build Path/Configure Build Path), on the source tab I ticked allow output folders for source folders,and added test/classes as the output folder for the tests. Note that after doing this, I visited the deployment assembly property page (right click the project in the explorer, select properties, and select Deployment Assembly in the left hand pane), and ensured that the /test directory was removed to ensure that the test classes would not be deployed in the war file.

5/ When running, I did get a couple of exceptions in the log, from the internal setting up of the embedded container. These did not prevent it from starting or working correctly, and all my unit tests ran fine. They are in fact known bugs (which can be ignored) which have been raised on the Glassfish Jira issue log here and here. Here is a sample of the error traces:-

17-Dec-2011 23:18:09 org.glassfish.flashlight.impl.provider.FlashlightProbeProviderFactory processXMLProbeProviders
SEVERE: MNTG0301:Cannot process XML ProbeProvider, xml = META-INF/mojarra-jsf-api-probe-provider.xml
java.lang.IllegalStateException: Provider already mapped glassfish:jsf:faces-servlet
    at org.glassfish.flashlight.impl.core.ProbeProviderRegistry.registerProbeProvider(ProbeProviderRegistry.java:96)
    at org.glassfish.flashlight.impl.provider.FlashlightProbeProviderFactory.registerProvider(FlashlightProbeProviderFactory.java:521)
    at org.glassfish.flashlight.impl.provider.FlashlightProbeProviderFactory.processXMLProbeProviders(FlashlightProbeProviderFactory.java:360)
    at org.glassfish.admin.monitor.MonitoringBootstrap.processProbeProviderXML(MonitoringBootstrap.java:407)
    at org.glassfish.admin.monitor.MonitoringBootstrap.addProvider(MonitoringBootstrap.java:282)
    at org.glassfish.admin.monitor.MonitoringBootstrap.verifyModule(MonitoringBootstrap.java:219)
    at org.glassfish.admin.monitor.MonitoringBootstrap.discoverProbeProviders(MonitoringBootstrap.java:165)
    at org.glassfish.admin.monitor.MonitoringBootstrap.enableMonitoringForProbeProviders(MonitoringBootstrap.java:539)
    at org.glassfish.admin.monitor.MonitoringBootstrap.postConstruct(MonitoringBootstrap.java:153)
    at com.sun.hk2.component.AbstractWombImpl.inject(AbstractWombImpl.java:174)
    at com.sun.hk2.component.ConstructorWomb$1.run(ConstructorWomb.java:87)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.hk2.component.ConstructorWomb.initialize(ConstructorWomb.java:84)
    at com.sun.hk2.component.AbstractWombImpl.get(AbstractWombImpl.java:77)
    at com.sun.hk2.component.SingletonInhabitant.get(SingletonInhabitant.java:58)
    at com.sun.hk2.component.LazyInhabitant.get(LazyInhabitant.java:107)
    at com.sun.hk2.component.AbstractInhabitantImpl.get(AbstractInhabitantImpl.java:60)
    at com.sun.enterprise.v3.server.AppServerStartup.run(AppServerStartup.java:212)
    at com.sun.enterprise.v3.server.AppServerStartup.start(AppServerStartup.java:128)
    at com.sun.enterprise.module.bootstrap.Main.launch(Main.java:457)
    at com.sun.enterprise.module.bootstrap.Main.launch(Main.java:401)
    at com.sun.enterprise.module.bootstrap.Main.launch(Main.java:310)
    at com.sun.enterprise.module.bootstrap.Main.launch(Main.java:303)
    at com.sun.enterprise.glassfish.bootstrap.ASEmbedded.run(ASEmbedded.java:101)
    at com.sun.enterprise.glassfish.bootstrap.AbstractMain.start(AbstractMain.java:78)
    at org.glassfish.api.embedded.Server.<init>(Server.java:288)
    at org.glassfish.api.embedded.Server.<init>(Server.java:61)
    at org.glassfish.api.embedded.Server$Builder.build(Server.java:158)
    at org.glassfish.api.embedded.Server$Builder.build(Server.java:140)
    at org.glassfish.ejb.embedded.EJBContainerProviderImpl.init(EJBContainerProviderImpl.java:154)
    at org.glassfish.ejb.embedded.EJBContainerProviderImpl.createEJBContainer(EJBContainerProviderImpl.java:114)
    at javax.ejb.embeddable.EJBContainer.createEJBContainer(EJBContainer.java:102)
    at javax.ejb.embeddable.EJBContainer.createEJBContainer(EJBContainer.java:78)
    at uk.co.salientsoft.cheepcheep.service.impl.DomainServiceImplTest.setUpBeforeClass(DomainServiceImplTest.java:44)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:27)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.junit.runners.Suite.runChild(Suite.java:128)
    at org.junit.runners.Suite.runChild(Suite.java:24)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

(then further down in the log…)

WARNING: Exception while performing resource-adapter’s security permission check :
java.io.FileNotFoundException: E:\Java\Dev\Helios-SR2\Workspaces\CheepCheep\TraderUI\gfembed880784300432477021tmp\config\server.policy (The system cannot find the file specified)
    at java.io.FileInputStream.open(Native Method)
    at java.io.FileInputStream.<init>(FileInputStream.java:106)
    at java.io.FileReader.<init>(FileReader.java:55)
    at com.sun.enterprise.connectors.service.ConnectorConfigurationParserServiceImpl.getFileContent(ConnectorConfigurationParserServiceImpl.java:133)
    at com.sun.enterprise.connectors.service.ConnectorConfigurationParserServiceImpl.getSecurityPermissionSpec(ConnectorConfigurationParserServiceImpl.java:92)
    at com.sun.enterprise.connectors.ConnectorRuntime.getSecurityPermissionSpec(ConnectorRuntime.java:495)
    at com.sun.enterprise.connectors.service.ResourceAdapterAdminServiceImpl.createActiveResourceAdapter(ResourceAdapterAdminServiceImpl.java:239)
    at com.sun.enterprise.connectors.service.ResourceAdapterAdminServiceImpl.createActiveResourceAdapter(ResourceAdapterAdminServiceImpl.java:338)
    at com.sun.enterprise.connectors.ConnectorRuntime.createActiveResourceAdapter(ConnectorRuntime.java:327)
    at com.sun.enterprise.connectors.service.ConnectorService.loadDeferredResourceAdapter(ConnectorService.java:164)
    at com.sun.enterprise.connectors.service.ConnectorService.loadResourcesAndItsRar(ConnectorService.java:133)
    at com.sun.enterprise.connectors.service.ConnectorService.checkAndLoadPool(ConnectorService.java:307)
    at com.sun.enterprise.connectors.service.ConnectorResourceAdminServiceImpl.createConnectorResource(ConnectorResourceAdminServiceImpl.java:91)
    at com.sun.enterprise.connectors.ConnectorRuntime.createConnectorResource(ConnectorRuntime.java:266)
    at com.sun.enterprise.resource.deployer.JdbcResourceDeployer.deployResource(JdbcResourceDeployer.java:107)
    at org.glassfish.javaee.services.ResourceProxy.create(ResourceProxy.java:84)
    at com.sun.enterprise.naming.impl.SerialContext.lookup(SerialContext.java:432)
    at javax.naming.InitialContext.lookup(InitialContext.java:392)
    at javax.naming.InitialContext.lookup(InitialContext.java:392)
    at com.sun.enterprise.connectors.service.ConnectorResourceAdminServiceImpl.lookup(ConnectorResourceAdminServiceImpl.java:203)
    at com.sun.enterprise.connectors.ConnectorRuntime.lookupPMResource(ConnectorRuntime.java:429)
    at org.glassfish.persistence.jpa.JPADeployer$ProviderContainerContractInfoImpl.lookupDataSource(JPADeployer.java:228)
    at org.glassfish.persistence.jpa.PersistenceUnitInfoImpl.<init>(PersistenceUnitInfoImpl.java:108)
    at org.glassfish.persistence.jpa.PersistenceUnitLoader.loadPU(PersistenceUnitLoader.java:130)
    at org.glassfish.persistence.jpa.PersistenceUnitLoader.<init>(PersistenceUnitLoader.java:96)
    at org.glassfish.persistence.jpa.JPADeployer.prepare(JPADeployer.java:121)
    at com.sun.enterprise.v3.server.ApplicationLifecycle.prepareModule(ApplicationLifecycle.java:644)
    at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:296)
    at org.glassfish.kernel.embedded.EmbeddedDeployerImpl.deploy(EmbeddedDeployerImpl.java:214)
    at org.glassfish.kernel.embedded.EmbeddedDeployerImpl.deploy(EmbeddedDeployerImpl.java:144)
    at org.glassfish.ejb.embedded.EJBContainerImpl.deploy(EJBContainerImpl.java:128)
    at org.glassfish.ejb.embedded.EJBContainerProviderImpl.createEJBContainer(EJBContainerProviderImpl.java:120)
    at javax.ejb.embeddable.EJBContainer.createEJBContainer(EJBContainer.java:102)
    at javax.ejb.embeddable.EJBContainer.createEJBContainer(EJBContainer.java:78)
    at uk.co.salientsoft.cheepcheep.service.impl.DomainServiceImplTest.setUpBeforeClass(DomainServiceImplTest.java:44)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:27)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.junit.runners.Suite.runChild(Suite.java:128)
    at org.junit.runners.Suite.runChild(Suite.java:24)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
17-Dec-2011 23:18:17 com.sun.ejb.containers.BaseContainer initializeHome

6/ In my case, my project used JPA 2 and Eclipselink, with Oracle XE. Happily I found that as long as I followed the above steps properly, everything ran fine with no messing about and no need for special setup or property passing to the embedded container. It feels a bit like ‘smoke and mirrors’ when you first see it and you wonder how everything is discovered automatically, but once you understand the point about using the embedded shell jar in the actual glassfish instance it all becomes clear. Note that it does not matter whether or not your project is currently deployed to the target glassfish instance – all that matters is that the necessary configuration such as data sources are present and correct.

7/ Note that whilst I did manage to get CDI injection of POJOS into an EJB working as in 2/, I was not able to directly instantiate a POJO from the container context, so for example I could not test a POJO which then called an EJB. It is of course vital that the initial bean under test is created from the container context or it will not run in the container. A number of posts on the net like this one here discuss trying to obtain a BeanManager using ctx.lookup("java:comp/BeanManager") which should work for Java EE 6, in order to use the BeanManager to obtain CDI bean reference from the embedded container context. However, all the posts I found failed to find a solution. This Jira post may indicate the fundamental problem.

I did attempt a workaround – all CDI beans (including EJBs) can obtain a BeanManager reference by using e.g. @Inject private BeanManager beanManager. I therefore tried creating a BeanManagerLocator EJB whose sole job was to inject the BeanManager and return it via a getter. This did allow me to obtain a valid BeanManager. I then tried to get a bean reference to my CDI model bean (a dependent bean used to decouple JSF controllers from the service layer) as follows :-

BeanManagerLocator beanManagerLocator = (BeanManagerLocator) ctx.lookup("java:global/classes/BeanManagerLocator");
BeanManager beanManager = beanManagerLocator.getBeanManager();

Bean<?> modelBean = beanManager.getBeans(Model.class).iterator().next();
CreationalContext<?> cc = beanManager.createCreationalContext(modelBean);
Model model = (Model)beanManager.getReference(modelBean, Model.class, cc)

Unfortunately, the final statement which actually gets the bean reference failed an error, at which point I gave up. Clearly some deeper magic is needed to create the CDI bean outside of the container. It might be possible to achieve this by bootstrapping CDI separately outside the container, and this is certainly possible in Java SE. However, there is then the issue of coupling the CDI environment outside the container to the one inside, so that the whole test environment is integrated like the normal one. I decided that all this was a bridge too far. Here is the error mentioned at the top of this paragraph:-

java.lang.IllegalStateException: No valid EE environment for injection of uk.co.salientsoft.test.view.ModelImpl

 

Whilst researching this, I found the following links useful:-

  • This post uses Glassfish 3.1 and maven, and sets up a custom glassfish configuration on the classpath using domain.xml. Interesting, but I prefer to tie to the configuration of an actual development instance as my configuration is then all centralised, in step, and can be maintained by the glassfish admin tool.
  • This post by Adam Bien is interesting but does not mention how to tie the configuration using the shell jar, and what to do about the above “no provider names had been found” error.
  • This post discusses the concept from a CDI perspective
  • Oracle documentation about the embedded container and embedded API may be found here and here

 

Code Example

AllTests.java

@RunWith(Suite.class)
@Suite.SuiteClasses({
    DomainServiceImplTest.class,
})
public class AllTests {}

DomainServiceImplTest.java

public class DomainServiceImplTest {
    private static EJBContainer ejbC;
    private static DomainServiceLocal domainService;
    
    @BeforeClass
    public static void setUpBeforeClass() throws Exception {

        /* Populate the database with the correct test data */
        ScriptRunner scriptRunner = new ScriptRunner();
        int exitCode = scriptRunner.run("test\\PopulateTestDatabase");

        assertTrue (String.format("SqlPlus script exit code was: %s, should be 0", exitCode), exitCode == 0);

        ejbC = EJBContainer.createEJBContainer();
        Context ctx = ejbC.getContext();
        
       /*
         * List the available ejbs for the container – useful when debugging the test environment
         * The empty name string lists all the top level binding categories
         * java:global/classes lists all the ejbs for the embedded container
         */
        NamingEnumeration<Binding> ne = ctx.listBindings("");       
        while(ne.hasMore()) {
            Binding b = (Binding) ne.next();
            System.out.println(b.getName() + " – " + b.getObject());
        }
        ne = ctx.listBindings("java:global/classes");       
        while(ne.hasMore()) {
            Binding b = (Binding) ne.next();
            System.out.println(b.getName() + " – " + b.getObject());
        }
        domainService = (DomainServiceLocal) ctx.lookup("java:global/classes/DomainServiceImpl");   
    }

    @AfterClass
    public static void tearDownAfterClass() throws Exception {

         // Close the container when done to save resources  
        ejbC.close();       
    }

    @Test public void testCDIPojoInjection() throws Exception {
        assertFalse("CDI POJO injection – embedded ejb container requires 2nd beans.xml in src/META_INF for this to work",
                                domainService.getTreeSearchBuilder() == null);       
    }
    @Test public void testFetchTaxonomiesNotNull() throws Exception {
        List<Taxonomy> taxonomies = domainService.fetchTaxonomies(true);       
        assertFalse("Taxonomies returned should not be null", taxonomies == null);
    }
    @Test public void testFetchTaxonomiesCount() throws Exception {
        List<Taxonomy> taxonomies = domainService.fetchTaxonomies(true);       
        assertTrue("Taxonomies returned should have count of 1", taxonomies.size() == 1);       
    }
    @Test public void testFetchTaxonomiesDefault() throws Exception {
        List<Taxonomy> taxonomies = domainService.fetchTaxonomies(true);       
        assertTrue("Taxonomy returned should be the default", taxonomies.get(0).isDefaultTaxonomy());       
    }
}

PopulateTestDatabase.properties

#ScriptRunner property file to populate test data via SqlPlus
scr.include=sqlplus
scr.name=Populate Test Data

scr.directory=test\\database
scr.param.user=testdb4
scr.param.password=password4
scr.param.database=xe
scr.param.scriptfile=PopulateAll.sql
scr.log.file=..\\PopulateTestDatabase.log
scr.log.append=false
scr.log.console=false

sqlplus.properties  (this property file is standard to ScriptRunner and is run directly from within ScriptRunner.jar)

# ScriptRunner definition for Oracle SqlPlus under Windows

# Give the script a name (this can be overridden by a calling script)
scr.name=SqlPlus

# Define the command and parameters
# Note that under Windows, the command, user/password/database and Sql script
# must all be specified as separate command strings, or SqlPlus does not see the correct arguments.
# Other systems may differ.
scr.command.1=sqlplus
scr.command.2=%1$s/%2$s@%3$s
scr.command.3=@%4$s

#Define named parameters for the arguments to SqlPlus, for the users convenience
scr.param-name.user=1
scr.param-name.password=2
scr.param-name.database=3
scr.param-name.scriptfile=4

No Comments »

March 6th, 2011
8:53 pm
Using the Decorator pattern when extending the underlying Class

Posted under Java
Tags , , , , ,

In some cases, a Decorator just wraps an underlying class and does not add any interface changes of its own – it just changes behaviour without adding any new methods or properties. An example of this would be this ‘coffee’ example in the chapter on the Decorator pattern from the excellent Head First Design Patterns book by Eric and Elisabeth Freeman. In this case, it is not necessary to have visibility of individual decorators in the chain – they all add their required changes to the price and description of the coffee, and calling methods on the outermost decorator causes all the inner ones to be called to do their thing.

In other cases, however, it is necessary to add new methods and properties to a Decorator. An example from later in the same chapter would be the LineNumberInputStream decorator in the standard java.io package. this performs line numbering on the lines that pass through it, so it is obviously necessary to use the properties of that particular decorator in the chain to fetch the line numbers.

Therefore, in cases like this, client code will need to refer to particular decorators in the chain to access such methods and properties. This in no way invalidates the decorator pattern – it is important to note that we have still extended the underlying class using the open/closed principle, i.e. we have not modified it but decorated it with one or more new classes. Also and equally importantly, the various decorators in the chain are completely decoupled both from the underlying class and from each other as well.

There will be occasions where a decorator needs to extend the behaviour not just of the underlying base class, but also some of the behaviour of another decorator. In this case, such a decorator will extend the decorator it is adding behaviour to, rather than the underlying base class. The general guiding principles here are as follows:-

A decorator should extend the lowest level class it needs to in order to perform its function. For example, if A is a base class and B and C are decorators, C should not extend B unless it actually has dependencies on B’s additional behaviour, as otherwise we are introducing unnecessary coupling between objects that do not need to be coupled.

Note that all the decorators can and should be generic. Any subclass of the class a decorator extends may be passed to it, and may be retrieved generically. For example, if class ClassB decorates class ClassA, then we would declare B as follows:-

public class ClassB<C extends ClassA> extends ClassA {

private C decoratedClass;

}

This allows ClassB full access to all of the ClassA methods and properties, even when it is passed an arbitrary subclass of ClassA. Also, we have ensured that we can generically access via a ClassB instance, the particular subclass of ClassA used as the decorated class.

When we need to access particular decorators in a chain, we can either remember the object references used when we created them, or we can fetch references to them from their container decorator. In this case, we obviously have to keep knowledge of how the decorator chain was set up, and what was decorated in what order.

Decorators are a powerful pattern for flexible behaviour extension, but can have their downsides. You can end up with a large number of small decorator classes and large decorator chains – just look at the java.io package to see this. Also, you have to create all the delegated methods and properties for every decorator, although if you are using an IDE like Eclipse this can all be done automatically for you which is a big boon when using decorators heavily, and eliminates a lot of sources of error. Also, the major benefit compared with static extension of a class to add behaviour is that you can set up a decorator chain with any decorators you like in any order – illustrating again the benefits of favouring composition over inheritance.

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 »