Skip to main content

skip to main content

developerWorks  >  Rational  >

Coarse-grained service pattern with SDOs and EJB Session Facades in Rational Application Developer (Part 1)

developerWorks
Document options

Document options requiring JavaScript are not displayed


Rate this page

Help us improve this content


Level: Introductory

Daniel Berg (danberg@us.ibm.com), Senior Software Engineer, IBM, Rational SOA tools
Narinder Makin (nmakin@us.ibm.com), Software Architect, IBM Rational SOA tools, IBM
Ritchie Schacher (schacher@us.ibm.com), Software Architect, IBM Rational SOA tools, IBM

15 Jun 2005
Updated 14 Nov 2005

This article is the first of a multi-part series that introduces a new feature in Rational Application Developer for WebSphere Software, which automates the generation of the Value Object and Session Facade patterns for EJB development. The generated code uses Service Data Objects (SDOs) as the Value Objects for data transfer, thus enabling coarse-grained services and the use of standards-based programming. The article gives you an overview of how to use the feature to generate code, and how to write a client application using the programming model.

Introduction

The Value Object and Session Facade patterns for EJB™ (Enterprise JavaBean™) development are well-known and widely used as a means to simplify or optimize programming with EJBs. This article is the first of a multi-part series that introduces a new feature in IBM® Rational® Application Developer (RAD) for IBM® WebSphere® Software, Version 6.0, which automates the generation of these patterns. Moreover, the generated code uses Service Data Objects (SDOs) as the Value Objects for data transfer, thus enabling coarse-grained services and the use of standards-based programming. This first article gives you an overview of how to use the feature to generate code, and how to write a client application using the programming model. More detailed and advanced usages will be presented in the subsequent parts of this series.



Back to top


Value Object pattern

Container-managed entity beans are shared server-side business objects that are transactional. For a remote client to directly manipulate these objects, remote interfaces would need to be exposed for the entity beans. The data is accessed by clients via remote calls, which means that obtaining the necessary persistent data can be resource-intensive given the network overhead. Therefore, it is typically not a good idea for a non server-side client to communicate directly with these business objects.

Since the EJB 2.0 specification, it is best practice to only access the entity beans locally through local interfaces. Local interfaces by definition are not remoteable. Therefore, in order to provide remote access to the persistent beans, remote clients should access the local entities by passing data through methods exposed on a session bean with a remote interface, thus encapsulating access to the entities. In order to pass persistent data between a remote client and the server side session bean, Value Objects must be defined for the underlying local CMP (Container Managed Persistence) entities. The Value Object (also known as a Transfer Object, Data Transfer Object (DTO), or Cargo bean) is a standard Java™ bean with fields for each persistent attribute of the CMP bean. Methods must exist to synchronize the data between the Value Object and CMP bean. In some implementations, these methods will exist on the CMP bean itself.

Benefits

One of the key benefits of using a Value Object is that non-server side clients can access persistent data without the network overhead that is observed when accessing the same data via a container managed entity bean. This means that a client can obtain and set each individual property without a remote invocation (RMI) call. With a remote CMP bean, every access to a persistent property by a remote client is done via RMI. This can be extremely expensive.

Existing technologies and limitations

As already indicated, a Value Object is any arbitrary Java bean. There is nothing inherently special about the bean itself. However, there are a couple of well-known technologies that create Value Objects: Data Access beans from IBM® WebSphere® Studio, and XDoclet annotation based value-objects (see Resources) from Source Forge. Both technologies generate very similar objects, so in this article we will focus on Data Access beans.

Example

From the shipped example, there is an EmployeeData access bean that was generated for the Employee CMP entity bean. Below is a snippet of the EmployeeData access bean file showing only the ssn field and accessors (since they are all the same generation pattern).

