The package structures shown in Figure 7-6 depict the dependencies between packages in the business tier. The package naming conventions used by the GreaterCause application in the business tier and the domain
Figure 7-6:
Business Tier Package Diagram
|
Business Tier |
Domain Tier |
|---|---|
|
|
|
|
com.gc.services.admin |
com.gc.persistence.admin |
|
|
|
|
com.gc.services.managecampaigns |
com.gc.persistence.managecampaigns |
|
|
|
|
com.gc.services.searchnpo |
|
The basic
|
|
The basic premise of this book is use of object-oriented paradigm and use case–driven approach. As such, we now examine how we have used the different patterns discussed in the preceding sections for realizing the use cases discussed in Chapter 1. In this chapter, we develop the use cases identified by the packages Site Administration, Manage Campaigns, and Search NPO. The intent of this endeavor is to assist the readers in understanding how to implement an architecture based on the patterns we just discussed, at the same time, we create static and dynamic models for representing our problem domain.
|
|
The following subsections provide the use case realization for use cases in the Site Administration package. To avoid repetition, we cover only essential use cases that introduce new concepts; for the rest of the use cases,
| Note |
The following subsections provide readers with an opportunity to understand class interactions and dependencies visualized through class and analysis-level sequence diagrams. Please refer to Chapter 1 for use case descriptions. |
This section covers the implementation of Register NPO use case. The implementation details described here provide the necessary foundation for other use cases; and the same concepts are reapplied for implementing other use cases.
The first step in realizing the use case is to identify the methods of the business interface necessary for realizing the use case. We identify the business interface methods by following the flow of events described for the use case. Since the Register NPO is an administration service, applying the business interface pattern described earlier in the section "Implementing the Business Interface Pattern," we define a business interface called
SiteAdmin
. This interface must provide a method called
registerNPO
for allowing the presentation tier to register NPO data. Using the data transfer object pattern, the presentation
public class NPORegistrationDTO implements Serializable { //Instance
variables
private String ein = null; private String npoName = null; private String adminID = null; private String address = null; private String city = null; private String state = null; private String zip = null; private String country = null; private String activationStatus = null;
... rest of the code ...
}
Since this DTO will go across the wire using RMI, ensure that it implements the Serializable interface. Once the registration information is created in the GreaterCause data store, the Register NPO use case will also need to maintain this information using the updateNPORegistration and getNPORegistration methods; these additional methods are added to the business interface as well. The following code fragment shows the business methods identified thus far in the business interface SiteAdmin :
public interface SiteAdmin { void registerNPO(NPORegistrationDTO detail) throws RemoteException, RegistrationException; void updateNPORegistration(NPORegistrationDTO details) throws RemoteException,NPONotFoundException, GCAppException; NPORegistrationDTO getNPORegistration(String ein, String adminID) throws RemoteException, NPONotFoundException, AdminNotFoundException, GCAppException; }
The method signatures identified for the business interface shown were selected based on the design decision that we will be
Please observe that the business methods declared in the business interface also declare the possible exceptions the business methods may throw to the presentation tier. In addition to the application exceptions, the business methods must also throw RemoteException ; this is because the remote interface for the session bean will be extended from this business interface. Recall from the discussion in the section "Implementing the Business Interface Pattern" that the business methods must throw RemoteException if they are to be exposed through a remote interface as required by the EJB 2.0 specification.
In this section, we discuss the implementation aspects of the business interface
SiteAdmin
defined in the
Figure 7-7:
Register NPO class diagram
Figure 7-8 depicts the creation of domain objects Admin and NPO using the DTO supplied by the presentation tier, whereas Figure 7-9 depicts the creation of DTO using the information from the domain objects Admin and NPO. From the sequence diagram, it is apparent that the session faade
SiteAdmin
is responsible for handling all the complexities of creating and managing domain objects while the presentation tier need only make a single call to the session faade. For brevity, certain steps are removed from the sequence diagrams and the reader is
Figure 7-8:
Sequence diagram for registerNPO
Figure 7-9:
Sequence diagram for getNPORegistration
The session bean SiteAdminBean defined in the preceding section needs to be configured for deployment in an EJB container. We use deployment descriptors for providing the configuration information.
There is
<session > <description>Site Admin Definitions</description> <ejb-name>SiteAdminEJB</ejb-name > <home>com.gc.services.admin.SiteAdminHome</home> <remote>com.gc.services.admin.SiteAdminRemote</remote> <ejb-class>com.gc.services.admin.SiteAdminBean</ejb-class> <session-type>Stateless</session-type> <transaction-type>Container</transaction-type> <!-- Referencing NPO Entity Bean --> <ejb-local-ref> <ejb-ref-name>com.gc.persistence.admin.NPOLocalHome</ejb-ref-name> <ejb-ref-type>Entity</ejb-ref-type> <local-home>com.gc.persistence.admin.NPOLocalHome</local-home> <local>com.gc.persistence.admin.NPOLocal</local> <ejb-link>NPOEntityEJB</ejb-link> </ejb-local-ref> <!-- Referencing Admin Entity Bean --> <ejb-local-ref> <ejb-ref-name>com.gc.persistence.admin.AdminLocalHome</ejb-ref-name> <ejb-ref-type>Entity</ejb-ref-type> <local-home>com.gc.persistence.admin.AdminLocalHome</local-home> <local>com.gc.persistence.admin.AdminLocal</local> <ejb-link>AdminEntityEJB</ejb-link> </ejb-local-ref> </session>
Using the
ejb-name
element, we assign a logical name to the session bean. This logical name must be unique within the ejb-jar.xml file. This name is referenced in other constructs such as the subelements of the
container-transaction
element and
ejb-relation
element (refer to the element
ejb-name
in these constructs). The session EJB is further described using the
home
,
remote
, and
ejb-class
elements that provide the fully qualified class
Recall that when a client
//Vendor specific code Hashtable props = new Hashtable(); props.put(InitialContext.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory"); props.put(InitialContext.PROVIDER_URL, "t3://localhost:7001"); InitialContext ctx = new InitialContext(props); SiteAdminHome siteAdminHome = (SiteAdminHome) javax.rmi.PortalRemoteObject.narrow( ctx.lookup("ejb/com.gc.services.admin.SiteAdminHome"),SiteAdmin.class);
The access mechanism shown here is not required when an EJB is accessing another EJB. The session bean
SiteAdminBean
references NPO and Admin entity beans as part of the implementation of Register NPO use case. The EJB 2.0 specification simplified the access mechanisms when an EJB in a container is accessing another EJB within the same or a different container. To reference an EJB from another EJB, you do not need to specify any JNDI initialization parameters; instead you acquire default JNDI
InitialContext
as
Context initialContext = new InitialContext();
When default JNDI InitialContext is used, the lookup mechanism will take the following form. In this form, the java:comp/env/ string specifies the default environment naming context.
NPOHome npoHome = (NPOHome) initialContext.lookup("java:comp/env/"+NPOHome.class);
The NPOHome.class is mapped by the container to the value of the ejb-ref-name element within the deployment descriptors; the value of the ejb-ref-name element is subsequently used by the container to get the descriptors of the corresponding EJB. The ejb-ref-name element has a sibling ejb-link element (defined under the parent ejb-local-ref element); this ejb-link element provides the link to the original definition of the entity bean; the value of this element is the logical name given in the ejb-name element of the corresponding entity bean where it was originally defined. Since the NPO entity bean is described in the same ejb-jar.xml file for our sample application, we can simply provide the value NPOEntityEJB for the ejb-link element.
For the session bean deployment descriptors being discussed in this section, notice that the ejb-ref-name element occurs under the ejb-local-ref element; these constructs assist the container in accessing the NPO and Admin entity beans. This concludes the discussion on the deployment descriptors for the SiteAdmin session bean. The JNDI name for the session bean is defined in a vendor-specific deployment descriptor; since we have used the WebLogic Server, the corresponding deployment descriptor is the weblogic-ejb-jar.xml file.
<!-- SiteAdmin Definition --> <weblogic-enterprise-bean> <ejb-name>SiteAdminEJB</ejb-name> <jndi-name>ejb/com.gc.services.admin.SiteAdminHome</jndi-name> </weblogic-enterprise-bean>
The ejb-name element refers to the ejb-name defined in the ejb-jar.xml file. The jndi-name element represents the JNDI name to be used for accessing the session bean. The EJB 2.0 specification recommends prefixing the JNDI names with "ejb/."
The EJB Specification greatly simplified declarative transaction management. Without this, the developer had to explicitly manage the transactions with
The bean provider may also choose to use programmatic transaction demarcation; this is called bean-managed transaction demarcation. With bean-managed transaction demarcation, the enterprise bean demarcates transactions using the javax.transaction.UserTransaction interface. Accesses to container-managed resources, between UserTransaction.begin() and UserTransaction.commit() , are part of this transaction. Please refer to the EJB specifications or Mastering Enterprise JavaBeans [JavaBeans] for detail information on using programmatic bean-managed transaction demarcation.
| Note |
The EJB architecture supports flat transactions, implying that a transaction cannot have other nested (child) transactions. We assume that the reader has prior knowledge of what a transaction is and the associated ACID properties. |
Scope of a Transaction
When using container-managed transaction demarcation, the scope of a transaction is controlled by the transaction attribute specified for the EJB's methods. Following
Transaction Attributes A transaction attribute is a value associated with a method of a session or entity bean's home or component interface that specifies how the Container must manage transactions for a method when a client invokes the method via the enterprise bean's home or component interface (i.e., local or remote interfaces). EJB specification supports the following values for the transaction attribute when using container-managed transaction demarcation for EJBs:
NotSupported
When the transaction attribute is set to
NotSupported
, the container invokes the
Required
When the transaction attribute is set to
Required
, the container must invoke the related enterprise bean method with a valid transaction context. If the client invokes the enterprise bean's method with a transaction context, the same transaction context is propagated to the bean's method. If the client is not associated with a transaction context, the container automatically starts a new transaction before calling the business method. This option is selected when the bean method is changing the state of the application; for example, creating one or more entity beans or updating the value of entity beans, and so on. This option is not necessary if the bean method is just reading the contents from the data store, and the application is not
Supports When the transaction attribute is set to Supports , the container invokes the related enterprise bean method as follows:
If the client call is associated with a transaction context, the semantics
If the client call is not associated with a transaction context, the semantics applicable are similar to the NotSupported case.
RequiresNew
When the transaction attribute is set to
RequiresNew
, the container invokes the related enterprise bean method with a new transaction context. This transaction context is propagated to methods of other enterprise beans. When the client invokes the enterprise bean while the client is already associated with a transaction context, then that transaction is
Mandatory
When the transaction attribute is set to
Mandatory
, the container must invoke the related enterprise bean method in a client's transaction context. If the client calls with a transaction context, the container
Never When the transaction attribute is set to Never , the container invokes the related enterprise bean method without a transaction context. If the client calls with a transaction context, the container throws java.rmi.RemoteException for a remote client, or javax.ejb.EJBException for a local client. If the client calls without a transaction context, the container performs the same steps as described in the NotSupported case.
The transaction attributes for each EJB are defined in deployment descriptors. The descriptors have the flexibility for providing a single transaction attribute for all the methods using the * notation, as shown here:
<container-transaction> <method> <ejb-name>SiteAdminEJB</ejb-name> <method-name> * </method-name> </method> <trans-attribute> Required </trans-attribute> </container-transaction>
This representation specifies that all methods of SiteAdminEJB will have the transaction attribute of Required . This implies that all the SiteAdminEJB method invocations are always under a transaction context even if the bean method is simply reading the data from data store. The transaction attribute must be set to Required for those methods that affect the persistent state of the application. For example, the transaction attribute is set to Required for the registerNPO and updateNPORegistration methods of the SiteAdmin session bean because these methods change the persistent state of the application. Transaction attributes for individual methods of the SiteAdminBean can be specified as follows.
<container-transaction> <method> <ejb-name>SiteAdminEJB</ejb-name> <method-name>registerNPO</method-name> </method> <method> <ejb-name>SiteAdminEJB</ejb-name> <method-name>updateNPORegistration</method-name> </method> <trans-attribute>Required</trans-attribute> </container-transaction>
The EJB 2.0 specification introduces conceptual difference between application exceptions and system exceptions. The EJB developer must understand this difference in addition to the relationship between exceptions and transaction semantics.
An application exception is an exception defined in the
throws
clause of a method of the enterprise bean's home and component interfaces (remote and local interfaces), other than
java.rmi.RemoteException
or
javax.ejb.EJBException
. An application exception is a direct or indirect subclass of
java.lang.Exception
; it must not be defined as a subclass of
java.lang.RuntimeException
or
java.rmi.RemoteException
. Application exceptions are used to
On the other hand, system-level exceptions are created as a result of situations that prevent EJB methods from completing successfully; for example, failure to obtain a database connection, JNDI exceptions, unexpected RemoteException from invocation of other enterprise beans, RuntimeException , JVM errors, and so on. The bean methods must not try to catch these RuntimeException s but let them propagate to the container. When a bean method is processing a checked exception and discovers that it cannot recover from the exception, the bean method should throw the javax.ejb.EJBException; EJBException is a subclass of RuntimeException , and therefore it does not have to be listed in the throws clause of business methods. The Container catches all non-application exceptions, logs the exception, marks the transaction for rollback, and subsequently throws a RemoteException (for clients using remote interfaces) or EJBException (for clients using local interfaces). The following code fragment has been excerpted from the getNPORegistration method of the SiteAdmin session bean:
try { NPOLocalHome npoHome = (NPOLocalHome) EJBHomeFactory.getFactory().lookUpLocalHome( NPOLocalHome.class);
... Rest of the code ...
} catch
(NamingException ne)
{
throw new EJBException(
"Unable to locate local reference to NPO:",
ne
); }
NamingException is thrown by the container during JNDI lookup; since this signifies a configuration issue, the application will throw an EJBException and not an application exception because the client is not expected to recover from this exception.
According to the EJB 2.0 specification, when a system exception is
When the business method encounters an application exception, and if the exception is deemed unrecoverable, it is the EJB developer's responsibility to identify and mark the transaction for rollback using setRollbackOnly() on EJBContext ; this marks the transaction for rollback. The setRollbackOnly method can be invoked only when bean methods are participating in a transaction context. Observe from the following code fragment that the setRollbackOnly method is invoked prior to throwing the RegistrationException , which is an application exception; the intent here is to mark the transaction for rollback because the NPO entity bean has already been created. Please note that the code shown is slightly modified for explaining the concepts; the actual code can be found in SiteAdminBean implementation.
try { AdminLocalHome adminHome = (AdminLocalHome) EJBHomeFactory.getFactory().lookUpLocalHome( AdminLocalHome.class); admin = adminHome.create(adminID, (NPOLocal) npo);
} catch (CreateException ce) { ctx.setRollbackOnly();
throw new RegistrationException("error.CannotCreateAdmin", "Unable to Register Admin with AdminID:" + adminID, ce); } catch (NamingException ne) {
/* setRollbackOnly() not required because the EJBException is a system exception */
throw new EJBException("Unable to locate local reference to Admin:", ne); }
The following is a brief discussion of standard application exceptions for entity beans. We discuss this in the context of marking transaction for
CreateException
This exception is thrown by the container when using container-managed persistence, or this exception can be thrown by the bean developer in the
ejbCreate
or
ejbPostCreate
method. The transaction may or may not be
DuplicateKeyException
This exception is a subclass of
CreateException
. It is thrown by the
ejbCreate
method to
FinderException
This exception indicates an application-level error occurring in the find methods on the home interface of an entity bean. The bean provider throws this exception to flag an error in the
ejbFind
method; this exception is not used to indicate entity not found conditions; for entity not found conditions, the bean provider uses the
ObjectNotFoundException
, which is discussed
ObjectNotFoundException This exception indicates that the requested entity was not found by the ejbFind method. This exception can be thrown only by a finder method that returns a single object. Finder methods that return a collection object do not use this exception; such methods return an empty collection to indicate that no matching objects were found. The EJB container typically does not mark the transaction for rollback. The container or the bean provider does not mark the client's transaction for rollback when ObjectNotFoundException is encountered; it is left to the client to take corrective measures.
RemoveException
This exception is thrown by the container when using container-managed persistence, or this exception can be thrown by the bean developer in
ejbRemove
. The client receiving this exception does not