Start page / Plug-In Development / Universal Extensions / Reports (Legacy) / Code Example / Data Provider
The Data Provider
Access API documentation: DataProvider<T>
The report data provider is responsible for supplying report entry objects of a type matching the report object's parameterization.
The provider is initialized as the report is first displayed in the client user interface and as filter parameters are changed by the user.
After initialization, the FirstSpirit client polls the data provider on an as-needed basis, collecting a specific number of report entry objects for display in the report's result list. As report result lists support continuous scrolling, the number of requested report entry objects in each poll may vary; generally, the FirstSpirit client attempts to request enough report entry objects to fill clear, vertical space in the result list. If the provider indicates it is no longer running (i.e., all available report results have been provided as report entry objects), the FirstSpirit client will stop polling the provider.
Due to the batch-oriented nature of this algorithm, data provider classes must be designed to avoid returning the same report entry object multiple times over repeated polls.
Code Example
This second-tier class implementing the interface DataProvider<T> is designed both to provide the initial batch of data items (displayed as the report is first opened or reconfigured) and to supply additional data items incrementally as the user requests them (caused by scrolling to the bottom of the report list). This class has no direct representation in the clients' user interface.
public class ExampleDataProvider implements DataProvider<ExampleReportObject> {
// Setup for private variables.
private SpecialistsBroker _broker;
private ParameterMap _param;
private boolean _running;
private final List<ExampleReportObject> _reportItems = new ArrayList<ExampleReportObject>();
private int _offset;
private int _total;
public void start(SpecialistsBroker broker, ParameterMap parameter) {
_broker = broker;
_param = parameter;
_total = 0;
_offset = 0;
_running = false;
}
public List<ExampleReportObject> getNext(final int count) {
// Place pre-made objects of type ExampleReportObject into an array list.
// To prevent complexity, this array list is our pendant to an external data source for this example.
_reportItems.add(new ExampleReportObject("Example Report Result 1"));
_reportItems.add(new ExampleReportObject("Report Result 2"));
_reportItems.add(new ExampleReportObject("Report Result 3"));
if ((count <= 0)) {
_total = 0;
_running = false;
return Collections.emptyList();
}
final List<ExampleReportObject> results = new ArrayList<ExampleReportObject>();
int i = _offset;
// In this example, we can easily find how many results we can possibly retrieve (_reportItems.size()).
// If the offset (stored in i) is already greater than the number of all results, we cannot return any more results,
// indicating that the results provisioning process is done (set _running = false).
if (i > _reportItems.size()) {
_total = 0;
_running = false;
return Collections.emptyList();
// If we haven't exhausted the complete set of results yet (i <= _reportItems.size()), continue collecting results.
} else {
while ((i < _offset + count) && (i < _reportItems.size())) {
results.add(_reportItems.get(i));
i++;
}
// Add the number of results found in this search increment to the running total.
_total += results.size();
}
// Add the number of results found in this search increment to the offset.
// When called next, the method getNext() should start searching from the new offset.
_offset += results.size();
// If the offset has surpassed the total number of possible results, or if less results were found than
// requested by WebClient, report that the search is over.
if (_offset >= _total || results.size() < count) {
_running = false;
}
// Return the list of all results found in this search increment.
return results;
}
public boolean isRunning() {
return _running;
}
public int getTotal() {
return _total;
}
public void close() {
_total = 0;
_running = false;
}
public String serialize(T object) {
return object;
}
public T deserialize(String string) {
return string;
}
}
start()
This method is called each time the report is reconfigured - this includes initial display of the report and changes to the report's filters. Private variables, such as total count, running state, etc. should be reset to default values, and the new filter configuration (provided by the ParameterMap object included in the method call) should be made available to other methods of this class.
isRunning()
This method returns the provider's state. While this running state is true, ContentCreator or SiteArchitect will display a progress indicator in the report list to communicate to users that additional data is still being retrieved. Once set to false, ContentCreator will remove this progress indicator from the list display.
Especially useful in data retrieval operations with a duration longer than a half-second, it is recommended that the running state be generated properly in order to communicate more intensive operations to users. During the generation of a new list (e.g. caused by reconfiguring a filter setting), an animated progress indicator graphic will be shown in lieu of the list until data is made available. In continuous scrolling operations in ContentCreator, as further list data is requested from the provider object, a virtual snippet is temporarily inserted at the bottom of the list until data snippets can be appended to the list.
getTotal()
getTotal() returns an integer corresponding to the total number of results retrieved so far since the most recent call of start(). This number is shown near the report list in the format "x Results".
getNext()
This method returns the next increment of data, starting from an offset stored privately in the provider object and including at most a given number of data objects corresponding to the parameter count included in the method call. The value of the parameter count may vary between calls: during initial list generation, it may be higher than in subsequent requests for additional data increments.
Bear in mind that getNext() is concerned with retrieving and providing the next x data objects, where x corresponds to the method's parameter count. Unless count evaluates to 1, this method is not designed to be a simple iterator, supplying one data object per call. |
Please note that a report provider's getNext() method is always called in conjunction with start(), immediately as the associated report panel is displayed for the first time. If collecting results with a default (potentially empty) filter configuration is associated with high costs (e.g. polling a web service that does not provide an easy way of limiting an initial set of data), you should ensure that getNext() only begins assembling results when specific conditions - e.g. a three-character minimum for a text search pattern or a non-default option being selected in a drop-down box pattern - are met. |
close()
close() is called before a single provider object is discarded. This method is responsible for stopping any data retrieval processes still occurring and destroying any temporary data that cannot be treated properly by Java's garbage collection.
serialize()
Required for report plug-in implementations targeting ContentCreator in conjunction with TransferHandler and report item implementations. |
This method provides a string representation of an individual report entry. The String should contain all information necessary to be reversed into a report entry object that complies with the parameterization of the data provider object.
deserialize()
Required for report plug-in implementations targeting ContentCreator in conjunction with TransferHandler and report item implementations. |
This method provides a report entry object that complies with the parameterization of the data provider object. Performing the reverse operation of serialize(), this method should instantiate a new report entry object based on the serialized String data provided.