I am only demonstrating the Product Maintenance here. The following ‘common’ classes were provided:
· MultiColumnList; This class extends Panel and is used to display the information in columns on the GUI.
· DBConnection; Objects of this class encapsulate the details needed for connecting to a database. The connect() method returns a connection object.
· Deployment; This provides a central and standard place to get deployment information.
· MessageBox; This class creates a modal message dialog box with a variable prompt.
· ProductPropertiesPanel; Methods in this class allow access to the properties of the products displayed on the GUI. It also sets up the panel for displaying the products.
The objective of this task is to design, code, and test the transaction logic for the Product Maintenance program (Business Layer). I was responsible for the following:
· Determine the necessary SQL statements.
· Determine and implement the logic for the transactions.
· Determine and implement logic for dealing with exceptions.
· Determine and implement any data validation requirements.
· Package transaction results (including exceptions) into a standard object for return to the caller of the transaction.
· Develop a test plan for each transaction.
· Test each transaction by writing a main that prints any outputs. It does not need to be interactive; hard coding of inputs or on the command line is acceptable.
We were provided with the declaration of the ProductTransactionITF class, which lists the methods we must implement in this class.
package product;
import common.*;
import java.sql.*;
public class
ProductTransactionImpl implements ProductTransactionITF
{
private Connection mSQLcon;
private Statement stmt;
public ProductTransactionImpl()
{
connectDataBase();
}
// Connect
to database using driver and database from Deployment class
public void
connectDataBase()
{
String driver = "sun.jdbc.odbc.JdbcOdbcDriver";
String url = "jdbc:odbc:" +
Deployment.ODBCDataSourceName;
connectDataBase(driver, url);
}
// Connect
to database using a specified driver and database URL
public void
connectDataBase(String driver, String url)
{
try
{
DBConnection
dataConnection = new DBConnection(driver, url);
mSQLcon =
dataConnection.connect();
// Use the
connection to create the statement object
stmt =
mSQLcon.createStatement ();
} catch (Exception e)
{
e.printStackTrace();
}
}
// Transaction
to return all of the product information
public synchronized Result getAllProducts()
{
Result ans = new Result();
try
{
String query =
"Select Distinct * from Products";
ResultSet rs = stmt.executeQuery(query);
while(rs.next())
{
String
queryResult[] = new String[5];
queryResult[0]
= rs.getString("ProductID");
queryResult[1]
= rs.getString("ProductDescription");
queryResult[2]
= rs.getString("UnitPrice");
queryResult[3]
= rs.getString("AvailableQuantity");
queryResult[4]
= rs.getString("TaxCode");
ans.add(queryResult);
}
} catch(Throwable e)
{
e.printStackTrace();
ans.clear();
ans.add(e);
}
return ans;
}
//
Transaction to return the information for one particular product
public synchronized Result getProduct(String
productID)
{
Result ans = new Result();
try
{ //
ProductID must be numeric, an integer and >0
if(Integer.parseInt(productID)<=0)
{
throw
new Throwable("Product ID must be greater than 0.");
}
String query =
"Select Distinct * from Products where ProductID=" + productID;
ResultSet rs =
stmt.executeQuery(query);
String queryResult[]
= new String[5];
while(rs.next())
{
queryResult[0]
= rs.getString("ProductID");
queryResult[1]
= rs.getString("ProductDescription");
queryResult[2]
= rs.getString("UnitPrice");
queryResult[3]
= rs.getString("AvailableQuantity");
queryResult[4]
= rs.getString("TaxCode");
ans.add(queryResult);
System.out.println(queryResult[1]);
}
}
catch(NumberFormatException nfe)
{
MessageBox.displayMessageBox("Product
ID must be an integer.");
ans.clear();
ans.add(nfe);
}
catch(Throwable e)
{
e.printStackTrace();
ans.clear();
ans.add(e);
}
return ans;
}
// Transaction
to update a product's information
public
synchronized Result updateProduct(String description, String price, String
quantity, String taxCode, String productID)
{
Result ans = new Result();
try
{
//
No empty strings among the arguments
if
((description.equals("")) || (price.equals("")) ||
(quantity.equals("")) || (taxCode.equals("")) ||
(productID.equals("")))
{
throw
new Throwable("No arguments can be empty.");
}
// Unit price must
be numeric and positive
if(Double.parseDouble(price)<0)
{
throw
new Throwable("The unit price must be positive.");
}
//
Quantity must be 0 or a positive integer
if(Integer.parseInt(quantity)<0)
{
throw
new Throwable("The quantity must be zero or greater.");
}
// Tax code must
be 0-3 only
if
(!(taxCode.equals("0")) && !(taxCode.equals("1"))
&& !(taxCode.equals("2")) &&
!(taxCode.equals("3")))
{
throw
new Throwable("Tax Code must be either 0,1,2 or 3.");
}
// ProductID must
be an integer and >0
if(Integer.parseInt(productID)<=0)
{
throw
new Throwable("Product ID must be greater than 0.");
}
String
updateRecord = "Update PRODUCTS Set " + "
ProductDescription=" + "'" + description
+
"'" + "," + " UnitPrice=" + price + ","
+ " AvailableQuantity=" +
quantity
+ "," + " TaxCode=" + taxCode + " Where ProductID="
+ productID;
int nRows =
stmt.executeUpdate(updateRecord);
System.out.println("On
update product " + nRows + " rows were modified");
ans.add(new
Integer(nRows));
}
catch(NumberFormatException nfe)
{
MessageBox.displayMessageBox("Incorrect
Data Type.");
ans.clear();
ans.add(nfe);
}
catch(Throwable e)
{
e.printStackTrace();
ans.clear();
ans.add(e);
}
return ans;
}
// Transaction
to insert a new product into the database
public synchronized Result insertProduct(String
description, String price, String quantity, String taxCode)
{
Result ans = new Result();
try
{ //
No empty strings among the arguments
if
((description.equals(""))||(price.equals(""))||(quantity.equals(""))||(taxCode.equals("")))
{
throw
new Throwable("No arguments can be empty.");
}
// Unit price must
be numeric and positive
if
(Double.parseDouble(price)<0)
{
throw
new Throwable("The unit price must be positive.");
}
// Quantity must
be 0 or a positive integer
if
(Integer.parseInt(quantity)<0)
{
throw
new Throwable("The quantity must be zero or greater.");
}
// Tax code must
be 0-3 only
if
(!(taxCode.equals("0")) && !(taxCode.equals("1")) &&
!(taxCode.equals("2")) &&
!(taxCode.equals("3")))
{
throw
new Throwable("Tax Code must be either 0,1,2 or 3.");
}
String insertRecord =
"Insert Into PRODUCTS (ProductDescription, UnitPrice, AvailableQuantity,
TaxCode) " + "Values (" +
"'" + description + "'" + "," + price +
"," +
quantity + "," + taxCode +
")";
int nRows =
stmt.executeUpdate(insertRecord);
System.out.println("On
insert product " + nRows + " rows were modified");
ans.add(new
Integer(nRows));
}
catch(NumberFormatException nfe)
{
MessageBox.displayMessageBox("Incorrect
data type.");
ans.clear();
ans.add(nfe);
}
catch(Throwable e)
{
e.printStackTrace();
ans.clear();
ans.add(e);
}
return ans;
}
// Transaction
to delete a product from the database
public synchronized Result deleteProduct(String
productID)
{
Result ans = new Result();
try
{
// ProductID must
be numeric, an integer and >0
if
(Integer.parseInt(productID)<=0)
{
throw
new Throwable("Product ID must be greater than 0.");
}
if (productID !=
null)
{
String
deleteRecord = " Delete From PRODUCTS where ProductID = " +
productID;
int
nRows = stmt.executeUpdate(deleteRecord);
System.out.println("On
delete product " + nRows + " rows were modified");
ans.add(new
Integer(nRows));
}
}
catch(NumberFormatException nfe)
{
MessageBox.displayMessageBox("Product
ID must be an integer.");
ans.clear();
ans.add(nfe);
}
catch(Throwable e)
{
e.printStackTrace();
ans.clear();
ans.add(e);
}
return ans;
}
}
The objective of this task is to design, code, and test a Product Maintenance user-interface class (Presentation Layer). This a graphical user interface for which we must also design a test plan.
The methods in this class communicate with the transaction logic only through the methods declared in ProductTransactionITF, and with any object whose class implements the same interface. This is one of the keys to converting the application from a single-process single-user application into a distributed multi-user system, as illustrated below:
Presentation
Layer Interface Business Layer
Product- MaintenanceUI TransactionImpl USER
package product;
import common.*;
import java.awt.*;
import java.awt.event.*;
public class
ProductMaintenanceUI extends Panel
{
// Reference to interface for transactions
private ProductTransactionITF productTran;
// UI components
private MultiColumnList productList;
private ProductPropertiesPanel productProperties;
private Panel navPanel;
private Button leftButton;
private Button rightButton;
private Button deleteButton;
// Invokes
getAllProducts and updates the GUI from the data in the Result object
private void
populateProducts()
{
Result allProductsResult =
productTran.getAllProducts();
if (allProductsResult.isResultSet())
{
productList.clear();
String prodRow[];
for (int count = 0;
count < allProductsResult.size(); count++)
{
prodRow
= (String[]) allProductsResult.elementAt(count);
double
db=Double.parseDouble(prodRow[2]);
prodRow[2]=round(db)+"";
productList.addItem(prodRow);
}
}
else
MessageBox.displayMessageBox(((Throwable)allProductsResult.firstElement()).getMessage());
}
//
Invokes getProduct and updates the GUI from the data in the Result object
private void populateProperties(String arr[])
{
if (arr != null)
{
Result
selectedProductResult = productTran.getProduct(arr[0]);
if
(selectedProductResult.isResultSet())
{
String
prodRow[];
for
(int count = 0; count < selectedProductResult.size(); count++)
{
prodRow
= (String[]) selectedProductResult.elementAt(count);
productProperties.setProductID(prodRow[0]);
productProperties.setDescription(prodRow[1]);
productProperties.setPrice(prodRow[2]);
productProperties.setQuantity(prodRow[3]);
productProperties.setTaxCode(prodRow[4]);
}
}
else
MessageBox.displayMessageBox(((Throwable)selectedProductResult.firstElement()).
getMessage());
}
}
// Invokes
updateProduct transaction and updates the GUI from the data in the Result
object
private void
updateProduct()
{
Result res =
productTran.updateProduct(productProperties.getDescription(),
productProperties.getPrice(),productProperties.getQuantity(),
productProperties.getTaxCode(), productProperties.getProductID());
if (res.isRowsAffected())
populateProducts();
else
MessageBox.displayMessageBox(((Throwable)res.firstElement()).getMessage());
}
// Invokes
insertProduct transaction and updates the GUI from the data in the Result
object
private void insertProduct()
{
Result res =
productTran.insertProduct(productProperties.getDescription(),
productProperties.getPrice(),productProperties.getQuantity(),
productProperties.getTaxCode());
if (res.isRowsAffected())
populateProducts();
else
MessageBox.displayMessageBox(((Throwable)res.firstElement()).getMessage());
}
// Invokes
deleteProduct transaction and updates the GUI from the data in the Result
object
private void deleteProduct()
{
String s[] =
productList.getSelectedItem();
if (s != null)
{
Result res =
productTran.deleteProduct(s[0]);
if
(res.isRowsAffected())
populateProducts();
else
MessageBox.displayMessageBox(((Throwable)res.firstElement()).getMessage());
}
}
// ActionListener
for the Add/New buttom at the botton of the ProductMaintenanceUI panel
class
AddOKHandler implements ActionListener
{
public void
actionPerformed(ActionEvent e)
{
if
(e.getActionCommand() == "Add Product")
{
remove(productList);
productProperties
= new ProductPropertiesPanel();
add(productProperties,
BorderLayout.CENTER);
leftButton.setLabel("OK");
rightButton.setLabel("Cancel");
deleteButton.setVisible(false);
validate();
productProperties.setProductID("New
Product");
}
else
if (e.getActionCommand() == "OK")
{
try {
// Data Validation
if
(productProperties.getDescription().equals("")||productProperties.getPrice().equals("")
||productProperties.getQuantity().equals("")||productProperties.getTaxCode().equals(""))
{
throw
new InvalidTransactionException("Each field must contain a value.");
} else {
if
(!(Double.parseDouble(productProperties.getPrice())>0))
{
throw
new InvalidTransactionException("UnitPrice must be positive.");
}
else {
if
(Integer.parseInt(productProperties.getQuantity())<0)
{
throw
new InvalidTransactionException("Cannot be negative.");
}
}
}
remove(productProperties);
add(productList,
BorderLayout.CENTER);
leftButton.setLabel("Add
Product");
rightButton.setLabel("Edit
Product");
deleteButton.setVisible(true);
validate();
if
(productProperties.getProductID()== "New Product")
{
insertProduct();
}
else {
updateProduct();
}
}
catch(InvalidTransactionException
ite)
{
MessageBox.displayMessageBox(ite.getMessage());
}
catch(NumberFormatException
nfe)
{
MessageBox.displayMessageBox("Quantity
must be a whole number.");
}
} else {
System.out.println("ERROR
in AddOKHandler");
}
}
}
//ActionListener
for the Edit button at the bottom of the ProductMaintenanceUI
class
EditCancelHandler implements ActionListener
{
public void
actionPerformed(ActionEvent e)
{
if
(e.getActionCommand() == "Edit Product")
{
String
arr[];
arr =
productList.getSelectedItem();
if
(arr != null)
{
remove(productList);
productProperties
= new ProductPropertiesPanel();
add(productProperties,
BorderLayout.CENTER);
leftButton.setLabel("OK");
rightButton.setLabel("Cancel");
deleteButton.setVisible(false);
validate();
populateProperties(arr);
}
}
else if
(e.getActionCommand() == "Cancel")
{
remove(productProperties);
add(productList,
BorderLayout.CENTER);
leftButton.setLabel("Add
Product");
rightButton.setLabel("Edit
Product");
deleteButton.setVisible(true);
validate();
} else {
System.out.println("ERROR
in EditCancelHandler");
}
}
}
// ActionListener
for the Delete button at the bottom of the ProductMaintenanceUI
class
DeleteHandler implements ActionListener
{
public void
actionPerformed(ActionEvent e)
{
deleteProduct();
}
}
// Build user interface. Load class that implements the
ProductTransactionITF.
private
ProductMaintenanceUI() throws Exception
{
setLayout(new BorderLayout());
productList = new MultiColumnList();
productTran
= (ProductTransactionITF)Class.forName (Deployment.productTransactionClassName)
.newInstance();
String headerList[] = {
"ID", "Description", "Price",
"Quantity", "Tax Code"};
int headerDim[] = { 10, 30, 15, 10,
10 };
productList.setHeaderDisplay(headerList);
productList.setHeaderDimensions(headerDim);
navPanel = new Panel();
leftButton = new Button("Add
Product");
rightButton = new Button("Edit
Product");
deleteButton = new
Button("Delete Product");
leftButton.addActionListener(new
AddOKHandler());
rightButton.addActionListener(new
EditCancelHandler());
deleteButton.addActionListener(new
DeleteHandler());
navPanel.add(leftButton);
navPanel.add(rightButton);
navPanel.add(deleteButton);
add(productList,
BorderLayout.CENTER);
add(navPanel, BorderLayout.SOUTH);
}
public static void main (String args[]) throws
Exception
{
// Process the command-line
arguments and set up any overrides for default deployment parameters
if (args.length < 1)
{
System.err.println("Usage,
one of:");
System.err.println("java
ProductMaintenanceUI ODBCDataSourceName");
System.err.println("java
ProductMaintenanceUI ODBCDataSourceName
productTransactionClassName");
System.err.println("java
ProductMaintenanceUI ODBCDataSourceName
productTransactionClassName
host:port");
System.exit(1);
}
Deployment.ODBCDataSourceName =
args[0];
if(args.length > 1)
Deployment.productTransactionClassName
= args[1];
if(args.length > 2)
Deployment.productTransactionHostID
= args[2];
Frame TestWindowFrame = new
Frame("Product Maintenance");
ProductMaintenanceUI prodPanel = new
ProductMaintenanceUI();
prodPanel.populateProducts();
TestWindowFrame.add(prodPanel,
BorderLayout.CENTER);
TestWindowFrame.setSize(800,300);
TestWindowFrame.setVisible(true);
WindowListener l = new
WindowAdapter() { public void windowClosing(WindowEvent e) {
System.exit(0);
}
};
TestWindowFrame.addWindowListener(l);
}
//
Currency formatting
public static
String round(double db)
{
String str=db+"";
int in1=str.length();
int in=(int)db;
//
If the value is an integer
if(in==db) {
return
in+".00";
} else if (str.charAt(in1-2)=='.') {
//
If the value has one number to the right of the decimal
return
db+"0";
} else {
//
The value has more than 1 number to the right of the decimal
int temp1=(int)
(db*1000);
int temp2=(int) (db*100);
if
(temp1-temp2*10>=5)
{
//
Round the number up
return ((double)temp2+1)/100.00+"";
} else {
return
((double)temp2)/100.00+"";
}
}
}
}
This final task involved making enhancements to the other packages. Most of these enhancements are seen in the previous code. This is what I was responsible for:
· Improve the appearance of the GUI (ProductPropertiesPanel).
· Improve handling of the headings (MultiColumnList).
· Replace the Tax Code text field with a drop down list box (ProductPropertiesPanel).
· Mask the password with asterisks (LoginPanel from Purchase package).
Edit Product
Add Product