Skip to content
liangjh edited this page Sep 1, 2012 · 1 revision

The best way to illustrate the strength of the casper datasets framework is through a simplified example that one may encounter in the real world.

Suppose I had an application that works with a fairly formidable catalog (let's say a dataset about 300,000 entries), with each entry representing a widget. A good initial first step to represent this widget may involve the creation of a java bean (or POJO) that represents all of the characteristics of a given widget.

public class Widget {
   private String widgetId;
   private String widgetName;
   private String widgetCategory;
   private Long serialNum;
   private String widgetManufacturer;
   private Date widgetCreationDate;
   // ... getters and setters, util methods, etc
}

But this may be where the simplicity ends.

Since you probably don't want your application to retrieve all 300K widgets all at once and display them on your app, you'd probably want to build some means to search through the list of widgets. You'd need to build another class that would create the functionality to search through any (one or more) of these chracteristics. Note that the searcher would not necessarily be discrete (i.e. you may want to search within a date range or a substring of these objects, for example.

//  Let's assume discrete searches. (this is a partial impl)
//  However, what you wanted to search on substring or a range of numbers or dates, for example ?

Widget[] searchWidget(Widget[] allWidgets, String widgetId, String widgetName, String widgetCategory)
{
   LinkedList matches = new LinkedList();
   if (allWidgets != null) {
        for (int it = 0; it < allWidgets.length; it++) {
            if (widgetId != null && allWidgets[i].getWidgetId().equals(widgetId)) {...}
            if (widgetName ....) {...}
            if (widgetCategory ...) {...}
        }
   }
   //  ....
}

After you retrieve results, you may want to expose the ability to allow the user to be able to sort by any of these characteristics. However, your sorter would need to see by which of these columns you are sorting, and you'd need to write cumbersome blocks of code for each column

//
//  You'd need a separate block for each attribute you are sorting by.
//  But this is just single case sorting.
//  What if you want to do composite sorting (i.e. sort by widgetCategory and then by widgetName, ascending??)
//

Widget[] sortWidgets(Widget[] widgets, String sortBy)
{
   if ("widgetId".equals(sortBy)) {
       // sort by widget id...
   }
   else if ("serialNum".equals(sortBy)) {
       // sort by serial num...
   }
   // ..  etc etc...
}

That's all fine if you're dealing with one particular type of object in your application. But imagine you had an application that manages Widgets, Manufacturers, Distributors, RetailOutlets?, etc... That's a lot of code to write. In addition, if you wanted to add an additional column to Widget table, you're going to have to add this column to the widget object, the widget sorter, and the widget searcher.

What casper solves is this problem of having to create customized beans for each object you are dealing with. The Widget object can be represented with a casper dataset by creating a meta data object, as follows:

//
//  Manual data container initialization 
// 
String[] columnNames = new String[] {"widgetId", "widgetName","widgetCategory", "serialNum", "widgetManufacturer", "widgetCreationDate"};
Class[] columnTypes = new Class[] {String.class, String.class, String.class, Long.class, String.class, java.util.Date.class};
String[] primaryKey = new String[] {"widgetId"};  
// (note in this case widgetId is the primarykey, but you can create composite primary keys as well)

CRowMetaData metadata = new CRowMetaData(columnNames, columnTypes, primaryKey);
CDataCacheContainer container = new CDataCacheContainer("mywidgetcache", metadata);
//    Then, add all rows to container (by constructing CDataRow object )

Alternatively, the CDataCacheDBAdapter class can also convert a JDBC Resultset into a casper dataset for you (there's no need to create a metadata object manually if you are loading from jdbc). You just need to supply the resultset that you get from a given query (look @ the javadocs, there are a number of methods to load this data)

String sql = "select widgetId, wdigetName, widgetCategory, serialNum, widgetManufacturer, widgetCreationDate from widgets";
Resultset rs = ... // perform query using (sql) above)
CDataCacheContainer container = CDataCacheDBAdapter.loadData(rs, "data", String[] {"widgetId"}, new HashMap());

Indexing: If you wanted to create indices on some columns, do the following (let's say that there are lots of searchs by widget name and by widget category). This will allow any searches on the widgetName to be optimized (by referring to the index rather than performing a full scan of the table for matching records)

container.addNonUniqueIndex("widgetName");
container.addNonUniqueIndex("widgetCategory");

You can also now search and sort on this dataset quite easily. You can do this either by using some of the convenient methods in CDataCacheContainer to construct a query against a discrete value, or by using something called a filter clause

Example 1: Search for all widgets in the category "CalvinAndHobbes?" or "FoxTrot?" (discrete search)

CDataRowSet results = container.get("widgetName", new String[] {"CalvinAndHobes", "FoxTrot"});

Example 2: Same search as above (using filter chains). In the below we can also search for anything NOT matching those values just by setting the "negated" flag in an overloaded constructor)

EqualsFilter filter = new EqualsFilter("widgetName", new String[] {"CalvinAndHobbes", "FoxTrot"});
CDataFilterClause clause = new CDataFilterClause();
clause.addFilter(filter);
CDataRowSet results = container.get(clause);
Sorting: The results can subsequently be sorted Lets say we want to sort first by widgetCategory then by widgetName, in ascending order

results.sortByColumn(String[] {"widgetCategory", "widgetName"}, true);

Example 3: Search for any widget created between 2008-2009, AND in the category "Tools" (this requires the use of a filter chain)

 //  Date range - anything between
 java.util.Date lbound = //  init to jan 1, 2008
 java.util.Date ubound = //  init to jan 1, 2009
 DateRangeFilter dateRange = new DateRangeFilter("widgetCreationDate", lbound, ubound);
 
 //  Category, tools
 EqualsFilter toolsF = new EqualsFilter("widgetCategory", new String[] {"Tools"});
 
 //  Create clause, issue query on container
 CDataFilterClause clause = new CDataFilterClause();
 clause.addFilter(dateRange);
 clause.addFilter(toolsF);
 CDataRowSet results = container.get(clause);

This is generally much easier to work with than creating special POJO's for each of the objects in your system. You still have the flexibility to convert into any subsequent data object representation that you want.

Clone this wiki locally