Home > Articles > Programming > Java

  • Print
  • + Share This
From the author of

State/Capital City Example

UML class diagrams describe objects and the associations between them. Associations detail how objects are related to each other, how many objects are involved in a relationship (multiplicity), whether you can determine the related objects of an entity relationship (navigability), and the life cycle characteristics (when relationships begin and when they end). These details are important to describe CMP entity bean persistent field methods, relationship field methods, and deployment descriptor declarations.

Let's start with a simple example. The idea is that every state has one capital city and each capital city belongs to only one state. Figure 1 shows a class diagram modeling these entities and their association (relationship).

Figure 1 State EJB and CapitalCity EJB class diagram.

Persistent Fields

This UML class diagram depicts the State EJB with a single attribute, name. Object attributes model persistent data; thus, State EJB has a single persistent data field. Furthermore, all entity beans have a primary key, which we do not need to model in a class diagram; its existence is implied. The CapitalCity EJB also contains a single name attribute and an implied primary key.

Mapping Persistent Fields

Every CMP entity bean has a local home interface, a local interface, and a bean implementation class. As a bean developer, you must write both interfaces as well as the bean implementation class. Here, we will focus only on the CMP bean implementation class and the modeling information provided by a UML class diagram. Ultimately, the data modeling depicted in the UML class diagram maps to methods in the bean implementation class. We map class diagram attributes as abstract access methods for persistent fields. Each attribute has a corresponding setter and getter access method. We also create access methods for the primary key. Listing 1 gives the attributes for entity beans State EJB and CapitalCity EJB.

Listing 1: State EJB and CapitalCity EJB Access Methods for Class Attributes and Primary Key

// StateBean.java
// Bean implementation class for State entity bean
public abstract class StateBean implements EntityBean {

   // Access methods for primary key
   public abstract String getStateID();
   public abstract void setStateID(String id);

   // Access methods for class attributes (persistent fields)
   public abstract String getName();
   public abstract void setName(String name);
   . . .
}

// CapitalCityBean.java
// Bean implementation class for CapitalCity entity bean
public abstract class CapitalCityBean implements EntityBean {

   // Access methods for primary key
   public abstract String getCapitalCityID();
   public abstract void setCapitalCityID(String id);

   // Access methods for class attributes (persistent fields)
   public abstract String getName();
   public abstract void setName(String name);
   . . .
}

Note that each bean implementation class is abstract because the application server generates database access code as well as the code to implement the abstract access methods.

Relationships

What else does Figure 1 tell us about state and capital city objects? The objects are connected by a line, denoting an association or relationship. We describe an entity bean relationship by specifying a name (role) on each end of the line and the multiplicity, navigability, and life cycle requirements for the relationship. Each state has exactly one capital city, and each capital city has exactly one state, denoted by the 1 next to the relationship arrow. Thus, the relationship multiplicity between state and capital city is one to one. When a relationship multiplicity is either 1 or optional (0 or 1), we call it singular. Furthermore, this relationship is bidirectional, meaning that you can navigate in both directions. You can determine the capital city from the state and the state from the capital city (denoted by the double-headed arrow). A bidirectional relationship is also called two-way navigation. Unidirectional relationships provide one-way navigation.

Mapping Relationships

Each association in a class diagram maps to an entity bean relationship. In CMR, the container maintains the relationship fields for you, but you must provide abstract access methods for those relationships that are navigable. Singular relationships (as in our example) specify the local interface of the related entity bean for arguments and return types. The bidirectional association between State EJB and CapitalCity EJB maps to the abstract access methods in Listing 2 in the corresponding bean implementation code. (We assume that the local interface for State EJB is StateLocal and the local interface for CapitalCity EJB is CapitalCityLocal.)

Listing 2: State EJB and CapitalCity EJB Access Methods for Relationship Fields

// StateBean.java
// Bean implementation class for State entity bean
public abstract class StateBean implements EntityBean {
   . . .
   // Access methods for relationship field
   public abstract CapitalCityLocal getCapital();
   public abstract void setCapital(CapitalCityLocal city);
   . . .
}

// CapitalCityBean.java
// Bean implementation class for CapitalCity entity bean
public abstract class CapitalCityBean implements EntityBean {
   . . .
   // Access methods for relationship field
   public abstract StateLocal getState();
   public abstract void setState(StateLocal state);
   . . .
}

Relationship Life Cycle Issues

