Skip navigation

RichFaces 4.5.5.Final is available for download.

 

This release contains mostly minor bug fixes on the client-side. One thing worth mentioning is added support for status on a4j:queue - instead of setting a status for each request you can set the status for a queue and each request going through the queue will use it if they do not have one set.

 

Release Notes

        Bug

  • [RF-11766] -         rich:tree - selectionChangeListener isn't called when the model org.richfaces.model.TreeNode is used
  • [RF-12491] -         Datatable model is accessed in tab panel which is not rendered using switch type "server"
  • [RF-12764] -         rich:select - javascript error when using myfaces with french locale
  • [RF-13138] -         a4j:log - should print partial-response value in a level=debug, but prints [Object] instead
  • [RF-14003] -         Richfaces included jboss-el-api_3.0_spec-1.0.4.Final.jar in the pom.xml
  • [RF-14011] -         a4j:mediaoutput does not work on wildfly 8.2 , uploaded Image is broken
  • [RF-14015] -         rich:calendar month and year selection does not work
  • [RF-14016] -         treeNode: missing @toggleListener in taglib and docs
  • [RF-14018] -         rich:select - js error - this.cache is undefined (or similar js error)
  • [RF-14020] -         Richfaces 4.5.2 not working in Websphere
  • [RF-14026] -         collapsiblePanel regression with switchType="client" and expanded="false"
  • [RF-14027] -         tooltip doesn't work with popupPanel (4.5.x).
  • [RF-14032] -         rich:calendar - pressing a key after manually changing the year resets the date
  • [RF-14033] -         calendar: fragment: DayPicker: selecting of a day uses unnecessary ctrl key

       

        Component  Upgrade

  • [RF-14012] -         Upgrade third-party libraries
  • [RF-14030] -         Upgrade Arquillian Core to 1.1.8

                   

        Feature Request

  • [RF-13203] -         a4j:queue should have status attribute
  • [RF-14019] -         Accordian Panel Item breaks in <= IE8 when Array polyfil is used
  • [RF-14022] -         Add support for "resetValues" for AbstractActionComponents (UIMenuItem, UIPanelMenuItem, UITab)

                                   

        Task

  • [RF-13996] -         Travis build failures due to VM termination
  • [RF-14009] -         log: document @mode=console

RichFaces 4.5.4.Final is available for download.

 

Important note:

A security issue concerning a4j:mediaOutput has been fixed in this release. Your applications may be vulnerable even if they don't use the component.

 

Aside from that in this release we've added keyboard support to rich:calendar - you can now skip through days, weeks, months and years without using mouse. (See documentation) We've also enabled file filtering in rich:fileUpload dialog window.

 

 

Release Notes

        Bug

  • [RF-13977] -         Remote Command Injection (EL Injection)
  • [RF-13990] -         Cannot deploy Showcase in JBDS 8
  • [RF-13991] -         GraphValidator is not working on Tomcat
  • [RF-13994] -         FileUpload: 'status' attribute not working
  • [RF-14000] -         Showcase: root path doesn't redirect to index page on EAP 6.3
  • [RF-14002] -         Calendar: cannot close popup by clicking on button

     

        Component  Upgrade

  • [RF-13971] -         Upgrade testing dependencies
  • [RF-13995] -         Upgrade third-party libraries

         

        Enhancement

  • [RF-11376] -         rich:panelMenu - barely visible label of submenu when it is hovered
  • [RF-11770] -         showcase - rich:dataScroller - the fastStep should be set to more than default 1
  • [RF-12934] -         ajax request for rich:tooltip should respect the showDelay parameter

 

        Feature Request

  • [RF-6687] -         Navigate Calendar with keyboard
  • [RF-11684] -         rich:dataScroller optimize behaviour of fastStep
  • [RF-11984] -         rich:fileUpload: implement file extension filtering
  • [RF-12799] -         Log: add attribute hotkey
  • [RF-13251] -         FocusManager to support complex components like rich:autocomplete

                                 

        Task

  • [RF-10350] -         Client API: collapsiblePanel api improvements
  • [RF-13997] -         Remove .jsp files from projects
  • [RF-14001] -         Add atmosphere-runtime-native to dependency managment

             

        Sub-task

  • [RF-13998] -         Add documentation for keyboard navigation

As you might have noticed with newer versions of Mojarra (2.2.6+) some RichFaces components do not work well when placed inside ui:repeat (MyFaces are not affected). This applies to functionality where components switch between different things (changing tabs, sorting columns in a table) - the full list of issues we track can be seen here. A reliable workaround is to use a4j:repeat instead.

 

The problem occurred with fixing JAVASERVERFACES-3152 which changed the way component state is being saved and restored inside ui:repeat. As far as I understand there isn't a clear specification on how ui:repeat is supposed behave but the state saving mechanism is a core part of the JSF framework and we relied on the way it worked before, whether it was intended or not. The impact for RichFaces is that interactive components don't "remember" their previous state - for example expanding a collapsed rich:collapsiblePanel will not trigger a PanelToggleEvent for its @toggleListener because the information that the panel is collapsed is not available to the component. I have been trying to resolve the issue with the Mojarra team but so far we've gotten nowhere (I was suggested a workaround but it made the state apply to every component inside ui:repeat, not just the one - i.e. collapsing one panel would collapse all panels), while the impact to JSF is not as big and they do not need to make sure our components work I do believe that the current behavior is a bug since I've been able to observe some undesirable results in pure JSF environment.

 

Currently there is a JIRA ticket filed - JAVASERVERFACES-3833, if this issue affects your application consider voting for it.

RichFaces 4.5.2.Final is available for download.

 

In this release we have mostly fixed look-and-feel client-side issues, the most impactful being the ability to scroll rich:extendedDataTable without the use of the scrollbar (e.g.with a touchpad or mouse scroll button). We have also fixed server-side issues with visiting components that were not supposed to be visited (such as unrendered columns or collapsed collapsiblePanels).

 

NOTE: We have upgraded jQuery to the latest version but due to a bug in one of its libraries Firefox users will often encounter a "not well-formed" console warning. It is safe to ignore and will be fixed in the next version of jQuery.

 

