Showing posts with label Design. Show all posts
Showing posts with label Design. Show all posts

Friday, July 13, 2007

Initialization on Demand Holder (IODH) Idiom Singleton

I read this short article about the controversial Singleton Pattern that explains the popular form of the pattern which is seen in so many Java applicaitons is basically flawed.

The conclusion of the article illustrates another approach using an inner class which is guaranteed to execute only once ensuring there is only one instance created (and is thread-safe).

The Java Language Specification (JLS) guarantees the object "instance" would not be initialised until someone calls getInstance() method.


public class Singleton {
static class SingletonHolder {
static Singleton instance = new Singleton();
}

public static Singleton getInstance() {
return SingletonHolder.instance;
}
}


Click to read article
Wiki on Initialization on Demand Holder pattern

Saturday, May 19, 2007

Application properties and storage strategies

It baffles and disappoints

I've been in this industry for a long time. I've seen the good and bad and take away from each experience lessons for the next project. It's not uncommon to look back on the way an application came together and think about how it could have been done differently to improve maintainability, robustness, etc.

Now in the Java world and enjoying it thoroughly, I'm continuously exposed to an aspect of Java development that both baffles and disappoints; property files.

What in the hell were “they” thinking?

The idea being employed by property files is to have a place to store application related information such as database connection criteria, behavioral specifications, etc. The property file is nothing but a common text file. I know of an inter-net application that relies upon a property file named “system.properties” which contains names of other property files to be processed during the startup phase!


#
# Property File name : dbConnection.properties
#
# DBTYPE.URL.NAME=VALUE
# DBTYPE : [mySQL, DB400]
# URL : Example localhost, 10.240.19.84, as240d
# Parm NAME : dbPooling [on, off]
# Parm NAME : dbPoolsize [1,2,3...] 0=off
# Parm NAME : dbName For mySQL, the DB Name. For iSeries, the library
# Parm NAME : dbUserID User ID having authorized access
# Parm NAME : dbPassword Password for the user having authorized access
#
# Syntax Examples:
# DB400.as240d.poolsize=5 defines a connection pool size of 5 for an AS400
# database located on the machine identified as as240d (IP add resolved via DNS).
#
# mySQL.as240d.dbPooling=off specifies that pooling of db connections is off. The
# application software is required to create a connection either by prompting or
# using the values specified here. Prompted values are treated as overrides.
#

mySQL.localhost.dbPooling=off
mySQL.localhost.dbPoolsize=0
mySQL.localhost.dbName=resources
mySQL.localhost.dbUserID=prbxf000
mySQL.localhost.dbPassword=prbxf000

DB400.as240d.dbPooling=on
DB400.as240d.dbPoolsize=3
DB400.as240d.dbName=scdbfp10
DB400.as240d.dbUserID=2br02b
DB400.as240d.dbPassword=07734

# end of property file


Although this approach to storing properties for use by applications is common to see, it is problematic. As stated, these files are nothing more than text files. To change their contents, various text editors or even word processors are used. By its nature, information entered is prone to error and it is easy for anyone with access to the machine to change the contents of these files. In addition, there is no audit capability.

Usually, these property files are given names to reflect their role within the system. Sometimes, due to system changes giving rise for the need to create new property entries or remove old ones, the name no longer reflects those contents. Other times, the developer just finds it easier to add new property entries rather than create a new property file to contain those entries. If lucky, a suitable property file is found and the property values are added. If not so lucky, the developer sticks the properties into any file that exists.

It gets unwieldy quickly. Take for example a certain inter-net based order entry system used by a distribution company. Because of the user-volume, traffic is balanced across three application servers connected to a common database server. This approach calls for three separate sets of property files with each set residing in the three application servers. Most of the data within the property files is identical but some of the properties reflect the name of the application server itself while other properties relate to data queue names allocated for that server. Due to design requirements there are many property files containing over 2,300 entries. Together, that architecture calls for the existence of over 7,000 properties.

There are better ways to address this design requirement of providing static or server specific data to an application.

A properties file editor

