Databases, CMPs, and Maps





Databases, CMPs, and Maps

Now that you've discovered what the basic object model of our case study looks like, you're ready to look at how that object model relates to the objects in a relational database. Before we begin, however, we need to review some basic relational technology terminology.

In a relational database, data is stored in tables as rows and columns. A table is a single entity that represents a particular record layout. You define a table by stating the names, data types, and (optionally) sizes of the columns that comprise the table. The database has groupings of schematas which are used to provide qualification to the table names. For example, a table named TEST.FOO has TEST as the schema name. Each schema has a set of tables that are defined as members of that particular schema. A table can belong to only one schema and each schema belongs to one database. So a database is the root object that contains a complete set of schematas and their associated tables.

In short, what we need to do is define how our objects (container-managed entity beans) map to a set of database tables. Thus we have to define a mapping between our container-managed entities within the EJB JAR and the tables within a database. To do this, you need to be able to view, and perhaps manipulate, both sides of the coin—the database tables and the object model.

WSAD contains a set of tools that allow you to do precisely this. In WSAD, you can define a database mapping to an EJB module in one of three ways:

  • A "top-down" mapping will automatically create a new database and tables from a set of container-managed entity beans by following some simple mapping rules.

  • A "bottom-up" mapping will create a new set of container-managed entity beans to a matching set of database tables.

  • A "meet-in-the-middle" mapping allows you to create a set of container-managed entity beans and database tables separately and then define the mapping between the two using some simple name and type matching rules.

1 Top-Down Mapping Example

To demonstrate a top-down mapping, we will use the TimeSheetGroup EJB module from the case study. To begin, launch the EJB to RDB mapping wizard by selecting the TimeSheetGroup EJB module from the J2EE Hierarchy view within the J2EE Perspective and select Generate > EJB to RDB Mapping from the context menu (Figure) opened by right-clicking.

2. EJB to RDB Mapping Action.

graphics/24fig02.jpg

The first page of the EJB to RDB mapping wizard (Figure) requires you to either create a new back-end folder or use an existing back-end folder. In WSAD 5.0, there is support for multiple EJB to RDB mappings for the same set of container-managed entities within a 2.0 EJB module. The metadata files associated with the database and its tables are all stored in subfolders of the folder named Backend.

3. Select back-end folder wizard page.

graphics/24fig03.jpg

Each subfolder is an existing back-end folder that is displayed in the wizard. Later in this chapter we will discuss multiple back-end support in WSAD. In our example, no database or mapping exists for our EJB module, so only the create a new back-end folder option is available at this time.

The second page of the mapping wizard (Figure) provides options for each of the three mapping approaches: bottom-up, top-down, meet-in-the-middle. For our top–down mapping example, we will keep the default Top Down selection. This option will create a database and schema, and tables for each container-managed entity bean within our EJB module. The tables will be named with the same name as that of the container-managed entity and each column will be named based on the corresponding cmp-field within the container-managed entity.

4. Select mapping option page.

graphics/24fig04.jpg

Any cmp-fields that have been added to the key of the container-managed entity will have its associated column added to the primary key of the new table. A mapping will be defined for each of the container-managed entity beans to the table that was created on its behalf.