Release Notes

        Bug

  • [RF-10714] -         Message: icon trimmed
  • [RF-10817] -         Panel menu item: same icon for enabled and disabled state
  • [RF-10834] -         File upload: default labels not used
  • [RF-10964] -         autocomplete delete key behavior creates inconsistent state
  • [RF-10971] -         rich:tooltip doesn't work in rich:extendedDataTable
  • [RF-11218] -         showcase - rich:fileUpload - there is no file name information of uploaded file
  • [RF-11678] -         rich:extendedDataTable column resize problem when placed in absolute positioned container
  • [RF-11679] -         rich:extendedDataTable window resize problem when placed in absolute positioned container
  • [RF-12482] -         rich:fileUpload, the upload button disappeared after deleting a uploaded file
  • [RF-13177] -         rich:extendedDataTable scrolling broken on OS-X
  • [RF-13595] -         rich:validator doesn't work when loaded via ajax (re-render)
  • [RF-13711] -         a4j:ajax status does not work as expected
  • [RF-13721] -         dataTable: columnClasses attribute doesn't work as described
  • [RF-13780] -         Random JavaScript error due to missing attribute 'richfaces.RICH_CONTAINER'
  • [RF-13949] -         push: error in browser console after push enabled/disabled
  • [RF-13950] -         Photoalbum tests need to be migrated + create testing profiles
  • [RF-13957] -         select: clicking on the bottom part of the input does not trigger onclick event
  • [RF-13958] -         collapsibleSubTable: the most nested CST remains collapsed after parent CST re-expands
  • [RF-13959] -         a4j:mediaOutput doesn't work if createContent is an EL expression
  • [RF-13961] -         push: initialization of topic with subtopic will prevent sending push messages to this topic or to its subtopics
  • [RF-13962] -         typo in rich:hotKey description on showcase
  • [RF-13963] -         a4j calls and repeatable components
  • [RF-13965] -         rich:select popup not displayed after clearing whole input
  • [RF-13968] -         Showcase: autocomplete sample is using wrong attribute autoFill instead of autofill
  • [RF-13969] -         rich:accordion height of first element is wrongly computed when switchType is "client".
  • [RF-13978] -         UIDataAdaptor doesn't handle VisitHint.SKIP_ITERATION, doesn't check unrendered columns
  • [RF-13979] -         editor: 'basic' toolbar is same as 'full'
  • [RF-13980] -         Initially Page loaded with Data in ExtendedDatatable, after zoom out in  Browser the Data is not displayed in ExtendedDatatable.
  • [RF-13982] -         Photoalbum - image for FB login missing
  • [RF-13988] -         collapsiblePanel stops rendering of following components

  

        Component  Upgrade

  • [RF-13730] -         Upgrade Mojarra in build/pom.xml
  • [RF-13975] -         Upgrade third-party libraries

      

        Enhancement

  • [RF-13939] -         Rich:chart plotClick shouldn't be restricted to series points.
  • [RF-13964] -         Pom Cleanup

RichFaces 4.5.2.Final is available for download.

 

Among other things, we have fixed several issues with Push and also enabled Websockets in our Showcase.


Important notes

 

Jar renaming

Two of our jars have been renamed:

  • richfaces-components-a4j to richfaces-a4j
  • richfaces-components-rich to richfaces-rich

If you're using maven for your projects this doesn't affect you.

 

FileUpload issue in IE10/11

<rich:fileUpload> may not work for you with Mojarra 2.2.7+ and Internet Explorer. This is caused by an error in Mojarra code and an irregular behavior of Internet Explorer. The issue is not always present but breaks the component. The issue will be fixed in Mojarra 2.3.0-m02; if you're using the JBoss distribution of JSF the patch has been backported into 2.2.9-jboss-2. In the meantime, this JavaScript function can be used as a workaround - make sure to run it before you start uploading:

addNames = (function () {
    var added = false;

    return function() {
        if (!added) {
            $.each(document.forms, function() {
                $.each(this.elements, function() {
                    this.name = this.name || "";
                });
            });
        }
        added = true;
    }
})();





 

Ui:repeat

Unfortunately several of our components do not function well inside <ui:repeat> in Mojarra 2.2.6+ as the behavior of the component was changed. We recommend using <a4j:repeat> instead until this issue is resolved.

 

Release Notes

        Bug

  • [RF-12695] -        rich:select incorrect behavior on IE with many selectItems
  • [RF-13913] -        Problem with rich:collapsiblePanel state/PartialViewState
  • [RF-13925] -        tooltip: the @onshow is called before the tooltip is displayed
  • [RF-13927] -        Nested collapsibleSubTable not collapse All Sub Level SubTable
  • [RF-13928] -        a4j:push events (dataavailable) do not trigger a4j:ajax listener
  • [RF-13929] -        a4j:push does not work with subtopics and JMS
  • [RF-13930] -        rich:select broken with empty list
  • [RF-13931] -        Showcase: remove reference to richfaces-parent
  • [RF-13933] -        ExtendedDataTable duplicates inside ui:repeat
  • [RF-13935] -        JMS Push long delay between eneable and disable after upgrade atmosphere
  • [RF-13938] -        page-fragments: inputNumber*: the setValue does not clean the input
  • [RF-13941] -        ExtendedDataTable - selecting all rows not working
  • [RF-13942] -        rich:select single item list still present
  • [RF-13945] -        ajax requests in multipart forms cause error in < 2.2.0
  • [RF-13946] -        The "onclick"event is not triggered when clicking on the bottom part of "rich:select" component.
  • [RF-13952] -        richfaces-core defines finalName conflicted with components/rich/pom.xml
  • [RF-13954] -        showcase: cannot be deployed on tomcat

 

        Component  Upgrade

  • [RF-13926] -        Update weld-servlet dependency to 2.2+

 

        Enhancement

  • [RF-13907] -        Positioning attributes - JointPoint and Direction Doc is confusing
  • [RF-13914] -        Showcase online: websockets don't work
  • [RF-13937] -        page-fragments: ignore StaleElementReference exceptions in all waiting methods

 

        Feature Request

  • [RF-13932] -        page-fragments: autocomplete: reimplement confirm and select methods so they will not submit the form with HTTP unnecessarily

                          

        Task

  • [RF-13934] -        Create Arquillian profile for WildFly 8.2

RichFaces 4.5.1.Final is available for download.

 

With this release we've implemented several improvements to rich:select - it is now possible to look up options by their first letter without enabling manual input, pressing a key repeatedly will cycle through available options. The Tab key can now be used to select an option.

 

Rich:chart has been made extensible with the hooks attribute and facets, allowing the use of plugins. For more information, see my previous blog post.

 

ResetValues attribute has been added to a4j components, this will let you properly reset values of components after a validation failure.

 

Finally we've updated several of the third-party libraries we use - Atmosphere to 2.2.3 (a4j:push), CKEditor to 4.4.6 (rich:editor), Flot to 0.8.3 (rich:chart), jQuery UI to 1.11.1 (many rich components).

 

Release Notes

        Bug

  • [RF-12166] -        richfaces distribution - missing assembler.xml in showcase sources
  • [RF-12654] -        PartialViewRender skips check for whether column is rendered before checking if children can be rendered
  • [RF-13828] -        a4j jsFunction does not work inside a form with enctype="multipart/form-data"
  • [RF-13883] -        render-attribute of a4j:commandLink is ignored
  • [RF-13892] -        rich:contextMenu with rich:dataTable - after ajax re-render of table contextMenu no longer works
  • [RF-13893] -        Resource optimization - Invalid reference for gradientA.png
  • [RF-13898] -        Not able to tab out from rich:select field in a table.
  • [RF-13899] -        selected item in rich:select not highlighted after refresh
  • [RF-13904] -        RF can be deployed to Mojarra < 2.1.28
  • [RF-13905] -        Select: attribute onlistshow doesn't work when enableManualInput=true
  • [RF-13906] -        Calendar - Show selected date JS error
  • [RF-13908] -        Validation quickstart: UnsupportedOperationException after confirmation of the registration
  • [RF-13909] -        Attribute render doesn't work in command button/link, jsFunction
  • [RF-13912] -        rich:select inside panelGrid
  • [RF-13916] -        Nested collapsibleSubTable only collapse ten row  BUG
  • [RF-13917] -        Showcase: update the version of RF in readme
  • [RF-13922] -        Ajax requests fail if triggered outside of form
  • [RF-13923] -        Editor toolbar configuration cannot be changed

 

        Component  Upgrade

  • [RF-13902] -        Upgrade dependencies in jsf-test
  • [RF-13915] -        Upgrade third-party libraries

     

        Enhancement

  • [RF-11088] -        rich:select modify manualInput behavior to avoid single item scoped item list popup when editing value
  • [RF-13232] -        Enable flexible changing of the deployed archive name for general deployments, e.g. CoreDeployment
  • [RF-13867] -        Provide a way to access FlotCharts options

 

        Feature Request

  • [RF-13532] -        Support JSF 2.2 resetValues attribute for a4j:ajax
  • [RF-13855] -        Rich line chart string value on one of axis
  • [RF-13861] -        rich:chart doesn't preserve ordering of data
  • [RF-13900] -        rich:select should support selection by first character if enableManualInput is not used

