Skip to main content

Using the EJB composer feature in Rational Application Developer

Rakesh Midha, Software Engineer, IBM Software Labs, Bangalore
Rakesh Midha
Rakesh Midha is a staff software engineer with IBM Software Labs in Bangalore. He is currently working on Express Design and Architecture. He has 5+ years of technical experience in Java and C++ server-side programming on multiple platforms, and various relational database systems like DB2 UDB, Oracle, MySQL, and Microsoft SQLServer. He holds a Bachelor's degree in Electronics Engineering from the Punjab University in Chandigarh.

Summary:  Using the EJB composer feature in IBM Rational Application Developer, you can map a single complex EJB Container Managed Persistence (CMP) field to multiple Java database columns. With supporting examples, design, and code, this article proposes some scenarios that shows you how to use composers. Using the Rational Application Developer Create Composer wizard, you will create a composer and use it in your EJB-RDB mapping. This article will also discuss various classes involved in the process.

Date:  07 Feb 2006
Level:  Intermediate
Activity:  286 views

Introduction

When deploying enterprise beans with container managed persistence (CMP), non-primitive fields do not have a natural Java™Database Connectivity (JDBC™) mapping. The top-down mapping approach maps these CMP fields to binary types in the database, where they are stored as serialized data. For example, in DB2 Universal Database™ (DB2® UDB) they will be mapped to the varchar format for bit data. This puts a restriction on using these fields in Enterprise JavaBeans™ Query Language (EJB®-QL) queries. Also, they cannot be used as object fields directly in your reports.

To work around these restrictions, IBM provides a feature called EJB composers in IBM® Rational® Application Developer (IRAD). Using the EJB composers, you can map a single complex EJB CMP field to multiple relational database (RDB) columns. For example, if the CMP type is a Java object X with an int field and a string field, then you can map X to two RDB fields, INTEGER and VARCHAR, using a composer.

With supporting examples, design, and code, this article proposes a scenario that shows you how to use composers. Using the IRAD Create Composer wizard, you will create a composer and use it in your EJB-RDB mapping. This article will also discuss various classes involved in the process.


Scenario

This article will first describe a simple Customer-Address scenario to show the advantages of using multiple RDB fields. Figure 1 shows two enterprise beans, Customer and NewCustomer. Each of these EJB components uses the Java™ object ejbs.Address as its attribute.


Figure 1. Customer-Address scenario
Customer-Address scenario

Address is a simple Java object and stores address information like street, apartment, city, state, and zip code.

If you use the default top-down EJB-RDB schema mapping, the Address attribute will be mapped to Varchar(1000) for bit data. It means the Address object will be streamed as binary data to the varchar RDB column.


The requirement

Consider a situation where a company using the above scenario requires a report on all its customer addresses. This will not be a straightforward task, like selecting data from an RDB table using a SQL query. Instead, it will require parsing binary data by reverse engineering (that is, by creating a Java object from binary data and using it to split the attributes of the Address Java object).

Another way you could solve this is by redesigning the above scenario in such a way that Address is not a Java object, but instead is another CMP entity bean with a container-managed relationship (CMR) between Address and the Customer entity bean. This method will have disadvantages associated with a high number of unnecessary entity beans. In fact, the cost associated with entity beans will always be high, compared to non-frequent tasks, like reporting.

EJB-QL is another place where default mapping for the previous scenario will cause problems. If your application requires you to use a query on an entity bean, where the query needs to check the value of one of the attributes of the CMP field of the entity bean, it won’t be possible with default mapping. For example, again in the previous scenario, your application requires you to find all the customers who stay in or around a particular zip code. The first answer to this problem that comes to mind is to add the findByZip ejb query as shown in Listing 1.


Listing 1. Adding a query

<query>
        <description></description>
	<query-method>
	<method-name>findByZip</method-name>
	<method-params>
	</method-params>
	</query-method>
	<ejb-ql>select object(o) from Customer o where o.address.zip is null</ejb-ql>
</query>

This will not solve the problem in default mapping. This is because o.address.zip is not a valid EJB attribute, so it cannot be directly used in EJB queries in the select clause.


Composers

Here is where the composer feature comes into the picture; composers enable one CMP field to be mapped to multiple columns. The composer class is assigned to a CMP field and used to map the CMP field attributes to correct columns in the newly created table. In the Customer-Address scenario -- in order to map the Address attribute of the EJB component Customer to multiple columns in a table -- you need to create a new compose class that defines which fields in the composed type class map to which columns in the database.

Creating a custom composer

IRAD provides a Create Composer or Converter wizard to help you create a composer. This wizard helps you to create a definition of your composer, but a few additional manual steps are required to define composer mapping.

Using the wizard

  1. Open the Java™2 Platform, Enterprise Edition (J2EE™) perspective: select Window -> Open perspective -> Other, then select J2EE and click OK.
  2. Select File -> New -> Other, which will open the New wizard window, shown in Figure 2.

