Drillbridge Custom Report Plugin Development Guide
Drillbridge Enterprise 2.0.0 and above support custom report plugins. Plugins are custom Java classes that can be added to Drillbridge (in the form of Java JAR files). Custom plugins have almost identical access to functionality that native Drillbridge reports have.
General Overview
In general, the process for developing, deploying, and using custom plugins will look like this:
-
Create a new Java project using a Java programming environment such as Eclipse
-
Link the project against the Drillbridge plugin JAR file (found in your Drillbridge Enterprise /lib folder)
-
Build a new class that extends the AbstractDrillthroughReport class. It’s not strictly necessary to extend this class, but it’s helpful. For the least part, custom plugins must implement the DrillthroughReport interface.
-
Develop and test your plugin. It may reference other Java libraries and classes if needed. It can also reference any functionality contained in libraries that are already included with Drillbridge (for example, Google Guava libraries and others)
-
Build a JAR file for your plugin project. It does not need to be a runnable JAR.
-
Stop the Drillbridge service, copy your JAR file in, and start the Drillbridge service.
-
Check the Drillbridge log to see that your plugin was detected and loaded
-
Develop a new report using the "-- class: " syntax
-
Test your report and deploy it to your Essbase server
Developing Your Custom Report
Reports must implement the DrillthroughReport interface. As of version 2.0.0, this interface consists of just three methods:
public String getDescription(); public Collection<ParsedToken> getRequiredTokens(); public void run(ReportContext context, EvaluationContext evalContext) throws DrillthroughReportException;
public getDescription();
This is the simplest method, and it should just return a description of the report type (although not the specific name of the report). For example, the Drillbridge native report type might return a description of "JDBC Drillthrough Report" or "Forwarding URL Report".
public Collection<ParsedToken> getRequiredTokens();
This method should return a collection of the tokens that are required for this report. This can be dynamically generated. For example, in the case of the typical Drillbridge JDBC Drillthrough Report (the main type of Drillbridge report), the tokens are generated based on the contents of the query (in this report type, recall that tokens are delimited by double curly braces such as {{"name" : "Period", "expression" : "#Period"}}
).
A description of the ParsedToken
class will be discussed momentarily. At a minimum, you will need to return Collection of ParsedToken objects that at least have the name
property set. This is used in the Drillbridge testing screen so that you can simulate a drill-through operation from the user.
public void run(ReportContext context, EvaluationContext evalContext) throws DrillthroughReportException;
This is the actual method that will be called when the report is run and where your custom logic will go. Note the presence of the ReportContext
and the EvaluationContext
as well as the fact that a DrillthroughReportException is part of the signature for the method. If your custom plugin fails for some reason (can’t connect to a database, etc.), it should throw a DrillthroughReportException or a subclass of this exception so that Drillbridge can display an error page with information for the user that will aid in debugging.
The ReportContext
object that is passed in includes most of the information that you will need in order to do something useful. It also contains references to the servlet objects that you should write your output to.
Drillbridge Foundation Objects
We have already seen many of these objects referenced, such as the ReportContext and ParsedToken. A brief description of each is included in this section.
ParsedToken
The ParsedToken
object models the tokens that are present in a Drillbridge report. The methods and properties on this object will be very familiar to those that have configured a report before. ParsedToken objects have the following properties:
-
String: name
-
String: expression
-
Boolean: drillToBottom
-
String: sampleValue
-
Boolean: quoteMembers
-
Boolean: suppressParentheses
-
String overflow
-
Integer: overflowAt
-
String: flags
A brief description of major properties is provided here, although a more in-depth description is provided in the Drillbridge Plugin Javadoc.
Note: You are not required to implement any of these properties. At a minimum, it is highly likely that you will at please set the name property of the ParsedToken, but mother other properties are for you to use as you see fit, if at all. As far as Drillbridge is concerned, it will use the tokens returned from getRequiredTokens() just to prepare the testing screen but otherwise doesn’t care.
name
Sets the name of this token. A token name is not always required but is almost always needed. The token name will generally be the same as the dimension name it corresponds to. For example, if a cube has a Time dimension, there will generally be a token named "Time". If the incoming dimension has spaces in it (for example, "Cost Centers") then the token name will generally match it (although the corresponding variables will have spaces replaced with underscores). The token name must match the dimension name exactly when using drillToBottom (this is so that Drillbridge knows how to line up the member to drill on).
Token names are not required to match up to dimension names from the cube. YOu may occasionally have "dummy" token names because you just need a box to show up on the report test screen but are able to get all the values you need from other existing tokens.
sampleValue
Sets the sample value for this token. This is not required and not used for execution of reports. It only exists to assist in testing. When the sample value is set, the Test tab on the Drillbridge interface will display a text box that is pre-filled with the sample value, greatly increasing development speed.
ReportContext
As we saw earlier, an object implementing the ReportContext
interface is passed to your custom report during for it’s run
method. This object contains most or all of the information that you will need in order to determine what the user’s original point of view was. This object has the following properties:
-
Object: originalReport
-
Map<String, String> tokenValues
-
Locale: locale
-
String: ssoToken
-
Map<String, String> systemVariables
-
String: query
-
File: tempFile
-
Writer: writer
-
ReportOutputType: outputType
-
HttpServletResponse: httpServletResponse
-
HttpServletRequest: httpServletRequest
A brief description of these items is provided here (also available in the Javadoc). The Java interface method will be shown, corresponding to the property. For example, there is a method on ReportContext called getOriginalReport() that returns an Object. This corresponds to the "originalReport" property that was noted above.
public Object getOriginalReport();
Returns the original report object. Using this is discouraged, but it is provided for certain use cases.
public Map<String, String> getTokenValues();
Returns a Map of token values from the POV. The key names correspond to dimensions from the cube the report was drilled from, and the values are the drilled member. For example, a user Drilling from a cube containing Scenario, Time, Year, and Account might end up creating a map with the following values:
-
Scenario: Actual
-
Time: Jan
-
Year: FY15
-
Account: Sales
Almost every custom report will make use of this object in order to retrieve the original POV values. Note that transformations are not applied. You may be used to the powerful Drillbridge mapping and expression language. For example, a common transformation would be to replace FY15 with the value '2015' (this means removing the prefix and concatenating to the text '20'. Note that this functionality is particular to the native Drillbridge report type, the JdbcDrillthroughReport. You will need to manually modify the incoming Strings per your business requirements, rather than rely on the Drillbridge mapping mechanism (unless of course, you program it in, which is beyond the scope of this document).
public Local getLocale();
The locale of the user executing the report (as reported by their web browser) is provided here. Note that the Locale object is a built-in Java concept. It is advised to read up on the Java documentation for such in order to understand it more, if needed. Simply note that the locale is used to determine the language you might want to return output in, and possibly even a variation on that language (for example, it is possible to discern the difference between the French language in France and Canada, or the English language as used in the United States versus Great Britain).
It may be useful to interrogate this value in order to determine what language to display to the user.
public String getSsoToken();
Returns the code of the SSO token provided from Smart View or the drill-through source. Can be used to log in to an Essbase cube. Note that the username and password are never transmitted from a drill-through source to Drillbridge.
public Map<String, String> getSystemVariables();
Returns a key-value mapping of all variables that have been defined on the system. These are useful to contain values that you wish to abstract away due to differences between environments. For example, you may wish to set a variable named "JDBC URL" and this contains the database URL that your report should query, thus allowing you to provide a single version of your custom report plugin that can be used without changes across all of your environments.
public String getQuery();
Returns the text contents of the query for this report. For example, on a typical native Drillbridge JdbcDrillthroughReport, this is the code that typically starts out as "SELECT …". Your custom report will have access to the contents of the query box as defined by the user. It does not have to be a SQL query. It can be your own notation or arbitrary text that you parse in order to determine how your custom report should operate.
public File getTempFile();
For the time being, do not attempt to use this as it may go away in a future release. It is used internally for the Excel spreadsheet generation functionality on Drillbridge Excel downloads. The Drillbridge servlet hands off a temporary file that the Excel generator writes to, then sends this to the user. The goal for future versions of Drillbridge is to incorporate this into the Writer directly without having to have a separate method.
public Writer getWriter();
Returns a Writer object that output is sent to. This is the servlet output stream that you will typically send an HTML document to, including the tags and everything. For example, a very simple usage of this in your run()
method might be:
context.getWriter().write("<html><body>Hello world!</body></html>");
public ReportOutputType getOutputType();
Returns the output type that was requested by the user. Custom report plugins should not make use of this functionality (yet). The ReportOutputType is a Java enumeration that just contains the values HTML and XLSX. This allows your report to determine, for example, if the user requested an HTML page (the default) or chose an XLSX page. The reason that custom reports should not use this yet is that it’s the responsibility of the page as generated for an HTML output type to craft the particular URL that will be used to indicate that XLSX output is requested instead. The JdbcDrillthroughReport handles this fine but future versions of Drillbridge will offer
public HttpServletResponse getHttpServletResponse();
This returns the standard Java servlet response object. Note that the getWriter() method above is a convenience method that actually just reaches into the response and pulls out the response writer. Check the standard Java documentation for available methods and properties on this object. It gives you absolutely full control over the response that is sent to the user. As an example of this, the Drillbridge native report type "Forwarding URL Report" (a special report designed to transform the given POV into a particular URL) uses the servlet response in order to issue a URL redirect to the user. This causes the web browser to go to the specified URL without ever showing any output to the user from Drillbridge.
Example Report Implementation
Now that we’ve taken a tour of most of the custom report functionality, let’s take a look at a full implementation of a minimal report:
package com.saxifrages.drillbridge.reports.example;
import java.io.IOException; import java.io.Writer; import java.util.Collection; import java.util.Collections;
import org.springframework.expression.EvaluationContext;
import com.saxifrages.drillbridge.reports.DrillthroughReport; import com.saxifrages.drillbridge.reports.DrillthroughReportException; import com.saxifrages.drillbridge.reports.ParsedToken; import com.saxifrages.drillbridge.reports.ReportContext;
public class HelloWorldReport implements DrillthroughReport {
private ParsedToken nameToken;
public HelloWorldReport() { nameToken = new ParsedToken(); nameToken.setName("name"); nameToken.setSampleValue("Jason"); }
@Override public String getDescription() { return "Hello World Report"; }
@Override public Collection<ParsedToken> getRequiredTokens() { return Collections.emptyList(); }
@Override public void run(ReportContext context, EvaluationContext evalContext) throws DrillthroughReportException { try { Writer writer = context.getWriter(); writer.write("Hello World!"); } catch (IOException e) { throw new DrillthroughReportException(e); } }
}
This report has no parameters (it returns an empty list in its getRequiredTokens() implementation), and it simply prints "Hello World!" to the user. Note in the run method that the Java Writer.write()
method can possibly throw an IOException, indicating that that was an issue. This is rare to happen in this context (it’s more common when writing to files, for example), but it is nonetheless part of the Writer interface and must be handled by calling programs. This implementation of the run() method wraps the exception (in the catch block), and rethrows it as a DrillthroughReportException (the type of Exception that Drillbridge expects a report to throw in case there is an error).
You will want to wrap your run method and other methods (such as connecting to a SQL datasource) with appropriate try/catch blocks and rethrow a DrillthroughReportException() as needed in your own implementation.
Deploying Your JAR File
Once you have developed and tested your report (Unit testing using JUnit is advised but beyond the scope of this document), you compile it to a JAR file (you can use the Export functionality in Eclipse).
Before doing this you must add one more thing to your Java project. Your JAR must be packaged with a META-INF folder. This folder then must contain a folder named services. Inside of services will be a text file named com.saxifrages.drillbridge.reports.DrillthroughReport
. Finally, inside of this text file should be one entry per line containing the name of each class of custom report. For example, the contents of this file might be this:
com.saxifrages.drillbridge.reports.example.HelloWorldReport com.saxifrages.drillbridge.reports.example.ExampleReport
This is a standard Java mechanism for detecting classes. Upon startup, Drillbridge asks a "service loader" for all service classes that implement the Drillbridge report interface and then reports them as available to use. The final contents of your JAR file should look similar to this (note that JAR files are zip files but with a .JAR extension):
drillbridge-plugin-hello-world.jar (for example) com/ saxifrages/ drillbridge/ reports/ example/ HelloWorldReport.class META-INF MANIFEST.MF services/ com.saxifrages.drillbridge.reports.DrillthroughReport
Note that the com/ folder hierarchy is a standard folder hierarchy that is consistent with the package of your Java class and should be generated automatically by Eclipse for you when you package things up. Assuming your project is laid out in the proper way, all you should have to do is just run Export and you will generate a .jar file with the proper format.
Then copy this JAR file into your Drillbridge installations' /lib sub-folder, and restart Drillbridge. Upon restart, Drillbridge will detect the custom report type (it will list the detected custom reports in the log file), and you are now able to use your custom report.
Creating the Custom Report
As of this writing, custom Drillbridge reports are implemented by "overloading" the normal report functionality with a special code (the goal for future versions of Drillbridge is to have a full GUI that provides enhanced support for custom plugins). Create a Drillbridge report as you normally would, but in the top of the report query, you will put in a special code indicating the fully qualified class name of your report. For example, if your report had a Java package of com.example
and the report class was "ImageRepository", then the fully qualified name of the class would be com.example.ImageRepository
. The first line in your query definition would therefore be:
-- class: com.example.ImageRepository
In other words, it would be two hyphens, a space, the word class, a colon, a space, and then the fully qualified name of your custom class. You may then put anything you want after this special line. For example, consider a report where you wanted to drill to a particular URL using the given POV (this is what the Drillbridge report type Forwarding URL Report does). Whereas in a typical JdbcDrillthroughReport you would have a SQL query, for this you might have a URL that is parameterized. For example, it might be this:
http://www.google.com/?q={{ACCOUNT}}
Note that the above "token" — the ACCOUNT token, is not a typical Drillbridge token that you are used to seeing such as in the JDBC drill-through report type. It might simply be the case that we want to send the user to the Google search engine and plugin the name of the account they drilled on. Assuming that the account dimension was named "Accounts", we would access the drilled POV, replace this text in the query string, and then redirect the user (using the Java String function .replace(), among other Drillbridge functionality).
Note that if we constructed a report in this manner, that is, taking a single parameter that we want to search Google with, it is highly likely that we’d like to provide such a token in the getRequiredTokens() method, so that we could easily test this from the Drillbridge interface.
In this case, rather than returning Collections.emptyList(), we would want to do something like the following:
@Override public Collection<ParsedToken> getRequiredTokens() { ParsedToken token = new ParsedToken(); token.setName("Account"); return Arrays.asList(token); }
The Drillbridge testing screen for this report would then show a box where we could simulate a value that was passed in by Smart View.
Other Thoughts
It is advisable that you use Maven to manage your project. If you do so, you’ll need to install the Drillbridge plugin API as a local artifact.
Drillbridge makes use of many industry standard libraries, such as big parts of the Spring framework and Google Guava. You can use anything that is in the /lib Drillbridge folder.
You can add your own JAR dependencies — just reference them in your project and then also deploy those to the /lib folder of Drillbridge when you go to deploy your own JAR file.
You do not have to deploy your custom plugin to Drillbridge in order to perform adequate testing on it. You can perform much of your testing by simply instantiating your report class and calling the run method, then verifying the output.
If you are using Maven, then you could include the JUnit dependency very easily to help do unit testing.
Do not package your dependencies (if any) and your custom report as an "uber jar" — just compile your class(es) to a normal JAR and include your necessary dependencies, if any, in the Drillbridge /lib folder.
If you get stuck, check out the Saxifrage Systems LLC support forums for help and post there, your issue might come in handy for someone else that Google’s it someday!
Even though the editor for custom reports appears just like that of the normal report, note that all options other than the query itself are completely ignored. Future versions of Drillbridge will provide a better editor.
Deployment of custom reports is the same as with normal reports. Custom reports have a unique ID just like normal reports, but otherwise share the exact same URL structure.