Implementation Tips

This section covers some tips that will help you write more complex implementations of the library:

Using Your Own Servlet

The simplest data source implementations inherit from the library's DataSourceServlet class. To inherit from a class other than DataSourceServlet, implement a data source as follows:

  1. Implement the DataTableGenerator interface and override getCapabilities() and generateDataTable().
  2. Call DataSourceHelper.executeDataSourceServletFlow() from within your servlet's code to run the data source flow. This method takes the following parameters :
    • An HttpServletRequest object.
    • An HttpServletResponse object.
    • Your implementation of the DataTableGenerator interface from step 1 above.
    • A boolean to specify restricted or unrestricted access mode.

For example, if you want to inherit your servlet from another servlet class, called AuthServlet that provides built-in authentication, you can rewrite the SimpleServletExample to inherit AuthServlet rather than DataSourceServlet as follows:

  1. Implement the DataTableGenerator interface.
  2. Move generateDataTable() from your DataSourceServlet implementation to your DataTableGenerator implementation.
  3. Override getCapabilities() in your DataTableGenerator implementation to return Capabilities.None.
  4. Call DataSourceHelper.executeDataSourceServletFlow() from within your servlet code (doGet() or doPost()), and pass your DataTableGenerator implementation. This method runs the entire flow of the datasource, including rendering the data source results into the servlet response.

You can use the same technique if you are using a servlet framework in which you normally inherit an abstract class provided by the framework. For example, if you are using WebWork you might want to inherit the ActionSupport class.

Defining Capabilities

If your data store contains a large amount of data, and you want to increase the efficiency of your data source, you can use the querying capabilities of your data store. For example, suppose that your data store is a database, and the database has a large number of columns. If a visualization requests only a few of those columns, then running a SELECT operation within the database is more efficient than retrieving all the columns and using the library's querying capabilities to perform the SELECT. To implement SELECT capabilities, you write code to run a SELECT operation within the database and to return a data table.

Use the Capabilities enum to define the querying capabilities that your code provides. Available options are:

  • NONE: the default, your code provides no query operations.
  • SQL: your code provides SQL query operations.
  • SORT_AND_PAGINATION: your code provides both sort and pagination query operations.
  • SELECT: your code provides a select operation.
  • ALL: your code provides SQL, SORT_AND_PAGINATION, and SELECT operations.

Note: In all cases the library handles any query operations that are not provided by your code.

To implement a capability other than NONE, override Capabilities.getCapabilities()and implement DataTable.generateDataTable() to query the data store and return a data table.

Three of the examples illustrate how to implement capabilities: AdvancedExampleServlet, AdvancedExampleServlet2, and SqlDataSourceServlet. All are in the example package. AdvancedExampleServlet2 is discussed in Defining Capabilities and the Flow of Events.

Customizing the Flow of Events

The default flow of events is defined in DataSourceHelper.executeDataSourceServletFlow. The default flow is as follows:

  1. Extract and parse query parameters.
  2. For restricted access mode only, verify that the request originates from the same domain as the servlet.
  3. Parse the request to create two query objects: the data source query and the completion query. Pass the data source query to your implementation of generateDataTable().
  4. Your implementation of generateDataTable() generates a data table.
  5. Run the completion query on the data table generated in step 5.
  6. Render the data table into the format specified by the visualization and set the servlet response.

To specify your own flow of events, call the helper functions in datasource.DataSourceHelper. See Defining Capabilities and the Flow of Events for an example implementation.

Passing Parameters to DataTableGenerator.generateDataTable

You can use the HttpServletRequest.setAttribute to pass data that is not part of a query or HttpServletRequest object to DataTableGenerator.generateDataTable. Example code is provided below.

In your servlet's code, put the object you want to pass into the HttpServletRequest as follows:

request.setAttribute("my_object_name", myObject);
DataSourceHelper.executeDataSourceServletFlow(request, response, dataTableGenerator);

In your dataTableGenerator interface implementation, get the object from the HttpServletRequest as follows:

public DataTable generateDataTable(Query query, HttpServletRequest request){
  Object myObject = request.getAttribute("my_object_name"); 
  // Add your code to manipulate myObject here 
} 

Implementing a Non-servlet Data Source

If you implement the library without using a servlet, you can use only those classes and helper functions that do not require a servlet environment. These include the Query and DataTable classes and some of the DataSourceHelper functions such as parseQuery, applyQuery, validateQuery and splitQuery. You can use these classes and functions to do the following:

  • Parse a visualization query.
  • Split the query into a data source query and a completion query.
  • Run the completion query to generate a data table.
  • Return the data table to the visualization in HTML, CSV, or JSON format.