Home

MassLight presents

Chapter 8. Enterprise Objects Framework

Object-Relational Mapping

Goals After completing this chapter, the student will
  • be able to use the Enterprise Objects Framework (EOF) with Enterprise JavaBeans.
Prerequisites In order to complete this chapter successfully, the student must
  • be able to read and develop Java code.
Objectives The objective for this chapter is to understand and use the Enterprise Objects Framework for O/R mapping.

The problem

Imagine a database of 100 tables each with 10 columns. Now imagine developing the EJBs for each of those tables. This reveals an apparent problem with BMP EJBs.

BMP EJB development is a lengthy process, even for very simple tables. But there are issues with modifications to the schema of the database, performance, and overall architecural design. There must be a way to avoid the pitfalls that accompany EJBs for persistence.

Enter EOF.


Introducing The Enterprise Objects Framework

The Enterprise Objects Framework (EOF) turns working with databases into child's play. EOF uses model files that describe information about the schema of the database, custom queries, and any information necessary to make a connection to the database. The EOModeler application is used to create these models; you can create one from scratch, or you can tell it to reverse engineer an existing database. Once the model has been created, the EOModeler application can automatically create the database, if it hasn't been created, and generate the java classes.

The Java classes generated by EOModeler contain accessor and mutator methods for every attribute that has been designated as a class attribute (most likely all of the attributes for a table except for primary keys). Remember all those getXyz() and setXyz() methods we created in our EJBs in the previous chapter? EOModeler handles all that automatically.

Each instantiation of these classes, corresponds to a table in the database (or databases). Coordinating these instances is a class named an EOEditingContext. An EOEditingContext instance represents a sandbox for editing. It ensures that the data in the application is consistent with those stored in the database.


Introducing EOModeler

EOModeler looks like this:


The entities shown on the left side of the window represent tables in the database. Selecting an entity displays the attributes that are associated with the entity in the top right area.


Used to add an entity (table)

Used to add a column (attribute) to the selected entity

Used to add a relationship between entities

Used to create a fetch specification

Used to flatten a property (beyond the scope of this material)

Used to browse the data in the database

Used to create the tables in the database, set up the primary and foreign keys, and generate SQL

Used to generate Java source for the selected entity


Used to denote that the selected column is a primary key for the selected entity

Used to denote that the selected column is a class attribute; that is, the column will have accessor and mutator methods in the generated Java source

Used for locking attributes (beyond the scope of this material)

Using EOF

In EOF, all database work is done in something called an editing context, represented by the EOEditingContext class. An editing context is a local working area that allows you to fetch data from the database, make changes (including adding or deleting entities, or modifying attributes), and then either save those changes back to the database or cancel them. In database terms, this is like doing various SELECT statements, then opening a transaction, doing INSERT, UPDATE, and/or DELETE statements, and doing a COMMIT. In fact, all these things happen under the covers while you're working with the Enterprise Objects Framework; they're simply well-hidden from you.

Fetching objects

The entire point of EOF is to abstract away all the details of the actual database. The first step towards this goal is to be able to get data out of the database without using an actual SQL statement, since the SQL could be database-specific. EOF does this with things called fetch specifications.

A fetch specification is a description of a database query. You create fetch specifications within EOModeler, and then you can use them in your Java code to fetch data into your editing context.

Here is an example of a simple fetch specification in our employee model. We will actually create and use this fetch specification later in this chapter.


Once you have a fetch specification defined in your model, you can use this to fetch data from the database. The data ends up in your editing context as Java objects.

First, create an EOEditingContext or (if you have one) get a handle to an existing one. Then retrieve the fetch specification with the static method fetchSpecificationNamed of the EOFetchSpecification class:

EOFetchSpecification.fetchSpecificationNamed(
    String name,
    String entityName)

where name is the name of the fetch specification for the entity given by entityName.

Next, create an NSMutableDictionary and add the appropriate key-value pairs that represent the bindings for the qualification. This can be done by invoking the method takeValueForKey method on an instance of NSMutableDictionary.

instanceOfNSMutableDictionary.takeValueForKey(
    Object someObject,
    String key)

Then use the static method objectsWithFetchSpecificationAndBindings of the EOUtilities class:

EOUtilities.objectsWithFetchSpecificationAndBindings(
    EOEditingContext ec,
    String entityName,
    EOFetchSpecification fs,
    NSDictionary bindings)

which will return NSArray of objects, representing the rows in the table entityName that were qualified by the fetch specification and bindings. If there are no bindings required by the fetch specification, null can be specified for the bindings.

To fetch all objects from the database, specify null for the fetch specification and bindings. If no key-value pair for a binding is not present in the dictionary, EOF will ignore the binding.