Because the multiplicity for both ends of the state/capital city relationship is exactly 1, this implies that there must always be a capital city for a state and a state for a capital city throughout the lifetime of both entities. When a multiplicity is mandatory (meaning at least 1), this implies that a capital city cannot exist without a state and a state cannot exist without a capital city. Mandatory multiplicities have two requirements:

  • You must define a mandatory relationship throughout the lifetime of the entity. This means that the relationship must be initialized during the creation process. Typically, this is done in the bean implementation method ejbPostCreate(). When you create an entity for the state of New York, you must also create and initialize its relationship with the capital city of Albany.

  • If you destroy an entity that has a mandatory relationship, you must delete the related entity. This is called a cascading delete. Thus, if you delete State EJB Nebraska, you must also delete CapitalCity EJB Lincoln.

Mapping Life Cycle Characteristics

When both ends of a relationship are mandatory, this produces the proverbial chicken-and-egg dilemma. That is, you can't initialize the capital city until the corresponding state entity exists, and you can't initialize the state until the corresponding capital city exists. To resolve this dilemma, you pick one end to initialize during the creation process; the good news is that the EJB container initializes the other end for you. Let's examine additional code snippets from the bean implementation class for State EJB in Listing 3, showing the initialization of its relationship with CapitalCity EJB.

Listing 3: State EJB Implementation Methods ejbCreate() and ejbPostCreate()

// StateBean.java
// Bean implementation class for State entity bean
public abstract class StateBean implements EntityBean {
   . . .
   // EntityBean method ejbCreate()
   public String ejbCreate(String name, CapitalCityLocal capital)
   throws CreateException {
     String newKey = DBUtil.dbGetKey();
     setStateID(newKey);
     setName(name);
     return newKey;
   }

   // EntityBean method ejbPostCreate()
   public void ejbPostCreate(String name, CapitalCityLocal capital) {
     setCapital(capital);
   }
   . . .
}

The parameters for ejbCreate() and ejbPostCreate() must be the same. Note that we generate a primary key by calling DBUtil.dbGetKey(). Primary key generation is beyond the scope of this article; many database servers provide primary key generation routines for you.

Method ejbCreate() initializes the entity bean's persistent fields by calling the set access methods that we defined earlier. At the same time, the container inserts a matching row in the underlying database for the entity bean. Because the entity bean is not fully instantiated at this time, you cannot invoke any methods except the persistent data field access methods.

The EJB container invokes ejbPostCreate() after ejbCreate(). We use the method ejbPostCreate() to initialize the relationship between State EJB and CapitalCity EJB by invoking the setCapital() access method that we defined earlier. The EJB container initializes the other end of the relationship. The container also inserts matching rows in the underlying database to maintain the relationship fields (typically in a cross-reference database table).

Mapping Declarative Information

Bean developers communicate much of an entity bean's characteristics through abstract access methods written in the bean implementation code. Deployment tools inspect this code and infer information about persistent fields and relationship fields. However, we must still identify primary key fields and specify characteristics of relationship fields. Armed with a class diagram that specifies the relationship, its multiplicity, and its navigability, this is quite straightforward. (And application servers will typically provide a deployment tool that generates an XML deployment descriptor for you.)

Listing 4 shows the deployment descriptor tags that describe the relationship between State EJB and CapitalCity EJB. (We made the XML tag values bold to improve readability.)

Listing 4: XML Tags Describing the Relationship Between CapitalCity EJB and State EJB

 <relationships>
 <ejb-relation>
  <ejb-relation-name></ejb-relation-name>
  <ejb-relationship-role>
  <ejb-relationship-role-name>CapitalCityBean
  </ejb-relationship-role-name>
  <multiplicity>One</multiplicity>
  <cascade-delete />
  <relationship-role-source>
   <ejb-name>CapitalCityBean</ejb-name>
  </relationship-role-source>
  <cmr-field>
   <cmr-field-name>state</cmr-field-name>
  </cmr-field>
  </ejb-relationship-role>
  <ejb-relationship-role>
  <ejb-relationship-role-name>StateBean</ejb-relationship-role-name>
  <multiplicity>One</multiplicity>
  <cascade-delete />
  <relationship-role-source>
   <ejb-name>StateBean</ejb-name>
  </relationship-role-source>
  <cmr-field>
   <cmr-field-name>capital</cmr-field-name>
  </cmr-field>
  </ejb-relationship-role>
 </ejb-relation>
 </relationships>

Here are some notes about the relationship described in the deployment descriptor:

  • The relationship multiplicity, <multiplicity>, is one to one.

  • Cascading deletes, <cascade-delete />, apply in both directions (because the relationship is mandatory in both directions).

  • The CMR fields, <cmr-field-name>, are state and capital for CapitalCity and State, respectively. Note that these are the labels (roles) we use on the relationship line in Figure 1.

  • + Share This
  • 🔖 Save To Your Account