Blogs Blogs

OpenXava 4.2.2 released OpenXava 4.2.2 released

OpenXava 5.9 released

May 23, 2018

OpenXava 5.9 allows to cut & paste in collections, the user can follow modules to get email notifications of changes, customizable access tracking, improvements in listscharts and collection totals, and many more things.

We invite you to download it and upgrade your OpenXava applications. Look at the migration instructions.

Cut & paste in collections

New buttons for cut & paste are available in all collections. The user can cut and paste between collection of the same type, even from different modules:

Follow modules

The user can follow any module just by clicking on an icon on the right top corner:

After clicking on it any change done by other users on the data of that module will be notified via email to him. He can click on any moment on the same button to unsubscribe. In order to work the user need to have a valid email defined in his account (XavaPro or Liferay) or well to use a valid email as user name (also available with plain OpenXava in Subscribing to a module is not available for modules with @Tab with baseCondition for security reasons.
Moreover, when a user creates a new record, all the changes in that invididual record by other users are emailed to him.
In each message the user has links to remove his subscription.
The changes notified are: creation of new records, modification, deletion of records, adding comment to discusion, adding/removing images from gallery, adding/removing attached files and modification of collections.

In the case of modification the email message informs about the properties modified with the old and new values. 

Look at the instructions to activate this feature in your applications.

Access tracking

OpenXava has a new mechanism to track any change done by users to the data and also read access. This mechanism is totally configurable and it's disable by default.

To track the data access you need an IAccessTrackerProvider (an interface from org.openxava.util). Creating one is easy, just create a class that implement that interface, like the next one:

package org.openxava.util;

import java.util.*;

import org.apache.commons.logging.*;
import org.openxava.application.meta.*;

public class LogAccessTrackerProvider implements IAccessTrackerProvider {

    private static Log log = LogFactory.getLog(LogAccessTrackerProvider.class);

    private static String fileName;

    public void consulted(String modelName, Map key) {
        log("CONSULTED: user=" + Users.getCurrent() +    ", model="
            + modelName + ", key=" + key);

    public void created(String modelName, Map key) {
        log("CREATED: user=" + Users.getCurrent() +    ", model="
            + modelName + ", key=" + key);

    public void modified(String modelName, Map key,
        Map oldChangedValues,
        Map newChangedValues)
        StringBuffer changes = new StringBuffer();
        for (String property: oldChangedValues.keySet()) {
            if (changes.length() > 0) changes.append(", ");
            changes.append(": ");
            changes.append(" --> ");
        log("MODIFIED: user=" + Users.getCurrent() +    ", model="
            + modelName + ", key=" + key + ", changes=" + changes);

    public void removed(String modelName, Map key) {
        log("REMOVED: user=" + Users.getCurrent() +    ", model="
            + modelName + ", key=" + key);

    private static void log(String line) {
        try {
            FileOutputStream f = new FileOutputStream(getFileName(), true);
            PrintStream p = new PrintStream(f);
        catch (Exception ex) {
            log.warn(XavaResources.getString("log_tracker_log_failed"), ex);

    private static void createFileIfNotExist() throws Exception {

    private static String getFileName() {
        if (fileName == null) {
            Collection applicationNames = MetaApplications.getApplicationsNames();
            String app = "openxava-app";
            if (!applicationNames.isEmpty()) {
                app = applicationNames.iterator().next().toString().toLowerCase();
            fileName = Files.getOpenXavaBaseDir() + app + "-access.log";
        return fileName;


This is the simplest possible implementation, just it registers the accesses in a log file. Note that you have to implement four simple methods: consulted(), created(), modified() and removed(). You can write your own tracker provider to include more data and to save the accesses in a database table, for example. The above tracker provider, LogTrackerAccessProvider, is included in OpenXava, in the package org.openxava.util, so you can use it "as is" if you don't need more. In order that your tracker provider works you have to declare it in of your project, using the accessTrackerProvidersClasses entry:


You can declare several access tracker providers separated by commas. Now, all changes and read access from the users will add a line in the .openxava/yourapplication-accesss.log file.

Lists improvements

Record count in list when "Group by" is used:

Note the "Record count" column, now available in all lists when you group.

Selecting filter/order configuration and grouping are available in all list format, including cards and charts:

Therefore the user can select a filtering from cards or charts, moreover the filter selected is remembered from session to session. However, now only the filter selected using the combo is remembered, if the user does a filtering entering values and clicking on filter button it is not set as default for the next time, this is a user experience improvement over 5.8.

Charts improvements

We have done a great effort to make the charts finally useful:

Note as you can group in charts, that pie shows the amount instead of percentage, that you cannot add more columns in pie, that you can change the filtering, etc. A lot of improvements, here is the complete list:

  • Data shown in charts is the data currently filtered in list.
  • Group summation in list is shown correctly when changing to charts.
  • Record count when "Group by" is available in charts.
  • Pie charts sums the results of the same category automatically.
  • Pie charts group the data and summarize even if the list is not grouped.
  • In pie charts the user can only choose a column for y values.
  • Group by for pie charts shows the summation of each group.
  • X column is not shown by default as Y column too in charts.
  • Pie charts show the real value instead of percentage, percentage is shown on hover.
  • Chart fits in the space available in the page.
  • Improved charts layout for Liferay.
  • Improved placement of buttons for choosing chart type.
  • Columns in charts show their qualified labels if they are from references.

Collection totals

Now total properties can be editable, not just calculated ones. Also a total property can be annotated with @Calculation. Therefore you can define the @ListProperties in this way:

@ListProperties("quantity, amount[invoice.amountsSum, invoice.vatPercentage, invoice.vat,]")

Where vatPercentage is a persistent property. This property will be shown in the totals, will be editable and work as a regular property in any other place. In this case vat and total are persistent properties annotated with @Calculation and @ReadOnly:

In v5.9 it's possible to combine column summation (the + in the property) with total properties, so you can write this @ListProperties:

@ListProperties("vatPercentage, total+[workCost.profitPercentage, workCost.profit,]")

Note the + after total and then the total properties inside [].This produces the next effect:

Here the 131.08 is the sum of the column, because of total+. Below you have profitPercentage, profit and total, the regular total properties. You can reference the column summation (that is the total+, the 131.08) from a @Calculation property using sum(columnName). For example, in this case you could define profit property in this way:

@Calculation("sum( * profitPercentage / 100")
private BigDecimal profit;

In this case the sum( inside @Calculation is the summation of the total property of all the elements of invoices collection, that is the same of total+ in @ListProperties, that is the 131.08 you see in the image.

Other improvements

We have done a lot of improvements in other areas:

  • @OneToMany collections show totals even if the collection has no lines.
  • The user can get the sum of any numeric column in calculated collections, @ElementCollection and @OrderColumn lists.
  • @ListProperties allows + as suffix for column sum in calculated collections, @ElementCollection and @OrderColumn lists.
  • Improved user experience for DISCUSSION.
  • Collection row count is shown in section label when the collection is the only section element.
  • Welcome and Sign In are separated pages, accessing to root goes to Welcome page.
  • Adding action to browser URL only for "new" actions.
  • Booleans in list and collections show the label of the property for true values instead of a check icon.
  • Summation in @OneToMany collections is available even if the list is empty.
  • New property fixModulesOnTopMenu in to have certain modules always present in top menu.
  • @Calculation property that depends on other @Calculation property is recalculated if the original is recalculated.
  • New method moveCollectionElementToAnotherCollection() in MapFacade.
  • Log includes module change with user host and user name.
  • Log for action execution include user host and name.
  • IJavaScriptPostAction to execute JavaScript after regular action execution.
  • IAvailableAction so an action can determine if it will be available or hidden programmatically.
  • Calculated collections supported for DefaultListActionsForCollections and DefaultRowActionsForCollections.
  • Some new common use labels to be used in applications.
  • IMetaPropertyFormatter to use the MetaProperty of the value to format or parse.
  • Improved Strings.naturalLabelToIdentifier() behavior to work with % character.
  • New method recursiveCloneWithCollections() in Maps utility class.
  • <xava:message/> taglib supports param1, param2, param3 and param4 to send parameters to the message.
  • New methods treeToPlainIncludingCollections() and getKeyFromValue() in Maps utility class.
  • New method isArray() in XArrays utility class.
  • Is.equal() and Is.empty() work fine with Java native arrays.
  • New sendInBackground() methods in Emails class to send emails in background.
  • New method setValuesNotTracking() in MapFacade.
  • New method createFileIfNotExist() in Files utility class.
  • New method Strings.toString() for doing a decent toString() of any object, supporting dates, numbers, arrays, etc.

Bug fixes

Though this is not a maintenance version we have done some fixes:

  • Fix: Totals has the font size too small.
  • Fix: Two collections in a line inside Liferay Portal 6.1.2 are displayed one below another.
  • Fix: Messages are not shown from dialog in Chrome.
  • Fix: @Depends does not work for collection total properties.
  • Fix: In detail only modules the view is not editable by default.
  • Fix: Import data fails when the file to import has empty numeric data.
  • Fix: Duplicate modules in menu when modules defined in application.xml.
  • Fix: The methods assertTotalXXX() of ModuleTestBase do not work if the collection has no lines.
  • Fix: When no @View is specified collection total properties are shown in main view and collection totals.
  • Fix: The default filter/order configuration is not available in some cases.
  • Fix: WebURL editor has an invisible space on right that misplaces next editor.
  • Fix: Incorrect rounding in list and collection summation.
  • Fix: Charts are misplaced with Internet Explorer.
  • Fix: Witn FILE steoretype adding a file, removing it and add it again fails.

Download OpenXava 5.9


blog comments powered by Disqus