Flot, the underlying library for rich:chart, is written in JavaScript. As such it is not practical to delegate all customization to the RichFaces components, although we might add more customization in there as well. In RichFaces 4.5.1 we are adding a new attribute and facet to rich:chart - hooks. These allow to customize the chart by hooking into the processing phases on the client-side (as described in the documentation). This is similar to rich:editor customization through the "config" facet. Let's see some examples:

 

Plugins - fillBetween

The fillBetween plugin allows you to fill areas between line charts (as opposed to the default that fills the area between the chart and the baseline).

 

Enabling the default fill can be done like this:

<rich:chart title="Sines" id="chart1">
    <f:facet name="hooks">
        {                           
            processRawData: [function(plot,series) {
                    series.lines.fill = true;
            }]
        }
    </f:facet>
    <rich:chartSeries type="line" color="red">
        <a4j:repeat value="#{sineBean.sinX}" var="sin" rowKeyVar="rk">
            <rich:chartPoint x="#{sin.x}" y="#{sin.y * 0.6 + 2.3}" />
        </a4j:repeat>
    </rich:chartSeries>
    <rich:chartSeries type="line" color="navy">
        <a4j:repeat value="#{sineBean.sinX}" var="sin" rowKeyVar="rk">
            <rich:chartPoint x="#{sin.x}" y="#{-sin.y}" />
        </a4j:repeat>
    </rich:chartSeries>
    <rich:chartSeries type="line" color="green">
        <a4j:repeat value="#{sineBean.sinX}" var="sin" rowKeyVar="rk">
            <rich:chartPoint x="#{sin.x}" y="#{sin.y * 0.2 - 1.7}" />
        </a4j:repeat>
    </rich:chartSeries>
    <rich:chartLegend />
</rich:chart>






filb.png

 

And now with fillBetween; first, we need to insert the plugin. Plugins register themselves to the main library automatically so linking the file is all you need:

<h:outputScript library="flot" name="jquery.flot.fillbetween.js" target="head" />






 

Then, we need to modify the hooks:

<f:facet name="hooks">
    (function() {
        var id = 0;

        return {                     
            processRawData: [function(plot,series) {
                series.id = "id" + id;
                if (id &lt; 2) {
                    series.fillBetween = "id" + (id + 1);
                    series.lines.fill = true;
                }
                id++;
            }]
        }
    })()
</f:facet>

Unfortunately Flot calls the hook on each series separately, that's why we need to keep track of the id.

filbetween.png

Label formatting

Another thing the hooks can be used for is formatting of axis labels, we can either format the values calculated by Flot or we can add our own values:

<f:facet name="hooks">
    (function() {
        var id = 0;
  
        return {                      
            processRawData: [function(plot,series) {
                series.id = "id" + id;
                if (id &lt; 2) {
                    series.fillBetween = "id" + (id + 1);
                    series.lines.fill = true;
                }
                id++;
            }],
            processOptions: [function(plot,options) {
                options.yaxes[0].tickFormatter = function (value, axis) {
                    return (value * 10000).toLocaleString('en-US', {minimumFractionDigits: 2});
                };
                options.xaxes[0].ticks = [
                    0, [ Math.PI/2, "\u03c0/2" ], [ Math.PI, "\u03c0" ],
                    [ Math.PI * 3/2, "3\u03c0/2" ], [ Math.PI * 2, "2\u03c0" ]
                ];
            }]
        }
    })()
</f:facet>

format.png

Taken from Lukáš Macko's blog series on charts, this is an up-to-date version.

 

Handling events of the chart component

 

My introduction set of posts about the chart component is coming to end. I have already covered creating a basic chart, chart types supported, customization of chart look and component’s JavaScript API. One of thing I haven’t explained is handling of the chart component events.

 

The chart component offers three events to be handled.

  • plotclick – fired when point in a chart is been clicked
  • plothover – mouse cursor is above  the point
  • mouseout – mouse cursor leaves chart grid

 

Each of events can be handled by JavaScript function. The PlotClick event can be assigned a server-side listener also. A listener or JavaScript handling function is given information about fired event:

  • seriesIndex – index of series whose point firing event belongs to
  • dataIndex – point index inside the series
  • x – point value on x-axis
  • y – point values on y-axis
  • item - javascript object holding other information about the event such as series label (only javascript)

Note: This information is not relevant for the mouseout event.

 

Let’s move to an example. I am going to use following chart.

<rich:chart>
    <a4j:repeat value="#{eventBean.countries}" var="country" >
         <rich:chartSeries label="#{country.name}" type="line">
             <a4j:repeat value="#{country.data}" var="record">
                 <rich:chartPoint x="#{record.year}" y="#{record.tons}" />
             </a4j:repeat>
         </rich:chartSeries>
    </a4j:repeat>
    <rich:chartXAxis  label="year"/>
    <rich:chartYAxis label="metric tons of CO2 per capita"/>
</rich:chart>

Client-side handlers

In first example I would like to show how to handle plotclick event. I am going to create a simple JavaScript function which will change the text in <span> element showing information about the point clicked.

 

At first add the span element, identify it with id attribute.

 

<span id='clickInfo'></span>



 

Create function which updates the span text.

 

<script type='text/javascript'>
        //<![CDATA[
           function log(e){
               $('#clickInfo').text("Series index: "+
                     e.data.seriesIndex +" DataIndex: "+
                     e.data.dataIndex+' ['+e.data.x+','+e.data.y+']');
           }

        //]]>
    </script>



Set handler in chart attribute attribute name is on+eventName, where eventName is one of plotclick, plothover or mouseout.

 

<rich:chart onplotclick="log(event)" >



JavaScript handler function is given an event object holding information mentioned above. They are located in data property. To access them use

 

e.data.seriesIndex
e.data.dataIndex
e.data.x
e.data.y
e.data.item.series.label



The similar approach might be used to handle plothover and mouseout events.

 

Server-side listener

 

To handle event you can also set server-side listener. I am going to use the same simple example setting a text after firing event.

 

