Monday, March 19, 2012

NextReports Engine : Report Conversion

Version 5.1 of NextReports was already released, but  there is the time to look into next version.

One of the biggest feature, NextReports will resolve in version 5.2 is report conversion. This is not a 'visible' feature to the end user, but a back-end functionality.

NextReports supported from start back-end compatibility with older type of reports. Any new functionality was brought to life without breaking compatibility. For NextReports Engine users (developers) this means that anytime when a ReportUtil.loadReport(String xml) or a ReportUtil.loadReport(InputStream is) was done, no xml exception was raised.

To be more flexible in NextReports evolution, an entirely new convert process was integrated. Using a chain of xml converters, a Next report can be modified to a new structure. Practically if a report with version X is loaded by an Y version of engine, where Y > X, the load method will do the following:
  • get report version (X in this case)
  • apply a converter chain process if needed
  • load the resulted xml
To explain the second step,  for example if we have a Converter_X1 (to version X1) and a Converter_X2 (to version X2) with X < X1 < X2 < Y then conversions X->X1 and X1->X2 are needed,they are applied using a chain of responsibility order and the new version of report is set to Y.

The only difference to NextReports Engine is the signature of the load method from ReportUtil class which now throws a LoadReportException:
public static Report loadReport(String xml) throws LoadReportException { ... }

Friday, March 09, 2012

NextReports : Notifications with Wicket Push

With version 5.1, NextReports Server implements a much-desired feature: message notification.

In previous versions, when a report was manually set to run, user was redirected to Monitor section. Here running processes can be seen and with an auto-refresh at some time the result will appear in history table, containing the link to the document.

In current version, after a manually run, a message in the top right corner will notify that the process started and that a new message will be issued after finish. This first message has a short life of 5 sec and it will disappear after time elapsed. When process is finished, a new message will be shown containing the link to resulted document. This message will live until the user will close it.


If an error occurred  during export process, an error message will be shown.


To see the actual error user has to go to Monitor section and look in history table to "Success" column.


If you schedule a report, you will only be notified about it. No messages when the process is finished will be issued.


To implement this notification feature, NextReports uses wicket-stuff push and jQuery jGrowl.

Using a general Observer pattern, first we need an event ReportResultEvent and a listener interface:
public interface ReportListener {    
    public void onFinishRun(ReportResultEvent result);
} 
Our ReportService will manage report listeners for current logged user:
public void addReportListener(ReportListener reportListener) {
    reportListeners.put(SecurityUtil.getLoggedUsername(), reportListener);        
}

public void removeReportListener() {        
    reportListeners.remove(SecurityUtil.getLoggedUsername());
}

public void notifyReportListener(ReportResultEvent event) {
    ReportListener reportListener = reportListeners.get(event.getCreator());
    if (reportListener != null) {
        reportListener.onFinishRun(event);
    }
}
When the process is finished we will create the event and we will notify all listeners:
ReportResultEvent event = new ReportResultEvent(...);
reportService.notifyReportListener(event);
To use jGrowl in Wicket it's easy with an AjaxBehavior. Messages will be kept in Session FeedbakMessages list.
public class MessageAjaxBehavior extends AbstractDefaultAjaxBehavior {

   public void renderHead(IHeaderResponse response) {

     super.renderHead(response);      
     response.renderJavascriptReference(
         new JavascriptResourceReference(MessageAjaxBehavior.class, "jquery.jgrowl.js"));
     response.renderCSSReference(
         new CompressedResourceReference(JGrowlAjaxBehavior.class, "jquery.jgrowl.css"));
     response.renderCSSReference(
         new CompressedResourceReference(JGrowlAjaxBehavior.class, "jgrowl.css"));

     String feedback = renderFeedback();
     if (!StringUtils.isEmpty(feedback)) {
         response.renderOnDomReadyJavascript(feedback);
     }

   }

   protected void respond(AjaxRequestTarget target) {
     String feedback = renderFeedback();
     if (!StringUtils.isEmpty(feedback)) {
        target.appendJavascript(feedback);
     }
   }
   ....... 
}
Rendered feedback message contains the jgrowl javascript text. Message can be sticky to live until user close it, or it can have a time-elapsed life using life with a millisecond value.
$.jGrowl("message",   
           {
             theme: 'css-class',
             sticky: true        //  life: 5000        
           }
        )
All options of jGrowl can be found here.

Finally our wicket page will contain a message label:
Label messageLabel = new Label("message", "");
messageLabel .setOutputMarkupId(true);
messageLabel .add(new MessageAjaxBehavior());
And we will initialize push service:
protected void onInitialize() {

    super.onInitialize();

    initPush();
           
    reportService.addReportListener(new ReportListener() {            
            
        public void onFinishRun(ReportResultEvent result) {                

            if (pushService.isConnected(pushNode)) {
                // forward the Message event via the push service 
                // to the push event handler
                Message message = createMessage(result);
                pushService.publish(pushNode, message);
            }
        }
    });
}

private void initPush() {

    // instantiate push event handler
    IPushEventHandler handler = new AbstractPushEventHandler() {     
            
        public void onEvent(AjaxRequestTarget target, Message event, 
                            IPushNode node, IPushEventContext context) {
            
            getSession().getFeedbackMessages().add(
                         new FeedbackMessage(null, event.getText(), messageType));
            target.addComponent(messageLabel);
        }       
    };

    // obtain a reference to a Push service implementation
    pushService = TimerPushService.get(); 
        // install push node into this panel
    pushNode = pushService.installNode(this, handler);
}