Click the Next button to move the top-down mapping options page shown in Figure. The first and most important option is Target Database. Figure shows the databases currently supported by WSAD 5.0. We will be using DB2 8.1 for our example. Database name will be the name of the target database. The Schema name is the name of the schema that you want all new tables to be a member of. This schema name will be used as the qualifier for the generated SQL. So, a table named EMPLOYEE that had the schema name set to TEST would appear in the generated SQL as fully qualified, (i.e., TEST.EMPLOYEE). If you want to control the qualification of the queries based upon a login ID (this is the common case with DB2 that the default schema name used within a query will be the user's login name if one is not supplied) you should enter NULLID for the Schema name. This name is treated special by the SQL generator so it will not add the schema qualification to the tables within the SQL queries. Therefore if the query being executed is being done using a DB user ID of "bob," then the fully qualified table name would become "bob.EMPLOYEE."

5. Top-down mapping options.

graphics/24fig05.jpg

The Generate DDL option will create a table.ddl file for the newly generated database which can be used to export the contents to the actual database. The WebSphere 3.x Compatible option should only be used if you plan to target a 3.x version of WebSphere. This option will adjust the type mappings so that they will be compatible for this version of WebSphere.

Now that all of the top-down mapping options have been set, the last thing to do is to click the Finish button. This will automatically generate a top-down mapping based on the selected options and the rules for top-down mapping that were described earlier. The mappings will be stored in the META-INF/backends/DB2UDBNT_V81_1/Map.mapxmi file. Figure is the resulting overview from the map editor which shows the new tables and their associated mappings to container-managed entities.

6. Top-down mapping results.

graphics/24fig06.jpg

Supported WSAD 5.0 databases.

Cloudscape, V5.0

DB2 Universal Database V6.1

DB2 Universal Database V7.1

DB2 Universal Database V7.2

DB2 Universal Database V8.1

DB2 Universal Database for OS/390, V6

DB2 Universal Database for OS/390, V7

DB2 Universal Database for iSeries, V4R5

DB2 Universal Database for iSeries, V5R1

Informix Dynamic Server, V7.3

Informix Dynamic Server, V9.3

Informix Dynamic Server.2000, V9.2

Microsoft SQL Server 2000

Microsoft SQL Server, V7.0

Oracle8i, V8.1.7

Oracle9i

SQL-92

SQL-99

Sybase Adaptive Server Enterprise, V11.9.2

Sybase Adaptive Server Enterprise, V12

Sybase Adaptive Server Enterprise, V12.5

2 Bottom-Up Mapping Example

A bottom-up mapping is used when there is a new EJB project without any EJBs defined within it and you have a set of database tables that you would like to access with container-managed entity beans. In this case, WSAD creates a container-managed entity bean for each table within the database for the back end selected on the previous page. Also, WSAD adds a cmp-field to the key of the newly created container-managed entity for each column within the primary key of the table.

For this example, we will be using the DEPARTMENT table shown in the DDL in Listing 24.1. If you wish to follow along with this example, you will need to execute the following DDL against your database (i.e., DB2). Refer to your database documentation for instructions to execute the DDL.

EMPLOYEE DDL

CREATE TABLE BOTTOMUP.EMPLOYEE

  (EMP_NO INTEGER NOT NULL,

   FIRSTNME VARCHAR(50),

   MIDINIT CHARACTER(1),

   LASTNME VARCHAR(50),

   PHONE VARCHAR(25),

   HIREDATE DATE);



ALTER TABLE BOTTOMUP.EMPLOYEE

  ADD CONSTRAINT EMPLOYEE_PK PRIMARY KEY (EMP_NO);

Start by creating an EJB project named BottomUpExample and set the enterprise application to a new application named BottomUpExampleEAR. Refer to Chapter 20 for instructions on creating an EJB project. Now follow the steps from the top-down example to open the EJB to RDB mapping wizard on the new BottomUpExample EJB module. Select the new back-end folder option as in the top-down mapping example. Click Next to go to the mapping options page shown in Figure and this time only the Bottom Up option is available and it is selected.

Click Next to continue to a page that is dynamic based upon whether you already have a logical database defined within your EJB project. In this example, the logical database does not exist. This means it is not necessary to already have a logical database defined within the EJB project in order to use the Bottom Up option. So, you can immediately use this wizard to create container-managed entity beans based upon an existing set of database tables with just the EJB project created.

The next bottom-up mapping page, assuming no existing database within the EJB project, allows you to specify information to create a database connection as shown in Figure. This is required because bottom-up mapping requires that logical database to exist within the EJB project. We will not go into details for every field on the connection page. If you need help, refer to the online documentation or the help for this page by clicking on F1.

7. Database connection wizard page.

graphics/24fig07.jpg

One other thing on this page that should be pointed out is the last option, Use existing connection. When this is selected, you can choose from database connections that have been created by using the Data perspective or the DB Servers view of the J2EE perspective (Figure). Click the Next button to proceed to the next page where the database tables can be selected.

The next page shows a Tree view of all tables defined within the specified database. They are grouped based on the schema for which they were defined as shown in Figure. You should select the BOTTOMUP schema for this example. Figure also shows another schema named DABERG which has multiple tables associated with it. Selecting the DABERG schema would automatically select all of the tables associated with this schema. You are not required to select tables from the same schema grouping nor are you required to import all of the tables from a given database. Doing so would create an EJB module that would be unmanageable due to its large size. Note, some tables may be imported even though you did not select them because the mapping tool requires target tables of foreign key relationships to be imported as well.

8. Selective database import wizard page.

graphics/24fig08.jpg

Click Next to move to the next page which provides details for the generated container-managed entities as shown in Figure. The first option, Select a specification level, allows you to choose the level of EJB you would like to create, either 1.1 or 2.0. Note, with the 2.0 specification option, only local client view interfaces will be created, in accordance with our best practice of only using local interfaces for container-managed entities.

9. Bottom-up mapping generation options wizard page.

graphics/24fig09.jpg

The Package for generated EJB classes option provides the ability to determine the package for which the newly generated Java files will be defined.

The Prefix for generated EJB classes provides the ability to define a prefix to be added to each EJB Java class name that is used to create a new Java class. If you enter a string it will be prefixed to the database table name to form the name of the associated Java class. If no prefix is specified this value is ignored. Note that this page would appear instead of the previous two if a database had already existed within the EJB project.

Now that all of the bottom-up mapping options have been set, the last thing to do is to click the Finish button. This will automatically import the selected BOTTOMUP.EMPLOYEE table into the BottomUpExample EJB project, an Employee container-managed entity will be generated for the table, and new mappings will be generated between the imported table and the generated container-managed entity.

The mappings will be stored in the META-INF/backends/DB2UDBNT_V81_1/Map.mapxmi file in the BottomUpExample EJB project. Figure shows the overview section of the mapping editor for this example. You can clearly see the naming of the container-managed entity and its fields reflects the table name and column names.

10. Bottom-up mapping results.

graphics/24fig10.jpg

3 Meet-in-the-Middle Mapping Example

The meet-in-the-middle mapping approach only applies if container-managed entity beans and a logical database and its tables already exist within an EJB project. With this approach, only mappings are created and nothing more (i.e., no container-managed entity beans are created nor are database tables). The mappings created will use simple name and type matching rules for matching tables to container-managed entities and columns to cmp-fields. With WSAD, there are independent type mapping rules for each supported database vendor (see Figure). These type mappings are not made accessible for modifications and they are mostly derived from common sense.

For this example, you will need to start by creating another EJB project named MeetInTheMiddleExample using the same steps as in the Bottom Up mapping example. Next a container-managed entity needs to be created within this project. Refer to Chapter 23 for details on creating a container-managed entity. Set the following information for the container-managed entity using the EJB Creation wizard and use all other default values to create the container-managed entity.

Bean name: Employee

Default package: meet.in.the.middle.example

CMP attributes:





ssn : java.lang.Integer    (Key)

firstName : java.lang.String

middleInit : char

lastName : java.lang.String

phone : java.lang.String

hireDate : java.sql.Date

Now follow the steps from the top-down example to open the EJB to RDB mapping wizard on the new MeetInTheMiddleExample EJB module. Select the new back-end folder option as in the top-down mapping example. Click Next to go to the mapping options page shown in Figure. Again both the Top Down and Meet in the Middle options are available. Select the Meet in the Middle option and click the Next button.

You are now presented with the same connection page as in the bottom-up example in Figure. At this point you can use the same connection you used in the previous mapping example. This page appears since a logical database does not exist in the EJB project. If one had existed, you would not see this or the next page. Click the Next button to select the tables to import. The select Database Import page, shown in Figure, appears. Select the BOTTOMUP.EMPLOYEE table and click the Next button.

The next page, shown in Figure, has three simple mapping rules that are available: None, Match by Name, and Match By Name and Type. Selecting None creates a new (empty) mapping between the database and the EJB JAR within the EJB project but it does not map any of the container-managed entities. The Match by Name option will do the same as the None option except it will attempt to create a mapping for each container-managed entity. It creates an entity mapping if the name of the container-managed entity matches one of the simple names of a database table (ignoring case). For example, if you have an EJB named Address, it will create a mapping if a database table is found with the name Address or ADDRESS or any other case combination. This option also applies when creating mappings for cmp-fields which are mapped to database table columns with the same name. The last option, Match By Name and Type, is nearly the same as the previous one except that when mapping cmp-fields to columns, both the name and type are used to determine if a mapping should be created. The name must match and the types must be compatible according to the type mapping rules for the selected database.

11. Meet-in-the-middle mapping options wizard page.

graphics/24fig11.jpg

Select the Match By Name and Type option and click the Finish button. This will import the BOTTOMUP.EMPLOYEE table to a new back-end folder within the MeetInTheMiddleExample EJB project and it will create mappings between the Employee container-managed entity and the imported table. Also, all cmp-fields are mapped to the correct columns in the EMPLOYEE table even though the names were not an exact match. The mapping rules were applied and the best matches were found. The mapping editor opens to reveal the resulting mappings shown in the Overview section of the mapping editor in Figure.

12. Meet-in-the-middle mapping results.

graphics/24fig12.jpg

3.1 Existing Back-end Folder Options

Now that you have seen an explanation of the mapping options within the EJB to RDB mapping wizard, we can return to Figure to provide descriptions of the remaining two mapping options. These options should now be enabled since you have created at least one back-end folder by using this wizard. With at least one back-end folder available, the Use an existing Backend folder is enabled. If you select this option, the back-end folder list in Figure is enabled. When you select one of the existing back-end folders from the list, the two radio buttons under the list are enabled.

The first option, Re-execute mapping commands to react to model changes, is used to re-execute the mapping commands that were used to create the map file. For example, if you created the map file using the top-down mapping option, this option will re-execute a top-down mapping command to pick up any changes that were made to the EJB module and reflect them in the database tables. Be forewarned that this option will delete and recreate the mapped database tables in this scenario. Also note in this example, if you made changes to one of the database tables or the database in any way, this option will not have any effect since the mapping was created using the top-down mapping option.

The same is true if you first created the map file using the bottom-up mapping option. This option will re-execute the bottom-up commands to react to changes made to the database and reflect them in the EJB module. Warning: This will delete all cmp-fields and relationships as well as the methods that support them. The action will then re-create the cmp-fields and relationships and their associated methods in the container-managed entities based on the database tables.

It should now be apparent that you cannot mix mapping approaches. Once you have decided upon one, you must continue to use it or switch to using the meet-in-the-middle mapping approach if you want to make changes to both the container-managed entities and the database tables.

The second option, Open mapping editor on selected backend map, opens the mapping editor for the selected back-end folder without running any commands or making any modifications to the file. This is a convenience option for opening the mapping editor for multiple backend folders. You can do the same by double-clicking the desired backend mapping under the Maps section within an EJB module from the J2EE Hierarchy view (see Figure).

4 EJB Mapping Editor

Now that we have described how to use the EJB to RDB mapping wizard to create a mapping for your EJB module, you are ready to learn the basics of using the EJB mapping editor. This is opened after running the EJB to RDB mapping wizard. Figure shows the contents of the EJB mapping editor that was opened after creating a top-down mapping for the TimeSheetGroup EJB project used within the case study. You would use this editor if you are required to make manual changes to a top-down or bottom-up mapping or if you simply use the meet-in-the-middle mapping approach.

13. EJB mapping editor.

graphics/24fig13.jpg

EJB to RDB mapping editor action buttons.

Action Name

Button Icon

Create a new mapping

graphics/24inl01.jpg

Create mappings for children with matching names

graphics/24inl02.jpg

Create mappings for children with matching types

graphics/24inl03.jpg

Re-execute Mapping Commands

graphics/24inl04.jpg

Overview filter mapped objects

graphics/24inl05.jpg

Overview flip orientation

graphics/24inl06.jpg

The EJB mapping editor is divided into three major areas: the Enterprise Beans list, the Tables list, and the overview as shown in Figure. The Enterprise Beans list is a tree view of the EJB JAR, its contained container-managed entities, and their CMP and CMR fields. The Tables list is a tree view of the database, its contained tables, and their columns and foreign keys. These two lists work together to create the desired mappings. In order for the map to be free of validation errors, you must map each element in the Enterprise Beans list to an element in the Tables list.

The actions in Figure are easy to carry out. To create a mapping between a container-managed entity bean and a database table, select the desired container-managed entity bean from the Enterprise Beans list and the database table that you would like to map to from the Tables list. Next, click one of the mapping toolbar buttons in order to create the mapping. The mapping buttons function as follows:

  • The Create a new mapping button creates a mapping between the CMP bean and the selected table and nothing more.

  • The Create mappings for children with matching names button does the same as the simple mapping button as well as creating mappings for each cmp-field to a table column where there is a column with the same name, ignoring case, within the selected table.

  • The Create mappings for children with matching types button will do the same as the simple mapping button and also create mappings for each cmp-field to a table column where there is an unmapped column with a type that can be mapped to the cmp-field type.

The last two actions may be used even after a simple mapping has been applied as long as there is an unmapped cmp-field and there is an available column that can be mapped by the action. Note that any simple mapping can also be accomplished by simply dragging and dropping a member from the Enterprise Beans list to the Tables list and vice versa.

Both the Enterprise Beans list and the Tables list have the same button bar (shown in Figure). The actions associated with these buttons are merely convenience actions to make traversal through the lists easier.

14. Mapping list button bar.

graphics/24fig14.gif

The first two actions, starting at the left, change the current selection to the next mapped object and the previous mapped object correspondingly. The third and fourth buttons are similar to the first two except that they change the current selection to the next unmapped object and the previous unmapped object. The fifth button, which looks like a window shade, is used to filter the list so that only unmapped objects are displayed when the button is pressed. The last button has the same action for both lists but it points in the opposite direction for each list. This button will select the mapped object(s) from the other list for the currently mapped selection. For example, if the city cmp-field was selected for the AddressEJB from the Enterprise Beans list and this button was selected, the CITY column for the ADDRESSEJB table in the Tables list will be selected.

The Overview section of the mapping editor provides a view of the current mappings from the point of view of either the enterprise beans or the tables. By default the view is with respect to the enterprise beans and it shows only mapped members. To see the unmapped objects as well, you can click the overview filter mapped objects button shown in Figure. The view is divided into two lists Enterprise Beans and Tables similar to the other lists. The way to read this view is to look at an object from the left list like the AddressEJB and then look directly at the object to the right to see which object(s) it maps to (i.e., ADDRESSEJB table). If the Overview filter mapped objects button is selected, the object to the right will be empty if the object to the left is not currently mapped. You can change or create a mapping by selecting the element in the right list and selecting from the available unmapped elements (tables or columns in this case) drop-down tree list.

Remove Mapping, Match by Name, and Match by Type are all available from the overview context menu for the element selected in the right list. You might have noticed by now that we continue to refer to the lists as right and left as opposed to Enterprise Beans list and Tables list. The reason is that the Enterprise Beans list is not necessarily always on the left. Remember that the right list is the master showing the mappings for these elements. The default is to show the container-managed entity beans but you can switch the lists such that the tables are on the right and enterprise beans are on the left. This is accomplished with the Overview flip orientation button shown in Figure. This is useful if you like to create or view mappings based on the database definition.

The mapping editor also has an outline view, shown in Figure, which is used to navigate between existing mapped objects. The outline shows all of the mappings that have been created between container-managed entity beans and database tables. Notice that the selections are all linked within each view. So, if you select a mapping from the outline, the corresponding EJB object is selected from the Enterprise Beans list, the corresponding database object is selected from the Tables list, and the mapping is also selected within the overview. The outline contains the same context menu actions as the overview where a mapping exists.

15. Mapping editor outline.

graphics/24fig15.jpg

There is one additional mapping action that we have yet to mention which appears in virtually all of the context menus and the workbench toolbar. This is the Re-execute mapping commands action which has an associated toolbar button shown in Figure. This action is equivalent to using the Re-execute mapping commands to react to model changes from the first page of the EJB to RDB mapping wizard as shown in Figure. This action is useful if you make a change to the EJB module after performing a top-down mapping. This action will cause the top-down mapping command to be re-executed, which would cause a database artifact to be created and mapped to the new features in the EJB module. The same is true if you did a bottom-up mapping and you changed the database tables or if you did a meet-in-the-middle mapping and you changed either the EJB module or database tables, or both.

5 Re-executing Mapping Commands

The Re-execute Mapping Commands action accomplishes its task by re-executing the persistent commands that were serialized within the Map.mapxmi file. This is the same action that would be executed if you had selected the Re-execute mapping commands to react to model changes option from the EJB to RDB mapping wizard shown in Figure.

When a mapping command is performed, it is tracked and added to the persistent commands list that is saved with the file. So you can perform a meet-in-the-middle mapping initially and then map a cmp-field that was not automatically mapped by the command to a database column. If you later select the Re-execute Mapping Commands action, this last mapping command is also executed since it was tracked and added to the persistent command stack. Only commands that create mappings are tracked. Delete mapping commands are not tracked.

We should re-emphasize a point that was made earlier when describing this option in the EJB to RDB mapping wizard. If you select the Re-execute Mapping Commands either from the toolbar or the context menu, and the Top Down mapping option was used to create the map, all database tables will be deleted and recreated based on the container-managed entities in the EJB module. Also, if you use the Bottom Up mapping option to initially create a map, the Re-execute Mapping Commands option will delete all of the cmp-fields and relationships in the mapped container-managed entities.

Re-executing the mapping command will also cause all of the methods that were created on the entity to be removed. Then new cmp-fields and relationships will be created based on the table that the container-managed entity is mapped. All methods that were added by the user will be maintained and not be deleted. Any table that is removed will cause the corresponding container-managed entity to be deleted from the EJB module.

6 Re-execute Mapping Commands Alternative

We have just seen how you can use the Re-execute Mapping Commands option to create mappings to pick up changes to either the database or to the EJB module, but not both. So you have a problem if you used the Bottom Up mapping option to create the map and later you update one or more of the container-managed entities that were generated and possibly add a new database table. The problem is that you want to use the Re-execute Mapping Commands action to pick up the changes to the database (i.e., the new table) but that will delete all of the container-managed entity generated methods, cmp-fields, and relationships and recreate only the ones based on the table. This is not the desired effect because you want to preserve your changes to the container-managed entities.

This can be solved by two different methods. First, you could create a container-managed entity for the new table and then use the meet-in-the-middle mapping approach to map the new container-managed entity and its cmp-fields to the new database table and its columns. This seems like a lot of work just to keep your modifications to the container-managed entities. The good news is that there is a much simpler solution. Let's use a very simple example to show how this would work.

We start by creating a database and one table, TABLEA, or you could simply import a table from an existing database. Next we use the EJB to RDB mapping wizard to generate a new bottom-up map which would create a Tablea container-managed entity. So far we have done nothing new. Now, let's assume that you wanted to add business logic to the ejbCreate method generated on the Tablea container-managed entity. Now the Tablea container-managed entity has been modified beyond the point of its generation using the mapping wizard.

Next, you might update the database by adding a new table, TABLEB. You would like to have a new container-managed entity created for TABLEB and have a new mapping defined for this table and bean. At first guess you think about using the Re-execute Mapping Commands action to pick up the database changes. Remember when re-executing a bottom-up mapping command, the cmp-fields and relationships of the container-managed entries are deleted (this also updates the ejbCreate method) and new ones are created to reflect the current shape of the database and its tables (the ejbCreate method is recreated at this point). This is not the desired effect because you have modified the Tablea bean.

This is where our second alternative comes in. From the mapping editor (shown in Figure) you can select the new database table, TABLEB, from the Tables list. Now you can drag the table to the EJB JAR (the root object in the tree view) in the Enterprise Beans list. Once you drag the table over the EJB JAR, the icon will switch to a plus (+) symbol indicating that it can be dropped. This is only possible because you created the map using the bottom-up mapping option so you can drag and drop tables to the EJB JAR.

If you drop the new TABLEB on the EJB JAR, WSAD creates a Tableb container-managed entity with cmp-fields for each column in the table. It also creates a mapping for the new container-managed entity and the table as well as for each cmp-field and its associated column. This is what you want since the new table will get a new container-managed entity created for it while leaving the other container-managed entities intact. Also, if just one or more columns were added to TABLEA, you can drag and drop the column to the Tablea container-managed entity to have a new cmp-field created and mapped.

Importing Changes from the Database

It is very common for individuals to import all tables for a specific schema within the database and then map it to a set of container-managed entities. At a later time changes may be made to the physical database and you will want to import those changes back into your EJB project. You will often not be aware of the specific changes so it is safer to import the entire set of tables within the schema and/or database. This causes a problem with WSAD 5.0.1 which will manifest itself as a loss of all of your mappings.

This loss of mappings takes place because the map file has references to the logical database tables and columns. Each of these tables and columns has a generated ID to ensure that they are unique. When the tables are imported a second time, new files are created to store the metainformation and, therefore, new IDs are generated. These new IDs are different than the ones in the map file, thus causing the problem. A more in-depth discussion of the problem and a new feature to correct the problem can be found in "Importing Database Table Changes into an EJB Module in WebSphere Studio While Preserving References" at http://submit.boulder.ibm.com/wsdd/library/techarticles/0305_berg/berg.html.


This example was for bottom-up mapping but there is a corresponding option when using top-down mapping. In this case, you created the map using the Top Down mapping option and then made changes to the database tables. If you create a container-managed entity, you will want a new table to be created for the bean but do not want to re-execute the top-down mapping command because that would delete the current database tables. This means that you will lose any changes that were made to the database tables. Instead, you can open the map editor and drag the new container-managed entity from the Enterprise Beans list and drop it on the database from the Tables list. This will create a database table, create columns for each cmp-field, and create new mappings for each of these, all without deleting any of the existing database tables. Also, if just one or more cmp-fields were added to Tablea, you can drag and drop the cmp-field to the TABLEA table to have a new column created and mapped.

Mapping Directions

Every map that is created has a direction associated with it. This direction indicates whether it was created using the top-down or bottom-up approach. These are the only two directions. If the meet-in-the-middle approach were used, the mapping will indicate the top-down direction by default. This will dictate the direction that objects can be created. For example, if bottom-up were used to create the mapping, you will be able to drag and drop changes to the database or tables onto the corresponding EJB JAR or container-managed entity but you will not be able to drag and drop container-managed entity changes to the database. The opposite is true for the top-down direction.


7 Defining and Using Converters

By default, complex EJB properties (i.e., subclasses of java.lang.Object which are not Java primitive type wrappers) that are serializable are serialized and mapped to an appropriate binary database column. While this does allow for properties of arbitrary Java types, it is not an optimal solution. Since the column is binary, it is impossible to query this column using standard SQL query tools. Likewise, the performance of serializing and deserializing an object into a binary large object (BLOB) can be poor. In order to improve the mapping options for these types, WSAD has the concept of converters. These helper classes provide an open framework for converting between object types and database types used by the mapping and deploy code specific to WebSphere. If you used the EJB development environment in VisualAge for Java in the past, the converters in WSAD are very similar those used in VAJ.

WSAD provides a number of common converters for use by the EJB to RDB mapping editor within any EJB project; however, you may need other types of conversion. If this is the case, you will need to create your own converter class and define this converter so that the EJB mapping framework will be aware of it.

This is done by using the converter or composer wizard. To help demonstrate how to define and use a converter, change the date cmp-field of our TimeSheetEntryEJB CMP bean from the TimeSheetGroup EJB module from a java.lang.String object type to a java.util.Date using the edit action on the Beans page of the EJB deployment descriptor editor. Also change the typing of the DATE1 column in the TIMESHEETENTRYEJB table from DATE to VARCHAR using the Table editor.

First we begin by defining and creating a converter class. Start by selecting New > Other > EJB > Converter or Composer from the workbench menu bar. This will open the EJB converter or composer wizard shown in Figure. Select the Converter radio button to create a converter and then enter the EJB project in which the converter will be defined. Then provide a fully qualified name for the converter class (com.wsbook.casestudy.ejb.DateToStringConverter) and its supertype name. The supertype is a combo box because you must select an already defined converter class. If you do not have a need for a specific supertype, use the default com.ibm.vap.converters.VapAbstractConverter.

16. EJB converter wizard.

graphics/24fig16.jpg

Lastly, define the target type of the converter. This is the Java type that the database type will be converted to. In this example, we choose java.lang.String. Note that the Generate a converter stub class option is checked by default. If the converter class name specified already exists, you should deselect this option in order to create a converter definition using the existing converter class. This option will automatically generate the new converter class for you leaving only two methods to be implemented.

When the wizard finishes, notice that it has created a file in the EJB project named UserDefinedConverters.xmi. This file contains the definition of converters that were defined specifically for this EJB project. If you would like to share these definitions with other EJB projects, you will need either to redefine the converter within each EJB project that you would like to use it or copy this file to the other EJB projects. You will also need to ensure that the converter class is accessible to the other EJB projects by putting it on both the development time and runtime classpaths. One way to do this would be to put the converters in a separate project and treat them as utility JAR files (see Chapter 18 for more details about configuring J2EE projects).

There is also a new Java class defined within the TimeSheetGroup EJB project. If you open a Java editor on the com.wsbook.casestudy.ejb.DateToStringConverter Java class you will see that the converter class is stubbed in for you. The only thing left to do is to implement the dataFrom(Object) and objectFrom(Object) methods. The dataFrom(Object) method is used to convert the java.lang.String object type that is passed to a java.sql.Date type to be used when writing to the database.





public Object dataFrom(Object anObject) {

            //date in format "mm-dd-yyyy"

            Date date = null;

            try {

                   String dateString = (String) anObject;

                   DateFormat formatter = new SimpleDateFormat(

                          "MM/dd/yyyy");

                   java.util.Date parsed =

                          formatter.parse(dateString);

                   return new java.sql.Date(parsed.getTime());

            } catch (ParseException e) {

                  // can't do anything, so eat the exception

            }

            return date;

    }

The objectFrom(Object) method is used to convert the java.sql.Date database type that is passed to a java.lang.String type to be used when reading from the database.





public Object objectFrom(Object aField) {

            //return a String in format "mm-dd-yyyy"

            java.sql.Date date = (java.sql.Date) aField;

            String value = null;

            DateFormat formatter = new SimpleDateFormat("MM/dd/yyyy");

            value = formatter.format(date);

            return value;

    }

Now that we have defined our converter, we are ready to use it within our map. Return to the EJB to RDB mapping editor for the TimeSheetGroup EJB project. Select the date cmp-field from the TimeSheetEntryEJB within the Overview section. Notice that the Properties view has changed to show the properties for the current field mapping. You could achieve the same results by selecting the field mapping from the Outline view.

8 Defining and Using Composers

In the Properties view, select the Transformation value field. It should change to a combo box. Scroll to the bottom of the list to see the new user defined converters. Select the new com.wsbook.casestudy.ejb.DateToStringConverter. Now this field mapping has a converter defined for it and this converter will be used when the deployed code is generated.

Composers, much like converters, are another mechanism for serializing a custom Java type to the database without using a BLOB column to accomplish this task. This is common with container-managed entities when using dependent values which are defined as concrete Java classes that are serializable and can be the type of a cmp-field. The internal structure of dependent values is not defined in the deployment descriptor.

Composers are unique to the mapping framework used by WSAD and the deploy code specific to WebSphere. A composer will take a single cmp-field type and map it to multiple database table columns, thus the table columns compose the object type used by the cmp-field. For example, a common composer type provided with WSAD is a composer for joining title, firstName, and lastName database columns into a single name attribute in a container-managed entity. In order to use a composer, we must first define it using many of the same steps that we did when creating the converter.

First, open the EJB Converter or Composer wizard following the same steps used to create a converter. Now select the composer radio button. The wizard page changes to display the contents for creating a composer as shown in Figure. Several of the fields are shared with the creation of a converter. First, specify the EJB project in which the composer will be defined. Then enter the fully qualified name of the composer class, (com.wsbook.casestudy.ejb.OfficeLocationComposer). Like the converter, we must select a supertype for our composer from the list of already defined composers. If there is not a known supertype, use the default VapAttributeComposer type. Enter the qualified Java target type for the composer (com.wsbook.casestudy.ejb.OfficeLocation). The type does not need to exist and probably will not exist at this time.

17. EJB composer wizard.

graphics/24fig17.jpg

The Fields section is where the composer differs from the converter. In this section, it is necessary to define the fields within the target type (i.e., com.wsbook.casestudy.ejb.OfficeLocation) that will be mapped to individual database columns. For this example we added four columns that are used to compose a person's unique office location. This was done by selecting a composed field type from the combo box and clicking the Add button. This adds the field to the table. We then can select the Name column entry and type in a new name of the field. Again the generation option, Generate a composer stub class, appears at the bottom of the wizard. With this option selected, a new composer class and the target type will be generated. Upon finish the composer class and the target type class are generated and the composer is defined in the new UserDefinedComposers.xmi file.

The target type that is generated is just a data structure that is free of compile errors and is ready to be used, but you may make changes to suit your needs. Just as with the converter, you will need to implement the dataFrom(Object) and objectFrom(Object[]) methods. The dataFrom(Object) method takes the target type (com.wsbook.casestudy.ejb.OfficeLocation) and returns an Object array with composed fields in the order that they are defined in the getAttributeNames() method (e.g., the order that they were defined within the wizard).





public Object[] dataFrom(Object anObject) {

    Object[] anArray = new Object[4];

    if (anObject != null) {

       OfficeLocation location = (OfficeLocation) anObject;

        anArray[0] = location.getState();

        anArray[1] = location.getCity();

        anArray[2] = location.getBuilding();

        anArray[3] = location.getOffice();

    }

    return anArray;

}

The objectFrom(Object[]) method receives the database column types passed within the Object[] in the order in which they appear in the getAttributeNames() method. It must return an instance of the com.wsbook.casestudy.ejb.OfficeLocation class with its attributes appropriately set.





public Object objectFrom(Object[] anArray) {

       OfficeLocation location = new OfficeLocation();

       location.setState((String) anArray[0]);

       location.setCity((String) anArray[1]);

       location.setBuilding((String) anArray[2]);

       location.setOffice((String) anArray[3]);

    return location;

}

In order to use this new composer first add a new office cmp-field to the EmployeeEJB using the EJB deployment descriptor editor on the Beans page within the CMP Fields list of the selected bean. Set the type to be the new composer target type (com.wsbook.casestudy.ejb.OfficeLocation). Also add four new columns, all typed to VARCHAR to the EMPLOYEEEJB table: STATE, CITY, BUILDING, and OFFICE. Do this using the Table editor by selecting the NULLID.EMPLOYEEEJB table from the TimeSheetGroup database under the Databases section in the J2EE Hierarchy view and selecting the Open action from the context menu, then adding the columns.

Now open the EJB to RDB Mapping editor for the TimeSheetGroup EJB project so that you can map the new office cmp-field. Select the office cmp-field from the EmployeeEJB from the EnterpriseBeans list and select the STATE, CITY, BUILDING, and OFFICE columns from the EMPLOYEEEJB table from the Tables list. Then select the Create Mapping context menu option or button from the workbench toolbar. This will open the EJB Composer wizard shown in Figure since you are mapping one cmp-field to multiple database columns.

18. EJB composer wizard.

graphics/24fig18.jpg

First select the new composer from the drop-down list (i.e., com.wsbook.casestudy.ejb.OfficeLocationComposer). This populates the table with the attributes defined when you created the composer. For each attribute, select one of the four columns selected in the mapping to be directly mapped to the attribute. The new mapping is defined after pressing Finish. If you look in the Overview section, you will see that the office cmp-field is now mapped to four columns. If you need to change the composer, you can do so from the Properties view when the mapping is selected from the Overview or the Outline views. Clicking on the button for the Transformation class will launch the EJB composer wizard once again.


     Python   SQL   Java   php   Perl 
     game development   web development   internet   *nix   graphics   hardware 
     telecommunications   C++ 
     Flash   Active Directory   Windows