This stand-alone editor provides the means to establish connection criteria to the database used by the client application. The data that can be maintained is listed in the table below.





The above is an example of an application designed to store values to be used by one or several other applications to govern database connection criteria. In addition it provides the means to establish other values. Such data could be the name or address and the contact information of the company that might be accessed by a billing application. You get the idea; static data.

The application stores the data entered into a Java serialized object. This provides a level of security in that the data within cannot be easily edited; you have to use the application to do that.

Below is a diagram that illustrates how the application stores the information entered.





Even though the above is by far a better approach compared to using a text file to store application property data, there is even a better method to storing static data such as state abbreviations, company addresses, application security contexts, etc., etc. ....


USE A DATABASE !!!

Wednesday, May 2, 2007

Iterating through a HashMap

Unlike Lists, and ArrayLists should come to mind, Maps don’t have an iterator() method like that provided by the Set or List classes. However, you can iterate through the keys or the key-value elements.

There are a few different types of maps. I’ve used HashMap and TreeMap, but I have yet had the need to use a LinkedHashMap. The ordering of the elements in each differ a bit depending on the type of map.


Type Order
---------- ---------------------------------------------------------------
HashMap The location of the entries added to a HashMap is unpredictable
in that it is governed by a hashing algorithm.

TreeMap Order is by key

LinkedHashMap The order of the entries in a LinkedHashMap is governed by the
previously entered element to which it is linked.


The method example below will print to the console the key/value pairs contained within an arbitrary map. The method can work with all Maps.


Object Description
-------------- ---------------------------------------------------
aHashMapOfObject This object is your HashMap containing objects
placed within it by using the HashMap’s put()
method.

pairs Contains the key/value pairs. These values will
mirror the values used on the HashMap’s put()
method.

key The value of the key used for the object placed
into the HashMap.

yerob This is the object initially placed into the
HashMap.




Creating the HashMap and then adding a key/value pair would then look like this:


NameAndAddr nameAddr = new NameAndAddr("Imgona Choitoya");

HashMap aHashMapOfObjects = new HashMap();
aHashMapOfObjects.put("NameAddr01", nameAddr);

Iterator iter = aHashMapOfObjects.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry pairs = (Map.Entry)iter.next();
String key = (String)pairs.getKey();
NameAndAddr yerob = (NameAndAddr)pairs.getValue();
String name = yerob.getName();

System.out.println("The key value within yerob is " + key);
System.out.println("The value of the property within the object is " + name );
}


This would print:
The key value within yerob is NameAddr01
The value of the property within the object is Imgona Choitoya

For completeness, the NameAndAddr class and the TestClass class is shown.
NameAndAddr.java



package testpackage;

public class NameAndAddr {

private String name;

/**
* Constructor
* @param value
*/
public NameAndAddr(String value) {
this.name = value;
}

public String getName() {
return name;
}

public void setName(String value) {
this.name = value;
}

}


TestClass.java


package testpackage;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class TestClass {

/**
* @param args
*/
public static void main(String[] args) {

TestClass test = new TestClass();
test.runIt();

}


/**
*
*
*/
public void runIt() {

NameAndAddr nameAddr = new NameAndAddr("Imgona Choitoya");

HashMap aHashMapOfObjects = new HashMap();
aHashMapOfObjects.put("NameAddr01", nameAddr);

Iterator iter = aHashMapOfObjects.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry pairs = (Map.Entry)iter.next();
String key = (String)pairs.getKey();
NameAndAddr yerob = (NameAndAddr)pairs.getValue();
String name = yerob.getName();

System.out.println("The key value within yerob is " + key);
System.out.println("The value of the property within the object is " + name );
}

}

}

Tuesday, May 1, 2007

Days elapsed since December 31, 1899

There seems to be a common practice to store dates into a database as days since January 1, 1900. The argument advanced is that it's done for performance reasons. The code shown here converts a Java date object to the number of days which have elapsed since that given date.



/**
* Accepts a Date object from which the number of days from 1899-12-31 is then
* which select upon table columns containing dates stored with this value.
* The value in columns such as this is actually the number of days from 1899-12-31.
* This method of storing dates can improve database performance, however, during
* research or manual selection of records using a DB tool, the analyst must know
* to use values such as 38700 instead of 2005-12-15 when formatting the SQL
* statement.
*
* @param date
* @return int days
*/
public int getDaysSince1900 (Date date) {

//Tested against the follwing SQL statement:
//select date = DATEDIFF(day, '1899-12-31', '2005-12-15') = 38700
//Today's date at time of test was 2005-12-15 yielding 38700 as diff
Date floorDate = new GregorianCalendar(1899,11,31,00,00).getTime();
long diff = date.getTime() - floorDate.getTime();
long daysSince1900 = diff /(1000*60*60*24);

//Convert to int (Stored in db as int)
String ds = Long.toString(daysSince1900);
int days = Integer.parseInt(ds);
return days;
}


/**
* Accepts an integer value representing the number of days from 1899-12-31 and
* converts it into a Date object.
*
* @param days
* @return dateSince1900
*/
public Date getDateSince1900 (int days) {

Date floorDate = new GregorianCalendar(1899,11,31,00,00).getTime();
long floorAsMilliseconds = floorDate.getTime();

long millisecondsInDay = (1000*60*60*24);
long daysAsMilliseconds = days * millisecondsInDay;

Date dateSince1900 = new Date( floorAsMilliseconds + daysAsMilliseconds );

return dateSince1900;
}


The following will take a formatted date string and convert it into a date object. It then takes the date object, coverts it into the Julian value measured from December 12, 1899, and converts it back into a date object.



Date testDate = null;
int testDays = 0;

try {
String dateAsString = "02/28/2006";
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");
testDate = sdf.parse(dateAsString);
//At this point dateObject has no time. Add 12 hours to place it at 12:00:00
testDate.setTime(testDate.getTime() + (12000*60*60));
System.out.println(dateAsString + " -----> " + testDate);
} catch (Exception e) {
}

//Conversion Pass
testDays = test.getDaysSince1900(testDate);
System.out.println(testDate + " -----> " + testDays);

testDate = test.getDateSince1900(testDays);
testDate.setTime(testDate.getTime() + (12000*60*60));
System.out.println(testDays + " -----> " + testDate);



The results of the above test are shown here.



02/28/2006 -----> Tue Feb 28 12:00:00 CST 2006

Tue Feb 28 12:00:00 CST 2006 -----> 38775
38775 -----> Tue Feb 28 12:00:00 CST 2006

Tue Feb 28 12:00:00 CST 2006 -----> 38775
38775 -----> Tue Feb 28 12:00:00 CST 2006

Saturday, April 28, 2007

Comparison using Java's ternary operator

When using Java's ternary operator which allows assignment to a variable based upon one or more Boolean decisions, construct the code in such a way as to mitigate null exception errors.

For example, in the event the field “verified” contains a null value, the following construct results in a null exception error:


boolean verifiedAsBoolean = "Y".equalsIgnoreCase(verified) ? true : false;


This version will return false.


boolean verifiedAsBoolean = verified.equalsIgnoreCase("Y") ? true : false;


Although acceptable, consider employing a basic if / then construct. The test example below will not fail if verified contains a null and will return false. The construct also allows new logic to be to implemented more efficiently.

If ('Y'.equals(verified)) {
verifiedAsBoolean = true;
} else {
verifiedAsBoolean = false;
}

Monday, April 23, 2007

Reconciling ArrayList contents with the Comparator class

For the current project requiring enhancements to be made to a JSF-based web application, I had to determine what was changed by the user and then write the changes identified into a new table for reporting purposes – an activity journal.

The page had the usual input text boxes and a list-box into which entries as seen within a companion list-box could be selected to add those selections to the second list-box. When the user removed items from the list-box, they were returned to the companion list-box. The problem was to capture those events as “adds’ or “deletes”.

The solution uses two ArrayLists. The first (named “preservedSelectedValues”) holds the list of items in a list-box BEFORE changes. The second (named “selectedValues”), holds the list of items in that list-box after changes. Both ArrayLists hold those entries as SelectItem objects.