Wednesday, February 29, 2012

NextReports: Some Internal Tips

From version 5.1, NextReports Designer allows to instantly open some report or chart  when it starts.

There are some system properties which can be used to achieve this:

next.datasource
This property is similar to singleSourceAutoConnect, but when we have more than one data source. NextReports Designer will start and it will connect to this datasource.

next.report 
If there is a connected data source (specified by next.datasource system property) this report will be auto-loaded.

next.chart
If there is a connected data source (specified by next.datasource system property) this chart will be auto-loaded.

next.path
If the report or chart is not found in the root node, but inside some folder, this property will specify the relative path.  Slashes or back-slashes can be used in any combination.

If both next.report and next.chart  system properties are specified, chart property is ignored. 

For your installed designer, you can specify system properties inside nextreports.vmoptions file.
For example adding these lines at the end of the file
-Dnext.datasource=Demo 
-Dnext.report=Timesheet
it will make your designer on start to auto-connect to Demo data source and to automatically open Timesheet report.

If your report is found inside /Test/Test1 folder path
-Dnext.datasource=Demo 
-Dnext.report=Timesheet
-Dnext.path=/Test/Test1
Path is converted to use specific file system separator, so you can enter it as you wish (/Test/Test1, Test/Test1, Test//Test1, \\Test\\Test1, Test\\Test1, \Test\Test1).

Thursday, February 16, 2012

NextReports: URL Custom Protocol & Version Dispatcher

When NextReports Server started its existence, users were able to upload reports and charts using server actions. This means:
  • a data source was already created
  • user selects the report from current location
  • user selects the existing data source
  • user selects the images used (if any) from current location
  • report/chart is uploaded in the current server path
After some versions, NextReports  Designer was able to allow publishing to server:
  • user selects server path
  • user selects a server data source; if there isn't created, he can publish it with a single click
  • when publish, used images are also published by default
Starting with version 5.1 a server action will allow to edit a report / chart with the designer:
  • no browsing needed
To allow this, a nextreports protocol is registered when NextReports Designer is installed. If this protocol is found, server edit action will open the designer asking for current logged user password:


After authentication, a data source is locally created (if not found) with following name convention:
<server_data_source_name>@<server_ip>
Designer will auto-connect to this data source and the report/chart is downloaded. If a report/chart with the same name exists, user is notified:


After downloading, the report/chart is automatically opened and user can start to edit it. When user saves it, a confirmation is needed to publish it also on the server:


Server 'Edit' action will launch an url request like:
nextreports://<server>?user=<loggeduser>&ver=<serverversion>&ref=<serverpathtoentity>
This can also be a simple  method to pass to someone a report to edit. If that person can access the report (has the needed rights) you do not need to tell him the server, location and let him download the report, modify it and publish it back. You just give him an url.

Specified version is used to open the needed designer which has the same version as the server avoiding following situations:
  • server version is older than designer version: you can download the report and edit it, but you cannot publish it to server
  • server version is newer than designer version: you cannot download the report
This is done by a dispatcher(installed with the designer) which is launched by nextreports URL protocol shell command.

If the designer with that version is not installed, user is informed and he can download the correct version from the links shown with the message:


If you are a Linux user, you do not have a dispatcher to start your needed version of NextReports, but you can register your nextreports url protocol with following commands:
gconftool-2 -t string -s /desktop/gnome/url-handlers/nextreports/command 
         '<installed_dir>/nextreports "%s"'
gconftool-2 -s /desktop/gnome/url-handlers/nextreports/needs_terminal false -t bool
gconftool-2 -s /desktop/gnome/url-handlers/nextreports/enabled true -t bool

Monday, February 06, 2012

NextReports: Variables, Functions & Expressions

NextReports has a simpler way of working with data, than other reporting solutions.

For example, inside iReport for JasperReports you can define a so-called variable just to use it in another fields. The problem with this approach is that the user must specify when this variable must be evaluated and when to be reset. (like page, report, group, column types). This is no easy task for non-business users who want to create some reports. This also can bring some invalid calculations if the user does not understand what he is doing.

NextReports does not have user-defined variables. In NextReports Variables are just application-defined like ROW, GROUP_ROW, PAGE_NO and so on.

Instead, users can create Expressions and Functions. Expressions can contain text, variables, parameters, columns and functions (from version 5.1). Functions can be any of SUM, AVERAGE, MIN, MAX, COUNT, COUNT DISTINCT and can be done on sql column or on expression.

For NextReports a field is evaluated if it is found inside layout. So, users do not need to ask themselves when to evaluate something. If you need an expression just to compute something without showing the result, you can make it hidden. But, you will always know when the expression is evaluated without asking yourself.

If we have two functions inside a group footer band

$F{SUM(HOURS)} : computes the sum of hours for a project (work, travel, administration, meeting)
$F{SUM(WORKHOURS)} : computes the sum of implementation hours

and we want also to see how much implementation represents in percentage, it is very easy to create an expression. From version 5.1 the user can select the functions found in the current band, in this case $F{SUM(HOURS)} and $F{SUM(WORKHOURS)}.


Report layout will show the defined expression:


Because functions are interpreted as double values the division will create a double. If you have an integer column $C_HOURS for example and you want to use div operations, be sure to convert it to double like $C_Hours.doubleValue(), otherwise the result will be an integer.


Result can be formatted with pattern property like in following exported pdf: