At our community conference in Frascati yesterday I gave a talk on how to replace the old GWT report viewer with a slim CDF based report viewer.
Giving Granny a Face-Lifting
This is the slightly edited full-text version of this talk.
Are you tired of our trusted GWT report viewer
When we introduced Pentaho Reporting 3.5, one of the major new features we added was the ability to run Pentaho Reports directly in the BI-Server without the need for writing or generating XActions. This feature instantly removed the number one headache our users had with reports on the server – the need for an additional runtime file, the XAction. The file contained the same information they already specified in the report designer. But to edit the file later, they would need to go into a totally different editor to do some sort of magical programming. Ordinary business users could and would not do that.
We created the report viewer with Google’s Webtoolkit, which promised an easy way of creating rich JavaScript UIs without having to resort to homegrown libraries.
Where has all the love gone?
There are no simple solutions. GWT turned out to create monolithic code that lived on its own island. GWT applications were nearly impossible to extend for normal (non-GWT-using) web-developers. The code was hard to debug (as normal debugger like Firebug cannot help much to make sense out of the autogenerated code). And GWT was slow. Slow to compile and slow to run (compared to other JavaScript alternatives).
Our partners had no particular love for GWT, and bit by bit we grew tired of it as well. Over time we realized that GWT would not be the silver bullet.
Our report viewer implementation also suffered from a few deficiencies. There is no easy way to create alternative layouts for the parameter UI, the date parameter input is simple and limited and long parameter texts can cause problems.
In the mean time, our consultants and partners worked around these limitations by using CDF to build custom parameter pages for reports.
And then replace the GWT Viewer
… with a normal CDF-Dashboard?
CDF instantly solved several of their problems. In CDF you are free to design your parameter page the way you like it. CDF is by far more flexible than the GWT viewer (as you have simple code with loads of extension points available). CDF is made to create interactive dashboards with a rich user experience.
And CDF comes with a PRPT component, so it already knows how to drive a report.
… but you know you pay the price
But once again: There is no magic silver bullet. Writing an extra CDF file suffers from the same problem that XActions have. Suddenly you have to duplicate the parameter information from the report designer into the dashboard. You have to replicate all parameter dependencies.
CDF requires some technical skill to create a dashboard. Similar to XActions, the report designer cannot read a CDF file for editing (and given that CDF is JavaScript that you can program in any way you want, there is no way we could ever hope to build such an editor). CDFs duplicate the information that is already in the report, and any change to the report parameters must also be applied to the dashboard.
Creating CDF files is not free – your IT department or an external consultant has to do it for the ordinary business user. So from a business point of view, that sort of “premium parameter viewer” would only be feasible for critical reports where you can justify the high development and maintenance costs.
To make CDF work for all reports, we need to solve the “duplication of parameter information” problem.
A simple solution:
Let PRPT’s information drive CDF
Mike D’Amour architected the GWT reporting plugin as a RESTful service. We do intentionally avoided all of the GWT server side libraries to communicate with the server. The report viewer uses standard HTTP-GET or PUT calls to query the server, which responds either with content or XML files.
The report viewer only uses the server’s public URLs to get information about the report’s current parameters. In fact, anyone can call these URLs to get the same information. We do not have any limits on what kind of client you use to interact with the reporting plugin.
Flow, Report Viewer, Flow
The GWT report viewer uses a very simple algorithm to communicate with the server.
- First we query the parameter XML by passing all known parameter to the server.
- We parse the XML and render the UI
- We check whether the server found any problems with the parameter we given. If everything is OK, we ask the server for the report content.
- We wait for input from the user.
- On any new input or if the user hits submit, we go back to the start and query the parameter-XML again.
You can find more information about this cycle in one of my previous postings.
Action time
Click here to see a simple form-based parameter page. This demonstrates how to communicate with a Pentaho BI-server and shows the basic steps to parametrize an existing report. If you see a login window in the lower frame, then login and restart the demo.
The form itself is simple:
<html> <head> <title>Report Viewer <body> <div style="border: 1px solid black; margin-bottom: 20px"> <h1>Parameter Input <hr /> <form action="http://demo.pentaho.com/pentaho/content/reporting" method="GET" target="viewer"> <div> Report to load: <input name="solution" value="steel-wheels"/> <input name="path" value="reports"/> <input name="name" value="Invoice Statements.prpt"/> </div> <h2>System parameter</h2> <label for="renderMode">Render Mode</label> <select id="renderMode" name="renderMode" size="1"> <option value="REPORT">REPORT</option> <option value="XML">XML</option> </select> <label for="output-target">Output Target</label> <select id="output-target" name="output-target" size="1"> <option value="table/html;page-mode=stream">Single page HTML (table/html;page-mode=stream)</option> <option value="table/html;page-mode=page">Paginated page HTML (table/html;page-mode=stream)</option> </select> <h2>User parameter</h2> <label for="Customer">Customer</label> <input type="text" id="Customer" name="CustomerNo" value="242"/> <label for="ReportStamp">Report Stamp</label> <input type="text" id="ReportStamp" name="Report Stamp" value="Review"/> <div/> <input type="submit"value="Go!"/> </form> <h1>Report</h1> <iframe name="viewer" width="100%" height="50%"/> </div> </body> </html>
In the first section we setup a few system level parameter. The form contains the path to the report we want to render (expressed as Pentaho Standard Triple – solution, path, name), the renderMode (that defines whether we query parameter information (XML) or whether we render the report (REPORT)) and finally the output target that defines what output the server should generate.
This form is already a valid method to supply parameter to the reporting plugin and shows that there is no magic involved.
Now, lets do the same again … in CDF
Jordan Ganoff wrote a prototype of a CDF dashboard reads the parameter information from the Pentaho reporting plugin to construct a dashboard.
Due to some security restriction in the JavaScript execution in browsers (same origin rule) I cannot provide a one-click example. Download the zip file and copy the contents into your BI-Server’s solution directory.
You can then switch to the new parameter viewer by replacing the “reportviewer/report.html” part with “web/reportviewer.html”.
So the original URL for your GWT report viewer
http://localhost:8080/pentaho/content/reporting/reportviewer/report.html?solution=steel-wheels&path=%2Freports&name=Invoice+Statements.prpt&locale=en_US
becomes this URL
http://localhost:8080/pentaho/content/reporting/resources/web/reportviewer.html?solution=steel-wheels&path=%2Freports&name=Invoice+Statements.prpt&locale=en_US
(Download the CDF based report viewer)
Lets hand over the microphone to Jordan to explain the architecture of this implementation.
Here’s a quick introduction:
The new report viewer is a collection of CDF components. You can follow
the logic starting in reportviewer.html’s load() function. We set up a
div to inject the prompt panel into and then call:
pentaho.common.prompting.createPromptPanel({ destinationId: "promptPanel", paramDefn: reportViewerParameterLookup(), refreshParamDefnCallback: reportViewerParameterLookup, extraComponents: [{type: "SubmitReportComponent", htmlObject: 'report-div'}] });
- destinationId: the element Id where the prompt panel will be injected into.
- paramDefn: this is the parameter definition (parsed Parameter XML into an object)
- refreshParamDefnCallback: function called whenever a parameter has changed its value. For now we will hit the ParameterXmlContentGenerator for a new parameter xml and parse it to a parameter definition every time a parameter value has changed.
- extraComponents: Any additional cdf components you’d like initialized. I have a quick prototype component defined in reportviewer.html called “SubmitReportComponent” that will listen for the parameter “submit” to change (which is fired by the submit button on the prompt panel). When this parameter changes the update() method of the SubmitReportComponent is called. We build a valid reporting url and set the iframe’s src to that url to load the report. Pretty straight forward and is exactly how the existing report viewer works today.
Core architecture: the parameter panel itself is a CDF component which defines a layout for all widgets provided. The submit button widget is configured to listen to all CDF components created from any non-hidden parameter. Any time the submit component receives a parameter change event its update() function is called and we check if all parameters are valid. If they are all valid we fire a change event for the parameter “submit” which someone else can listen to and do what they need to do.
Once all components are created we pass them to CDF to initialize them. This will register them CDF and eventually calls update() on all components. It’s this update() that will inject the CDF components into the page.
That being said, the thinking here is that in the future anyone can create a prompting panel from a parameter xml and provide their own callback when the submit button is clicked (or any parameter is changed for that matter).
Extension points:
- The mapping for widget types to parameter types is done in: parameter-prompting-builders.js in the object: pentaho.common.prompting.builders.ParameterWidgetBuilder.paramTypeToWidgetMapping. That’s the internal widget mapping that we use when looking up a widget type in pentaho.common.prompting.builders.ParameterWidgetBuilder.lookupCDFWidgetBuilder.
- Most of the javascript is structured so it can be extended at any point. Hopefully I provided enough functions that can be overridden to make it easy for a hacker to tear it apart!
One of the items I’m expecting to change is the delegation of widget creation to layout panels. I’d like to pass the parameter definition to the layout panel and let it create any widgets it needs instead of creating them ahead of time for each non-hidden parameter. This should be a bit more extensible.
Thank you Jordan for creating this amazing marriage of dashboards and reporting!
Even though this is a prototype build, it proves the point that we can tweak CDF to become the new report viewer.
At this point, Gretchen asked me whether this will have any impact on any existing integration with the reporting plugin. Changing server side URLs is always a bad thing and Gretchen voiced the concerns of all our OEMs and partners who built an existing solution for the reporting plugin.
The changes we propose are purely client side changes. There is no need nor any plan to change server side APIs or change URLs or returned formats or any server side behaviour. You are safe.
As far as I know, this new report viewer will be part of the upcoming Pentaho BI-Server 4.5.
A world of new possibilities
This new report viewer adds a bunch of new possibilities to our reporting system. We can easily extend it, we can add new components and new ways of parametrizing reports. Parameters can look sexy and can be visually rich.
With CDF’s flexibility and ability to style the dashboard in any way you want, we can produce more flexible layouts that match existing corporate style guidelines of our customers. With the ability to quickly integrate new components we solve more business cases.
On top of my head, I can imagine a Google-Maps widget to select locations, clickable charts to select customers or product lines. Our Drill-linking can be used in new ways. Why not use a report or analyzer view to present your selection?
With CDF and the power of JavaScript in our hands we can also easily show or hide parameter as needed, or even produce selective parameter input paths based on the user’s selection.
With better parametrization, our reporting system will look more sexy, which means more people will be willing to use it. More customers is always a good thing.
But to make this bird fly, we need all the help that we can get.
How can you help to get it right from the start?
First and foremost: Give us your requirements. For us from engineering it is hard to know what obstacles you hit in the fields or what your clients ask you to solve. So instead of producing a system that is based on our limited “Steel-wheels” world, I would see an open discussion that comes up with a set of true requirements that match what you see from your customers every day.
If you already use CDF to drive parametrized reports, tell us all about it? What is the problem you are solving here? What extra work did you have to do to make it work for your use case? If you wrote some parameter input that might be useful for other: Would you share it with us?
Help us to expand the parameter definition dialog in the report designer so that we can easily add additional attributes to the report parameters. This way we can prototype faster and you can use this to pass additional configuration settings to the CDF parameter viewer.
And if you cannot give anything, then at least test what we write with your data. The earlier you test, the better we will be able to react to the results. And please, please: Test the early builds as well. If the product is already in RC (Release-Candidate) state then it is very hard to make major architectural changes. Your tests of the early builds help us to know whether we move in the right direction and allow us to correct our course when we are not.
So lets start the discussion here and now
What would you need from a parameter viewer? What requirements did you meet that forced you to implement your own dashboard-parameter-viewer?
Hi Thomas, I just downloaded the webviewer and gave it a quick try. For me it does only show the reports html output when I call the url. No dashboard or whatsoever…
Are you using the latest 3.9 build from our CI server?
http://ci.pentaho.org/view/x45x/job/BRANCH_BISERVER-CE/
I have not tested it much with older builds, but it does not work with 3.8.0-GA, for instance.
i wonder how that could ever have worked before.
i had to do the following:
add
static-path url=”/reporting/web” localFolder=”resources”
to plugin.xml
and in reportviewer.html
replace all
src=”../../../pentaho-cdf/js/ …
with
src=”../../../content/pentaho-cdf/js/ …
I made a mistake in zipping up the files.
First, the plugin.xml needs to contain a resources-declaration for the new report viewer or you end up just calling the raw content generator itself.
Second: The directory structure was missing a “web” directory. That is the reason why the “..” do not match up.
I updated the ZIP file with the fixed content. As before: download, unzip and then finally run.
I am sorry for the error and confusion caused!
Hry,
I’m using BI 4.0 and can’t get it to work.
I’ve done what MGiepz said and I get the following:
[GenericServlet] GenericServles.ERROR_0002 – Could not get content generator: content
[DefaultThemeManager] Unable to retrieve module theme for (cdftest) as the module theme definition was not found
Cheers
For updated developer documentation on the CDF-based Reporting Web Viewer check out the Pentaho Wiki:
http://wiki.pentaho.com/display/ServerDoc2x/Pentaho+Prompting+API
http://wiki.pentaho.com/display/Reporting/Pentaho+Reporting+Web+Viewer
hi
Do you now how i can get the username variable from the dashboard side to use in a query to create a dashboard.All help sincerely appreciated.
kind regards
This is a good question for the Pentaho Forum over here: http://forums.pentaho.com/forumdisplay.php?80-Community-Tools-CTools
At the end you probably have to write a small xaction or other service to expose that information to the outside world.
But be aware that anyone with half a brain-cell can modify values on the client side. If you base your security on a client-side parameter, you are deep in trouble. That sort of magical rewrite/parametrization should be done purely on the server-side, for instance with either Metadata’s Row-level security or a security definition in a Mondrian schema.
thanks Thomas for the response.i will look into it.