Since I need to know what was added to or deleted from the list-box represented by the second ArrayLists it can be treated as a simple reconciliation problem. The brute force code, reeking of COBOL or RPG approaches, is represented here:


//Capture changes.
if (preservedSelectedValues.size() >= selectedValues.size()) {
int foundCount = 0;
for (int i=0; i < preservedSelectedValues.size(); i++) {
boolean found = false;
SelectItem psi = (SelectItem)preservedSelectedValues.get(i);
for(int j=0; j < selectedValues.size(); j++){
SelectItem si = (SelectItem)selectedValues.get(j);
//Found - No change
if(psi.getLabel().equals(si.getLabel()) ) {
found = true;
foundCount++;
break;
}
}
//The item was deleted
if (!found ) {
System.out.println("Deleted : " + psi.getLabel() + " " + psi.getValue());
}
}
if(preservedSelectedValues.size() == foundCount) {
System.out.println("No changes were detected.");
}
if(preservedSelectedValues.size() > foundCount) {
System.out.println("Some items have been deleted.");
}
}

if (selectedValues.size() >= preservedSelectedValues.size()) {
int foundCount = 0;
for (int i=0; i < selectedValues.size(); i++) {
boolean found = false;
SelectItem psi = (SelectItem)selectedValues.get(i);
for(int j=0; j < preservedSelectedValues.size(); j++){
SelectItem si = (SelectItem)preservedSelectedValues.get(j);
//Found - No change
if(psi.getLabel().equals(si.getLabel()) ) {
found = true;
foundCount++;
break;
}
}
//The item was added
if (!found ) {
System.out.println("Added : " + psi.getLabel() + " " + psi.getValue());
}
}
if(selectedValues.size() == foundCount) {
System.out.println("No changes were detected.");
}
if(selectedValues.size() > foundCount) {
System.out.println("Some items have been added.");
}
}


The better way is to create a comparator class which has dual responsibilities. The first responsibility is to act as a comparator to assist in sorting the ArrayLists. The second responsibility is to assist in the comparison for differences between the ArrayLists. The comparator class accepts 2 objects and then casts them to SelectItem objects to perform compares against the value properties. The returned value from this exercise is an integer reporting whether it was found to be less than, equal to or greater than. The comparator:


/**
* Modification History
*
* Date Project Pgmr Description
* -------- --------- ------- -----------------------------------------------
*
*
*/
package com.util;

import java.util.Comparator;

import javax.faces.model.SelectItem;


public class SelectItemComparator implements Comparator {

String name = this.getClass().getName();

/**
* Constructor
*
*/
public SelectItemComparator() {
super();
}

/**
* Compares the suppled SelectItem objects to each other. This method is used
* to resolve sorts and to determine equality.
*
*/
public int compare(Object o1, Object o2) {
SelectItem s1 = (SelectItem)o1;
SelectItem s2 = (SelectItem)o2;
return s1.getValue().toString().compareTo((s2.getValue().toString()));
}

}




The implementation does the sort followed by the comparison operations. The sprit is the same as the first set of code shown at the top of this post.

//Capture changes. First, sort the arraylists containing the SelectItem objects
Collections.sort(preservedSelectedValues, new SelectItemComparator());
Collections.sort(selectedValues, new SelectItemComparator());

//Second, perform the compares
for (int i=0,size=preservedSelectedValues.size(); i < size; i++) {
SelectItem psi = (SelectItem)preservedSelectedValues.get(i);
int pos = Collections.binarySearch(selectedValues, psi, new SelectItemComparator() );
if (pos<0) {
System.out.println("Comparator method. Deleted : " + psi.getLabel() + " " + psi.getValue());
}
}
for (int i=0,size=selectedValues.size(); i < size; i++) {
SelectItem si = (SelectItem)selectedValues.get(i);
int pos = Collections.binarySearch(preservedSelectedValues, si, new SelectItemComparator() );
if (pos<0) {
System.out.println("Comparator method. Added : " + si.getLabel() + " " + si.getValue());
}
}



There. Much better.