5. Appendices
5.1. Code from the [istia.st.articles.dao] package
5.1.1. IArticlesDao
package istia.st.articles.dao;
import istia.st.articles.domain.Article;
import java.util.List;
/**
* @author serge
*
*/
public interface IArticlesDao {
/**
* @return: list of all articles
*/
public List getAllArticles();
/**
* @param anArticle:
* : the article to add
*/
public int addArticle(Article anArticle);
/**
* @param articleId:
* ID of the article to delete
*/
public int deleteArticle(int articleId);
/**
* @param article:
* the article to modify
*/
public int modifyArticle(Article anArticle);
/**
* @param articleId:
* : ID of the article being searched for
* @return: the found article or null
*/
public Article getArticleById(int articleId);
/**
* clears the article table
*/
public void clearAllArticles();
/**
*
* @param itemId ID of the item whose stock is being updated
* @param movement value to add to stock (signed value)
*/
public int updateItemStock(int itemId, int movement);
}
5.1.2. ArticlesDaoSqlMap
package istia.st.articles.dao;
import java.io.*;
import java.sql.*;
import java.util.*;
import com.ibatis.common.resources.*;
import com.ibatis.sqlmap.client.*;
import istia.st.articles.domain.*;
import istia.st.articles.exception.*;
/**
* @author ST-ISTIA
*
*/
public class ArticlesDaoSqlMap
implements IArticlesDao {
/**
* sqlMap object providing access to data in a DBMS
* is built from a configuration file
* executes SQL queries that are also stored in a configuration file
*/
private SqlMapClient sqlMap = null;
/**
*
* @return the sqlMap object for data access
*/
public SqlMapClient getSqlMap() {
return sqlMap;
}
/**
*
* @param sqlMap the sqlMap object for data access
*/
public void setSqlMap(SqlMapClient sqlMap) {
this.sqlMap = sqlMap;
}
/**
*
* @param sqlMapConfigFileName the name of the SqlMap configuration file
* @throws UncheckedAccessArticlesException if any issues occur
*/
public ArticlesDaoSqlMap(String sqlMapConfigFileName) {
Reader reader = null;
UncheckedAccessArticlesException ex = null;
try {
reader = Resources.getResourceAsReader(sqlMapConfigFileName);
sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader);
}
catch (Exception ex1) {
ex = new UncheckedAccessArticlesException(
"Error constructing the [sqlMap] object from the configuration file ["
+ sqlMapConfigFileName + "] : ", ex1);
}
finally {
try {
reader.close();
}
catch (Exception ex2) {
if (ex != null) {
ex = new UncheckedAccessArticlesException(
"Error closing the [reader] object from the configuration file ["
+ sqlMapConfigFileName + "] : ", ex2);
}
}
}
// Should an exception be thrown?
if (ex != null) {
throw ex;
}
}
/**
* @return a list of all items of type Article
*/
public synchronized List getAllArticles() {
try {
return sqlMap.queryForList("getAllArticles", null);
}
catch (SQLException ex) {
throw new UncheckedAccessArticlesException(
"Failed to retrieve all articles: [" + ex + "]", ex);
}
}
/**
* @param anArticle the article to add
* @return the number of items added
* @throws UncheckedAccessArticlesException if failed
*/
public synchronized int addArticle(Article anArticle) {
try {
// prepare the parameters
Map parameters = new HashMap(5);
parameters.put("id", new Integer(article.getId()));
parameters.put("name", unArticle.getName());
parameters.put("price", new Double(anItem.getPrice()));
parameters.put("currentStock", new Integer(anItem.getCurrentStock()));
parameters.put("minStock", new Integer(anItem.getMinStock()));
// execute the query
return sqlMap.update("insertArticle", parameters);
}
catch (SQLException ex) {
throw new UncheckedAccessArticlesException(
"Failed to add article [" + unArticle + "] : [" + ex + "]",
ex);
}
}
/**
* @param idArticle ID of the article to delete
* @return the number of articles deleted
* @throws UncheckedAccessArticlesException if failed
*/
public synchronized int deleteArticle(int articleId) {
try {
// prepare the parameters
Map parameters = new HashMap(1);
parameters.put("id", new Integer(articleId));
// execute the query
return sqlMap.update("deleteArticle", parameters);
}
catch (SQLException ex) {
throw new UncheckedAccessArticlesException(
"Error deleting article with id [" + idArticle
+ "] : [" + ex + "]", ex);
}
}
/**
* @param anArticle the modified article that should replace the old one with the same ID
* @return the number of modified articles
* @throws UncheckedAccessArticlesException if failed
*/
public synchronized int modifyArticle(Article anArticle) {
try {
// prepare the parameters
Map parameters = new HashMap(5);
parameters.put("id", new Integer(article.getId()));
parameters.put("name", unArticle.getName());
parameters.put("price", new Double(anItem.getPrice()));
parameters.put("currentStock", new Integer(anItem.getCurrentStock()));
parameters.put("minStock", new Integer(anItem.getMinStock()));
// execute the query
return sqlMap.update("modifyArticle", parameters);
}
catch (SQLException ex) {
throw new UncheckedAccessArticlesException(
"Error updating article [" + article +
"]: ["
+ ex + "]", ex);
}
}
/**
* @param idArticle ID of the article being searched for
* @return Article: the found article or null
* @throws UncheckedAccessArticlesException if unsuccessful
*/
public synchronized Article getArticleById(int articleId) {
try {
// prepare the parameters
Map parameters = new HashMap(1);
parameters.put("id", new Integer(articleId));
// execute the query
Article article = (Article) sqlMap.queryForObject("getArticleById",
parameters);
// Return the result
return article;
}
catch (SQLException ex) {
throw new UncheckedAccessArticlesException(
"Error retrieving the article with id [" + idArticle
+ "] : [" + ex + "]", ex);
}
}
/**
* clears the article table
* @throws UncheckedAccessArticlesException on failure
*/
public synchronized void clearAllArticles() {
try {
sqlMap.update("clearAllArticles", null);
}
catch (SQLException ex) {
throw new UncheckedAccessArticlesException(
"Error clearing the articles table: [" + ex +
"",
ex);
}
}
/**
*
* @param percentage the percentage increase as an integer
* @throws UncheckedAccessArticlesException on failure
*/
public synchronized void increaseAllPrices(int percentage) {
try {
// prepare the parameters
Map parameters = new HashMap(1);
parameters.put("percentage", new Double(0.01 * percentage));
// execute the query
sqlMap.update("priceIncrease", parameters);
}
catch (SQLException ex) {
throw new UncheckedAccessArticlesException(
"Price increase error: [" + ex + "]", ex);
}
}
/**
* test method
*/
public void badOperationThrowsException() {
// artificially throws an exception
throw new UncheckedAccessArticlesException();
}
/**
*
* @param articles Article[] list of articles to insert in a single transaction
* @throws UncheckedAccessArticlesException if failed
*/
public synchronized void doInsertionsInTransaction(Article[] articles) {
// insert all articles as a single unit
UncheckedAccessArticlesException ex = null;
int i = 0;
Connection connection = null;
try {
// Start the transaction
sqlMap.startTransaction();
// perform the inserts
for (; i < articles.length; i++) {
addItem(items[i]);
}
// Commit the transaction
sqlMap.commitTransaction();
}
catch (Exception ex1) {
// wrap the exception
ex = new UncheckedAccessArticlesException(
"doInsertionsInTransaction, database access error: [" + ex1 +
"",
ex1);
}
finally {
try {
sqlMap.endTransaction();
}
catch (SQLException ex2) {
if (ex != null) {
ex = new UncheckedAccessArticlesException(
"doInsertionsInTransaction, close failed: [" + ex2 + "]", ex2);
}
}
}
// Should an exception be thrown?
if (ex != null) {
throw ex;
}
}
/**
*
* @param idArticle ID of the item whose stock is being updated
* @param movement stock movement
*/
public synchronized int updateItemStock(int itemId, int movement) {
try {
// Prepare the parameters
Map parameters = new HashMap(2);
parameters.put("id", new Integer(itemId));
parameters.put("movement", new Integer(movement));
// execute the query
return sqlMap.update("updateItemStock", parameters);
}
catch (SQLException e1) {
throw new UncheckedAccessArticlesException(
"Error updating stock [idArticle=" + idArticle +
", movement=" + movement + "] : [" + e1 + "]", e1);
}
}
}
5.1.3. Article
package istia.st.articles.dao;
import istia.st.articles.exception.UncheckedAccessArticlesException;
/**
* @author ST - ISTIA
*
*/
public class Article {
private int id;
private String name;
private double price;
private int currentStock;
private int minimumStock;
/**
* default constructor
*/
public Item() {
}
public Article(int id, String name, double price, int currentStock,
int minimumStock) {
// Initialize instance attributes
setId(id);
setName(name);
setPrice(price);
setCurrentStock(currentStock);
setMinStock(minStock);
}
// getters - setters
public int getId() {
return id;
}
public void setId(int id) {
// Is the ID valid?
if (id < 0)
throw new UncheckedAccessArticlesException("Invalid id[" + id + "]");
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
// Is the name valid?
if(name == null || name.trim().equals("")){
throw new UncheckedAccessArticlesException("The name is [null] or empty");
}
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
// Is the price valid?
if(price < 0) throw new UncheckedAccessArticlesException("Invalid price [" + price + "]");
this.price = price;
}
public int getCurrentStock() {
return currentStock;
}
public void setCurrentStock(int currentStock) {
// Is the stock valid?
if (currentStock < 0)
throw new UncheckedAccessArticlesException("currentStock[" + currentStock + "] is invalid");
this.currentStock = currentStock;
}
public int getMinimumStock() {
return stockMinimum;
}
public void setStockMinimum(int stockMinimum) {
// Is the stock valid?
if (stockMinimum < 0)
throw new UncheckedAccessArticlesException("stockMinimum[" + stockMinimum + "] is invalid");
this.stockMinimum = stockMinimum;
}
public String toString() {
return "[" + id + "," + name + "," + price + "," + currentStock + ","
+ stockMinimum + "]";
}
}
5.2. The package [istia.st.articles.domain]
5.2.1. IArticlesDomain
package istia.st.articles.domain;
import java.util.ArrayList;
import java.util.List;
public interface IArticlesDomain {
public void buy(ShoppingCart shoppingCart);
public List getAllArticles();
public Article getArticleById(int id);
public ArrayList getErrors();
}
5.2.2. Purchase
package istia.st.articles.domain;
public class Purchase {
/**
* the purchased item
*/
private Article article;
/**
* the quantity purchased
*/
private int qty;
/**
* @return Returns the amount to be paid for the purchase
*/
public double getTotal() {
return item.getPrice() * qty;
}
/**
*
* @param item
* s the purchased item
* @param qty
* the quantity purchased
*/
public Purchase(Article item, int qty) {
this.item = item;
this.qty = qty;
}
/**
* @return Returns the purchased item
*/
public Item getItem() {
return item;
}
/**
* @param article
* s the purchased item
*/
public void setArticle(Article article) {
this.article = article;
}
/**
* @return Returns the quantity purchased
*/
public int getQuantity() {
return qty;
}
/**
* @param qte
* s the quantity purchased
*/
public void setQty(int qty) {
this.qte = qte;
}
/**
* @return string representing the purchase
*/
public String toString() {
return "[" + this.item.toString() + "," + this.qty + "]";
}
}
5.2.3. Cart
package istia.st.articles.domain;
import java.util.ArrayList;
public class ShoppingCart {
/**
* list of purchases
*/
private ArrayList purchases = new ArrayList();
/**
* @return Returns the purchases.
*/
public ArrayList getPurchases() {
return purchases;
}
/**
* adds a purchase
*
* @param aPurchase
*/
public void add(Purchase purchase) {
// add the purchase
// check if the item has already been purchased
int itemId = purchase.getItem().getId();
Item item = null;
Purchase purchase = null;
boolean found = false;
for (int i = 0; !found && i < purchases.size(); i++) {
purchase = (Purchase) purchases.get(i);
item = (Item) purchase.getItem();
if (item.getId() == itemId) {
purchase.setQuantity(purchase.getQuantity() + onePurchase.getQuantity());
found = true;
}
}
// Item found?
if (!found) {
// Not purchased yet - add the purchase
purchases.add(aPurchase);
}
}
/**
*
* @param purchaseId
* the ID of the purchase to remove from the cart
*/
public void remove(int itemId) {
// Remove the purchase with id idPurchase
for (int i = 0; i < purchases.size(); i++) {
if (((Purchase) purchases.get(i)).getItem().getId() == itemId) {
purchases.remove(i);
}
}
}
/**
*
* @return the total amount due
*/
public double getTotal() {
// calculate the total of purchases
double total = 0;
for (int i = 0; i < purchases.size(); i++) {
total += ((Purchase) purchases.get(i)).getTotal();
}
return total;
}
/**
* @return a string representing the shopping cart
*/
public String toString() {
return this.purchases.toString();
}
}
5.2.4. PurchasesItems
package istia.st.articles.domain;
import java.util.ArrayList;
import java.util.List;
import istia.st.articles.dao.IArticlesDao;
public class PurchasedItems implements IArticlesDomain {
private IArticlesDao articlesDao;
private Object synchro = new Object();
private ArrayList errors;
/**
* @return Returns the errors.
*/
public ArrayList getErrors() {
return errors;
}
/**
*
* @param articlesDao
* the data access service
*/
public PurchaseItems(IArticlesDao articlesDao) {
this.articlesDao = articlesDao;
}
public List getAllArticles() {
return articlesDao.getAllArticles();
}
public Article getArticleById(int id) {
return articlesDao.getArticleById(id);
}
public void buy(Cart cart) {
// iterate through the purchases
ArrayList purchases = cart.getPurchases();
errors = new ArrayList();
Item item = null;
Purchase purchase = null;
for (int i = purchases.size() - 1; i >= 0; i--) {
// retrieve the purchase
purchase = (Purchase) purchases.get(i);
// attempt to update the item's stock in the database
int nbarticles =
articlesDao.updateItemStock(
purchase.getArticle().getId(),
-purchase.getQuantity());
// Was it successful?
if (nbarticles != 0) {
purchases.remove(i);
} else {
errors.add(
"Purchase item ["
+ purchase.getArticle()
+ ","
+ purchase.getQty()
+ "] not possible - Check stock");
}
}
}
}
5.3. The package [istia.st.articles.exception]
package istia.st.articles.exception;
public class UncheckedAccessArticlesException
extends RuntimeException {
public UncheckedAccessArticlesException() {
super();
}
public UncheckedAccessArticlesException(String mesg) {
super(mesg);
}
public UncheckedAccessArticlesException(String mesg, Throwable th) {
super(mesg, th);
}
}