Figure 2. The New wizard window
The New wizard window
  1. In the New wizard window, select EJB -> Converter or Composer, then click Next.
  2. Your next view will be the New EJB Converter or Composer wizard. Select the Composer option button as shown in Figure 3.

Figure 3. New EJB Composer or Converter wizard
New EJB Composer or Converter wizard
  1. Select an EJB project.
  2. Type a fully-qualified composer name. It is always recommended to give your composer a name that suits its usage. This should be the name of the class for the instance instantiated as a result of the objectFrom in stub class, which is discussed in the Manual code change section. For example, in your scenario you are going to use this composer to map the Address class, so name it AddressComposer.
  3. Select a fully qualified supertype, which is the composer from which a newly created composer is inherited. In IRAD it could be:
    1. com.ibm.vap.composers.Namecomposer
    2. com.ibm.vap.composers.VapUSPhoneNumberComposer
    3. com.ibm.vap.composers.VapAttributeComposer

    Select VapAttributeComposer in this scenario.

  4. Type or select a fully qualified target type. This is the class, which has to be mapped using the newly created composer.
  5. Add the New composed field type. Composer fields represent the actual mapping of object attributes. You must add all the required composed field types, which is to say one composer field for each column in the RDB column to be used. The new composer field type can be added by typing or selecting New Composer field type and clicking the Add button.
  6. After adding the New composed field type, it is recommended that you rename it to an appropriate name. In your scenario, you added the following composed field types:
    1. java.lang.String -- street
    2. java.lang.String -- apt
    3. java.lang.String -- city
    4. java.lang.String -- state
    5. java.lang.Integer -- zip
  7. If required, you can remove an added composed field type by selecting it and clicking the Remove selected field button
  8. Optional: Select the Generate a composer stub class checkbox to generate a new composer class template for the new composer definition. The composer stub class is discussed in detail in the Manual code change section.
  9. Click Finish. If you selected Generate a composer stub class in Step 12, you should see a composer class generated in the proper package. When you open the Mapping editor, the composer name that you defined appears in the Outline view.

Manual code change

The next step is to create a composer stub class, or complete the composer stub class generated by the Create Composer wizard. This class is responsible for mapping attributes to the desired RDB columns. If the Generate a composer stub class checkbox was selected in Step 12 of the Using the wizard section, the AddressComposer class shown in Listing 2 is automatically generated.


Listing 2. AddressComposer class

package composers;
/** ..  */
public class AddressComposer extends com.ibm.vap.composers.VapAttributeComposer {
	static AddressComposer singleton = null;
	public static String getTargetClassName() {
		return "ejbs.Address";
	}
	public Object[] dataFrom(Object anObject) {
		// Default shown is for a Name composer with title, first name, and last name.
		/*  Name name = (Name) anObject;
		 Object[] anArray = new Object[3];
		 if (anObject == null) {
		 Object[] anArray2 = { null, null, null };
		 return anArray2;
		 } else {
		 anArray[0] = name.getTitle();
		 anArray[1] = name.getFirstName();
		 anArray[2] = name.getLastName();
		 }
		 return anArray; */
	}
	public static String[] getAttributeNames() {
		String[] attributes = { "street", "apt", "city", "state", "zip" };
		return attributes;
	}
	public static String[] getSourceDatatype() {
		String[] types = { "java.lang.String", "java.lang.String",
				"java.lang.String", "java.lang.String", "java.lang.Integer" };
		return types;
	}
	public Object objectFrom(Object[] anArray) {
		// Default shown is for a Name composer with title, first name, and last name.
		/*  String first, last, title;
		 title = (String) anArray[0];
		 first = (String) anArray[1];
		 last = (String) anArray[2];
		 return new Name(title, first, last); */
	}
	public static void reset() {
		singleton = null;
	}
	public static AddressComposer singleton() {
		if (singleton == null)
			singleton = new AddressComposer();
		return singleton;
	}
}


If you look closely, you will see that the AddressComposer class is a singleton class, and it extends the class com.ibm.vap.composers.VapAttributeComposer as desired in Step 7 of the Using the wizard section. It also contains two methods -- dataFrom and objectFrom -- that have to be implemented manually.

public Object[] dataFrom(Object anObject)

The dataFrom method is responsible for object-to-object collection conversion, which is used while storing object-to-multiple datastore fields. This scenario required ejb.Address to be mapped to 5 columns of type String, String, String, String and Integer, so you implement the dataFrom() method, which takes Object as its parameter.

The first step is to typecast Object to a TargetClass like ejbs.Address:

  1. Create an Object array of the desired size (5 in this case)
  2. Now fill this object array with data from ejbs.Address Object

The dataFrom method will look like Listing 3.


