Email:   
Home
In This Issue
EasyPrint
Click here for the RSS feed's XML code. This is not a browser URL.
Using a reusable code approach to HTML select option lists: part III (continued)

Since the filtering of lists is very implementation-specific, we could have simply made the two new methods in our base class abstract and forced all implementing classes to provide their own methods for this functionality. The problem with that approach is that adding new abstract methods to the base class would cause all existing classes that extend that class to fail. By providing a default implementation that simply ignores the filter and invokes the corresponding original (unfiltered) method, we retain the integrity of the original design and no existing modules will require modification.

Still, new modules that want to support filtering can override these methods and add that feature to their specific implementation. As a general rule, you do not want to do anything in such a way that you have to go back and rework everything else in your framework, particularly if there is another approach that is just as valid, but does not invalidate those items that are already in existence.

Incremental Improvement #2: creating another implementing class
Right now we have two implementing classes in our portfolio, the SimpleOptionListSource and the PropertiesOptionListSource. Neither one of these supports filtered lists, and while we could go back and enhance them to do so, we might as well take this opportunity to create yet another implementing class and let this new class take advantage of our newest feature. Listing 3 contains our new SqlOptionListSource, which supports both filtered and unfiltered lists.


package step.three;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;

import org.apache.struts.util.LabelValueBean;

/**
* Returns the name/value pairs for the options related to an HTML
* "select" tag.
*
* Source data for this implementation is obtained from a JDBC
* DataSource. You can instantiate this class by providing the
* DataSource directly, or by providing the JNDI DataSource name.
*/
public class SqlOptionListSource extends OptionListSourceBase {
private DataSource dataSource = null;
private String unfilteredSql = null;
private String filteredSql = null;
private HashMap options = new HashMap();
private HashMap optionsPlusBlank = new HashMap();

/**
* Constructs a new "SqlOptionListSource" object using the
* parameters provided.
*
* @param dataSourceName a String containing the JNDI DataSource
* name
*/
public SqlOptionListSource(String dataSourceName, String unfilteredSql, String filteredSql) {
this(getDataSource(dataSourceName), unfilteredSql, filteredSql);
}

/**
* Constructs a new "SqlOptionListSource" object using the
* parameters provided.
*
* @param dataSource the JDBC DataSource from which we will obtain
* our labels and values
*/
public SqlOptionListSource(DataSource dataSource, String unfilteredSql, String filteredSql) {
this.dataSource = dataSource;
this.unfilteredSql = unfilteredSql;
this.filteredSql = filteredSql;
}

/**
* Looks up the dataSource by name.
*
* @param dataSourceName a String containing the JNDI DataSource
* name
* @return the dataSource
*/
private static DataSource getDataSource(String dataSourceName) {
Hashtable parms = new Hashtable();
parms.put(Context.INITIAL_CONTEXT_FACTORY, "com.ibm.websphere.naming.WsnInitialContextFactory");
DataSource dataSource = null;
try {
Context ctx = new InitialContext(parms);
dataSource = (DataSource) ctx.lookup(dataSourceName);
} catch (Throwable t) {
// here is where you would invoke your own event management or logging
System.out.println("DataSource lookup error: " + t.toString());
}
return dataSource;
}

/**
* Returns a filtered array of LabelValueBean
* objects defining the available options.
*
* @param filter an implementation-defined filter parameter
* further identifying or limiting the available options
* @param required a boolean indicating whether or not input is
* required for this field. Setting this indicator to false will
* cause the generation of an additional option for no selection.
* @return an ArrayList of LabelValueBean
* objects defining the available options
*/
public ArrayList getOptions(Object filter, boolean required) {
if (!options.containsKey(filter)) {
loadFilteredOptionsArrays(filter);
}

if (required) {
return (ArrayList) options.get(filter);
} else {
return (ArrayList) optionsPlusBlank.get(filter);
}
}

/**
* Obtains the filtered options from the DataSource.
*
* @param filter an implementation-defined filter parameter
* further identifying or limiting the available options
*/
protected void loadFilteredOptionsArrays(Object filter) {
// get the options
ArrayList filteredOptions = loadOptions(filter);

// store the options
options.put(filter, filteredOptions);

// create the "not required" option list
ArrayList optsPlusBlank = new ArrayList();
LabelValueBean blankOption = new LabelValueBean("-- No Selection --", "");
optsPlusBlank.add(blankOption);
optsPlusBlank.add(filteredOptions);

// store the "not required" option list
optionsPlusBlank.put(filter, optsPlusBlank);
}

/**
* Loads the list of available options from the DataSource.
*/
protected void loadOptions() {
setOptions(loadOptions(null));
}

/**
* Loads the list of available options from the DataSource.
*
* @param filter an implementation-defined filter parameter
* further identifying or limiting the available options
*/
protected ArrayList loadOptions(Object filter) {
ArrayList list = new ArrayList();
Connection conn = null;
PreparedStatement ps = null;
try {
conn = dataSource.getConnection();
ps = conn.prepareStatement(unfilteredSql);
if (filter != null) {
ps = conn.prepareStatement(filteredSql);
ps.setString(1, filter.toString());
}
ResultSet rs = ps.executeQuery();
while (rs.next()) {
LabelValueBean thisOption = new LabelValueBean(rs.getString(2), rs.getString(1));
list.add(thisOption);
}
rs.close();
ps.close();
conn.close();
} catch (Throwable t) {
// here is where you would invoke your own event management or logging
System.out.println("database access error: " + t.toString());
}

return list;
}
}




[ Prev | Next ]

ZATZ Home  ·  News  ·  Back Issues  ·  Credits/Trademarks ·  Link To Us
-- Advertisement --

Sun Virtualization offerings for IBM WebSphere infrastructures
Increase the value of your enterprise IT environment through server consolidation

  • Reduced costs lead to improved TCO
  • Optimized application performance
  • Added flexibility
  • Enhanced service levels


Watch the webcast to learn more
Copyright © 2008, ZATZ Publishing. All rights reserved worldwide.