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 3

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.

Reading RDF Data
You have a lot of libraries at your disposal for importing or reading RDF. In the examples discussed here, you can see how to read RDF data with a subset of the Java Persistence API (JPA) and OpenRDF.org's Elmo implementation.

To get started, first create a JavaBeans interface. Elmo maps the Java interfaces to RDF resources using the @rdf annotation, which is placed on the bean interfaces and its properties. For this example you will need a SearchQuery and a SearchFilter interface with mapped properties:

public class Vocabulary { public static final String NS = http://example.org/rdf/search#; public static final String BASE = http://example.org/rdf/search-metadata/; } @rdf(NS + "SearchQuery") public interface SearchQuery { @rdf(NS + "sql") String getSql(); @rdf(NS + "searchFilters") List<SearchFilter> getSearchFilters(); } @rdf(NS + "SearchFilter") public interface SearchFilter { @rdf(NS + "name") String getName(); @rdf(NS + "sql") String getSql(); }

Next, create the persistence.xml file that the JPA interface will load:

<?xml version="1.0"?> <!-- META-INF/persistence.xml --> <persistence> <persistence-unit name="search-metadata"> <provider>org.openrdf.elmo.sesame.SesamePersistenceProvider</provider> <class>org.example.metadata.SearchQuery</class> <class>org.example.metadata.SearchFilter</class> <properties> <property name="resources" value="META-INF/metadata/order-search.xml"/> </properties> </persistence-unit> </persistence>

Now use the JPA interface to load your JavaBeans into memory:

EntityManagerFactory factory; EntityManager manager; SearchQuery query; factory = Persistence.createEntityManagerFactory("search-metadata"); // load RDF manager = factory.createEntityManager(); // acquire access query = manager.find(SearchQuery.class, new QName(BASE, "orders")); // .. do something with query here manager.close(); // objects can not be used once manager is close factory.close(); // free up resources

With the RDF data available to your application, you can now use this data to dynamically create the query string and search filter interface.

Dynamic Searching
Here is a query builder that accesses the search filter metadata through JavaBeans:

StringBuilder sb = new StringBuilder(); sb.append(query.getSql()); for (SearchFilter filter : query.getSearchFilters()) { String value = req.getParameter(filter.getName()); if (value != null && value.length() > 0) { sb.append(filter.getSql()).append('\n'); } } ... stmt = conn.prepareStatement(sb.toString()); int p = 0; for (SearchFilter filter : query.getSearchFilters()) { String value = req.getParameter(filter.getName()); if (value != null && value.length() > 0) { stmt.setString(++p, value); } } rs = stmt.executeQuery();

It loops through all searchFilters and, if included in the parameters, it includes the sql of the filter in the query string and the parameter in the query parameters. This method has a cyclomatic complexity of 4 (which is low risk), regardless of how many search filters you are using. The search interface can also be driven by the same metadata that is used in the query builder. Listing 1 provides another set of RDF/XML and JavaBeans interfaces that—expanding on the previous example—add presentation information.

Using the previous metadata, a search.jsp can loop through the available filters and output their label and an input value:

<form> <fieldset> <legend>Search Criteria</legend> <table> <% for (SearchFilter filter : query.getSearchFilters()) { %> <tr> <td><%= filter.getLabel() %> </td> <td><input type="text" name="<%= filter.getName() %>" id="<%= filter.getName() %>" size="<%= filter.getWidth() %>" value='<%= param.containsKey(filter.getName()) ? param.get(filter.getName())[0] : "" %>'/> </td> </tr> <% } %> </table> </fieldset> <input class="button" type="submit" value="Submit"/> </form>

Notice that the query builder and search JSP have no knowledge of orders or their search filters. This concept is important as it shows that you are not repeating yourself and are improving the reusability and maintainability of the software. By using this technique you can reduce the complexity of the query builder and have the query string and query parameters drive from the same metadata.

Comment and Contribute






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