<h:form>
    <rich:chart clickListener="#{eventBean.handler}">
         <a4j:repeat value="#{eventBean.countries}" var="country" >
             <rich:chartSeries label="#{country.name}" type="line">
                 <a4j:repeat value="#{country.data}" var="record">
                     <rich:chartPoint x="#{record.year}" y="#{record.tons}" />
                 </a4j:repeat>
             </rich:chartSeries>
         </a4j:repeat>
         <a4j:ajax event="plotclick" render="msg" execute="msg"/>
         <rich:chartXAxis label="year"/>
         <rich:chartYAxis label="metric tons of CO2 per capita"/>
    </rich:chart>
    <h:outputText id="msg" value="#{eventBean.msg}"/>
</h:form>



To be able to use server-side listener you have to surround the chart tag by the form. There is also added outputText showing the String updated by server-side listener. <a4j:ajax> tag set the outputText to be rerendered after the plotclick event.

 

The server-side listener is given an instance of plotclick object which contains the same information as client side object except item object.

 

public void handler(PlotClickEvent event){
    msg="Server's speaking:"+event.toString();
}



The setting of server-side listener is done by attribute clickListener.

 

Online demo can be found here and bean source code is on github.

 

Particular series handler

If you want to handle event fired by particular series only you can set handler for the one series only by using attribute in series tag. The name is the same as in chart tag.

 

Note: mouseout event handler is available only in chart tag.

 

Links

Taken from Lukáš Macko's blog series on charts, this is an up-to-date version.


How to customize the chart look

 

This post explains how to customize chart created by RichFaces chart component. The first steps how to create basic chart and chart types supported can be found in previous posts. If you’ve read some of these blog or API design proposal, you know that chart component uses a hierarchical tag structure. It means that chart configuration is divided into several tags. Each of them customizes a part of the chart.

 

<rich:chart>
   <rich:chartSeries type="line">
      <a4j:repeat value="" var="">
         <rich:chartPoint x="" y=""/>
      </a4j:repeat>
   </rich:chartSeries>
   <rich:chartXAxis/>
   <rich:chartYAxis/>
   <rich:chartLegend/>
</rich:chart>



The general chart structure is shown above. I’ll run through tags and their attributes. All attributes are optional except the ones mentioned above type, x and y.

 

rich:chart

  • title – text shown above the chart (not styled properly yet)
  • styleClass – css class assigned to a chart div
  • zoom – set true to enable zooming (works on line chart) you can reset zoom throught JavaScript API
  • eventHandlers: onplotclick, onmouseover, onmouseout, clickListener explained in detail in event handling post

 

rich:chartSeries

  • type – required attribute selects the chart type. Allowed values are line, bar and pie
  • symbol – selects point symbol in line chart (the attribute is ignored by other chart type) allowed values are circle, square, cross, triangle, diamond
  • color – defines series color (works with line and bar chart)
  • data – it used to pass data into component when you fill dataModel by your self explained in data model post
  • eventHandlers for particular series. See event handler post

 

rich:chartXAxis, rich:chartYAxis

  • format – currently used only by date series
  • label – axis description show next to axis
  • min – the smallest value shown on axis
  • max – the biggest values shown on axis
  • pad – if you don’t want to set fixed min and max value you can use this attribute it definesthe fraction of margin that the scaling algorithm will add to avoid that the outermost points ends up on the grid border.

 

rich:chartLegend

  • position – where the legend should be placed. Allowed values are nw (top left), sw (bottom left), ne (top right), se (bottom right)
  • sorting – defines the rule how the labels in legend are ordered. If not set they are in order asi defined in facelet. If you want to order them alphabetically you can use ascending or descending option.

 

Chart JavaScript API

 

The chart component it is built above the jQuery widget factory, so it offers also JavaScript API. Handling JavaScript events I’ll cover in another post. Component’s JavaScript API offers for now two public methods.

 

getPlotObject – used for testing returns JavaScript plot object

 

resetZoom is used to reset axis ranges and display whole chart after zooming is done. I’ll demonstrate it in a small example.

 

<rich:chart id="myChart" zoom="true" >
  <rich:chartLegend sorting="ascending"/>
  <a4j:repeat value="#{bean.series}" var="s">
    <rich:chartSeries type="line" label="#{s.label}" >
       <a4j:repeat value="#{s.data}" var="point">
          <rich:chartPoint x="#{point.x}" y="#{point.y}" />
       </a4j:repeat>
    </rich:chartSeries>
  </a4j:repeat>
</rich:chart>



To call a method on a particular chart you use id attribute.

 

RichFaces.component("form:myChart").resetZoom()

Example above calls method resetZoom on a chart identified by ID myChart. You can see live example here. (Note: the example is not up-to-date)

 

There is one more method not implemented yet highlight. It should allow to programmatically highlight a point in a series.

 

Links

Taken from Lukáš Macko's blog series on charts, this is an up-to-date version.

 

Chart component

 

The chart component has landed in RichFaces. Let’s take a quick look how to use it.

 

chart.png

 

I am going to show steps how to create chart like this. It shows countries carbon dioxide emissions per capita in several years. I am going to use following data. Data are stored in a list of Country objects in a backing bean.

 

public class Country{
    private String name;
    //CO2 production year-> metric tons per capita
    private List<Record> data;

    public Country(String name){
        this.name = name;
        this.data = new LinkedList<Record>();
    }
    public void put(int year, double tons){
        this.data.add(new Record(year, tons));
    }

    public List<Record> getData() {
        return data;
    }

    public String getName() {
        return name;
    }

    public class Record{
        private int year;
        private double tons;

        public Record(int year, double tons) {
            this.year = year;
            this.tons = tons;
        }

        public double getTons() {
            return tons;
        }

        public int getYear() {
            return year;
        }
    }
}




Country object has name and list of records (year and tons of C02 produced in that year by the country)

 

Prerequisite: Create JSF maven project (I am not going to dive in details.) with JBOSS public repository enabled.

 

Create chart

<rich:chart>
   <a4j:repeat value="#{bean.countries}" var="country" >
      <rich:chartSeries label="#{country.name}" type="line">
         <a4j:repeat value="#{country.data}" var="record">
            <rich:chartPoint x="#{record.year}" y="#{record.tons}" />
         </a4j:repeat>
      </rich:chartSeries>
   </a4j:repeat>
   <rich:chartXAxis label="year"/>
   <rich:chartYAxis label="metric tons of CO2 per capita"/>
</rich:chart>




 

I’ll explain these lines in details. You don’t have to create any extra java Object and fill it. You just pass what you gain from database or wherever and use it. In our case we have backing bean called bean and there is a list of Country objects storing data named countries.

 

Tag chartSeries represents one line in our chart – the values for one country. It has one mandatory attribute type defining the look of chart. It selects whether the chart displays line, bar or pie.

 

As you probably noticed, there is missing data in series tag. Data is passed into the series using tag chartPoint. It express one key-value pair/ x,y coordinates of a point in that line.

 

Tag repeat iterates over an array and it “generates” tags for you. That’s why you see only one series in a facelet and for lines in a chart. The same approach is used with points of each series.

 