public class EmployeeData extends AbstractEntityData {
/**
* @generated
*/
private java.lang.Integer ssn;
/**
* @generated
*/
private boolean isssnDirty = false;

...

/**
* getIsssnDirty
* @generated
*/
public boolean getIsssnDirty() {
return this.isssnDirty;
}
/**
* getSsn
* @generated
*/
public java.lang.Integer getSsn() {
return this.ssn;
}
/**
* setSsn
* @generated
*/
public void setSsn(java.lang.Integer value) {
this.ssn = value;
this.isssnDirty = true;
this.isDirty = true;
}

...

/**
* Store
* @generated
*/
public interface Store extends AbstractEntityData.Store {
/**
* getSsn
* @generated
*/
public java.lang.Integer getSsn();
/**
* setSsn
* @generated
*/
public void setSsn(java.lang.Integer value);

...

}
/**
* EmployeeData
* @generated
*/
public EmployeeData() {
super();
}
/**
* EmployeeData
* @generated
*/
public EmployeeData(EmployeeData.Store initializer) {
super(initializer);
initialize(initializer);
}
/**
* initialize
* @generated
*/
protected void initialize(EmployeeData.Store initializer) {
this.ssn = initializer.getSsn();
this.dateOfBirth = initializer.getDateOfBirth();
this.firstName = initializer.getFirstName();
this.lastName = initializer.getLastName();
}
/**
* copyTo
* @generated
*/
public void copyTo(EmployeeData.Store target) {
if (!this.isDirty)
return;
if (this.isssnDirty)
target.setSsn(this.ssn);
if (this.isdateOfBirthDirty)
target.setDateOfBirth(this.dateOfBirth);
if (this.isfirstNameDirty)
target.setFirstName(this.firstName);
if (this.islastNameDirty)
target.setLastName(this.lastName);
}
}

Note that there is an inner interface named Store, which has the public getter and setter methods for each persistent property. This is used to initialize the EmployeeData bean as well as to copy the persistent property values to a particular target, as seen in the copyTo(...) method. In this case the Employee CMP bean implements the EmployeeData.Store interface. The following three methods are generated on the Employee CMP bean class to create a new EmployeeData access object, and to synchronize data to and from the access object and the entity bean itself.

/**
* getEmployeeData
*/
public ejbs.EmployeeData getEmployeeData() {
return new ejbs.EmployeeData(this);
}
/**
* setEmployeeData
*/
public void setEmployeeData(ejbs.EmployeeData data)
throws com.ibm.etools.ejb.client.runtime.FieldChangedException {
data.copyTo(this);
if (!data.getIsssnDirty()) {
if (this.getSsn() != null && data.getSsn() != null) {
if (!this.getSsn().equals(data.getSsn())) {
throw new com.ibm.etools.ejb.client.runtime.FieldChangedException();
}
} else if (!(this.getSsn() == null && data.getSsn() == null)) {
throw new com.ibm.etools.ejb.client.runtime.FieldChangedException();
}
}
if (!data.getIsdateOfBirthDirty()) {
if (this.getDateOfBirth() != null && data.getDateOfBirth() != null) {
if (!this.getDateOfBirth().equals(data.getDateOfBirth())) {
throw new com.ibm.etools.ejb.client.runtime.FieldChangedException();
}
} else if (!(this.getDateOfBirth() == null && data.getDateOfBirth() == null)) {
throw new com.ibm.etools.ejb.client.runtime.FieldChangedException();
}
}
if (!data.getIsfirstNameDirty()) {
if (this.getFirstName() != null && data.getFirstName() != null) {
if (!this.getFirstName().equals(data.getFirstName())) {
throw new com.ibm.etools.ejb.client.runtime.FieldChangedException();
}
} else if (!(this.getFirstName() == null && data.getFirstName() == null)) {
throw new com.ibm.etools.ejb.client.runtime.FieldChangedException();
}
}
if (!data.getIslastNameDirty()) {
if (this.getLastName() != null && data.getLastName() != null) {
if (!this.getLastName().equals(data.getLastName())) {
throw new com.ibm.etools.ejb.client.runtime.FieldChangedException();
}
} else if (!(this.getLastName() == null && data.getLastName() == null)) {
throw new com.ibm.etools.ejb.client.runtime.FieldChangedException();
}
}
}
/**
* syncEmployeeData
*/
public ejbs.EmployeeData syncEmployeeData(ejbs.EmployeeData data) {
data.copyTo(this);
return this.getEmployeeData();
}

Limitations and drawbacks

Even though the Value Object pattern itself is a good pattern, the current technologies do have a few limitations:

  • Using the Value Object requires that you modify the entity bean class include methods for obtaining and synchronizing the Value Object.
  • Most Value Object implementations only have persistent fields from the CMP entity, and they typically do not deal with persistent relationships (that is, CMR fields).
  • The Value Objects are derived from CMP bean instances. Therefore, if a Value Object is a projection of the entire entity bean (for example,containing only a subset of the persistent fields on the bean), all the attributes are still read into the entity bean itself on the server.



Back to top


Session Facade pattern

The Session Facade pattern in a nutshell provides an interface for clients to interact with business objects without needing a tight coupling to the actual implementation of the business objects. So the Session Facade provides coarse-grained services to clients that typically return Value Objects and accept Value Objects as arguments.

Benefits

