Enterprise Java and UML - 668632
Enterprise Java and UML - 668632
Enterprise Java ™
UML
™
and
2nd Edition
TimeEntryEntityBean
TimeEntryInt.java
TimeEntryLocal.java is the local interface for the TimeEntry entity bean. It defines the
locally accessible methods for the TimeEntry entity bean. This is shown in Figure 01.
<<EntityLocal>>
TimeEntryLocal
+ getHours() : int
+ getDate() : Date
+ getChargeCode() : ChargeCodeLocal
+ getTimecard() : TimecardLocal
+ setHours(hours : int)
+ setDate(day : Date)
+ setChargeCode(code : ChargeCodeLocal)
package com.wiley.compBooks.EJwithUML.TimeCardDomain;
import java.util.*;
import javax.ejb.*;
/**
* The TimeEntryInt is the interface that ties the Bean with the Remote
1
267783 WS01.qxd 5/5/03 9:17 AM Page 2
2 TimeEntryEntityBean
TimeEntryLocal.java
TimeEntryLocal.java is the local EJB interface that inherits from TimeEntryInt and
hence the body is empty. This is in line with what we have set as our implementation
strategy for all of our EJBs.
package com.wiley.compBooks.EJwithUML.TimeCardDomain;
import java.util.*;
import javax.ejb.*;
/**
* The TimeEntry bean holds a single time entry.
* TimeEntryLocal is the local interface through which local clients
* access the underlying entity bean.
*/
public interface TimeEntryLocal extends EJBLocalObject, TimeEntryInt
{
}
267783 WS01.qxd 5/5/03 9:17 AM Page 3
TimeEntryEntityBean 3
TimeEntrytLocalHome.java
TimeEntryLocalHome.java is the Home interface for the TimeEntry entity bean. It
defines the methods for finding and creating TimeEntry entity beans. This is shown in
Figure 02.
<<EntityLocalHome>>
TimeEntryLocalHome
+ create(id : String, hour : int, day : Date, code : ChargeCodeLocal, tcard : TimecardLocal) : TimeEntryLocal
+ findByPrimaryKey(key : TimeEntryPK) : TimeEntryLocal
+ findByTimecard(tcardId : String) : Collection
package com.wiley.compBooks.EJwithUML.TimeCardDomain;
import java.util.*;
import javax.ejb.*;
/**
* The TimeEntry bean holds a single time entry.
*
* TimeEntryLocalHome is the local interface through which local clients
* find and create the underlying entity beans.
*
*/
public interface TimeEntryLocalHome extends EJBLocalHome
{
/** Answers a local reference to the newly created Timecard bean. */
public TimeEntryLocal create(String timeEntryId, Date day, int Æ
hours, ChargeCodeLocal code,
TimecardLocal tcard) Æ
throws CreateException;
}
267783 WS01.qxd 5/5/03 9:17 AM Page 4
4 TimeEntryEntityBean
TimeEntryPK.java
TimeEntryPK.java represents the primary key class of the TimeEntry entity bean. It is
important to note here that it implements hashCode() and equals() methods and imple-
ments the Serializable interface.
package com.wiley.compBooks.EJwithUML.TimeCardDomain;
import java.io.Serializable;
/**
* The TimeEntry bean holds a single time entry.
*
* TimeEntryPK is the primary key class for the underlying entity Æ
bean. It is,
* id = timecard-id + entry-count-for-timecard
*/
public class TimeEntryPK implements Serializable
{
public String id;
public TimeEntryPK()
{
TimeEntryEntityBean 5
if (!key.getClass().equals(this.getClass()))
{
return false;
}
else
{
return ((TimeEntryPK)key).id.equals(this.id);
}
}
}
}
TimeEntryBean.java
TimeEntryBean.java is the implementation class for the TimeEntry entity bean. It pro-
vides the data and logic for the bean. Again, there is not much to it. Each TimeEntry
entity bean holds an ID, total hours worked, the day of the work, a reference to the
charge code entity bean, and a reference to the timecard entity bean to which it
belongs.
package com.wiley.compBooks.EJwithUML.TimeCardDomain;
import com.wiley.compBooks.EJwithUML.Base.EjbUtil.*;
import java.util.*;
import javax.ejb.*;
import javax.naming.*;
/**
* The TimeEntry bean holds time entries for a date range.
* TimeEntryBean is the actual entity bean implementation.
*/
6 TimeEntryEntityBean
/**
* Create an TimeEntryBean with the specified parameters. This is
* never called directly.
*/
public TimeEntryPK ejbCreate(String timeEntryId, Date day, int hours,
ChargeCodeLocal code, TimecardLocal tcard) throws Æ
CreateException
{
System.out.println(“in ejbCreate() of TimeEntryBean!”);
// sets the CMP fields
setId(timeEntryId);
setDay(day.getTime());
setHours(hours);
return null;
}
ChargeCodeEntityBean
ChargeCodeInt.java
ChargeCodeInt.java is the local Business interface for the ChargeCode entity bean. It
defines all of the locally accessible methods for the ChargeCode entity bean.
package com.wiley.compBooks.EJwithUML.TimeCardDomain;
import javax.ejb.*;
/**
* The ChargeCodeInt is the interface that ties the Bean with the Remote
* interface to provide compile time type checking.
*/
public interface ChargeCodeInt
{
/** Answers the name of this ChargeCode. */
public String getName();
7
267783 WS02.qxd 5/5/03 9:17 AM Page 8
8 ChargeCodeEntityBean
ChargeCodeLocal.java
ChargeCodeLocal.java is the local EJB interface for the ChargeCode entity bean that
inherits from ChargeCodeInt.
package com.wiley.compBooks.EJwithUML.TimeCardDomain;
import javax.ejb.*;
/**
* The ChargeCode bean holds descriptive information about a billable
* charge code. Since each ChargeCode is part of a larger project, the
* parent project can be accessed from the charge code.
* ChargeCodeLocal is the local interface through which local clients
* access the underlying entity bean.
*/
public interface ChargeCodeLocal extends EJBLocalObject, ChargeCodeInt
{
}
ChargeCodeLocalHome
ChargeCodeLocalHome.java is the Home interface for the ChargeCode entity bean. It
defines the methods for finding and creating ChargeCode entity beans.
package com.wiley.compBooks.EJwithUML.TimeCardDomain;
import java.util.*;
import javax.ejb.*;
/**
* The ChargeCode bean holds simple descriptive information on a common
* activity that is performed by development teams. This activity may be
* used to create a ChargeCode.
*
* ChargeCodeLocalHome is the local interface through which local
* clients find and create the underlying entity beans.
*
*/
public interface ChargeCodeLocalHome extends EJBLocalHome
{
ChargeCodeEntityBean 9
ChargeCodeBean.java
ChargeCodeBean.java is the implementation class for the ChargeCode entity bean. It
provides the data and logic for the bean. Again, there is not much to it. Each Charge-
Code entity bean holds an ID, a name, a description, and a reference to the project
entity bean to which it belongs.
package com.wiley.compBooks.EJwithUML.TimeCardDomain;
import com.wiley.compBooks.EJwithUML.Base.EjbUtil.*;
import java.util.*;
import java.rmi.*;
import javax.ejb.*;
import javax.naming.*;
/**
* The ChargeCode bean holds descriptive information about a billable
* charge code. Since each ChargeCode is part of a larger project, the
* parent project can be accessed from the charge code.
* ChargeCodeBean is the actual entity bean implementation.
*/
public abstract class ChargeCodeBean extends BasicEntityBean Æ
implements ChargeCodeInt
{
/** CMP fields */
public abstract long getId();
public abstract void setId(long id);
public abstract String getName();
public abstract void setName(String name);
public abstract String getDescription();
public abstract void setDescription(String desc);
public ChargeCodeBean()
{
}
267783 WS02.qxd 5/5/03 9:17 AM Page 10
10 ChargeCodeEntityBean
ClientEntityBean
ClientInt.java
ClientInt.java is the local Business interface for the Client entity bean. It defines all of
the locally accessible methods for the Client entity bean.
package com.wiley.compBooks.EJwithUML.TimeCardDomain;
import java.util.*;
import javax.ejb.*;
/**
* The ClientInt is the interface that ties the Bean with the Remote
* interface to provide compile time type checking.
*/
public interface ClientInt
{
/** Answers the name of this Client. */
public String getName();
11
267783 WS03.qxd 5/5/03 9:17 AM Page 12
12 ClientEntityBean
ClientLocal.java
ClientLocal.java is the local EJB interface for the Client entity bean that inherits from
ClientInt.
package com.wiley.compBooks.EJwithUML.TimeCardDomain;
import java.util.*;
import javax.ejb.*;
/**
* The Client bean holds descriptive information about a client.
* ClientLocal is the local interface through which local clients access
* the underlying entity bean.
*/
public interface ClientLocal extends EJBLocalObject, ClientInt
{
}
ClientLocalHome.java
ClientLocalHome.java is the Home interface for the Client entity bean. It defines the
methods for finding and creating Client entity beans.
package com.wiley.compBooks.EJwithUML.TimeCardDomain;
import java.util.*;
import javax.ejb.*;
/**
* The Client bean holds descriptive information about a client.
* ClientLocalHome is the local interface through which local clients
* find and create the underlying entity beans.
*/
public interface ClientLocalHome extends EJBLocalHome
{
/** Answers a Collection that holds references to all of the Client Æ
beans. */
public Collection findAll() throws FinderException;
/**
* Answers a Collection that holds references to all of the Client
* beans that match the name parameter.
*/
public Collection findByName(String name) throws FinderException;
ClientEntityBean 13
ClientBean.java
ClientBean.java is the implementation class for the Client entity bean. It contains the
data and logic for the bean.
package com.wiley.compBooks.EJwithUML.TimeCardDomain;
import com.wiley.compBooks.EJwithUML.Base.EjbUtil.*;
import java.util.*;
import java.rmi.*;
import javax.ejb.*;
import javax.naming.*;
/**
* The Client bean holds descriptive information about a client.
* ClientBean is the actual entity bean implementation.
*/
public abstract class ClientBean extends BasicEntityBean implements Æ
ClientInt
{
/** CMP fields */
public abstract long getId();
public abstract void setId(long id);
public abstract String getName();
public abstract void setName(String name);
public abstract String getDescription();
public abstract void setDescription(String desc);
public ClientBean()
{
}
14 ClientEntityBean
setDescription(description);
return null;
}
ProjectEntityBean
ProjectInt.java
ProjectInt.java is the local Business interface for the Project entity bean. It defines the
locally accessible methods for the Project entity bean.
package com.wiley.compBooks.EJwithUML.TimeCardDomain;
import java.util.*;
import javax.ejb.*;
/**
* The ProjectInt is the interface that ties the Bean with the Remote
* interface to provide compile time type checking.
*/
public interface ProjectInt
{
/** Answers the name of this Project. */
public String getName();
15
267783 WS04.qxd 5/5/03 9:18 AM Page 16
16 ProjectEntityBean
ProjectLocal.java
ProjectLocal.java is the local EJB interface for the Project entity bean that inherits from
ProjectInt.
package com.wiley.compBooks.EJwithUML.TimeCardDomain;
import java.util.*;
import javax.ejb.*;
/**
* The Project bean holds descriptive information about a project.
* ProjectLocal is the local interface through which local clients
* access the underlying entity bean.
*/
public interface ProjectLocal extends EJBLocalObject, ProjectInt
{
}
ProjectLocalHome.java
ProjectLocalHome.java is the Home interface for the Project entity bean. It defines the
methods for finding and creating Project entity beans.
package com.wiley.compBooks.EJwithUML.TimeCardDomain;
import java.util.*;
import javax.ejb.*;
/**
* The Project bean holds descriptive information about a project.
* ProjectLocalHome is the local interface through which local clients
* find and create the underlying entity beans.
*/
ProjectEntityBean 17
ProjectBean.java
ProjectBean.java is the implementation class for the Project entity bean. It holds the
data and logic for the bean.
package com.wiley.compBooks.EJwithUML.TimeCardDomain;
import com.wiley.compBooks.EJwithUML.Base.EjbUtil.*;
import java.util.*;
import java.rmi.*;
import javax.ejb.*;
import javax.naming.*;
/**
* The Project bean holds descriptive information about a project.
* ProjectBean is the actual entity bean implementation.
*/
public ProjectBean()
{
267783 WS04.qxd 5/5/03 9:18 AM Page 18
18 ProjectEntityBean
RecordTimeServletjava
RecordTimeServlet.java
The RecordTimeServlet uses the RecordTimeWorkflow to retrieve and update time-
cards. If no entry or new charge code is specified, the RecordTimeServlet retrieves the
current timecard and builds an entry form. If an entry is submitted, the RecordTime-
Servlet first updates the timecard through the RecordTimeWorkflow and then builds
an entry form. If a new charge code is specified, then the RecordTimeServlet creates
new zero hour entries for the charge code, updates the timecard, and then builds an
entry form.
package com.wiley.compBooks.EJwithUML.TimecardUI;
import javax.servlet.http.*;
import javax.servlet.*;
import javax.naming.*;
import javax.ejb.*;
import java.rmi.*;
import javax.rmi.PortableRemoteObject;
import javax.servlet.http.*;
import javax.servlet.*;
import javax.naming.*;
19
267783 WS05.qxd 5/5/03 9:18 AM Page 20
20 RecordTimeServletjava
import javax.ejb.*;
import java.rmi.*;
import javax.rmi.PortableRemoteObject;
import java.io.*;
import java.util.*;
import java.text.*;
import com.wiley.compBooks.EJwithUML.Base.HtmlPrimitives.Core.*;
import com.wiley.compBooks.EJwithUML.Base.HtmlPrimitives.FormPrimitives.*;
import com.wiley.compBooks.EJwithUML.Base.HtmlPrimitives.Layout.*;
import com.wiley.compBooks.EJwithUML.Base.HtmlPrimitives.ContentElements.*;
import com.wiley.compBooks.EJwithUML.TimeCardWorkflow.*;
import com.wiley.compBooks.EJwithUML.Dtos.*;
import com.wiley.compBooks.EJwithUML.TimecardProducers.*;
import com.wiley.compBooks.EJwithUML.Base.EjbUtil.*;
import com.wiley.compBooks.EJwithUML.Base.ApplicationExceptions.*;
/**
* The RecordTimeServlet uses the TimecardWorkflow and
* HtmlProduction packages to create the formatted HTML
* for the time entry form and to capture the entered hours.
*/
public class RecordTimeServlet extends BasicTimecardServlet
{
private static final DateFormat longFormat = new SimpleDateFormat Æ
(“MMM dd, yyyy”);
private static final DateFormat shortFormat = new Æ
SimpleDateFormat(“MMM dd”);
private static final DateFormat keyFormat = new Æ
SimpleDateFormat(“MMM.dd.yyyy”);
private static final DateFormat dayOfWeekFormat = new Æ
SimpleDateFormat(“EE”);
RecordTimeServletjava 21
// extract parameters
String client =
request.getParameter(TimecardKey.CLIENT.getKeyText());
String project =
request.getParameter(TimecardKey.PROJECT.getKeyText());
String code = request.getParameter(TimecardKey.CODE.getKeyText());
// save timecard
else if
(request.getParameterMap().containsKey(TimecardKey.SAVE_TIMECARD. Æ
getKeyText()))
{
updateTimecardFromRequest(timecard, request);
rtwf.updateTimecard(timecard);
}
22 RecordTimeServletjava
rtwf.updateTimecard(timecard);
}
if (!entry_map.isEmpty())
{
267783 WS05.qxd 5/5/03 9:18 AM Page 23
RecordTimeServletjava 23
codes_it = codes.iterator();
row_ctr = 1;
while (codes_it.hasNext())
{
String code = (String) codes_it.next();
String key = “entry_” +date_string+ “_” +code;
TimeEntryDTO entry = (TimeEntryDTO) entry_map.get(key);
String hours = “0”;
if (entry != null)
{
hours = “” + entry.getHours();
}
24 RecordTimeServletjava
text_box.setInitialValue(hours);
text_box.setWidth(5);
table.setPrimitiveAt(row_ctr, col_ctr, text_box);
row_ctr++;
}
col_ctr++;
}
return page;
}
return dates;
}
RecordTimeServletjava 25
{
ArrayList charge_codes = new ArrayList();
Collections.sort(charge_codes);
return charge_codes;
}
return entries_map;
}
26 RecordTimeServletjava
if (parameter.startsWith(“entry”))
{
String key = parameter;
String hours = request.getParameter(parameter);
TimeEntryDTO entry = (TimeEntryDTO) entries_map.get(key);
entry.setHours(Integer.parseInt(hours));
}
}
}
}
267783 WS06.qxd 5/5/03 9:18 AM Page 27
RecordTimeWorkflow-
SessionBean
RecordTimeWorkflowInt.java
RecordTimeWorkflowInt.java is the local interface for the RecordTimeWorkflow entity
bean. It defines the remotely accessible methods for the RecordTimeWorkflow entity
bean. Since RecordTimeWorkflow is a stateful session bean, each method assumes a
particular session, which involves a single user and a single current timecard. This
allows the getChargeCodes to have an empty parameter list. Again, notice that each
return type is either Java data type or a custom Data Transfer Object (DTO).
package com.wiley.compBooks.EJwithUML.TimeCardWorkflow;
import java.rmi.*;
import javax.ejb.*;
import java.util.*;
import com.wiley.compBooks.EJwithUML.TimeCardDomain.*;
import com.wiley.compBooks.EJwithUML.Dtos.*;
import com.wiley.compBooks.EJwithUML.Base.ApplicationExceptions.*;
/**
* The RecordTimeWorkflowInt is the interface that ties the Bean
* with the Remote interface to provide compile time type checking.
*/
public interface RecordTimeWorkflowInt
27
267783 WS06.qxd 5/5/03 9:18 AM Page 28
28 RecordTimeWorkflowSessionBean
{
/** Answers the current timecard. */
public TimecardDTO getCurrentTimecard() throws
DataCreateException,FatalApplicationException, RemoteException;
/** Marks the current timecard as closed and creates a new one. */
public void submitTimecard() throws DataCreateException,
FatalApplicationException,RemoteException;
/**
* Answers a ClientDTO with client related information- projects
* and charge codes.
*/
public ClientDTO getClient(String clientName) throws Æ
DataNotFoundException,FatalApplicationException, RemoteException;
/**
* Answers a Collection of ClientDTOs with client related
* information- projects and charge codes.
*/
public Collection getAllClients() throws DataNotFoundException,
FatalApplicationException, RemoteException;
}
RecordTimeWorkflow.java
RecordTimeWorkflow.java is the remote EJB interface that inherits from RecordTime-
WorkflowInt and hence it has an empty body. This is in line with what we have set as
our implementation strategy for all of our EJBs. This is shown in Figure 03.
<<SessionRemote>>
RecordTimeWorkflow
+ getCurrentTimecard() : TimecardDTO
+ submitTimecard() : void
+ updateTimecard(currentTimecard : TimecardDTO) : void
+ getClient(name : String) : ClientDTO
RecordTimeWorkflowSessionBean 29
package com.wiley.compBooks.EJwithUML.TimeCardWorkflow;
import javax.ejb.*;
import java.util.*;
import com.wiley.compBooks.EJwithUML.TimeCardDomain.*;
import com.wiley.compBooks.EJwithUML.Dtos.*;
import com.wiley.compBooks.EJwithUML.Base.ApplicationExceptions.*;
/**
* The RecordTimeWorkflow allows client objects to record their
* time. RecordTimeWorkflow is the remote interface through which
* clients access the underlying session bean.
*/
public interface RecordTimeWorkflow extends EJBObject, Æ
RecordTimeWorkflowInt
{
}
RecordTimeWorkflowHome.java
RecordTimeWorkflowHome.java contains the methods for creating RecordTimeWork-
flowHome session beans. The create method requires a username. This associates the
RecordTimeWorkflow session bean with a single user for the life of the session. This is
shown in Figure 04.
<<SessionHome>>
RecordTimeWorkflowHome
package com.wiley.compBooks.EJwithUML.TimeCardWorkflow;
import java.util.*;
import java.rmi.*;
import javax.ejb.*;
import com.wiley.compBooks.EJwithUML.Base.ApplicationExceptions.*;
/**
* The RecordTimeWorkflow allows client objects to record their time.
* RecordTimeWorkflowHome is the remote interface through which Æ
clients find
* and create the underlying session beans.
*/
public interface RecordTimeWorkflowHome extends EJBHome
267783 WS06.qxd 5/5/03 9:18 AM Page 30
30 RecordTimeWorkflowSessionBean
{
/** Answers a reference to the newly created Activity bean. */
public RecordTimeWorkflow create(String username) throws
RemoteException,
CreateException;
}
RecordTimeWorkflowBean.java
RecordTimeWorkflowBean.java is the implementation class for the RecordTimeWork-
flow session bean. Most of this code should be somewhere between familiar and
monotonous, by this point. However, there is one new wrinkle, as the ejbCreate
method finds a User entity bean based on the username parameter. This bean reference
is kept for the duration of the stateful session. The RecordTimeWorkflow session bean
wraps the data for a timecard into a custom TimecardDTO object.
package com.wiley.compBooks.EJwithUML.TimeCardWorkflow;
import com.wiley.compBooks.EJwithUML.Dtos.*;
import com.wiley.compBooks.EJwithUML.TimeCardDomain.*;
import com.wiley.compBooks.EJwithUML.Base.ApplicationExceptions.*;
import com.wiley.compBooks.EJwithUML.Base.DateUtil;
import com.wiley.compBooks.EJwithUML.Base.EjbUtil.*;
import java.util.*;
import java.rmi.*;
import javax.ejb.*;
import javax.naming.*;
/**
* The RecordTimeWorkflow allows client objects to record their time.
* RecordTimeWorkflowBean is the actual session bean implementation.
*/
public class RecordTimeWorkflowBean extends BasicSessionBean
{
private UserLocal user;
RecordTimeWorkflowSessionBean 31
if (userIterator.hasNext())
{
this.user = (UserLocal) userIterator.next();
}
System.out.println(“done creating RecordTimeWorkflowBean with user
-” +
username);
}
catch (NamingException e)
{
throw new CreateException(“User Bean Not Found”);
}
catch (FinderException e)
{
throw new CreateException(“User(“ + username + “) Not Found”);
}
}
32 RecordTimeWorkflowSessionBean
timeEntry.getHours(), timeEntry.getDate());
tcDTO.addEntry(timeEntryDTO);
}
System.out.println(tcDTO);
return tcDTO;
}
catch(InvalidDataException e)
{
throw new DataCreateException(Origin.TIMECARD_WORKFLOW, e,
“failed to retrieve current Æ
timecard.”);
}
}
/** Marks the current timecard as closed and creates a new one. */
public void submitTimecard() throws DataCreateException,
FatalApplicationException, RemoteException
{
System.out.println(“in submitTimecard().”);
TimecardLocal currentTimecard = user.getCurrentTimecard();
createTimecard(currentTimecard);
}
RecordTimeWorkflowSessionBean 33
entryDTO. Æ
getChargeCodeName());
if (ccodes.size() == 1)
{
// we have single hit
ccode = (ChargeCodeLocal) ccodes.iterator().next();
}
else
{
//we have multiple hits; we need to narrow it down to 1
Iterator ccIterator = ccodes.iterator();
while(ccIterator.hasNext())
{
ChargeCodeLocal nextCcode = (ChargeCodeLocal) Æ
ccIterator.next();
if (nextCcode.getProject().getClient().getName().equals(
entryDTO.getClientName()))
{
ccode = nextCcode;
break;
}
}
if (ccode == null)
{
System.out.println(“could not find the charge code. Æ
cannot update/create - “
+ entryDTO);
continue;
}
}
if (entryDTO.isUpdated())
{
try
{
tentry = (TimeEntryLocal) tehome.findByPrimaryKey(new
TimeEntryPK Æ
(entryDTO.getId()));
/* makes sure that the entry belongs to the right timecard*/
if (!tentry.getTimecard().getPrimaryKey().equals(
user.getCurrentTimecard().getPrimaryKey()))
{
throw new DataUpdateException(Origin.TIMECARD_WORKFLOW,
“Duplicate Time Entry-” + Æ
entryDTO.toString());
}
System.out.println(“updating entry-” + entryDTO);
tentry.setDate(entryDTO.getDate());
tentry.setHours(entryDTO.getHours());
tentry.setChargeCode(ccode);
}
267783 WS06.qxd 5/5/03 9:18 AM Page 34
34 RecordTimeWorkflowSessionBean
catch(FinderException exception)
{
throw new DataUpdateException(Origin.TIMECARD_WORKFLOW,
“Marked as an update, but no entry found-” + Æ
entryDTO.toString());
}
}
else if (entryDTO.isNew())
{
// new entry- we need to add it; new entry has partial key; we
// need to add the timecard id to it. see TimeEntryDTO for
// more details.
String newId =((TimecardPK)user.getCurrentTimecard Æ
().getPrimaryKey()).id
+ “-” + entryDTO.getId();
System.out.println(“adding a new entry-” + entryDTO);
System.out.println(“actual id=” + newId);
tehome.create(newId,entryDTO.getDate(), entryDTO.getHours(),
ccode, user.getCurrentTimecard());
}
}
System.out.println(“total entries#” +
user.getCurrentTimecard(). Æ
getTimeEntries().size());
System.out.println(“done getUpdateTimecard().”);
}
catch(NamingException exception)
{
// invalid charge code
throw new FatalApplicationException(Origin.TIMECARD_WORKFLOW, Æ
exception,
“ChargeCode/TimeEntry Bean Not Æ
Found”);
}
catch(FinderException exception)
{
// invalid charge code
throw new DataNotFoundException(Origin.TIMECARD_WORKFLOW, exception,
“invalid charge code, failed to update Æ
timecard.” );
}
catch (CreateException e)
{
throw new DataUpdateException(Origin.TIMECARD_WORKFLOW, e,
“Failed to update timecard.”);
}
/**
267783 WS06.qxd 5/5/03 9:18 AM Page 35
RecordTimeWorkflowSessionBean 35
/**
* Answers a Collection of ClientDTOs with client related information-
* projects and charge codes.
*/
public Collection getAllClients() throws DataNotFoundException,
FatalApplicationException, Æ
RemoteException
267783 WS06.qxd 5/5/03 9:18 AM Page 36
36 RecordTimeWorkflowSessionBean
{
try
{
System.out.println(“in getAllClients().”);
Context initialContext = getInitialContext();
ClientLocalHome chome = (ClientLocalHome)initialContext.lookup(
Æ
EjbReferenceNames.CLIENT_HOME);
Collection clients = chome.findAll();
Iterator clientIterator = clients.iterator();
Collection clientDtos = new ArrayList();
ClientLocal client = null;
while(clientIterator.hasNext())
{
client = (ClientLocal) clientIterator.next();
ClientDTO cDTO = new ClientDTO(client.getName());
extractClientInfo(client, cDTO);
clientDtos.add(cDTO);
}
System.out.println(“done getAllClients().”);
return clientDtos;
}
catch (NamingException exception)
{
// invalid charge code
throw new FatalApplicationException(Origin.TIMECARD_WORKFLOW, Æ
exception,
“Client Bean Not Found”);
}
catch (FinderException exception)
{
throw new DataNotFoundException(Origin.TIMECARD_WORKFLOW, Æ
exception,
“no client found.” );
}
}
RecordTimeWorkflowSessionBean 37
38 RecordTimeWorkflowSessionBean
//one to be current.
if(user.getCurrentTimecard()!= null)
{
user.getCurrentTimecard().setIsCurrent(false);
}
user.setCurrentTimecard(nextTimecard);
System.out.println(“done creating a new Timecard.”);
return nextTimecard;
}
catch (NamingException e)
{
throw new FatalApplicationException(Origin.TIMECARD_WORKFLOW, e,
“Timecard Bean Not Found”);
}
catch (CreateException e)
{
throw new DataCreateException(Origin.TIMECARD_WORKFLOW, e,
“Failed to create timecard.”);
}
}
}
267783 WS07.qxd 5/5/03 9:18 AM Page 39
SelectChargeCodeServletjava
SelectChargeCodeServlet.java
The SelectChargeCodeServlet uses the RecordTimeWorkflow to get a collection of
charge codes that are valid for the system. It uses TablePrimitive, TextPrimitive, and
LinkPrimitive to build a list of charge codes with an associated “Add” link for each
charge code. When the user clicks on an “Add” link, RecordTimeServlet uses the
request parameters to identify the correct charge code to add to the timecard.
package com.wiley.compBooks.EJwithUML.TimecardUI;
import javax.servlet.http.*;
import javax.servlet.*;
import javax.naming.*;
import javax.ejb.*;
import java.rmi.*;
import javax.rmi.PortableRemoteObject;
import java.io.*;
import java.util.*;
import java.text.*;
import com.wiley.compBooks.EJwithUML.Base.HtmlPrimitives.Core.*;
39
267783 WS07.qxd 5/5/03 9:18 AM Page 40
40 SelectChargeCodeServletjava
import com.wiley.compBooks.EJwithUML.Base.HtmlPrimitives.FormPrimitives.*;
import com.wiley.compBooks.EJwithUML.Base.HtmlPrimitives.Layout.*;
import com.wiley.compBooks.EJwithUML.Base.HtmlPrimitives.ContentElements.*;
import com.wiley.compBooks.EJwithUML.TimeCardWorkflow.*;
import com.wiley.compBooks.EJwithUML.TimeCardDomain.*;
import com.wiley.compBooks.EJwithUML.TimecardProducers.*;
import com.wiley.compBooks.EJwithUML.Dtos.*;
import com.wiley.compBooks.EJwithUML.Base.EjbUtil.*;
import com.wiley.compBooks.EJwithUML.Base.ApplicationExceptions.*;
/**
* The RecordTimeServlet uses the TimecardWorkflow and
* HtmlProduction packages to create the formatted HTML
* to build a charge code selection grid.
*/
public class SelectChargeCodeServlet extends BasicTimecardServlet
{
private RecordTimeWorkflowHome rtwhome = null;
int row_ctr = 0;
267783 WS07.qxd 5/5/03 9:18 AM Page 41
SelectChargeCodeServletjava 41
table.setPrimitiveAt(row_ctr, 0, new Æ
SpanPrimitive(TimecardStyle.IMPORTANT_TEXT, “Client”));
table.setPrimitiveAt(row_ctr, 1, new Æ
SpanPrimitive(TimecardStyle.IMPORTANT_TEXT, “Project”));
table.setPrimitiveAt(row_ctr, 2, new Æ
SpanPrimitive(TimecardStyle.IMPORTANT_TEXT, “Code”));
table.setPrimitiveAt(row_ctr, 3, new Æ
SpanPrimitive(TimecardStyle.IMPORTANT_TEXT, “Action”));
row_ctr++;
while (clients.hasNext())
{
ClientDTO client = (ClientDTO) clients.next();
Iterator projects = client.getProjects();
while (projects.hasNext())
{
ProjectDTO project = (ProjectDTO) projects.next();
Iterator codes = project.getChargeCodes();
while (codes.hasNext())
{
String code = (String) codes.next();
String url = “/Timecard/RecordTimeServlet?” Æ
+TimecardKey.CLIENT.getKeyText()+”=” +client.getName()+
“&” +TimecardKey.PROJECT.getKeyText()+”=” Æ
+project.getName()+ “&”+ TimecardKey.CODE.getKeyText()+”=” +code;
TextPrimitive client_text = new Æ
TextPrimitive(client.getName());
TextPrimitive project_text = new Æ
TextPrimitive(project.getName());
TextPrimitive code_text = new TextPrimitive(code);
TextPrimitive link_text = new TextPrimitive(“Add”);
LinkPrimitive add_link = new LinkPrimitive(url);
add_link.addText(link_text);
table.setPrimitiveAt(row_ctr, 0, client_text);
table.setPrimitiveAt(row_ctr, 1, project_text);
table.setPrimitiveAt(row_ctr, 2, code_text);
table.setPrimitiveAt(row_ctr, 3, add_link);
row_ctr++;
}
}
}
42 SelectChargeCodeServletjava
response.getWriter().close();
}
catch (Exception e)
{
throw new ServletException(e);
}
}
Visual Glossary
The following glossary shows how several important object-oriented concepts are
shown in the UML and how they can be implemented in Java. Each section describes a
concept, provides a sample UML diagram that uses the concept, implements the UML
in Java, and offers some guidance on the proper use of the concept.
Generalization
One or more subclasses may share the attributes and behavior that are defined for the
base class. There are two ways to describe this relationship in proper object-oriented
terminology. First, a class inherits all of the attributes and behaviors from a superclass
or base class. From the opposite perspective, the superclass is a generalization of the
attributes and behaviors that are common to all of its subclasses. In UML, the relationship
is described as a generalization and is denoted by a solid line with a hollow arrow
pointing to the base class.
43
267783 WS08.qxd 5/5/03 9:19 AM Page 44
44 Visual Glossary
Vehicle
+ go() : String
+ startEngine() : void
+ stopEngine() : void
+ isEngineOn() : boolean
Car Truck
UML Example
Consider a brief example of generalization. Vehicle is a generalization of both Car and
Truck. The two subclasses, Truck and Car, inherit all of the attributes and behavior
from the base class. Figure VG.1 shows the two subclasses, with generalization arrows
pointing to the base class. In this case, there is no default go behavior for vehicles, so
the base class must be abstract. Each concrete subclass of Vehicle must provide an
implementation of the go method. Each concrete subclass may accept the default
behavior for startEngine, stopEngine, and isEngineOn. If the default implementation is
inappropriate, the subclass may override the default implementation by providing its
own implementation.
In UML, rendering the abstract class name in italics indicates that the class is
abstract. Showing a method in both the base class and in the subclass indicates that the
subclass overrides that method.
Java Example
The following Java files show how the UML model in Figure VG.1 can be implemented
in Java.
Vehicle.java
Vehicle.java is the abstract base class in Figure VG.1. This is reflected in the source
code, as the class and the go method are both abstract. The other methods have imple-
mentations, but are not final, so they may be overridden by subclasses.
/**
* The Vehicle class contains the data and behavior that
267783 WS08.qxd 5/5/03 9:19 AM Page 45
Visual Glossary 45
Car.java
Car.java is a subclass of Vehicle, which in Java is indicated by the reserved word
“extends.” Car overrides the go method and uses the base class implementation of the
isEngineOn method.
/**
* The Car class inherits from Vehicle and overrides the go method.
* It encapsulates all data and behavior that is specific to Cars.
*/
public class Car extends Vehicle
{
/** Answers the noise made by the Car when it goes. */
public String go()
{
if (this.isEngineOn())
{
return “Vroom”;
267783 WS08.qxd 5/5/03 9:19 AM Page 46
46 Visual Glossary
}
else
{
return “...”;
}
}
}
Truck.java
Truck.java is a subclass of Vehicle, which in Java is indicated by the reserved word
“extends.” Truck overrides the go method and uses the base class implementation of
the isEngineOn method. Truck is almost identical to Car, with a different implementation
of the go method.
/**
* The Truck class inherits from Vehicle and overrides the go method.
* It encapsulates all data and behavior that is specific to Trucks.
*/
public class Truck extends Vehicle
{
/** Answers the noise made by the Truck when it goes. */
public String go()
{
if (this.isEngineOn())
{
return “Rumble”;
}
else
{
return “...”;
}
}
}
Guidelines
It is extremely important for the generalization relationship to be an accurate descrip-
tion of the underlying reality that you are modeling. Each subclass must really be a
refinement of the superclass. Do not subclass a class just to get useful behavior or
attributes. Doing so makes the system significantly more difficult to understand, and
may result in strange errors as the system evolves.
267783 WS08.qxd 5/5/03 9:19 AM Page 47
Visual Glossary 47
Realization
A class realizes an interface by implementing each method that is defined in the inter-
face. By realizing the interface, the class is promising to make the interface real. In
UML, the realization relationship is denoted by a dashed line, with a hollow arrow
pointing to the interface.
UML Example
Continuing the earlier example, some Vehicles can carry cargo, some cannot. Also,
some classes that are not “normal” vehicles may also carry cargo. So, rather than intro-
ducing a separate subclass for all cargo-carrying vehicles, we introduce an interface,
ICargoTransport. Our design allows any class to realize the ICargoTransport by
providing an implementation for the loadCargo method. Figure VG.2 shows Truck
realizing the ICargoTransport interface, while Car does not.
Java Example
The following Java files show how the UML model in Figure VG.2 can be implemented
in Java. Only the files that have changed from the generalization example are shown.
Vehicle
<<Interface>>
+ go() : String ICargoTransport
+ startEngine() : void
+ stopEngine() : void + loadCargo() : void
+ isEngineOn() : boolean
Car Truck
48 Visual Glossary
Truck.java
Truck.java is a subclass of Vehicle, which in Java is indicated by the reserved word
“extends.” Truck overrides the go method and uses the base class implementation of
the isEngineOn method. Truck also realizes the ICargoTransport interface, as indicated
by the “implements” reserved word in the class definition.
/**
* The Truck class inherits from Vehicle, and overrides the go
* method. It encapsulates all data and behavior that is specific to
* Trucks.
*/
public class Truck extends Vehicle implements ICargoTransport
{
/** Answers the noise made by the Truck when it goes. */
public String go()
{
if (this.isEngineOn())
{
return “Rumble”;
}
else
{
return “...”;
}
}
ICargoTransport.java
ICargoTransport.java simply defines the name and signature for the loadCargo
method. As an interface, it is precluded from providing an implementation.
/**
* The ICargoTransport interface defines the methods
* that must be implemented by all classes that
* transport cargo.
*/
public interface ICargoTransport
{
267783 WS08.qxd 5/5/03 9:19 AM Page 49
Visual Glossary 49
Guidelines
All of the methods in an interface must combine to describe a coherent responsibility.
Association
An association is a long-term relationship between objects. In an association, an object
keeps a reference to another object, and can call the object’s methods as it needs them.
Real life is replete with association relationships. Consider a person with his or her
own automobile. As long as he or she remembers where it is parked, the car will let the
person in to drive to his or her destination. In the UML, a solid line between the two
classes represents an association.
In some cases, an object may instantiate another object and keep a reference to it for
future use. An object may also receive an object as a parameter to a configuration
method and keep a reference to the object.
UML Example
Consider an association relationship in which each Person object knows about zero or
more Vehicle objects. Figure VG.3 shows this relationship in a class diagram. The rela-
tionship is read as “every Person object is associated with zero or more Vehicle
objects,” and “every Vehicle object is associated with one or more Person objects.” It
may help to think of this as a “knows-about-a” relationship, as in “each Person object
knows about some Vehicle objects.”
Vehicle
<<Interface>>
Person ICargoTransport
+ go() : String
+ startEngine() : void
+ addVehicle(v : Vehicle) : void 1..* 0..*
+ stopEngine() : void + loadCargo() : void
+ isEngineOn() : boolean
Car Truck
50 Visual Glossary
Java Example
Person.java shows how the association relationship shown in Figure VG.3 between
Person and Vehicle can be implemented in Java. Each reference to a Vehicle object is
kept in a Vector.
Person.java
The Person class simply holds the vehicles for a person.
import java.util.*;
/**
* The Person class contains all data and logic for a person
* in the system.
*/
public class Person
{
public Vector vehicles = new Vector();
Guidelines
Association is the default long-term relationship between objects. If you are in doubt as
to which long-term relationship to use, use association.
Aggregation
Aggregation indicates a long-term relationship, with the additional restriction that
some of the objects are part of another object. It is this whole-part nature of the rela-
tionship that distinguishes aggregation from association.
UML Example
To continue the example, each Vehicle object may contain zero or one Engine objects.
There is a clear whole-part relationship, as the engine is part of the car or truck. Figure
VG.4 shows a modified association from Vehicle to Engine, with the hollow diamond
at the Vehicle indicating aggregation. The hollow diamond is always drawn next to the
enclosing whole.
267783 WS08.qxd 5/5/03 9:19 AM Page 51
Visual Glossary 51
Engine
+ start() : void
+ stop() : void
Vehicle + isOn() : boolean
0..1
Person 1
+ go() : String
+ startEngine() : void <<Interface>>
+ addVehicle(v : Vehicle) : void 1..* 0..* ICargoTransport
+ stopEngine() : void
+ isEngineOn() : boolean
+ loadCargo() : void
Car Truck
Java Example
The following Java files show how the UML model in Figure VG.4 can be implemented
in Java. Only the files that have changed from the previous running example are
shown.
Vehicle.java
Vehicle no longer determines whether it is running or not. Instead, this behavior is
delegated to an Engine object.
/**
* The Vehicle class contains the data and behavior that
* is common to all Vehicles.
*/
public abstract class Vehicle
{
private Engine engine;
52 Visual Glossary
return false;
}
}
Engine.java
Engine.java provides very simple behavior for starting, stopping, and checking the
current value.
/**
* The Engine class contains the data and behavior for all engines
* for use with Vehicles.
*/
public class Engine
{
private boolean on;
Visual Glossary 53
Guidelines
Aggregation requires a clear whole-part relationship. Any uncertainty about the need
for aggregation or ambiguity over which object is the whole and which is the part
should lead you to use association instead.
Composition
Composition is an even stronger relationship, with one object essentially owning the
other object or objects. The subordinate objects are created when the whole is created,
and are destroyed when the whole is destroyed. Also, an object cannot play the role of
a subordinate part in two composition relationships.
UML Example
Every engine contains many wheels, cogs, and gears that are integral and indivisible
parts of the greater whole. Figure VG.5 shows that each Engine object contains zero or
many Cog objects. The filled-in diamond next to the enclosing class indicates the com-
position relationship.
Java Example
The following Java file shows how the UML model in Figure VG.5 can be implemented
in Java. Only the files that have changed from the previous running example are
shown.
267783 WS08.qxd 5/5/03 9:19 AM Page 54
54 Visual Glossary
Vehicle
Person <<Interface>>
+ go() : String
ICargoTransport
+ startEngine() : void
+ addVehicle(v : Vehicle) : void 1..* 0..*
+ stopEngine() : void
+ loadCargo() : void
+ isEngineOn() : boolean
1
0..1
Engine
+ start() : void
Car Truck
+ stop() : void
+ isOn() : boolean + go() : String
+ go() : String
1 + loadCargo() : void
Cog
Engine.java
The Cog objects are created when the Engine is created, and become eligible for
garbage collection along with their enclosing Engine.
import java.util.*;
/**
* The Engine class contains the data and behavior for all engines
* for use with Vehicles.
*/
public class Engine
{
private boolean on;
private Vector cogs = new Vector();
public Engine()
{
this.cogs.addElement(new Cog());
this.cogs.addElement(new Cog());
}
Visual Glossary 55
this.on = true;
}
Guidelines
As with aggregation, when in doubt, do not use composition.
Dependency
Objects often need to use another object. An object may receive a reference as a param-
eter to a method, or it may create the object, use it, and lose it before the end of the cur-
rent method. The key idea is that the dependent object acquires, uses, and forgets the
object within a single method.
UML Example
Continuing the example, people use gas pumps to get gas, but most people do not keep
track of every pump that they have used. The Person object receives a reference to a
GasPump object as a parameter to the purchaseGas method. The reference is used
within the method; it is not kept. The resulting dependency relationship can be seen as
the dashed line from Person to GasPump in Figure VG.6.
Java Example
Person.java shows how the dependency relationship between Person and GasPump
can be implemented in Java.
267783 WS08.qxd 5/5/03 9:19 AM Page 56
56 Visual Glossary
Vehicle
Person <<Interface>>
+ go() : String
ICargoTransport
+ startEngine() : void
+ addVehicle(v : Vehicle) : void 1..* 0..*
+ stopEngine() : void
+ purchaseGas(pump : GasPump) : void + loadCargo() : void
+ isEngineOn() : boolean
1
0..1
Engine
GasPump
+ start() : void Car
+ stop() : void Truck
+ isOn() : boolean + go() : String
+ go() : String
1 + loadCargo() : void
Cog
Person.java
Now, the Person class has a purchaseGas method that accepts a reference to a GasPump
object as a parameter.
import java.util.*;
/**
* The Person class contains all data and logic for a person
* in the system.
*/
public class Person
{
public Vector vehicles = new Vector();
Visual Glossary 57
Guidelines
Dependency should be used whenever an object is used and forgotten within a single
method.
267783 WS08.qxd 5/5/03 9:19 AM Page 58