Note: If you prefer more traditional  way. You can create chart data model by your self and pass it into the series tag using data attribute. It’ll be shown in another blog.

 

The source code of the shown example can be found here.

 

What chart type does component offer?

 

In this post I am going to describe what types of chart the component allow to create, how to switch among them and other things you should know about it.

 

The component supports line, bar and pie chart at the moment. The switching among chart type is easy, you change series tag attribute type to corresponding value.

<rich:chart>
   <rich:chartSeries type="line">
      <a4j:repeat value="" var="">
         <rich:chartPoint x="" y=""/>
      </a4j:repeat>
   </rich:chartSeries>
</rich:chart>



Each type expects Number type in y attribute. Line chart allows to use Number and Date (not fully supported yet) type in x attribute. Bar chart allows to use Number, String and Date (not fully supported yet). Pie chart use only String in x attribute.

 

Line and bar chart allow to use more than one series in a chart if the same type is used in x axis. You can also combine bar and line chart.

 

Switching among chart types get a little more complicated when you create data model by your self but it is topic for another post.

 

Links

In RichFaces 4.5 we've upgraded the rich:fileUpload component to take advantage of new APIs both on client and server side.

 

These changes are mostly in the background. The two visible changes are differently styled progress bars (based on Bootstrap) and the ability to drag and drop files onto the component. However the new APIs really simplified the somewhat difficult task of submitting and processing the files and are worth a few lines:

 

File API

A new API comes to browsers with HTML5, allowing access to the files provided by the user

input.val();
// "C:\fakepath\chart1.png"



The "C:\fakepath" is obfuscation by the browser, this is the only valuable information we can retrieve from an <input type="file" />, but with File API we can do better

 

input.prop("files")[0];
/* File: {
    lastModifiedDate: Mon Sep 29 2014 13:35:47 GMT+0200 (CEST)
    name: "chart1.png"
    size: 14679
    type: "image/png"
} */

 

Drag and Drop

With the File API and drag and drop support we can also retrieve files from a dropEvent (event.dataTransfer.files). The dropEvent can be intercepted on any element so it is possible to implement a file upload without the use of a file input.

 

XmlHttpRequest Level 2

The second important change in HTML5 is the FormData interface that let's us create a form-like object to be sent by an AJAX request. In this case we can append the files we retrieved previously to that object. Without access to any kind of File representation, the way to get the file to the server was to submit the form, loading the result into an <iframe> and intercepting the AJAX response to apply the changes to the main page.

 

var formData = new FormData(form);

formData.append(fileUpload.id, file); // key-value mapping
this.xhr = new XMLHttpRequest();
this.xhr.open('POST', url, true);

/*
  xhr handlers
   …
*/
this.xhr.send(formData);







there are several other things that have to be taken care of with regards to JSF but those are above the scope of this post.

 

XHR also allows us to handle the progress of the file upload on the client side. Previously we had to handle it on the server, inserting rich:progressBar into the element during rerender and connecting it to a request parser through a JSON resource.

this.xhr.upload.onprogress = function(e) {
    if (e.lengthComputable) {
        var progress = Math.floor((e.loaded / e.total) * 100);
        /*
          update the progressbar 
          …
        */
    }
};







 

NOTE: these APIs and thus the fileUpload component are not supported by older browsers, most notably IE9

 

Servlet 3.0

On the server side the big change was the implementation Servlet 3.0, making it easier to process the incoming request.

 

Collection<Part> parts = request.getParts();

for (Part part : parts) {
    // one of the parts will be the file we appended to formData
    String contentDisposition = part.getHeader("Content-Disposition");
    // form-data; name="form:upload"; filename="chart1.png"
    String filename = MultipartRequestParser.parseFileName(contentDisposition);
    if (filename != null) {
        files.add(new UploadedFile30(part.getName(), filename, part));
        // the file is then retrieved through part.getInputStream()
    }
}



We still support Servlet 2.5 which doesn't provide access to the parts, in that case the entire request has to be parsed piece by piece.

 

Links

With RichFaces 4.5.0 comes a new component for rendering charts, built on the Flot JavaScript library (www.flotcharts.org).

 

Chart

 

A simple chart can be created like this:

<rich:chart title="Basic trigonometry">
    <rich:chartSeries label="sin(x)" type="line">
        <a4j:repeat value="#{sineBean.sinX}" var="point">
            <rich:chartPoint x="#{point.x}" y="#{point.y}" />
        </a4j:repeat>
    </rich:chartSeries>
</rich:chart>






chart1.png

NOTE: The naming of chart-related components was changed in 4.5.0.CR1, if you've already started using the chart component you will need to change the tags.

 

rich:chart

besides the standard the attributes like id, style or rendered also enables event handling (more below)

 

rich:chartSeries

sets the type of the chart (line, bar or pie) and a label, it can also be used set the color for the series and the style of the points.

 

rich:chartPoint

defines the "x" and "y" values of a point in the series.

 

A single chart can contain more than one series:

<rich:chart title="More basic trigonometry">
    <rich:chartSeries label="sin(x)" type="line" symbol="circle" color="blue">
        <a4j:repeat value="#{sineBean.sinX}" var="point">
            <rich:chartPoint x="#{point.x}" y="#{point.y}" />
        </a4j:repeat>
    </rich:chartSeries>
    <rich:chartSeries label="2*sin(x)" type="line" symbol="square" color="red">
        <a4j:repeat value="#{sineBean.twoSinX}" var="point">
            <rich:chartPoint x="#{point.x}" y="#{point.y}" />
        </a4j:repeat>
    </rich:chartSeries>
    <rich:chartSeries label="cos(2*x)" type="line" symbol="diamond" color="green">
        <a4j:repeat value="#{sineBean.cosTwoX}" var="point">
            <rich:chartPoint x="#{point.x}" y="#{point.y}" />
        </a4j:repeat>
    </rich:chartSeries>
</rich:chart>






chart2.png

There are three more tags that can be included in rich:chart to further customize the chart's appearance:

 

rich:chartLegend

can be used to specify the position of the legend and ordering of the labels

<rich:chartLegend position="sw" sorting="ascending" />



 

rich:chartXAxis and rich:chartYAxis

can be used to specify minimum and maximum values or labels of the axes, and also to insert padding (whitespace) on the ends of an axis

<rich:chartXAxis label="Relevant months" min="2" max="9" />


Chart Types

Besides line charts the component can also render bar and pie charts (defined by type attribute of chartSeries, line and bar series can be combined in a single chart):

barchart.pngpiechart.png


Event handling

Chart offers two custom events that can be listened to:

plothover

triggers when mouse is hovered over the chart

plotclick

triggers when a part of the chart is clicked (a bar, a slice or a point)


The event listeners (onplothover, onplotclick) can be defined for the whole chart or separately for each series.


Links

I have recently finished migrating a photoalbum application from RF 3.3.X to RF 4.X. I will describe the things I needed to update so that you can migrate your applications as well and maybe avoid some hassle I had to deal with. I will cover things that are for the most part not strictly related to RichFaces - as far as updating the RichFaces components goes the two migration guides should be sufficient.

Links

 

Packaging