Here is an example of fetching with and without a fetch specification and bindings:

  EOEditingContext ec = new EOEditingContext();

   // fetch all objects from the Employee table
   NSArray employees = (NSArray)EOUtilities.objectsWithFetchSpecification(
                         ec, "Employee", null, null);

   // display all employees
   for (int count = 0; count < employees.count(); count++)
       System.out.println((Employee)(employees.objectAtIndex(count)));

   // -----------------------------------------

   // now fetch just employees in a single department
   EOFetchSpecification fs = EOFetchSpecificationNamed("Employee", "fetchByDeptId");

   // set the bindings
   NSMutableDictionary bindings = new NSMutableDictionary();
   bindings.takeValueForKey(new Integer("1"), "deptId");

   // fetch the objects
   NSArray specialEmployees = (NSArray(EOUtilities.objectsWithFetchSpecification(
                                ec, "Employee", fs, bindings);

   // display just employees in department 1
   for (int count = 0; count < specialEmployees.employees(); count++)
       System.out.println((Employee)(specialEmployees.objectAtIndex(count)));

Inserting and deleting objects

To add a row to a table in the database, create an instance of the corresponding class generated by EOModeler. For instance, to create a new employee in the employee table, create an instance of the Employee class, which EOModeler generated as Employee.java. Set the appropriate values with the mutator methods, insert the object into an EOEditingContext, and finally tell the EOEditingContext to save the changes.

Deleting a row is just as easy. To delete an object, tell the EOEditingContext which contains the object to remove it, and then have the EOEditingContext save the changes.

The insertObject method is invoked on an instance of EOEditingContext to add an object to the EOEditingContext.

instanceOfEOEditingContext.insertObject(EOEnterpriseObject someObject)

The deleteObject method is invoked on an instance of EOEditingContext to remove the object.

instanceOfEOEditingContext.deleteObject(EOEnterpriseObject someObject)

Saving changes is done by invoking saveChanges on the instance of EOEditingContext to which the objects have been added. At this point, EOF starts an actual transaction, figures out which SQL statements need to be generated based on the changes you have made within the editing context, issues those SQL statements, and issues a COMMIT.

instanceOfEOEditingContext.saveChanges()

Updating objects

By now, you should be able to guess how to update a row in a database.

  1. Perform a fetch, qualifying on the primary key or some other attribute unique to the row.
  2. Check to make sure that only one object was fetched.
  3. Use the mutator methods to set the appropriate attributes for the object within the editing context.
  4. Finally, save the changes.

Here's some sample code that updates the last name of employee 1 to be Pilgrim:

  EOEditingContext ec = new EOEditingContext();

   // get the fetch specification for qualifying with an name
   EOFetchSpecification fs = EOFetchSpecificationNamed("employee", "fetchByEmployeeId");

   // set the bindings for the name
   NSMutableDictionary bindings = new NSMutableDictionary();
   bindings.takeValueForKey(new Integer("1"), "id");

   // fetch the employees
   NSArray employees = (NSArray(EOUtilities.objectsWithFetchSpecification(
                           ec, "Employee", fs, bindings);

   // make sure we found the employee we wanted
   if (employees.count() == 1) {
       // update the "last name" attribute within the editing context
       Employee employee = (Employee)(employees.objectAtIndex(0));
       employee.setLastName("Pilgrim");
   }

   // save the changes back to the database
   ec.saveChanges();

Integrating Enterprise Objects Framework with JBoss

  1. To use EOF with JBoss, the EOF frameworks need to be added to JBoss's class path. The following folders should be copied from Apple/Library/Frameworks/ into the lib/ folder in your JBoss installation:
  2. To add these to the class path, edit the main JBoss startup script (run.sh, not run_with_tomcat.sh) and add these lines:
  3. # add WebObjects frameworks
    JBOSS_CLASSPATH=$JBOSS_CLASSPATH:../lib/JavaJDBCAdaptor.framework
    JBOSS_CLASSPATH=$JBOSS_CLASSPATH:../lib/JavaJDBCAdaptor.framework/Resources/Java/javajdbcadaptor.jar
    JBOSS_CLASSPATH=$JBOSS_CLASSPATH:../lib/JavaEOAccess.framework
    JBOSS_CLASSPATH=$JBOSS_CLASSPATH:../lib/JavaEOAccess.framework/Resources/Java/javaeoaccess.jar
    JBOSS_CLASSPATH=$JBOSS_CLASSPATH:../lib/JavaEOControl.framework
    JBOSS_CLASSPATH=$JBOSS_CLASSPATH:../lib/JavaEOControl.framework/Resources/Java/javaeocontrol.jar
    JBOSS_CLASSPATH=$JBOSS_CLASSPATH:../lib/JavaFoundation.framework
    JBOSS_CLASSPATH=$JBOSS_CLASSPATH:../lib/JavaFoundation.framework/Resources/Java/javafoundation.jar
    JBOSS_CLASSPATH=$JBOSS_CLASSPATH:../lib/JavaXML.framework
    JBOSS_CLASSPATH=$JBOSS_CLASSPATH:../lib/JavaXML.framework/Resources/Java/javaxml.jar
    

    (Under Windows, you would edit the run.bat startup script, like this:)

    REM add WebObjects frameworks
    set JBOSS_CLASSPATH=%JBOSS_CLASSPATH%;../lib/JavaJDBCAdaptor.framework
    set JBOSS_CLASSPATH=%JBOSS_CLASSPATH%;../lib/JavaJDBCAdaptor.framework/Resources/Java/javajdbcadaptor.jar
    set JBOSS_CLASSPATH=%JBOSS_CLASSPATH%;../lib/JavaEOAccess.framework
    set JBOSS_CLASSPATH=%JBOSS_CLASSPATH%;../lib/JavaEOAccess.framework/Resources/Java/javaeoaccess.jar
    set JBOSS_CLASSPATH=%JBOSS_CLASSPATH%;../lib/JavaEOControl.framework
    set JBOSS_CLASSPATH=%JBOSS_CLASSPATH%;../lib/JavaEOControl.framework/Resources/Java/javaeocontrol.jar
    set JBOSS_CLASSPATH=%JBOSS_CLASSPATH%;../lib/JavaFoundation.framework
    set JBOSS_CLASSPATH=%JBOSS_CLASSPATH%;../lib/JavaFoundation.framework/Resources/Java/javafoundation.jar
    set JBOSS_CLASSPATH=%JBOSS_CLASSPATH%;../lib/JavaXML.framework
    set JBOSS_CLASSPATH=%JBOSS_CLASSPATH%;../lib/JavaXML.framework/Resources/Java/javaxml.jar
    
  4. Your Enterprise Objects, which are the compiled classes from the .java files that EOModeler generated, also need to be added in the same file. As we'll see later in this chapter, these compiled classes will end up in a .jar file called EmployeeEO.jar and placed deep within one of the framework directories. This is where EOF expects to find it.
  5. JBOSS_CLASSPATH=$JBOSS_CLASSPATH:../lib/JavaJDBCAdaptor.framework/Resources/Java/EmployeeEO.jar
    

That's it! Configuration of JBoss is complete. Now let's see what it takes to convert our case study to use the Enterprise Objects Framework.


Converting the Case Study from BMP EJB to EOF

Since the case study was designed with a clear separation of presentation and business logic, very few of the JSP files need any changes. The EJBs have been replaced by the EOEnterpriseObjects classes (generated by EOModeler). That leaves only the Struts Action classes, each of which will have to be changed to invoke the EOEnterpriseObjects instead of the EJBs.

First, we will create a model from our existing employee database that we created in the previous chapter. EOModeler can reverse-engineer an existing database to create a model from it automatically.

(If you have not already done so, you can download this and other examples used in this course. Mac OS X or other UNIX users click here instead.)

Do this:

  1. Run EOModeler
  2. From the menu, select Model, then New
  3. The adaptor is always JDBC. (This is a historical legacy from the days before WebObjects supported various native database drivers. These days, everything goes through JDBC.)
  4. Set up your database connection.

    Username: admin
    Password: admin
    URL: jdbc:openbase://127.0.0.1/employee

    (If you get an error saying that the database is not started, open OpenBase Manager, select the employee database, and click Start.)

  5. You should always include everything in your model (primary keys, relationships, stored procedures, custom Enterprise Objects)
  6. Include all 3 tables (CITY, DEPARTMENT, EMPLOYEE)
  7. There shouldn't be any stored procedures, so just click Finish.

You should now have an untitled model. In order for WebObjects to find it at runtime, it needs to be in a specific folder, so let's just save it there now. The correct location is deep within your JBoss installation, in lib/JavaJDBCAdaptor.framework/Resources/. Call it employee.eomodel.

Now let's look at the model we've created. It has 3 entities, City, Department, and Employee. These should look familiar; they're the same as the tables in the underlying database. Clicking on City reveals 3 attributes, cityId, name, and rowid. These correspond to database columns. (You can ignore the rowid; that's just an internal OpenBase pseudo-column.)

Similarly, the Department entity has attributes like departmentId, name, phone, and secretaryId. Employee has cityId, departmentId, employeeId, extension, firstname, and lastname.

Each entity should have one attribute with a key icon next to it; this is the primary key.

Note that some of the attribute names do not exactly match the underlying database columns. For instance, the employee table has a primary key of employee_id, but it shows up in EOModeler as employeeId. This is intentional; in your Java code, you will refer to the employeeId attribute of the Employee class, and WebObjects will map that to the original employee.employee_id database column.

Now let's create the fetch specifications we need. The first one we need is fetchById, which will fetch an employee by the primary key, employeeId.

Do this:

  1. In EOModeler, select the Employee entity from the left-hand pane
  2. From the menu, select Property, then Add Fetch Specification
  3. Name the fetch specification fetchById
  4. Select the employee attribute from the list of attributes
  5. Type = $id to complete the expression. The complete expression should read (employeeId = $id)

We also need additional fetch specifications for fetching all rows from each table.

Do this:

  1. Select the Department entity from the left-hand pane
  2. From the menu, select Property, then Add Fetch Specification
  3. Name the fetch specification allDepartments
  4. You don't have to set any qualifiers; the default is to select all rows, which is what we want.
  5. Select the City entity from the left-hand pane
  6. From the menu, select Property, then Add Fetch Specification
  7. Name the fetch specification allCities
  8. Select the Employee entity from the left-hand pane
  9. From the menu, select Property, then Add Fetch Specification
  10. Name the fetch specification allEmployees

EOModeler can create .java files that are wrappers for accessing each entity in the model. These are analagous to EJBs in a J2EE application, but they inherit from the WebObjects framework classes instead of Sun's EJB framework classes. Under the covers, EOModeler uses its own template language and a template file to generate these. This is stored in c:\Apple\Library\PrivateFrameworks\EOModelWizard.framework\Resources\EOJavaClass.template.

Unfortunately, this file needs a minor revision for use with Struts, which requires all accessor and mutator methods to be named getXyz() and setXyz().

Do this:

  1. Open the EOJavaClass.template file in a text editor.
  2. Find ##loop $entity.classAttributes$.
  3. Immediately after that is a line that looks like this:

    public $property.javaValueClassName$ $property.name$() {

    Change this to

    public $property.javaValueClassName$ get$property.name$() {

OK, we're finally ready to generate the .java files from our model.

Do this:

  1. In EOModeler, select the root node in the left-hand pane. If you saved your model as employee.eomodel, then the node should be labeled employee. Do not just select the Employee entity that corresponds to the employee database table. You want the one above that, above Department, above City.
  2. From the menu, select Property, then Generate Java files...
  3. You will get prompted repeatedly to save City.java, Department.java, and Employee.java. Save each of them in d:\work\j2ee\code\Chapter8\Employee\EO\

And now we can create the rest of the files. As we mentioned earlier, most of the JSPs and all of the Struts configuration files can be copied directly from the previous chapter's code example. There's one JSP which needs to be changed, plus all the Action subclasses for Struts. The EJBs are gone; they have been completely replaced by the .java files that we just generated from EOModeler.

Do this:

  1. Create a new web-application source hierarchy.
  2. Copy all of the JSPs from the case study, except the employeeviewsuccess.jsp
  3. Copy struts.jar into WEB-INF/lib/
  4. Copy all the .xml, .tld, and the ApplicationResources.properties files into WEB-INF/
  5. Create a WEB-INF/classes/com/masslight/Employee/ hierarchy
  6. Copy the following files listed below into the hierarchy
  7. Double-check to make sure that your .eomodel (EOModeler model) is in jboss/lib/JavaJDBCAdaptor.framework/Resources/
  8. Run ant all
  9. Test at http://localhost:8080/Employee/index.jsp
code/Chapter8/Employee
Employee
  |
  +-- employeeadd.jsp (*)
  |
  +-- employeeaddfailure.jsp (*)
  |
  +-- employeeaddsuccess.jsp (*)
  |
  +-- employeedeletefailure.jsp (*)
  |
  +-- employeedeletesuccess.jsp (*)
  |
  +-- employeeviewfailure.jsp (*)
  |
  +-- employeemodify.jsp (*)
  |
  +-- index.jsp (*)
  |
  +-- employeeviewsuccess.jsp (*)
  |
  +-- build.xml (*)
  |
  +-- employeemodifyfailure.jsp (*)
  |
  +-- WEB-INF
  |     |
  |     +-- ApplicationResources.properties (*)
  |     |
  |     +-- web.xml (*)
  |     |
  |     +-- app.tld (*)
  |     |
  |     +-- struts-bean.tld (*)
  |     |
  |     +-- struts-form.tld (*)
  |     |
  |     +-- struts-html.tld (*)
  |     |
  |     +-- struts-logic.tld (*)
  |     |
  |     +-- struts-template.tld (*)
  |     |
  |     +-- struts.tld (*)
  |     |
  |     +-- struts-config.xml (*)
  |     |
  |     +-- classes
  |     |     |
  |     |     +-- Chapter8Utils.java (*)
  |     |     |
  |     |     +-- com
  |     |           |
  |     |           +-- masslight
  |     |                 |
  |     |                 +-- Employee
  |     |                       |
  |     |                       +-- EmployeeAddForm.java (*)
  |     |                       |
  |     |                       +-- EmployeeAddAction.java (*)
  |     |                       |
  |     |                       +-- EmployeeModifyAction.java (*)
  |     |                       |
  |     |                       +-- EmployeeViewAction.java (*)
  |     |                       |
  |     |                       +-- EmployeeModifySetupAction.java (*)
  |     |                       |
  |     |                       +-- EmployeeModifyForm.java (*)
  |     |                       |
  |     |                       +-- EmployeeAddSetupAction.java (*)
  |     |                       |
  |     |                       +-- EmployeeDeleteAction.java (*)
  |     |                       |
  |     |                       +-- EmployeeModifySetupForm.java (*)
  |     |                       |
  |     |                       +-- EmployeeDeleteForm.java (*)
  |     |
  |     +-- lib
  |           |
  |           +-- struts.jar (*)
  |
  +-- EO
        |
        +-- City.java (*)
        |
        +-- Department.java (*)
        |
        +-- Employee.java (*)

(*) denotes a file

code/Chapter8/Employee/employeeviewsuccess.jsp
<%@ page language="java" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-form.tld" prefix="form" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>

<html:html locale="true">
 <head>
 <title>
  My Co - Employee Directory
 </title>
 <html:base/>
 </head>
 <body bgcolor="white">
 <h3>
  My Co - Employee Directory
 </h3>
 <html:errors/>
 <hr/>
  <table border="1">
   <tr>
    <th>
     Employee ID
    </th>
    <th>
     First Name
    </th>
    <th>
     Last Name
    </th>
    <th>
     Extension
    </th>
    <th>
     Department
    </th>
    <th>
     City
    </th>
    <th>
    </th>
    <th>
    </th>
   </tr>
   <logic:present name="employees">
    <logic:iterate id="currentEmployee" name="employees">
     <tr>
      <td>
       <bean:write name="currentEmployee" property="employeeId"/>
                                                       </td>
      <td>
       <bean:write name="currentEmployee" property="firstname"/>
      </td>
      <td>
       <bean:write name="currentEmployee" property="lastname"/>
      </td>
      <td>
       <bean:write name="currentEmployee" property="extension"/>
      </td>
      <td>
       <bean:write name="currentEmployee" property="department.name"/>
      </td>
      <td>
       <bean:write name="currentEmployee" property="city.name"/>
      </td>
      <td>
       <a href="employeedelete.do?id=<bean:write
         name="currentEmployee" property="employeeId"/>">Delete</a>
      </td>
      <td>
       <a href="employeemodifysetup.do?id=<bean:write 
         name="currentEmployee" property="employeeId"/>">Modify</a>
      </td>
     </tr>
    </logic:iterate>
   </logic:present>
  </table>
 <hr/>
 <html:link href="index.jsp">
  Return to My Co - Main Menu
 </html:link>
 </body>
</html:html>

code/Chapter8/Employee/WEB-INF/classes/Chapter8Utils.java
import Employee;
import Department;
import City;
import java.util.*;
import com.webobjects.eoaccess.*;
import com.webobjects.eocontrol.*;
import com.webobjects.foundation.*;

public class Chapter8Utils {

 private static EOEditingContext ec = new EOEditingContext();

 public static Vector fetchAllEmployees() { 

    NSMutableArray employees = null; 

    ec.lock(); 
    employees = (NSMutableArray)(EOUtilities.objectsWithFetchSpecificationAndBindings(
		                   ec, "Employee", "allEmployees", null));  
    ec.unlock(); 

    Vector toReturn = new Vector(); 

    for(int count = 0; count < employees.count(); count++) { 
	//        System.out.println(employees.objectAtIndex(count)); // debugging
	Employee employee = (Employee)(employees.objectAtIndex(count));
	toReturn.addElement(employee); 
    } 

    return toReturn; 

  } 

 public static Employee fetchEmployeeById(Number id) throws Exception {

   Employee employee;

   NSMutableDictionary bindings = new NSMutableDictionary();
   bindings.setObjectForKey(id, "id");

   ec.lock();
   try {
     employee = (Employee)EOUtilities.objectWithFetchSpecificationAndBindings(
         ec, "Employee", "fetchById", bindings);
     System.out.println(employee); // debugging
   } catch (Exception e) {
     throw e;
   }
   ec.unlock();

   return employee;

 }

 public static void addEmployee(Employee employee) throws Exception {

   ec.lock();
   try {
     ec.insertObject(employee);
     ec.saveChanges();
     ec.invalidateAllObjects();
   } catch (Exception e) {
     throw e;
   }
   ec.unlock();

   return;

 }

 public static void deleteEmployeeById(Number id) throws Exception {
   Employee employee;

   NSMutableDictionary bindings = new NSMutableDictionary();
   bindings.setObjectForKey(id, "id");

   ec.lock();
   try {
     employee = (Employee)EOUtilities.objectWithFetchSpecificationAndBindings(
         ec, "Employee", "fetchById", bindings);
     ec.deleteObject(employee);
     ec.saveChanges();
     ec.invalidateAllObjects();
   } catch (Exception e) {
     throw e;
   }
   ec.unlock();

   return;

 }

 public static void modifyEmployee() throws Exception {

   ec.lock();
   try {
     ec.saveChanges();
     ec.invalidateAllObjects();
   } catch (Exception e) {
     throw e;
   }
   ec.unlock();

 }

 public static Vector fetchAllCities() {

   NSArray cities;

   ec.lock();
   cities = EOUtilities.objectsWithFetchSpecificationAndBindings(
       ec, "City", "allCities", null);
   ec.unlock();

   Vector toReturn = new Vector();

   for(int count = 0; count < cities.count(); count++) {
     City city = (City)cities.objectAtIndex(count);
     toReturn.addElement(city);
   }

   return toReturn;

 }

 public static Vector fetchAllDepartments() {

   NSArray departments;

   ec.lock();
   departments = EOUtilities.objectsWithFetchSpecificationAndBindings(
       ec, "Department", "allDepartments", null);
   ec.unlock();

   Vector toReturn = new Vector();

   for(int count = 0; count < departments.count(); count++) {
     Department department = (Department)departments.objectAtIndex(count);
     toReturn.addElement(department);
   }

   return toReturn;

 }

}

code/Chapter8/Employee/WEB-INF/classes/com/masslight/Employee/EmployeeAddForm.java
package com.masslight.Employee;

import javax.servlet.http.*;
import org.apache.struts.action.*;
public class EmployeeAddForm extends ActionForm {

 private Integer employeeid = new Integer(0);
 private String firstname = new String();
 private String lastname = new String();
 private String extension = new String();
 private Integer cityid = new Integer(0);
 private Integer departmentid = new Integer(0);

 public EmployeeAddForm() {
 }

 public void reset(ActionMapping mapping, HttpServletRequest request) {
 }

 public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {
   ActionErrors errors = new ActionErrors();

   return errors;
 }

 public Integer getEmployeeid() { return employeeid; }
 public void setEmployeeid(Integer value) { employeeid = value; }
 public String getLastname() { return lastname; }
 public void setLastname(String value) { lastname = new String(value); }
 public String getFirstname() { return firstname; }
 public void setFirstname(String value) { firstname = new String(value); }
 public String getExtension() { return extension; }
 public void setExtension(String value) { extension = new String(value); }
 public Integer getDepartmentid() { return departmentid; }
 public void setDepartmentid(Integer value) { departmentid = value; }
 public Integer getCityid() { return cityid; }
 public void setCityid(Integer value) { cityid = value; }

}

code/Chapter8/Employee/WEB-INF/classes/com/masslight/Employee/EmployeeAddSetupAction.java
package com.masslight.Employee;

import Chapter8Utils;
import java.util.*;
import java.io.*;
import java.lang.reflect.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import org.apache.struts.action.*;
import org.apache.struts.util.*;
import java.util.Collection;
import com.webobjects.eocontrol.*;
import com.webobjects.eoaccess.*;
import com.webobjects.foundation.*;

public final class EmployeeAddSetupAction extends Action {

 public EmployeeAddSetupAction() {
 }

 public ActionForward perform(ActionMapping mapping,
                              ActionForm form,
                              HttpServletRequest request,
                              HttpServletResponse response)
   throws IOException, ServletException {

   Locale locale = getLocale(request);
   MessageResources messages = getResources();
   HttpSession session = request.getSession();

   ActionErrors errors = new ActionErrors();

   // insert logic here

   try {

     // set the cities
     session.setAttribute("cities", Chapter8Utils.fetchAllCities());

     // set the departments
     session.setAttribute("departments", Chapter8Utils.fetchAllDepartments());

   } catch (Exception e) {
     return (mapping.findForward("employeeaddsetupfailure"));
   }

   if (mapping.getAttribute() != null) {

     if ("request".equals(mapping.getScope()))
       request.removeAttribute(mapping.getAttribute());
     else
       session.removeAttribute(mapping.getAttribute());

   }

   return (mapping.findForward("employeeaddsetupsuccess"));

 }

}

code/Chapter8/Employee/WEB-INF/classes/com/masslight/Employee/EmployeeDeleteAction.java
package com.masslight.Employee;

import Chapter8Utils;
import java.util.*;
import java.io.*;
import java.lang.reflect.*;
import javax.servlet.*;
import javax.servlet.http.*;
import org.apache.struts.action.*;
import org.apache.struts.util.*;
import com.webobjects.eocontrol.*;
import com.webobjects.eoaccess.*;
import com.webobjects.foundation.*;

public final class EmployeeDeleteAction extends Action {

 public EmployeeDeleteAction() {
 }

 public ActionForward perform(ActionMapping mapping,
                              ActionForm form,
                              HttpServletRequest request,
                              HttpServletResponse response)
   throws IOException, ServletException {

   Locale locale = getLocale(request);
   MessageResources messages = getResources();
   HttpSession session = request.getSession();
   EmployeeDeleteForm employeeDeleteForm = (EmployeeDeleteForm)form;

   ActionErrors errors = new ActionErrors();

   // insert logic here
   try {
     Chapter8Utils.deleteEmployeeById(employeeDeleteForm.getId());
   } catch (Exception e) {
     return (mapping.findForward("employeedeletefailure"));
   }

   if (mapping.getAttribute() != null) {

     if ("request".equals(mapping.getScope()))
       request.removeAttribute(mapping.getAttribute());
     else
       session.removeAttribute(mapping.getAttribute());

   }

   return (mapping.findForward("employeedeletesuccess"));

 }

}

code/Chapter8/Employee/WEB-INF/classes/com/masslight/Employee/EmployeeDeleteForm.java
package com.masslight.Employee;

import javax.servlet.http.*;
import org.apache.struts.action.*;

public class EmployeeDeleteForm extends ActionForm {

 private Integer id;

 public EmployeeDeleteForm() {
 }

 public Integer getId() { return id; }
 public void setId(Integer value) { id = value; }

 public void reset(ActionMapping mapping, HttpServletRequest request) {
 }

 public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {
   ActionErrors errors = new ActionErrors();

   // validate fields here

   return errors;
 }

}

code/Chapter8/Employee/WEB-INF/classes/com/masslight/Employee/EmployeeModifyAction.java
package com.masslight.Employee;

import Chapter8Utils;
import Employee;
import java.util.*;
import java.io.*;
import java.lang.reflect.*;
import javax.servlet.*;
import javax.servlet.http.*;
import org.apache.struts.action.*;
import org.apache.struts.util.*;
import com.webobjects.eocontrol.*;
import com.webobjects.eoaccess.*;
import com.webobjects.foundation.*;

public final class EmployeeModifyAction extends Action {

 public EmployeeModifyAction() {
 }

 public ActionForward perform(ActionMapping mapping,
                              ActionForm form,
                              HttpServletRequest request,
                              HttpServletResponse response)
   throws IOException, ServletException {

   Locale locale = getLocale(request);
   MessageResources messages = getResources();
   HttpSession session = request.getSession();
   EmployeeModifyForm employeeModifyForm = (EmployeeModifyForm)form;

   ActionErrors errors = new ActionErrors();

   // insert logic here
   try {
       System.out.println(employeeModifyForm.getEmployeeId());
       System.out.println(employeeModifyForm.getFirstname());
       System.out.println(employeeModifyForm.getLastname());
       System.out.println(employeeModifyForm.getExtension());
       System.out.println(employeeModifyForm.getCityId());
       System.out.println(employeeModifyForm.getDepartmentId());

     Employee employee = Chapter8Utils.fetchEmployeeById(employeeModifyForm.getEmployeeId());
     employee.setFirstname(employeeModifyForm.getFirstname());
     employee.setLastname(employeeModifyForm.getLastname());
     employee.setExtension(employeeModifyForm.getExtension());
     employee.setCityId(employeeModifyForm.getCityId());
     employee.setDepartmentId(employeeModifyForm.getDepartmentId());
     Chapter8Utils.modifyEmployee();
   } catch (Exception e) {
       System.out.println(e); // debugging
       e.printStackTrace(); // debugging
     return (mapping.findForward("employeemodifyfailure"));
   }

   if (mapping.getAttribute() != null) {

     if ("request".equals(mapping.getScope()))
       request.removeAttribute(mapping.getAttribute());
     else
       session.removeAttribute(mapping.getAttribute());

   }

   return (mapping.findForward("employeemodifysuccess"));

 }

}

code/Chapter8/Employee/WEB-INF/classes/com/masslight/Employee/EmployeeModifyForm.java
package com.masslight.Employee;

import javax.servlet.http.*;
import org.apache.struts.action.*;

public class EmployeeModifyForm extends ActionForm {

 private Integer employeeid = new Integer(0);
 private String firstname = new String();
 private String lastname = new String();
 private String extension = new String();
 private Integer cityid = new Integer(0);
 private Integer departmentid = new Integer(0);

 public EmployeeModifyForm() {
 }

 public void reset(ActionMapping mapping, HttpServletRequest request) {
 }

 public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {
   ActionErrors errors = new ActionErrors();

   return errors;
 }

 public Integer getEmployeeId() { return employeeid; }
 public void setEmployeeId(Integer value) { employeeid = value; }
 public String getLastname() { return lastname; }
 public void setLastname(String value) { lastname = new String(value); }
 public String getFirstname() { return firstname; }
 public void setFirstname(String value) { firstname = new String(value); }
 public String getExtension() { return extension; }
 public void setExtension(String value) { extension = new String(value); }
 public Integer getDepartmentId() { return departmentid; }
 public void setDepartmentId(Integer value) { departmentid = value; }
 public Integer getCityId() { return cityid; }
 public void setCityId(Integer value) { cityid = value; }

}

code/Chapter8/Employee/WEB-INF/classes/com/masslight/Employee/EmployeeModifySetupAction.java
package com.masslight.Employee;

import Chapter8Utils;
import java.util.*;
import java.io.*;
import java.lang.reflect.*;
import javax.servlet.*;
import javax.servlet.http.*;
import org.apache.struts.action.*;
import org.apache.struts.util.*;

public final class EmployeeModifySetupAction extends Action {

 public EmployeeModifySetupAction() {
 }

 public ActionForward perform(ActionMapping mapping,
                              ActionForm form,
                              HttpServletRequest request,
                              HttpServletResponse response)
   throws IOException, ServletException {

   Locale locale = getLocale(request);
   MessageResources messages = getResources();
   HttpSession session = request.getSession();
   EmployeeModifySetupForm employeeModifySetupForm = (EmployeeModifySetupForm)form;

   System.out.println(form);
   ActionErrors errors = new ActionErrors();

   // insert logic here

   try {

     // get all of the cities
     session.setAttribute("cities", Chapter8Utils.fetchAllCities());

     // get all of the departments
     session.setAttribute("departments", Chapter8Utils.fetchAllDepartments());

     // get the employee by id
     //     System.out.println(employeeModifySetupForm.getId()); // debugging
     session.setAttribute("employee", 
	  Chapter8Utils.fetchEmployeeById(employeeModifySetupForm.getId()));

   } catch (Exception e) {
     return (mapping.findForward("employeemodifysetupfailure"));
   }

   if (mapping.getAttribute() != null) {

     if ("request".equals(mapping.getScope()))
       request.removeAttribute(mapping.getAttribute());
     else
       session.removeAttribute(mapping.getAttribute());

   }

   return (mapping.findForward("employeemodifysetupsuccess"));

 }

}

code/Chapter8/Employee/WEB-INF/classes/com/masslight/Employee/EmployeeModifySetupForm.java
package com.masslight.Employee;

import javax.servlet.http.*;
import org.apache.struts.action.*;

public class EmployeeModifySetupForm extends ActionForm {

 private Integer id;

 public EmployeeModifySetupForm() {
 }

 public Integer getId() { return id; }
 public void setId(Integer value) { id = value; }

 public void reset(ActionMapping mapping, HttpServletRequest request) {
 }

 public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {
   ActionErrors errors = new ActionErrors();

   // validate fields here

   return errors;
 }

}

code/Chapter8/Employee/WEB-INF/classes/com/masslight/Employee/EmployeeViewAction.java
package com.masslight.Employee;

import Chapter8Utils;
import java.util.*;
import java.io.*;
import java.lang.reflect.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import org.apache.struts.action.*;
import org.apache.struts.util.*;

public final class EmployeeViewAction extends Action {

 public EmployeeViewAction() {
 }

 public ActionForward perform(ActionMapping mapping,
                              ActionForm form,
                              HttpServletRequest request,
                              HttpServletResponse response)
   throws IOException, ServletException {

   Locale locale = getLocale(request);
   MessageResources messages = getResources();
   HttpSession session = request.getSession();

   ActionErrors errors = new ActionErrors();

   // insert logic here

   try {
       session.setAttribute("employees", Chapter8Utils.fetchAllEmployees());
   } catch (Exception e) {
       return (mapping.findForward("employeeviewfailure"));
   }

   if (mapping.getAttribute() != null) {

     if ("request".equals(mapping.getScope()))
       request.removeAttribute(mapping.getAttribute());
     else
       session.removeAttribute(mapping.getAttribute());

   }

   return (mapping.findForward("employeeviewsuccess"));

 }

}

code/Chapter8/Employee/build.xml
<project name="Employee" default="dist" basedir=".">

 <!-- set global properties for this build -->
 <property environment="env"/>
 <property name="top" value="."/>
 <property name="src" value="."/>
 <property name="build" value="build"/>
 <property name="dist" value="dist"/>
 <property name="war_dir" value="${dist}/lib"/>
 <property name="war_file" value="${war_dir}/Employee.war"/>

 <property name="eo_src" value="EO"/>
 <property name="eo_build" value="eo_build"/>
 <property name="eo_dist" value="eo_dist"/>
 <property name="eo_jar_dir" value="${eo_dist}/lib"/>
 <property name="eo_jar_file" value="${eo_jar_dir}/EmployeeEO.jar"/>
 <property name="eo_deploy" value="${env.JBOSS_HOME}/lib/JavaJDBCAdaptor.framework/Resources/Java"/>
 <property name="eo_classpath" value="${env.JBOSS_HOME}/lib/JavaJDBCAdaptor.framework;
   ${env.JBOSS_HOME}/lib/JavaJDBCAdaptor.framework/Resources/Java/javajdbcadaptor.jar;
   ${env.JBOSS_HOME}/lib/JavaEOAccess.framework;
   ${env.JBOSS_HOME}/lib/JavaEOAccess.framework/Resources/Java/javaeoaccess.jar;
   ${env.JBOSS_HOME}/lib/JavaEOControl.framework;
   ${env.JBOSS_HOME}/lib/JavaEOControl.framework/Resources/Java/javaeocontrol.jar;
   ${env.JBOSS_HOME}/lib/JavaFoundation.framework;
   ${env.JBOSS_HOME}/lib/JavaFoundation.framework/Resources/Java/javafoundation.jar;
   ${env.JBOSS_HOME}/lib/JavaXML.framework;
   ${env.JBOSS_HOME}/lib/JavaXML.framework/Resources/Java/javaxml.jar"/>

 <property name="webinf" value="${top}/WEB-INF"/>
 <property name="web.xml" value="${webinf}/web.xml"/>
 <property name="classes" value="${webinf}/classes"/>
 <property name="lib" value="${top}/WEB-INF/lib"/>
 <property name="struts.jar" value="${env.TOMCAT_HOME}/lib/servlet.jar;${webinf}/lib/struts.jar"/>
 <property name="deploy" value="${env.JBOSS_HOME}/deploy"/>

 <target name="clean">
   <!-- Delete our the ${build} and ${dist} directory trees -->
   <delete dir="${build}"/>
   <delete dir="${eo_build}"/>
   <delete dir="${dist}"/>
   <delete dir="${eo_dist}"/>
   <delete dir="${war_dir}"/>
   <delete dir="${eo_jar_dir}"/>
 </target>

 <target name="init">
   <!-- Create the build directory structure used by compile and dist -->
   <mkdir dir="${build}"/>
   <mkdir dir="${eo_build}"/>
   <mkdir dir="${dist}"/>
   <mkdir dir="${eo_dist}"/>
   <mkdir dir="${war_dir}"/>
   <mkdir dir="${eo_jar_dir}"/>
 </target>

 <target name="compileeo" depends="init">
   <!-- Compile the EOF objects generated by EOModeler -->
   <javac
     srcdir="${top}/${eo_src}"
     destdir="${eo_build}"
     classpath="${eo_classpath}"/>
 </target>

 <target name="compilestruts" depends="init,compileeo">
   <!-- Compile the java code from ${src} into ${build} -->
   <javac
     srcdir="${top}/${src}"
     destdir="${build}"
     classpath="${struts.jar};${eo_classpath};${eo_jar_file}"/>
 </target>

 <target name="compile" depends="compileeo,compilestruts"/>

 <target name="diststruts" depends="compilestruts">
   <!-- Put everything in a war file -->
   <war warfile="${war_file}" webxml="${web.xml}">
     <!-- include all JSPs in root level, and all .properties files anywhere -->
     <fileset dir="${top}/${src}">
       <include name="*.jsp"/>
       <include name="**/*.properties"/>
     </fileset>

     <!-- include all tag libraries in WEB-INF, and all .xml config files,
          but not web.xml (that's handled separately) -->
     <webinf dir="${webinf}">
       <include name="*.tld"/>
       <include name="*.xml"/>
       <exclude name="web.xml"/>
     </webinf>

     <!-- include all libraries in WEB-INF/lib (like struts.jar) -->
     <lib dir="${lib}"/>

     <!-- include all compiled classes -->
     <classes dir="${build}"/>
   </war>
 </target>

 <target name="disteo" depends="compileeo">
   <jar jarfile="${eo_jar_file}">
     <!-- include all compiled class files -->
     <fileset dir="${eo_build}">
       <include name="*.class"/>
     </fileset>
   </jar>
 </target>

 <target name="dist" depends="disteo,diststruts"/>

 <target name="deploystruts">
   <!-- Copy the war file to the JBoss deploy directory -->
   <copy file="${war_file}" todir="${deploy}"/>
 </target>

 <target name="deployeo">
   <!-- Copy the jar file to the directory -->
   <copy file="${eo_jar_file}" todir="${eo_deploy}"/>
 </target>

 <target name="deploy" depends="deployeo,deploystruts"/>

 <target name="all" depends="clean,dist,deploy"/>

</project>


Exercises

Exercise 1. Think

Discuss the benefits of using an O/R mapping framework. Compare the development times of the EJB and EOF versions of the applications. Also, compare the complexity of each application. What implications are caused by database schema changes?