Login | Register   
RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Employ Metadata to Enhance Search Filters  : Page 4

Discover how to use metadata for pooling information already resident in an application to create a flexible search interface that reduces complexity and increases users' productivity.

Extending SearchFilter
Now take a look at handling a more complicated input, such as date information. Dates can become really simple if you are using a component-oriented framework like JavaServer Faces (JSF) because you can have the paramaters automatically converted. The Spring Framework can also provide this behavior by binding to a variable. If you rely on a framework to parse the value, or you choose to parse the value yourself, you need to include type information in the SearchFilter. You can also implement parsing yourself by adding a parse() method to the SearchFilter interface:

@rdf(NS + "SearchFilter") public interface SearchFilter { @rdf(NS + "label") String getLabel(); @rdf(NS + "width") String getWidth(); @rdf(NS + "type") String getType(); Object parse(String input) throws ParseException; @rdf(NS + "name") String getName(); @rdf(NS + "sql") String getSql(); }

Notice that the parse() method is not mapped to an RDF property because you will be implementing it yourself as stated earlier. Create this SearchFilterParser mixin class (you will need to add this class to the persistence.xml file):

@rdf(NS + "SearchFilter") public class SearchFilterParser { private static ThreadLocal<DateFormat> dateFormat = new ThreadLocal<DateFormat>() { @Override protected DateFormat initialValue() { return new SimpleDateFormat("yyyy-M-d"); } }; private SearchFilter filter; public SearchFilterParser(SearchFilter filter) { this.filter = filter; } public Object parse(String input) throws ParseException { if (input == null || input.length() == 0) return null; if ("date".equals(filter.getType())) return new java.sql.Date(dateFormat.get().parse(input).getTime()); return input; } }

This class implements the parse() method declared in the previous interface. Notice that both the interface and this class have the same @rdf annotation. You also might want to create subclasses to keep the Parser class from becoming too complicated, but for this example the previous class is adequate. The query builder now needs to be changed to call the parse() method:

stmt.setObject(++p, filter.parse(value));

Independent Search Filters
With the complexity removed, now you are able to add a large number of search filters without the risk associated with changing complex software. The search filters are stored in RDF, allowing you to continue to explore different ways to make the search interface more flexible.

Inside the RDF/XML document there are technical implementation details (sql and parameter); presentation details (title, label, and width); and the list of SearchFilters. The technical details and presentation details are likely going to be written by the same technical group—so keep them together. However, the choice of search filters is more variable and might vary by installation or user. By separating the list of search filters into its own file, you can better control the variability of change and isolate the unique requirements of different users.

Listing 2 shows the same RDF data separated by the searchFilters property into two different RDF/XML files (which doesn't require the code to be recompiled).

The benefit you gain is the ability to deploy these files separately. Consider the advantages of updating a deployment. The order-search.xml file is replaced with the new version, while the order-search-filters.xml file is preserved. This technique keeps the desired list of filters unique to each deployment. The list could even be more finely grained to role or user. The SearchQuery also may be extended to contain a list of possible SearchFilters for selection—or perhaps use an exclusion list. Maybe your application could have an administrative interface to select the desired search filters that are made available or removed. If you add setter methods to your interfaces (without the annotation) the model can be modified, and the repository can be set up to persist the changes in the persistence.xml file (provided the modifications do not conflict with loaded resources).

By orders of magnitude, the degree of flexibility for database search interfaces can be increased with better customization and not much additional overhead cost. (This technique can be applied to a variety of situations beyond creating a reusable search engine.) By gathering together information that is already available elsewhere in an application, you can remove both code and knowledge duplication to reduce the risk of defects and the complexity of your software while at the same time increasing its flexibility and—by extension—your users' productivity.

James Leigh is an independent software consultant based in Toronto, has experience modeling business problems and concepts in software, and specializes in performance and technology integration. James has a background in semantic web technologies and decentralized networks. He is an active member in the OpenRDF community, and he's a developer of Sesame and Elmo.
Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.