The original application was split into three packages - EJB, WAR and EAR. This was causing some deployment issues (that might have been entirely on my part) but later I merged all the files into the WAR package and that simplified things a bit and got rid of the issues.

XML configuration files

RichFaces 4 (or rather JSF 2) have deprecated some previous technologies and as result you can get rid of some of the configuration files. You will most likely find these in your project:

FileNote
components.xmlThese are safe to delete (but you might want to check what they were used for).
pages.xml
faces-config.xml

Change of schema version (1.2 -> 2.0):

<faces-config xmlns="http://java.sun.com/xml/ns/javaee" version="2.0" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd">
web.xmlRemove all Seam related components

Beans.xml

This is a new file you might need to create (put it in src/main/webapp/WEB-INF/). It is necessary for CDI to work, however it can be completely empty. Or almost empty with schema definitions:

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:weld="http://jboss.org/schema/weld/beans"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaeehttp://docs.jboss.org/cdi/beans_1_0.xsd http://jboss.org/schema/weld/beanshttp://jboss.org/schema/weld/beans_1_1.xsd">
</beans>

SEAM and Hibernate annotations

All SEAM annotations have been removed as the current application uses CDI for injection. Hibernate annotations have been updated (the package structure has changed).

SEAM annotations

Old AnnotationNew AnnotationNotes
org.jboss.seam.annotations.@AutoCreate- (removed)Beans are now being auto-created by default
org.jboss.seam.annotations.@Namejavax.inject.@Named
org.jboss.seam.annotations.@Injavax.inject.@Inject
org.jboss.seam.annotations.@Outjavax.enterprise.inject.@ProducesSEAM injection allowed @In and @Out to be paired, however @Inject and @Produces cannot be paired. In such cases @In @Out was changed to @Inject, the application should work even without the @Produces annotation.
org.jboss.seam.annotations.@Createjavax.annotation.@PostConstruct
org.jboss.seam.annotations.@Destroyjavax.annotation.@PreDestroy
org.jboss.seam.annotations.security.@Restrict- (removed)It was removed because it wasn't needed, however restrictions are being done differently now.

Bean scope

Old annotationNew annotationNote
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Scope;

@Scope(ScopeType.CONVERSATION)
class A …
import javax.enterprise.context.ConversationScoped;

@ConversationScoped
class A …
Every ScopeType.SOMETHING has a @SomethingScoped equivalent except for ScopeType.EVENT which I changed to @RequestScoped.

Issue with Bean scope

For the application to work properly it was not possible to keep the original scope for all beans. The beans that dealt with rendering the pages (or parts thereof) did not work if they were only @RequestScoped. For example this concerned beans that take care of dynamically rendered page fragments:

<ui:include src="#{model.mainArea.template}" />