The key benefit of the Session Facade pattern is the decoupling of the client and the underlying business objects. This allows the application designer the freedom to change the underlying business objects without changing the APIs (Application Programming Interface) presented to the client within the facade. The facade also provides coarse-grained services to clients in terms of Value Objects. Thus clients have access to persistent data in a disconnected fashion.

Existing technologies and limitations

WebSphere Studio does not currently generate a Session Facade, but it is easy enough to code a Session bean and add APIs for interacting with the container managed entities to manipulate persistent data via data access beans. XDoclet has an annotation named @ejb.remote-facade which is used to create a session bean for interacting with a single container managed entity. However, this does not follow the true Session Facade pattern, since it does not work with Value Objects. It basically generates lookup code for the entity bean.

Example

It is easy enough to create a Session Facade. The example with this article has a hand-coded EmployeeDataAccessFacade which uses the EmployeeData access bean for transferring data to and from the Employee container managed entity. The facade has create, read, update, and delete (CRUD) methods for interacting with EmployeeData access beans, as shown following.

private EmployeeLocalHome getEmployeeHome() {
if (employeeHome == null) {
try {
Context ctx = new InitialContext();
Object home = ctx.lookup("java:comp/env/ejb/Employee");
employeeHome = (EmployeeLocalHome) PortableRemoteObject.narrow(home,
EmployeeLocalHome.class);
} catch (ClassCastException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NamingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return employeeHome;
}

public EmployeeData[] getEmployees() {
Collection col = null;
try {
col = getEmployeeHome().findAll();
} catch (FinderException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (col == null)
return new EmployeeData[0];
EmployeeData[] data = new EmployeeData[col.size()];
Iterator it = col.iterator();
for (int i = 0; it.hasNext(); i++) {
EmployeeLocal employee = (EmployeeLocal) it.next();
data[i] = employee.getEmployeeData();
}
return data;
}

public EmployeeData getEmployeeByKey(Integer ssn) {
EmployeeLocal employee = null;
try {
employee = getEmployeeHome().findByPrimaryKey(ssn);
} catch (FinderException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (employee != null)
return employee.getEmployeeData();
return null;
}

public void createEmployee(EmployeeData data) {
EmployeeLocal employee = null;
try {
employee = getEmployeeHome().create(data.getSsn());
} catch (CreateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (employee != null)
employee.syncEmployeeData(data);
}

public void updateEmployee(EmployeeData data) {
EmployeeLocal employee = null;
try {
employee = getEmployeeHome().findByPrimaryKey(data.getSsn());
} catch (FinderException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (employee != null)
employee.syncEmployeeData(data);
}

public void deleteEmployee(EmployeeData data) {
EmployeeLocal employee = null;
try {
employee = getEmployeeHome().findByPrimaryKey(data.getSsn());
} catch (FinderException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (employee != null)
try {
employee.remove();
} catch (EJBException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (RemoveException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}

Limitations and Drawbacks

The current technology is correct but it has some drawbacks:

  • In order to get a Value Object, you must look up the container managed entity.
  • You must coordinate all reads and updates of the persistent data through the container managed entity.
  • Only one type of Value Object is operated upon within each service call.


Back to top


Using RAD to build Session Facades

New in RAD Version 6 is the capability to define and generate Session Facades and Value Objects for container managed entity beans using annotations on the bean class.

Benefits and differences

There are several key differences from the RAD Session Facade pattern and the pattern described above. These differences provide a distinct advantage over the current technologies.

Service Data Objects

The first noticeable difference is that the Session Facade deals with specialized Value Objects called Service Data Objects (SDOs). The Service Data Object specification is a joint specification developed by IBM and BEA to provide a more advanced Value Object pattern. The SDOs generated in RAD Version 6 are based on the open source implementation available at Eclipse. SDOs can have relationships to other SDOs, and these relationships are automatically maintained by the runtime. The SDOs are also part of a Data Graph that can record all changes made to all SDOs within the graph, so that the exact changes are known at the time of being persisted to a data store.

No impact to entity bean files

One very obvious difference with the RAD Session Facade is its use of SDO objects rather than typical Value Objects. In addition, the CMP entity bean files are not modified to return and synchronize persistent data to and from the SDO objects. In fact, the Session Facade generated within RAD Version 6 does not even use the entity beans. This article will provide more information on this topic in subsequent sections.

CMP entities are bypassed entirely

As already discussed in this article, the typical Session Facade pattern will look up a particular Home interface and call a finder method in order to return a collection of entity instances. This collection can then be iterated such that a Value Object is obtained for each entity bean instance. The implementation of the RAD Session Facade does not look up any Home interface, and thus does not find any CMP entity instances. The SDO instances are populated by an object called an EJB mediator. The EJB mediator is responsible for reading data from the database using a modified EJB QL syntax, and for processing changes to a DataGraph that result in updates to the database. It should be noted that the RAD Session Facade pattern using the EJB mediator does not read CMP data from a persistent cache at runtime. The data is read directly from the database. You can find more information regarding caching and the use of CMP entities in the Application considerations section.

Multiple SDOs per facade

The tooling support for defining a Session Facade in RAD Version 6 allows you to add a particular SDO object to the facade to be managed. In current technologies that support the generation of the Session Facade, there is typically one Session Facade per entity bean. In RAD Version 6, you have the capability to add multiple SDO objects from one CMP entity to a particular Session Facade, as well as add SDOs from other CMP entity beans to the same Session Facade. This way Session Facades can be defined to best fit the application.

SDO query support

In RAD Version 6 there is also support to define queries in terms of the SDOs that you wish to manage by a Session Facade. You can write these queries using annotations on a CMP entity bean class, and simplify the syntax of the query so it is not necessary to define the shape (that is, select the fields), since this information is already known based on the selected SDO object. You can write them to query upon the properties of the selected SDO or any of its related SDO objects. More details about SDO-based queries will be provided in part two of this series.

User modification to generated code

In the RAD Version 6 EJB Session Facade over SDOs pattern, you can modify the generated code, and your code will be preserved and merged on subsequent generations. Earlier solutions, such as access beans, did not have such a mechanism. This will be discussed further in a future part of this series.

When to use

Now that we've described the benefits of using the RAD Version 6 based Session Facade over SDO pattern, let's discuss when you would want to consider using this in your EJB and J2EE™ (Java 2 Platform, Enterprise Edition) applications.

When you need disconnected data access

If you are using the data from your entity beans from a remote client -- such as a J2EE application client, or from a web page in a web application used to display the data -- you will want a mechanism to iterate over a collection of objects without invoking a remote call for each object. This pattern will enable such data access. With improved technology, however, you now have this access using SDOs as the data transfer objects. As mentioned above, this enables many things:

  • The introduction of relationships to a graph of transferred objects
  • Inverse maintenance and referential integrity of the related objects
  • Automatic serialization
  • Meta-model capabilities for reflecting and setting values for attributes and relationships on the SDOs

When you need coarse grained updates

Introducing relationships to the pattern -- as well as the robust support for associations in the SDO specification, and the Eclipse Modeling Framework (EMF)-based implementation of SDOs -- enables some very interesting applications that require coarse grained services. For example, you can read a collection of CMP-based SDOs, along with their related objects, as part of a single database query. Those familiar with the preload support of WebSphere Application Server will appreciate that the preload is an alternate, existing method for optimizing reads of a collection of related objects. The RAD-based Session Facade, however, takes this one step further: by using SDOs and a datagraph, you can transfer the graph of resulting SDOs in a single remote call. Moreover, you can make updates to the graph, including changing the values of the objects, adding new objects, and removing existing objects, in a disconnected manner. Furthermore, you can commit the changes to the graph as a single transaction with a single remote call, thus resulting in single transfer of the entire modified graph.

When you need projections and selections of the underlying entity data

By design, when you read a CMP entity bean into the EJB container, all the fields of the entity bean are populated. However, there are many times when you will only be working with a small subset, or projection, of the fields. For example, suppose you are generating a report that displays a list of employees by firstName and lastName, but you do not need the employees ssn or salary fields. This pattern will allow you to create lightweight SDOs (with only those fields in which you are interested) for a given application. Moreover, in contrast to earlier implementations, this Session Facade will not read all the CMP fields from the database, but rather only the fields contributed to the SDOs. As you will see later, this is because the underlying implementation performs direct reads to the data source and bypasses container managed persistence, thus optimizing the performance of the coarse grained updates described above.

In other cases you may wish to create deep SDOs, which bring in some of the CMR fields of a collection of entities, as well as the CMP fields. You can use this facility to model these SDOs to perform the reads and updates to the data in an optimal manner.

Additionally, there are scenarios where -- in the process of performing a coarse grained transaction, as described previously -- you will want to filter the returned data based on a complex set of search criteria (or in simple parlance, with a lot of where clauses). As you will see later, this facility provides the ability to create complex queries which can go n levels deep into a set of related CMP-based SDOs, adding where clauses at any level of the graph of objects. These queries will be executed at runtime in an optimal manner, thus facilitating the coarse grained updates pattern.

Sample Application

Scenario

Let's create an application scenario for a Company to illustrate the steps involved in using this feature. The following class diagram depicts the entities and their relationships that are used in the application. This class diagram is created using the visual editor in RAD, as shown in Figure 1.

Class diagram
Figure 1: Class diagram

Project Interchange
The examples are prepared for you in a project interchange ZIP file. To add the examples, import the project interchange Company_PI.zip into your workspace. As a result, the following projects (seen in Figure 2, following) are imported into the workspace:

  • CompanyEAR -- This is the Enterprise Application project that contains references to all the JAR and module projects to compose a J2EE EAR file.
  • CompanyEJB -- This is the EJB module that contains the related CMP EJBs. The classdiagram.dnx describes the EJBs present in the project and their relationships.
  • CompanyEJBClient -- This is the EJB client JAR project, that contains all the client interfaces for Company EJB and any required classes. Company EJB depends on CompanyEJBClient; any client application (for instance, a Web application or J2EE Application Client) would also depend on CompanyEJBClient.

Imported example projects
Figure 2: Imported example projects

Note that the sample contains the hand-coded facade, as described in previous sections. It does not contain the generated facade or the application client, which you will create using the steps in the following sections. For reference, a completed solution is contained in the project interchange file Company_SolutionPI.zip.

Using the wizard

The Session Facade for any CMP2.x entity bean can be created using a wizard, which you can open by using an action on the entity bean. This action is available from the entity bean in the Project Explorer, and also on the visualized entity bean in the visual editor, as illustrated in Figure 3.

Create Session Bean Facade action on visualized entity bean
Figure 3: Create Session Bean Facade action on visualized entity bean

Let's create a Session Facade on the Employee entity bean as EmployeeFacade using the Create Session Bean Facade action, as shown in Figure 4. The name of the facade in the wizard page is based on the selected entity bean (the default is EmployeeFacade). The folder for the generated output is preset to gen/src folder, where all the generated content resides. The name of the package for the Session Facade is derived from the package name of the entity bean. All the entity beans present in the module are listed here. You may select any CMP 2.x entity bean other than the Employee to create the facade on.

Create Session Bean Facade wizard
Figure 4: Create Session Bean Facade wizard

Generated output

When the wizard finishes, annotations are injected in the entity bean Java files. These annotations define the model for the generation of the target Session Facade and the static SDO java classes. The meta-model for the tag-sets for the Session Facade annotations consists of the ws.sbf and ws.sdo namespaces. More information on these tags-sets can be found in the product documentation. From the menu bar, select Help -> Help Contents, and navigate through the table of contents as shown in Figure 5 below.

Annotation tag reference help
Figure 5: Annotation tag reference help

When a facade is created in a project, that action adds a framework utility (sbf-runtime.jar) to the EAR projects that contain the EJB module, and to the Java JAR dependencies of the EJB client JAR project. The contents of this JAR will be required by the generated facade that results.

As in the example, value-object and session-facade annotation contributions are made to the Employee entity bean Java file. The value-object annotation tag is defined as @ws.sdo.value-object for an Employee bean class. The SDO name defaults to Employee, which is derived from the name of the bean. The value of the read-only attribute signifies whether the operations defined on the Employee value-object are for read-only purposes:

 * @ws.sdo.value-object
* name="Employee"
* read-only="false"

The session-facade annotation for the EmployeeFacade is defined using a @ws.sbf.session-facade tag. The name attribute of the tag defines the name of the session bean. The value-objects attribute defines the list of value-objects that are added to, and thus managed by, the Session Facade:

* @ws.sbf.session-facade
* name="EmployeeFacade"
* value-objects="Employee"

Figure 6 depicts how, if the project in which this Session Facade is created does not have annotation support enabled, the Session Facade creation action also enables the annotation support on the EJB project by adding an annotation builder and a data object builder to the project.

Figure 6: Annotation support for EJB project
Figure 6: Annotation support for EJB project

Once the project is built -- either when you Save if auto-build is turned on, or when you invoke an explicit build for the project -- the above annotations are processed. For each of the @ws.sdo.value-object annotations, a static SDO Java class is created that contains all the attributes that are added to the defined value-object, along with get/set methods. These generated SDO classes implement the DataObject interface as pure SDO classes. As in this example, the ejbs.sdo.Employee Java class is created in the client EJB project.

Additionally, for each of the session-facade annotations, a session bean is created with the bean name as the value of the name attribute of the tag. Lastly, a root SDO Java class is created for each of the value-object values that is added to the Session Facade tags value-objects attribute. For example (as shown in Figure 7), the SDO ejbs.sdo.EmployeeRoot is created, corresponding to the Employee top-level SDO that was contributed to the facade. This root class acts as a container for all of the other SDO objects that are created at runtime, and is used at runtime for creating a data mediator for persistence.

Best of all, as you will see in a later article, you are not limited to the generated code. A mechanism exists where you can add user code to the generated output.

Figure 7: SDO package
Figure 7: SDO package

The EmployeeFacade session bean contains the CRUD APIs to manage the instances of the Employee SDO, which has been added to the facade using the value-objects attribute. The methods it creates (shown in Figure 8) are getAllEmployeeObjects, getEmployeeByKey, createEmployee, updateEmployee, and deleteEmployee . Advanced APIs, such as getEmployeeRoot and applyEmployeeRootChanges, are also created that provide more control to manage the Employee SDO in the client code for the facade. The generated code in these APIs access the database via the EJB mediator using the EJB-QL syntaxed queries.

Figure 8:  Session Facade Bean
Figure 8: Session Facade Bean

The session bean Java class that is created with all the CRUD methods is also annotated with the XDoclet style @ejb annotation tagset. Once these annotations are processed, the session bean is added to the EJB deployment descriptor.

 /** 
* @ejb.bean
* name="EmployeeFacade"
* view-type="both"
* type="Stateless"
* transaction-type="Container"
*<!-- begin-user-doc -->
*<!-- end-user-doc -->
* This is a system generated session bean facade source file.
* Any modifications to the tags should be done in the
* primary source Entity Bean file for this facade.
* @see EmployeeBean
* @generated
*/
public class EmployeeFacadeBean implements SessionBean {

Figure 9 illustrates that the remote and home interfaces are also created for the session bean, and they contain all the methods that have been promoted to the interface using the @ejb.interface tags.

	/**
* Return an array of "Employee" value-objects from the database.
* @ejb.interface-method
* view-type="both"
* @generated
*/
public Employee[] getAllEmployeeObjects() throws FindException {

Figure 9: Session bean addition
Figure 9: Session bean addition



Back to top


An example client application

Now that you've seen how to create a Session Bean Facade, we're going to show you in the following sections how to build a client application and use the client programming model to use the facade. We will build a J2EE application client and create a main class, and then use the facade to read an employee, modify some values, and update the object.

Creating the client example

The first thing we will do is create an application client project. From the CompanyEAR project, in the project explorer, select New - > Application Client Project, as shown in Figure 10.

 The New Application Client action
Figure 10: The New -> Application Client action

Name the project CompanyAppClient. Click the Show Advanced button, and verify that the settings are like those in Figure 11.

Figure 11: Application Client project settings
Figure 11: Application Client project settings

Next, select a dependency from the app client module to CompanyEJBClient.jar. Then press Finish. Locate the file Main.java -- in the default package, it's in the appClientModule folder in the new project -- and double-click it to open the Java editor.

Using the client factory

Next we will add methods to the Main class to create and initialize a new Employee.

Notice that as part of the code generation process, a convenience factory was generated for creating new root SDOs. This factory is part of the SDO packages generated in the gen/src folder of the EJB client project. As described previously, there is one root SDO generated for each top-level SDO associated with the Session Facade, using the value-objects attribute in the @ws.sbf.session-facade annotation. And for each root SDO, there is one create method generated on the client factory, as shown in Figure 12.

Figure 12: The client factory interface
Figure 12: The client factory interface

Why is this necessary? The reason is that -- as part of RMI serialization of SDOs -- the SDOs must be contained within a DataGraph. The DataGraph contains all the necessary code to serialize and deserialize the objects contained within. In fact, one of the things you'll want to be aware of as you code with SDOs is that, if you transfer one SDO, you're actually transferring all the SDOs contained in the same DataGraph. For example, if you obtain an array of Employee SDOs using the generated facade, and you update each employee, you only need to apply changes once to apply changes for all the Employees. We'll discuss this more in future articles.

Given the above background, you would need to write at least a few lines of code for the following actions:

  • Creating a new data graph
  • Creating a new root object
  • Creating a new employee object
  • Adding the root to the datagraph
  • Adding the employee object to the root

Fortunately, the tools have made this much easier with the generation of the client factory and the APIs on the containing SDOs themselves (for example, roots).

You can copy the code below and paste it into the editor. Then press Ctrl+Shift+O to add the necessary import statements.

	private Employee createNewEmployeeWithGraph() {
//Obtain the single instance of the client factory
SdoClientFactory factory = SdoClientFactory.INSTANCE;
//Create the root SDO used for transport. It will be associated with
//a datagraph
EmployeeRoot root = factory.createNewEmptyEmployeeRoot();
//Use the generated API on the root to create a new employee. It will automatically
//add the new object to the parent, "EmployeeRoot"
return root.createEmployee();
}

private void setValues(Employee employee) {
employee.setFirstName("Ritchie");
employee.setLastName("Schacher");
employee.setSsn(new Integer(123456789));
employee.setDateOfBirth(new Date(2000, 0, 1));
}

As you can see from the comments in the code, the generated APIs hide some of the details, and allow a cleaner programming model for creating new SDOs and adding them to their containing SDOs. Thus after execution of this code the new Employee SDO is ready for transfer.

Referencing the facade EJB

Now let's add code to lookup the facade EJB so we can use it to program with SDOs.

Add the following instance variable and method to your Main class:

private EmployeeFacadeRemote facade;
private EmployeeFacadeRemote getFacade() {

}

Next, place the cursor in the method body, and use the EJB snippets support to create the EmployeeFacade bean, as shown in Figure 13.

Figure 13: EJB create action in Snippets View
Figure 13: EJB create action in Snippets View

From the snippets wizard, you will need to add a new reference to the bean.

Add a return statement and lazy initialization to the method body so that it now looks like the following:

	private EmployeeFacadeRemote getFacade() {
if (facade == null)
facade = createEmployeeFacadeRemote();
return facade;
}

Using the facade interface

Next, we will use the methods above to create a new Employee, insert it using the facade, find the employee, modify its values, and finally use the facade to update the changes to the persistence data store.

For starters, let's hook the pieces together, to insert a new Employee into the database. Copy the code below to your main class:

	private void testNewEmployeeCreation() throws Exception {
EmployeeFacadeRemote facade = getFacade();
Employee employee = createNewEmployeeWithGraph();
setValues(employee);
facade.createEmployee(employee);
System.out.println("Employee creation successful. This was easy!!");
}

As you can see, the above method will obtain a facade instance, create a new employee, set the values on the employee, and use the facade to insert the SDO. Now let's add a method below to find an Employee, change its values, and update it:

	private void testEmployeeUpdate() throws Exception {
EmployeeFacadeRemote facade = getFacade();
Employee employee = facade.getEmployeeByKey(new Integer(123456789));
if (employee == null) {
System.out.println("Employee not found :-(");
return;
}
System.out.println("Employee found. Name = "+employee.getFirstName()+"
"+employee.getLastName());
employee.setFirstName("Ritchard");
facade.updateEmployee(employee);
System.out.println("Employee has been updated.");
}

Finally, let's tie it all together in the main method of the main class, so it can be tested:

	public static void main(String[] args) {
Main tester = new Main();
try {
tester.testNewEmployeeCreation();
tester.testEmployeeUpdate();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

And now you're ready. The client you just developed uses the generated facade to create an instance of the Employee using SDOs, and also finds and updates that instance. It is left as an exercise for you to run this on the WebSphere Application Server version 6.0.



Back to top


Application considerations

At this point in the article a brief introduction to the RAD session facade pattern has been described, and this pattern appears similar to the J2EE core Session Facade pattern; however, it does have some subtle differences. When developing an application using the RAD Session Facade, you need to be aware how the facade may impact the output.

EJB mediator

The SDO specification talks about data mediator services (DMS). A DMS is responsible for constructing the SDOs and the DataGraph for which the SDOs are contained. It constructs the SDOs from data that is obtained from a specific target, such as a database. The SDO specification does not force any particular APIs on a DMS, because how a DMS obtains its data can be very different across different DMS implementations. For example, you may have a DMS that acquires data from a database using SQL statements, or you may have a DMS that retrieves data from a Web Service which takes SOAP calls.

The RAD Session Facade retrieves and updates its SDOs via an EJB mediator DMS, included in WebSphere Application Server Version 6. The EJB mediator uses EJB QL query statements (based on an extended syntax), and the mapping information from the CMP entity beans to a back-end database, to dynamically generate SQL statements to execute against the database. The RAD Session Facade will generate these EJB QL queries for the EJB mediator based on the shape of managed SDOs. Since the EJB mediator is using EJB QL queries, it experiences the same limitations that would be seen generating an EJB QL finder for a CMP bean -- the biggest limitation being that using EJB relationship roles in the key shape of the CMP entity may not work.

Another important difference with the RAD Session Facade pattern is the fact that the CMP persistent cache is not used when populating the SDO instances with data. This means that the data is obtained from the database each time, and that updates are made directly to the database (the persistent data cache is not updated). As a user using this pattern you should be aware of the consequences of this design pattern. This means that if you attempt to access data via both a CMP entity and an SDO from the CMP entity directly, there is a chance you will not get the same data. More information for dealing with this situation can be found in the Coexistence with CMP persistence and caching section. Even though the Session Facade pattern described here does not have the benefit of using the persistent cache it does make up for it in performance increases for reading and updating an entire data tree of related SDOs, as well as the ease of querying over a collection of related SDOs (more information regarding the query benefit will be discussed in Part 2 of this series).

Can I delete the CMP entities now?

The simple answer to this question is no. The reason you cannot delete the CMP entity beans was touched upon in the paragraph above. The CMP entity beans cannot be deleted since the EJB mediator will read the CMP mapping information at runtime to dynamically generate the necessary SQL for a given EJB QL query. Without the CMP entity beans and the mapping information, the EJB mediator will fail to operate.

It may seem odd then to keep the CMP entity beans, since the RAD Session Facade does not access them. Keep in mind that the CMP entity beans represent your persistent object model, and the SDOs defined for them are just projections and selections upon this data. Granted an SDO can contain all of the persistent data for a CMP entity bean but it does not have to. It is also not a requirement to expose all persistent data with an SDO. For example you may have a private CMP entity bean with only a local client view that is accessed and updated via a session bean. It is possible that the RAD Session Facade is updated to interact with these private CMP entity beans using data from an SDO data graph. Even if a CMP entity does have an SDO defined, it wouldn't necessarily make sense to obtain the SDO when code is added to the RAD session facade to operate directly with the data of the CMP entity bean. For example, you may decide to add logic in your Session Facade to perform a complicated computation on a CMP entity, and have it persist the result due to some values retrieved in an SDO data graph. In this case it would be better to access the CMP entity bean directly.

Coexistence with CMP persistence and caching

You need to take care when dealing with SDOs and the CMP entity beans from which they are defined. The problem is that the SDO contains disconnected data and the CMP entity bean contains shared, cached, container managed persistent data. So, if you have an SDO that contains modified data and you attempt to use the corresponding CMP entity bean, the values may not be the same. This is especially true when dealing with the SDO and CMP entity bean within the same transaction (in other words, within the same Session Facade method). There are basically two ways to ensure that data does not become stale or invalid.

  1. Don't mix persistent access within the same transaction: for example, within a transaction (that is, within the same Session Facade method), if you use SDOs to update persistent data from a CMP, do not use the CMP itself to update the data.
  2. Update the length of time the CMP entity bean is cached for mixed access across transactions: for example, if you are updating data using SDOs over DMS within one transaction and updating CMPs directly in another, then you can change the Bean Cache setting to load at the TRANSACTION. Thus the CMP entity will be reloaded between transactions, and will maintain the data integrity. This setting is updated in the EJB Deployment Descriptor on the beans page for the specific CMP entity bean, as shown in Figure 14 below.

Figure 14: Setting the Bean Cache to load at TRANSACTION
Figure 14: Setting the Bean Cache to load at TRANSACTION



Back to top


What's next?

In Part 2 of this series, we're going to explore in more detail the complex structures that can be created using this new feature. Specifically, you will learn how to:

  • Create lightweight SDOs that represent a subset of CMP entity data
  • Create deep SDOs that contain associations which correspond to CMR relationships between entities
  • Make incremental changes to existing defined SDOs and session facades
  • Combine the contributions from multiple entity beans to a single Session Facade
  • Add user-defined queries, in terms of the SDOs, to the Session Facade

So please read on, come back, and give us your feedback.



Back to top


Conclusion

Having read this article, you should now be familiar with the concepts of the Value Object and Session Facade design patterns for EJB development, and the tools for generating this pattern using Rational Application Developer for WebSphere version 6.0. You've seen how to use these tools to generate the pattern, and how to build a client application using the pattern. You've seen how the pattern incorporates Service Data Objects (SDOs) for data transfer, change tracking, and persistence. You should have basic familiarity with when and how to use the Session Facade.

In future articles we will explore more advanced topics and usage patterns for this new feature, and finally, we will create an example end-to-end application that builds on all the advanced features.



Back to top


Resources



About the authors

Daniel Berg is a software engineer at IBM Research Triangle Park Lab in Durham, North Carolina. He is a lead architect for J2EE and SOA/SDO tools for the Rational Application Developer team.


Narinder Makin is a software engineer at IBM Research Triangle Park Lab in Durham, North Carolina. He is an architect of J2EE and SOA/SDO tools for the Rational Application Developer team.


Ritchie Schacher is a software engineer at IBM Research Triangle Park Lab in Durham, North Carolina.. He is an architect of J2EE and SOA/SDO tools for the Rational Application Developer team.




Rate this page


Please take a moment to complete this form to help us better serve you.



 


 


Not
useful
Extremely
useful
 


Share this....

digg Digg this story del.icio.us del.icio.us Slashdot Slashdot it!



Back to top