This package contains the implementation of the application use-cases. It uses an abstract base class based on the command pattern that implements common methods for all transactions and defines an abstract execute method. Each use-case class extends this abstract class and implements the execute method.
The base class for the use-cases implements the basic methods to get the PersistenceManagerFactory and PersistenceManager instances, begin and commit transactions, and handle exceptions.
As shown in earlier chapters, PersistenceManagerFactory bootstrapping can be done using a singleton pattern and reading properties from a file to avoid hard coding connection or JDO implementation specific details.
/** * Creates or returns a JDO factory. * The properties are loaded * from a file. */ public static PersistenceManagerFactory getPersistenceManagerFactory() { if (pmf == null) { String filename = System.getProperty("jdo.properties"); if (filename == null) { throw new JDOFatalUserException( "System property 'jdo.properties' not defined"); } Properties properties = new Properties(); try { FileInputStream file = new FileInputStream(filename); properties.load(file); file.close(); pmf = JDOHelper.getPersistenceManagerFactory( properties); } catch (java.io.IOException e) { throw new JDOFatalUserException( "Error reading '" + filename + "'", e); } } return pmf; }
This method uses a singleton pattern to maintain a reference to a PersistenceManager instance for a given use-case instance.
/** * Creates or returns a PersistenceManager. * If a servlet helper is associated with * the current use case, a persistence manager * may be taken from the helper object. */ PersistenceManager getPM() { if (currentPersistenceManager == null) { currentPersistenceManager = getPMF().getPersistenceManager(); } return currentPersistenceManager; }
This method releases the singleton PersistenceManager instance at the end of the use-case.
/** * Called by outside application management. * * In case of servlets, this method is called * on session timeout. * The command line version calls this method * at system exit. */ void close() { if (currentPersistenceManager != null) { currentPersistenceManager.close(); currentPersistenceManager = null; } }
This method runs the use-case; it gets the PersistenceManager instance, begins a transaction, and then calls the internal execute method to run the use-case. It then commits the transaction and handles any exceptions. If an exception is caught, the transaction is rolled back.
/** * This method creates a transaction context, * starts the transaction * and commits all work, after the <tt>_execute</tt> * method has been * successfully invoked. If the subclass throws * an exception, the transaction is aborted. */ public final void execute() { if (!isAllowed()) throw new UseCaseException("Not allowed."); getPM().currentTransaction().begin(); boolean active = true; try { _execute(); getPM().currentTransaction().commit(); active = false; } finally { if (active) { try { getPM().currentTransaction().rollback(); active = false; } catch (JDOUserException ex) { ex.printStackTrace() ; } } } }
This first use-case is straightforward; it creates a new Book instance and makes it persistent.
Package com.corejdo.casestudy.usecase; import com.corejdo.casestudy.model.Book; import com.corejdo.casestudy.model.User; import com.corejdo.casestudy.tools.CmdLine; import java.util.Date ; import java.text.DateFormat ; import java.text.ParseException; /** * This class adds a book to the library. * It implements a bean pattern, which can * be used simply in the JSP. */ public class AddBook extends AbstractUseCase { /** * This is the book that gets inserted. * While it is transient, we * can set and get values directly. */ Book book = new Book(); public AddBook() { } public void setISBN(String ISBN) { book.ISBN = ISBN; } public void setAuthor(String author) { book.author = author; } public void setCopyright(String copyright) { book.copyright = copyright; } public void setPublished(String published) { book.published = parseDate(published); } public void setFirstPublished(String firstPublished) { book.firstPublished = parseDate(firstPublished); } public void setTitle(String title) { book.title = title; } /** * Adds a book via command line. */ public static void main(String[] args) { new AddBook().runCmdLine(args); } protected void runCmdLine(String[] args) { setTitle(CmdLine.getStringVar("Title","")); setISBN(CmdLine.getStringVar("ISBN","")); setAuthor(CmdLine.getStringVar( "Author","Heiko Bobzin")); setCopyright(CmdLine.getStringVar( "Copyright","© 2003 Prentice H"ll")); String now = new Date().toString(); setPublished(CmdLine.getStringVar( " "Publishing d"te",now)); setFirstPublished(CmdLine.getStringVar( " "First publishing d"te",now)); execute(); } private Date parseDate(String d) { try { return DateFormat.getInstance().parse(d); } catch (ParseException e) { throw new RuntimeExcepti"n("Illegal dat": "+d); } } public boolean isAllowed() { return getContext().userRights.canManage(); } protected void _execute() { // this is a really simple operation: User user = getUser(); book.insertedBy = user; getPM().makePersistent(book); // set for next insert: book = new Book(); } public String getFirstPublished() { return new Date().toString(); } public String getPublished() { return new Date().toString(); } }