The issue I encountered was that Ajax was not working in these fragments despite working outside of them. The solution was to change the affected beans to @ApplicationScoped (any lesser scope won't work).

 

Validation Constraints

Old AnnotationNew Annotation
org.hibernate.validator.NotNulljavax.validation.constraints.NotNull
org.hibernate.validator.Lengthorg.hibernate.validator.constraints.Length
org.hibernate.validator.NotEmptyorg.hibernate.validator.constraints.NotEmpty
org.hibernate.validator.Emailorg.hibernate.validator.constraints.Email

Annotations from the javax.persistence package (Id, Column, OneToMany, …) remain the same.

Seam 3 Security (access restriction)

NOTE: This isn't implemented in the application because it wasn't needed and because I stopped using Seam (except for Solder), the documentation of Seam Security can be found here. An alternative for this is PicketLink 3.

Seam security uses the class org.jboss.seam.security.Identity for identification. In terms of access restriction the important change between Seam 2 and 3 is in the methods addRole and hasRole:

  • Seam 2 - identity.addRole(String role)
  • Seam 3 - identity.addRole(String role, String group, String groupType)

 

 

When user is authenticated a role can be added to him ("admin") and based on that role we can restrict access:

Old way

import org.jboss.seam.annotations.security.Restrict;

@Restrict("#{s:hasRole('admin')}")
public void addAlbum(Album album) {
   // do something
}

New way

Admin @interface

import org.jboss.seam.security.annotations.SecurityBindingType;

@SecurityBindingType
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
public @interface Admin { }

Authorizer method

import org.jboss.seam.security.annotations.Secures;

public class Restrictions {   
    public @Secures @Admin boolean isAdmin(Identity identity) {
        return identity.hasRole("admin", "USERS", "GROUP");
    }
}

the important part is the @Secures annotation, the name of the method and of the class is up to you. The methods will become injection points.

Restrict access

public @Admin void addAlbum(Album album) {
   // do something
}

Programmatic Bean validation

There have been some changes in the way beans are validated programmatically:

Old way

import org.hibernate.validator.ClassValidator;
import org.hibernate.validator.InvalidValue;

ClassValidator<Album> shelfValidator = new ClassValidator<Album>(Album.class);
InvalidValue[] validationMessages = shelfValidator.getInvalidValues(album, "name");
if (validationMessages.length > 0) {
    for(InvalidValue i : validationMessages) {
        // do something
    }
}

New way

import javax.validation.ConstraintViolation
import javax.validation.Validation;
import javax.validation.Validator;

Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
Set<ConstraintViolation<Album>> constraintViolations = validator.validate(album);
if (constraintViolations.size() > 0) {
    for (ConstraintViolation<Album> cv : constraintViolations) {
        // do something
    }
}

 

Both InvalidValue and ContraintViolation provide getMessage() method which returns a String so the rest of the functionality is unchanged.

Event handling

In SEAM events were based on Strings. In CDI events are simple classes that can carry values. Detailed explanation of how events work in CDI can be found in the documentation. I will describe the steps I took in short.

1. Strings -> Enum

The Strings that were used to indicate events were changed into enum values:

Old way

New way

public static final String CHECK_USER_EXPIRED_EVENT = "checkUserExpiredEvent";
public static final String ADD_ERROR_EVENT = "addErrorEvent";
public static final String ALBUM_DELETED_EVENT = "albumDeleted";
public static final String ALBUM_EDITED_EVENT = "albumEdited";
…
public enum Events {
CHECK_USER_EXPIRED_EVENT,
ADD_ERROR_EVENT,
ALBUM_DELETED_EVENT,
ALBUM_EDITED_EVENT,
…
}

2. EventType and EventTypeQualifier

These two classes tell the beans what events you want to use. They work with the Events enum from previous step.

EventType

only needs the value() method with return type of the enum

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import javax.inject.Qualifier;

@Qualifier
@Retention(RUNTIME)
@Target({ FIELD,PARAMETER })
public @interface EventType {
    Events value();
}

EventTypeQualifier

Implements the EventType interface

import javax.enterprise.util.AnnotationLiteral;

@SuppressWarnings("all")
public class EventTypeQualifier extends AnnotationLiteral<EventType> implements EventType {
    private Events value;

    public EventTypeQualifier(Events value) {
        this.value = value;
    }

    public Events value() {
        return value;
    }
}

3. Events

I have created several events for special purposes in the photoalbum (all album related events can carry the album etc.), you will need at least one.

public class AlbumEvent {
    private Album album;
    private String path;

    public AlbumEvent(Album album) {
        this.album = album;
    }

    public AlbumEvent(Album album,String path) {
        this.album = album;
        this.path = path;
    }

    public Album getAlbum() {
        return album;
    }

    public String getPath() {
        return path;
    }
}

4. Firing events

Old way

New way

import org.jboss.seam.core.Events;

Events.instance().raiseEvent(Constants.ALBUM_ADDED_EVENT, album);
import org.richfaces.photoalbum.event.AlbumEvent;
import org.richfaces.photoalbum.event.EventType;
import org.richfaces.photoalbum.event.EventTypeQualifier;
import org.richfaces.photoalbum.event.Events;

@Inject
@Any // event of any type
Event<AlbumEvent> albumEvent;

albumEvent.select(new EventTypeQualifier(Events.ALBUM_ADDED_EVENT))
    .fire(new AlbumEvent(album));  
    // select the type of the event before firing

@Inject
@EventType(Events.ALBUM_ADDED_EVENT) // specific type of event
Event<AlbumEvent> albumEvent;

albumEvent.fire(new AlbumEvent(album)); // no need to select

5. Observing events

Old way

New way

import org.jboss.seam.annotations.Observer;

@Observer(Constants.ALBUM_ADDED_EVENT)
public void onAlbumAdded(Album album) {
    // process the event
}
import org.richfaces.photoalbum.event.AlbumEvent;
import org.richfaces.photoalbum.event.EventType;
import org.richfaces.photoalbum.event.Events;

import javax.enterprise.event.Observes;

public void onAlbumAdded(@Observes @EventType(Events.ALBUM_ADDED_EVENT) AlbumEvent ae) {
    // process the event
}

 


 

File upload

The way rich:fileUpload handles the uploading has been slightly changed.

Old class/method

New class/method

Note

org.richfaces.event.UploadEvent

*.FileUploadEvent

Just a name change

uploadEvent.getUploadItem()

fileUploadEvent.getUploadedFile()


org.richfaces.model.UploadItem

*.UploadedFile


uploadItem.getFileName():String

uploadedFile.getInputStream()

In case you used the filename to create an InputStream, otherwise there is a getName():String method.

Faces messages

Another thing that changed is the way of creating messages (which are later handled by rich:message components)

Old way

import org.jboss.seam.faces.FacesMessages;

@In FacesMessages facesMessages;

facesMessages.addToControl(Constants.SHELF_ID, Constants.SHELF_MUST_BE_NOT_NULL_ERROR, new Object[0]);

New way

import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;

FacesContext.getCurrentInstance().addMessage(Constants.SHELF_ID,
    new FacesMessage(Constants.SHELF_MUST_BE_NOT_NULL_ERROR));

(FacesContext can also be injected)

Changes in view layer

JSTL core namespace

xmlns:c="http://java.sun.com/jstl/core" has changed to "http://java.sun.com/jsp/jstl/core"

(in case you're switching to JSTL 1.2 or higher which you probably are)

Collection size in EL

It used to be possible to call bean.list.size() in EL but this no longer works - the EL resolver looks for a getSize() method which does not exist:

Old way

New way

<html …>
<h:outputText value="#{bean.list.size()}" />
</html>
<html …
xmlns:fn="http://java.sun.com/jsp/jstl/functions">

<h:outputText value="#{fn:length(bean.size)}" />
</html>

Custom skins

In case you were using custom skins you will find they are not working in RF 4. To solve the issue consult my previous blog post about resource optimization.

Unresolved issues

PARTIAL_STATE_SAVING

class java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to com.sun.faces.application.view.StateHolderSaver

I have encountered a - so far not reliably reproducible - issue with PARTIAL_STATE_SAVING being enabled (which is by default). The issue causes the application to stop responding to anything (and only showing the above error in the log, with no further explanation) but can be resolved by reloading the page. The problem seems to be in JSF itself (JSF_1427).

 

PSS can be disabled but a workaround has to be implemented because some RichFaces components will stop working (RF-12222).

 

However, when PSS is disabled drag-and-drop does not work (RF-10967). So in the end I had to enable it again.

In RichFaces 4.X custom skins do not work with resource optimization resulting in RF components not being properly styled. This is because your application expects a resource file named packed.css that contains styles for these components. This file is bundled with the predefined skins but not with your custom skin.

 

However you can generate that file with the resource plugin.

Get the URL

First make you sure you have resource optimization enabled in your web.xml:

 

<context-param>
     <param-name>org.richfaces.resourceOptimization.enabled</param-name>
     <param-value>true</param-value>
</context-param>

 

Your application is expecting to find the file on a specific URL, you need to find it and then generate the file on that location. The link to the missing file will look similar to this:

{code}<link type="text/css" rel="stylesheet" href="/richfaces-photoalbum/org.richfaces.resources/javax.faces.resource/org.richfaces.staticResource/4.2.3.Final/PackedCompressed/photoalbum/packed/packed.css">{code}

The important part is org.richfaces.staticResource/4.2.3.Final/PackedCompressed, you will need this to set up the plugin.

Set up the plugin

Create a richfaces.version property in your pom.xml if you haven’t already (this makes it easier when you upgrade to a new version),

 

<properties>
     <richfaces.version>4.2.3.Final</richfaces.version>
       …
</properties>

 

and put this inside the <build> element:


<plugin>
     <groupId>org.richfaces.cdk</groupId>
     <artifactId>maven-richfaces-resources-plugin</artifactId>
     <version>${richfaces.version}</version>
     <configuration>
          <skins>
               <!-- the name of your skin -->
               <skin>photoalbum</skin>
          </skins>
          <excludedFiles>
               <exclude>^\Qorg.richfaces.renderkit.html.images.\E.*</exclude>
               <exclude>^\Qorg.richfaces.renderkit.html.iconimages.\E.*</exclude>
          </excludedFiles>
          <includedContentTypes>
               <include>text/css</include>
               <include>image/.+</include>
          </includedContentTypes>
          <fileNameMappings>
                <property>
                     <name>^.*showcase.*/([^/]+\.css)$</name>
                     <value>org.richfaces.showcase.css/$1</value>
                </property>
                <property>
                     <name>^.+/([^/]+\.(png|gif|jpg))$</name>
                     <value>org.richfaces.images/$1</value>
                </property>
                <property>
                     <name>^.+/([^/]+\.css)$</name>
                     <value>org.richfaces.css/$1</value>
                </property>
          </fileNameMappings>
     </configuration>
     <executions>
          <execution>
               <id>process-resources</id>
               <goals>
                    <goal>process</goal>
               </goals>
               <configuration>    
                    <!-- the actual name of this file is not important but it should be inside the META-INF folder -->
                    <staticResourceMappingFile>${project.build.outputDirectory}/META-INF/richfaces/photoalbum-packedcompressed-resource-mappings.properties</staticResourceMappingFile>
                    
                    <!-- the URL part goes after /META-INF/resources/ -->
                    <resourcesOutputDir>${project.build.outputDirectory}/META-INF/resources/org.richfaces.staticResource/${richfaces.version}/PackedCompressed/</resourcesOutputDir>
                    
                    <!-- replace completely with the URL part -->
                    <staticResourcePrefix>org.richfaces.staticResource/${richfaces.version}/PackedCompressed</staticResourcePrefix>
                        
                    <pack>true</pack>                            
                    <compress>true</compress>

                    <excludedFiles>
                         <exclude>^javax.faces</exclude>
                         <exclude>^\Qorg.richfaces.renderkit.html.images.\E.*</exclude>
                         <exclude>^\Qorg.richfaces.renderkit.html.iconimages.\E.*</exclude>
                         <exclude>^jquery\.js$</exclude>
                    </excludedFiles>

               </configuration>
          </execution>

          <!-- If you are in Development stage the compression is ignored, include this execution to generate uncompressed files --> 

          <execution>
               <id>process-resources-packed</id>
               <goals>
                    <goal>process</goal>
               </goals>
               <configuration>
                    <staticResourceMappingFile>${project.build.outputDirectory}/META-INF/richfaces/photoalbum-packed-resource-mappings.properties</staticResourceMappingFile>
                            
                    <!-- the directory is named “Packed”, not “PackedCompressed” as in the previous execution -->
                    <resourcesOutputDir>${project.build.outputDirectory}/META-INF/resources/org.richfaces.staticResource/${richfaces.version}/Packed/</resourcesOutputDir>
                    <staticResourcePrefix>org.richfaces.staticResource/${richfaces.version}/Packed</staticResourcePrefix>
                            
                    <pack>true</pack>
                    <compress>false</compress> <!-- do not compress -->

                    <excludedFiles>
                         <exclude>^javax.faces</exclude>
                         <exclude>^\Qorg.richfaces.renderkit.html.images.\E.*</exclude>
                         <exclude>^\Qorg.richfaces.renderkit.html.iconimages.\E.*</exclude>
                         <exclude>^jquery\.js$</exclude>
                    </excludedFiles>
               </configuration>
          </execution>
     </executions>
</plugin>

Excuse the weird highlighting.

The important tags are resourcesOutputDir and staticResourcePrefix. Change them according to the URL part for the missing file (and replace the RichFaces version with ${richfaces.version}).

 

Now you can run the maven build and all necessary files will be generated. Enjoy your custom skin.

Notes

Plugin execution not covered by lifecycle configuration: org.richfaces.cdk:maven-richfaces-resources-plugin:4.2.3.Final:process (execution: process-resources-packed, phase: process-classes)


Your IDE may complain complain like (JBDS does) this but you can ignore that.

 

Troubleshooting

Skin not found

 

WARNING: Error creating resource org.richfaces.renderkit.html.BaseGradient

javax.faces.FacesException

          at org.richfaces.application.DependencyInjectionServiceImpl.inject(DependencyInjectionServiceImpl.java:361)

          at org.richfaces.resource.ResourceFactoryImpl.injectProperties(ResourceFactoryImpl.java:197)

          at org.richfaces.resource.ResourceFactoryImpl.createHandlerDependentResource(ResourceFactoryImpl.java:320)

          at org.richfaces.resource.ResourceFactoryImpl.createDynamicResource(ResourceFactoryImpl.java:468)

          at org.richfaces.resource.ResourceFactoryImpl.createResource(ResourceFactoryImpl.java:412)

          at org.richfaces.cdk.resource.handler.impl.DynamicResourceHandler.createResource(DynamicResourceHandler.java:85)

          at org.richfaces.cdk.resource.handler.impl.AbstractResourceHandler.createResource(AbstractResourceHandler.java:42)

          at org.richfaces.cdk.task.ResourceTaskFactoryImpl$ResourcesRendererCallable.createResource(ResourceTaskFactoryImpl.java:71)

          at org.richfaces.cdk.task.ResourceTaskFactoryImpl$ResourcesRendererCallable.renderResource(ResourceTaskFactoryImpl.java:83)

          at org.richfaces.cdk.task.ResourceTaskFactoryImpl$ResourcesRendererCallable.call(ResourceTaskFactoryImpl.java:155)

          at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)

          at java.util.concurrent.FutureTask.run(FutureTask.java:166)

          at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)

          at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)

          at java.util.concurrent.FutureTask.run(FutureTask.java:166)

          at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)

          at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)

          at java.lang.Thread.run(Thread.java:722)