Listing 3. The dataFrom method

public Object[] dataFrom(Object anObject) {
		 Address name = (Address) anObject;
		 Object[] anArray = new Object[5];
		 if (anObject == null) {
		 Object[] anArray2 = { null, null, null, null, null };
		 return anArray2;
		 } else {
		 anArray[0] = name.getStreet();
		 anArray[1] = name.getApt();
		 anArray[2] = name.getCity();
		 anArray[3] = name.getState();
		 anArray[4] = new Integer(name.getZip());		 
		 }
		 return anArray; 
	}

public Object objectFrom(Object[] anArray)

The objectFrom method is a mirror image of the dataFrom method, so it converts the data returned from the datastore to a target object. It takes the object array as an input and returns an object as a result. The implementation of this method in your scenario will look like Listing 4.


Listing 4. The dataFrom method


public Object objectFrom(Object[] anArray) {
		Address address=new Address();
		 address.setStreet((String) anArray[0]);
		 address.setApt((String) anArray[1]);
		 address.setCity((String) anArray[2]);
		 address.setState((String) anArray[3]);
		 address.setZip(((Integer)) anArray[4]).intValue());
		 return address;
	}



Using the custom EJB composer

Once you've created the EJB composer, it immediately becomes available in the Mapping editor. To use the EJB composer for mapping a field that has a mapping to a single column, follow the steps below:

  1. Open Map.mapxmi in Mapping editor.
  2. Delete any existing mapping for the desired cmp field.
  3. Open the Table editor for the table mapped for your entity bean. This scenario used NewCustomer EJB, so open its table (NewCustomer table) in the Table editor.
  4. Delete the column which was un-mapped in Step 1. To do so, go to the Columns tab, right-click the column name and select Delete.
  5. Add the desired columns by right-clicking and selecting Add. This scenario added the following columns in the NewCustomer table.
    1. ADDRESS_STREET : VARCHAR
    2. ADDRESS_APT : VARCHAR
    3. ADDRESS_CITY : VARCHAR
    4. ADDRESS_STATE : VARCHAR
    5. ADDRESS_ZIP : INTEGER
  6. Save and close the Table Editor.
  7. In the Mapping editor, select all of the newly added columns in the Table pane (and the cmp field in the Enterprise Bean pane), right-click and select Create Mapping. This scenario selected address in the Enterprise Beans pane and ADDRESS_STREET, ADDRESS_APT, ADDRESS_CITY, ADDRESS_STATE, and ADDRESS_ZIP in the table pane. This will open the EJB Composed Mapping window shown in Figure 4.

Figure 4. The EJB Composed Mapping window
The EJB Composed Mapping window
  1. In the EJB Composed Mapping window, select the required composer, which in this case is ejbs.AddressComposer.
  2. Map each attribute to a column by selecting the column corresponding to each attribute.
  3. Click Finish.
  4. Recreate the table and deploy the project by right-clicking EJBProject and selecting Deploy.

Now composer will automatically use the mapped table column with the appropriate composed attribute of the composed type.


Restrictions

  1. IRAD composer support requires that all fields mapped to database columns must have corresponding instance variables defined in the target class.
  2. The Java field names in the composed class must exactly match the attribute names in the getAttributes method of the composer class. If these field names do not match, the Tasks view displays a warning.
  3. After you create a composer, you can use it in other projects by copying the userDefinedComposer.xmi file, the composer class, and the composed type class to another EJB project.
  4. Nested composers are not supported by the Composer wizard. In other words, the wizard does not support composing fields that are already composed types.
  5. Composer maps do not support converters. If converters are required between two types, this must be handled in the dataFrom and ObjectFrom methods of the composer by creating an instance of the converter.

Conclusion

Rational Application Developer can be used to create and use the EJB composer, which maps a single complex EJB CMP field to multiple RDB columns. This concept can be quite useful for scenarios where you have EJB attributes that do not have a direct one-to-one database mapping.


Resources

Learn

Get products and technologies

Discuss

About the author

Rakesh Midha

Rakesh Midha is a staff software engineer with IBM Software Labs in Bangalore. He is currently working on Express Design and Architecture. He has 5+ years of technical experience in Java and C++ server-side programming on multiple platforms, and various relational database systems like DB2 UDB, Oracle, MySQL, and Microsoft SQLServer. He holds a Bachelor's degree in Electronics Engineering from the Punjab University in Chandigarh.

Comments (Undergoing maintenance)



Trademarks  |  My developerWorks terms and conditions

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Rational
ArticleID=102983
ArticleTitle=Using the EJB composer feature in Rational Application Developer
publish-date=02072006
author1-email=midharakesh@in.ibm.com
author1-email-cc=clarkega@us.ibm.com

My developerWorks community

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere).

My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Rate a product. Write a review.

Special offers