Caused by: java.lang.reflect.InvocationTargetException

          at sun.reflect.GeneratedMethodAccessor23.invoke(Unknown Source)

          at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

          at java.lang.reflect.Method.invoke(Method.java:601)

          at org.richfaces.application.DependencyInjectionServiceImpl.invokeMethod(DependencyInjectionServiceImpl.java:187)

          at org.richfaces.application.DependencyInjectionServiceImpl.inject(DependencyInjectionServiceImpl.java:354)

          ... 17 more

Caused by: org.richfaces.skin.SkinNotFoundException: Skin with name photoalbum not found

          at org.richfaces.skin.AbstractSkinFactory.getSkin(AbstractSkinFactory.java:161)

          at org.richfaces.cdk.skin.SkinFactoryImpl.getSkin(SkinFactoryImpl.java:49)

          at org.richfaces.renderkit.html.BaseGradient.initialize(BaseGradient.java:124)

          ... 22 more

Caused by: java.util.concurrent.ExecutionException: org.richfaces.skin.SkinNotFoundException: Skin with name photoalbum not found

          at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:252)

          at java.util.concurrent.FutureTask.get(FutureTask.java:111)

          at org.richfaces.skin.AbstractSkinFactory.getSkin(AbstractSkinFactory.java:157)

          ... 24 more

Caused by: org.richfaces.skin.SkinNotFoundException: Skin with name photoalbum not found

          at org.richfaces.skin.AbstractSkinFactory.loadProperties(AbstractSkinFactory.java:133)

          at org.richfaces.skin.AbstractSkinFactory.buildSkin(AbstractSkinFactory.java:107)

          at org.richfaces.skin.AbstractSkinFactory$SkinBuilder.call(AbstractSkinFactory.java:56)

          at org.richfaces.skin.AbstractSkinFactory$SkinBuilder.call(AbstractSkinFactory.java:47)

          at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)

          at java.util.concurrent.FutureTask.run(FutureTask.java:166)

          at org.richfaces.skin.AbstractSkinFactory.getSkin(AbstractSkinFactory.java:156)

          at org.richfaces.cdk.skin.SkinFactoryImpl.getSkin(SkinFactoryImpl.java:49)

          at org.richfaces.resource.CompiledCSSResource.getSkinHashCode(CompiledCSSResource.java:142)

          at org.richfaces.resource.CompiledCSSResource.writeState(CompiledCSSResource.java:217)

          at org.richfaces.util.Util.saveResourceState(Util.java:468)

          at org.richfaces.cdk.resource.handler.impl.DynamicResourceHandler.createResource(DynamicResourceHandler.java:89)

          ... 12 more

If you encounter this error during the maven build (the actual stacktrace will be far longer) your custom skin is missing from the classpath. To fix it add the directory containing the skin as a resource to pom.xml:

 

<build>
     <resources>
          <resource>
               <directory>path/to/your/skin</directory>
          </resource>
            …
     </resources>
        …
</build>