Example: Warehouse Management (EJB 2.0)


Our goal in this section is to demonstrate, by means of an example, how the techniques discussed in the previous sections (persistent attributes, persistent relationships in connection with the local client view, EJB-QL) can be combined. In comparison to the other examples in this book, this example is quite complex. To maintain clarity and save space we will not reproduce here the complete source code of this example. We will restrict our attention to those parts that highlight the points that we wish to stress.

The Problem

The accounting department of Amalgamated Intergalactic Enterprises requires access to the data showing the state of the company warehouses (which we will call "stores"). The management of the stores is partially automated. However, the store management system has no client application that meets the needs of the accounting department. Therefore, a client application is to be developed for the accounting department that offers read access to the database of the store management system.

Figure 5-12 shows the principal features of the data model of the store management system. The table STORES keeps track of all the stores. This includes, for example, a store for product parts, a store for half-finished products, a store for end products, a store for warranty return, and so on. Each store contains a system of racks, stored in the table RACKS. Information as to which racks are contained in which store is stored via a foreign key (STOREID) in the table RACKS.

click to expand
Figure 5-12: Database schema for the store management problem.

Each rack has several positions in which items can be stored. The store management system assumes that at a given position on a given rack only a single type of article can be stored (though there may be more than one of them). A particular position on a rack is pinpointed by the shelf (PROW) and position on that shelf (PCOLUMN). The positions available on a given rack are stored in a foreign key (RACKID) in the table POSITIONS. In the positions of a rack are to be found the various articles (ITEMS). The items that exist are stored in the table ITEMS. Which type of article is stored at a given position is stored via the foreign key ITEMID in the table POSITIONS.

The client program was developed on the basis of a needs analysis, which was carried out with input from the employees of the accounting department. Figure 5-13 shows the client program (ejb.store.client.StoreManager). In the top part of the application window appears a select box labeled Store. Here one can select the store whose status is to be investigated. The default position is to show the first store in the list of all existing stores. In the left column all racks in the selected store are shown. In the store Products, for example, the names Monitors, Housings, and Miscellaneous appear.

click to expand
Figure 5-13: StoreManager.

When a rack is selected, a table appears in the middle of the application window that displays the available positions in the various racks. If a position is occupied, then the row and column of the position are displayed. If the position is unoccupied, then a blank field is displayed. In Figure 5-13 position 2/2 was displayed (location 2 on shelf 2). To see what articles are to be found at position 2/2 of the rack Housings, a dialog can be displayed by means of the menu selection View:Article, which displays the articles located at this position. One can see in Figure 5-14 that in position 2/2 of the rack Housings is stored the article Housings Big Tower produced by Plangate Inc.

click to expand
Figure 5-14: StoreManager— article display.

Instead of browsing through the different positions of a rack, one can search for the position of a particular article. For this the menu item Search:Article is used, as shown in the dialog box in Figure 5-15. In the upper part of the dialog box there appears a list of all articles available in the system. To see where the article TFT Monitor 15 inch is stored, that item is selected in the list and the button Search pressed. Then in the lower part of the dialog box a list appears with rack positions at which the article is stored. In the example of Figure 5-15 the article is stored in the rack Monitors at positions 1/1, 1/2, and 1/3.

click to expand
Figure 5-15: StoreManager— article search.

Now that we see what the client program and user interface need to look like, we can begin to solve our problem.

Solving the Problem

Each of the four database tables will be represented by an entity bean. The table columns are mapped to persistent attributes of the corresponding entity bean. The table's foreign key relations are relayed to the entity beans via persistent relationships. Figure 5-16 shows the entity beans and their interrelationships.

click to expand
Figure 5-16: Modeling the data with entity beans.

The store bean is the only bean that supports the remote client view. All the other beans support the local client view. Because of the way they are related they must support the local client view; however, they can additionally offer a remote interface. The goal of this design strategy is to make only one bean, the store bean, accessible to the client. This offers the client an advantage, in that it does not have to know anything about the internal structure and dependencies on the server side. For the client there is only one location where communication takes place, namely, at the store (with the store bean), which alone provides the client the information that it needs. The result is that the use of the server interface is considerably simplified for the client. The internal relationships remain hidden. Thus there are no dependencies between the client and the internal workings of the server. As long as the store bean maintains its interface, the client is completely unaffected by changes on the server side.

The client sees Racks, Positions, and Items only in the form of simple Java classes (see Figure 5-17). These classes are container classes for the data of the rack, position, and item beans. The store bean supplies information to the client via these classes. It fills the instances of these container classes with data from the corresponding entity beans. The client knows nothing about the existence of rack, position, and item beans. The container classes are thus also components of the public interface of the store bean. Listing 5-42 shows the implementation of the class Rack. The classes Position and Item are developed along the exact same lines and are therefore not shown.

Listing 5-42: The container class Rack.

start example
 package ejb.store; public class Rack implements java.io.Serializable {     private Integer id;     private String description;     private Integer storeId;     public Rack(Integer id, String desc, Integer storeId) {         if(id == null || id.intValue() < 0)             throw new IllegalArgumentException("id");         if(desc == null)             throw new IllegalArgumentException("desc == null!");         if(storeId == null || storeId.intValue() < 0)             throw new IllegalArgumentException("storeId");         this.id = id;         this.description = desc;         this.storeId = storeId;     }     public Integer getId() {         return this.id;     }     public String getDescription() {         return this.description;     }     public Integer getStoreId() {         return this.storeId;     }     public String toString() {         return "[Rack[;description=" + this.description + "]";     } } 
end example

click to expand
Figure 5-17: Communication with the remote client.

Listing 5-43 shows the home interface, Listing 5-44 the remote interface, of the Store bean. The classes Rack, Position, and Item, as well as the two interfaces Store and StoreHome, together constitute the server interface for the client. Listing 5-45, which we shall discuss shortly, shows the deployment descriptor. It represents the most significant portion of the problem solution. All the information comes together in the deployment descriptor.

Listing 5-43: Home interface of the Store bean.

start example
 package ejb.store; import javax.ejb.CreateException; import javax.ejb.EJBHome; import javax.ejb.FinderException; import java.rmi.RemoteException; import java.util.Collection; public interface StoreHome extends EJBHome {     public Store create(Integer id, String name)         throws CreateException, RemoteException;     public Store findByPrimaryKey(Integer key)         throws FinderException, RemoteException;     public Collection findAllStores()         throws FinderException, RemoteException; } 
end example

Listing 5-44: Remote interface of the store bean.

start example
 package ejb.store; import javax.ejb.EJBObject; import java.rmi.RemoteException; import java.util.Collection; public interface Store extends EJBObject {     public Integer getStoreId()         throws RemoteException;     public String getStoreName()         throws RemoteException;     public Collection getStoreRacks()         throws RemoteException;     public Collection getStoreRackPositions(Rack rack)         throws RemoteException;     public Item getItemInPosition(Position pos)         throws RemoteException;     public Collection getAllStoreItems()         throws RemoteException;     public Collection getPositionsForItem(Item item)         throws RemoteException; } 
end example

Listing 5-45: Deployment descriptor for warehouse management.

start example
 <?xml version="1.0" encoding="UTF-8"?> <ejb-jar version="2.1" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/ejb-jar_2_1.xsd">     <enterprise-beans>         <entity>             <ejb-name>Store</ejb-name>             <home>ejb.store.StoreHome</home>             <remote>ejb.store.Store</remote>             <ejb-class>ejb.store.StoreBean</ejb-class>             <persistence-type>Container</persistence-type>             <prim-key-class>java.lang.Integer</prim-key-class>             <reentrant>False</reentrant>             <cmp-version>2.x</cmp-version>             <abstract-schema-name>Store</abstract-schema-name>             <cmp-field>               <field-name>id</field-name>             </cmp-field>             <cmp-field>               <field-name>name</field-name>             </cmp-field>             <primkey-field>id</primkey-field>             <query>               <query-method>                 <method-name>findAllStores</method-name>                 <method-params>                 </method-params>               </query-method>               <ejb-ql>                 SELECT OBJECT(s) FROM Store AS s               </ejb-ql>             </query>             <query>               <query-method>                 <method-name>ejbSelectAllItems</method-name>                 <method-params>                 </method-params>               </query-method>               <result-type-mapping>Local</result-type-mapping>               <ejb-ql>                 SELECT DISTINCT p.item FROM Store AS s,                                               IN (s.racks) AS r,                                               IN(r.positions) AS p               </ejb-ql>             </query>             <query>               <query-method>                 <method-name>ejbSelectPositionsForItem                 </method-name>                 <method-params>                   <method-param>java.lang.Integer</method-param>                 </method-params>               </query-method>               <result-type-mapping>Local</result-type-mapping>               <ejb-ql>                 SELECT OBJECT(p) FROM Store AS s,                                         IN (s.racks) AS r,                                         IN(r.positions) AS p                                   WHERE p.itemId = ?1               </ejb-ql>             </query>         </entity>         <entity>             <ejb-name>RackLocal</ejb-name>             <local-home>ejb.store.rack.RackLocalHome</local-home>             <local>ejb.store.rack.RackLocal</local>             <ejb-class>ejb.store.rack.RackBean</ejb-class>             <persistence-type>Container</persistence-type>             <prim-key-class>java.lang.Integer</prim-key-class>             <reentrant>False</reentrant>             <cmp-version>2.x</cmp-version>             <abstract-schema-name>Rack</abstract-schema-name>             <cmp-field>               <field-name>id</field-name>             </cmp-field>             <cmp-field>               <field-name>description</field-name>             </cmp-field>             <cmp-field>               <field-name>storeId</field-name>             </cmp-field>             <primkey-field>id</primkey-field>         </entity>         <entity>             <ejb-name>PositionLocal</ejb-name>             <local-home>                 ejb.store.rack.position.PositionLocalHome             </local-home>             <local>ejb.store.rack.position.PositionLocal</local>             <ejb-class>                 ejb.store.rack.position.PositionBean             </ejb-class>             <persistence-type>Container</persistence-type>             <prim-key-class>                 ejb.store.rack.position.PositionPK             </prim-key-class>             <reentrant>False</reentrant>             <cmp-version>2.x</cmp-version>             <abstract-schema-name>Position</abstract-schema-name>             <cmp-field>                <field-name>rackId</field-name>             </cmp-field>             <cmp-field>                <field-name>row</field-name>             </cmp-field>             <cmp-field>                <field-name>column</field-name>             </cmp-field>             <cmp-field>                <field-name>itemId</field-name>             </cmp-field>             <cmp-field>                <field-name>quantity</field-name>             </cmp-field>         </entity>         <entity>             <ejb-name> ItemLocal</ejb-name>             <local-home>ejb.store.item.ItemLocalHome</local-home>             <local>ejb.store.item.ItemLocal</local>             <ejb-class>ejb.store.item.ItemBean</ejb-class>             <persistence-type>Container</persistence-type>             <prim-key-class>java.lang.Integer</prim-key-class>             <reentrant>False</reentrant>             <cmp-version>2.x</cmp-version>             <abstract-schema-name>Item</abstract-schema-name>             <cmp-field>                <field-name>id</field-name>             </cmp-field>             <cmp-field>               <field-name>description</field-name>             </cmp-field>             <cmp-field>               <field-name>supplier</field-name>             </cmp-field>             <primkey-field>id</primkey-field>         </entity>     </enterprise-beans>     <relationships>         <ejb-relation>             <ejb-relation-name>Store-Rack</ejb-relation-name>             <ejb-relationship-role>                 <ejb-relationship-role-name>                     store-has-racks                 </ejb-relationship-role-name>                 <multiplicity>One</multiplicity>                 <relationship-role-source>                     <ejb-name>Store</ejb-name>                </relationship-role-source>                <cmr-field>                    <cmr-field-name>racks</cmr-field-name>                    <cmr-field-type>                        java.util.Collection                    </cmr-field-type>                </cmr-field>             </ejb-relationship-role>             <ejb-relationship-role>                 <ejb-relationship-role-name>                     rack-belongs-to-store                 </ejb-relationship-role-name>                 <multiplicity>Many</multiplicity>                 <cascade-delete/>                 <relationship-role-source>                     <ejb-name>RackLocal</ejb-name>                </relationship-role-source>             </ejb-relationship-role>         </ejb-relation>         <ejb-relation>             <ejb-relation-name>Rack-Position</ejb-relation-name>             <ejb-relationship-role>                 <ejb-relationship-role-name>                     rack-has-positions                 </ejb-relationship-role-name>                 <multiplicity>One</multiplicity>                 <relationship-role-source>                     <ejb-name>RackLocal</ejb-name>                </relationship-role-source>                <cmr-field>                    <cmr-field-name>positions</cmr-field-name>                    <cmr-field-type>                        java.util.Collection                    </cmr-field-type>                </cmr-field>             </ejb-relationship-role>             <ejb-relationship-role>                 <ejb-relationship-role-name>                     position-belongs-to-rack                 </ejb-relationship-role-name>                 <multiplicity>Many</multiplicity>                 <cascade-delete/>                 <relationship-role-source>                     <ejb-name>PositionLocal</ejb-name>                </relationship-role-source>                <cmr-field>                    <cmr-field-name>rack</cmr-field-name>                </cmr-field>             </ejb-relationship-role>         </ejb-relation>         <ejb-relation>             <ejb-relation-name>Position-Item</ejb-relation-name>             <ejb-relationship-role>                 <ejb-relationship-role-name>                     position-has-item                 </ejb-relationship-role-name>                 <multiplicity>Many</multiplicity>                 <relationship-role-source>                     <ejb-name>PositionLocal</ejb-name>                </relationship-role-source>                <cmr-field>                    <cmr-field-name>item</cmr-field-name>                </cmr-field>             </ejb-relationship-role>             <ejb-relationship-role>                 <ejb-relationship-role-name>                     item-is-in-position(s)                 </ejb-relationship-role-name>                 <multiplicity>One</multiplicity>                 <relationship-role-source>                     <ejb-name>ItemLocal</ejb-name>                </relationship-role-source>             </ejb-relationship-role>         </ejb-relation>     </relationships> </ejb-jar> 
end example

The method findAllStores of the home interface is used to fill the select box labeled store with values (see Figure 5-13). If the user selects a particular store, the client application obtains access to the corresponding store using findByPrimaryKey.

In order to fill the list that shows the racks, the client application uses the method getStoreRacks of the remote interface. The store bean stands in a 1-to-n relationship to the rack bean (see Listing 5-45, the relation Store-Rack). Thus it is easy for the store bean to determine which racks are located in this store. It has only to navigate over the relation to obtain access to the relevant rack beans. The data of the rack beans are packaged in Rack objects and returned to the client application as the return value of the method call.

If the user selects a particular rack, then all the rack positions in the table must be displayed. For this the client application calls the method getStoreRackPositions and passes as parameter a Rack object for which the positions are desired. The store bean then obtains, by navigation over the relation, access to the corresponding rack bean. For its part, the rack bean is in a1-to-n relation with the position bean (see Listing 5-45, relation Rack-Position). The rack bean is instructed by the store bean to determine, via navigation over the relation, all of its position beans and to transform them into Position objects. These Position objects are returned by the store bean to the client as the result of the method call.

If the user selects a particular position, in order to display the articles contained therein (see Figure 5-14), then the client application calls the method getItemInPosition. It passes the Position object for which the article is to be displayed. The store bean obtains, by a call to findByPrimaryKey on the position bean's local home interface, access to the corresponding position bean. The position bean stands in an n-to-1 relation with the item bean (Listing 5-45, relation Position-Item). The position bean is instructed to determine, by navigation over the relation, the item bean belonging to it and to transform it into an Item object. This Item object is returned by the store bean to the client as the result of the method call and can be displayed by the client application. Alternatively, the store could have found the corresponding item bean with a select method linked to an EJB-QL query in the deployment descriptor.

To enable the user to undertake a search for positions of a particular article in the stores (see Figure 5-15), the search dialog must first be filled with the articles available in the system. To this end the client application calls the method getAllStoreItems. For this the store bean uses a select method that was linked to an EJB-QL query in the deployment descriptor (see Listing 5-45, method ejbSelectAllItems). The select method returns all item beans found in the system. The store bean transforms the local entity bean references into Item objects and returns them as result of the method call to the client program. The client program uses these Item objects to fill in the article list in the search dialog.

If the user selects a particular article and pushes the Search button, the client program calls the method getPositionsForItem. Here the store bean also uses a select method that was linked in the deployment descriptor with an EJB-QL query (see Listing 5-45, method ejbSelectPositionsForItem). The select method returns the position beans in which the article resides. The store bean transforms the local references into Position objects and returns them to the client program as result of the method call. The client program uses the Position objects to fill in the list of search results in the search dialog.

Summary

Store, rack, position, and item beans can be understood as a sort of supercomponent that functions only in conjunction with all the Enterprise Bean components. The store bean is at once the controlling instance of this supercomponent and the interface for the client. The existence of the other entity beans is not apparent from the outside. The linking of Enterprise Beans into a supercomponent is accomplished by the EJB container by means of persistent relationships. It knows what instances of what Enterprise Beans belong together and looks after the resolution of relations at run time. It generates bean instances and equips them with data from the database whenever there is navigation over a relation. Communication between Enterprise Beans takes place via the local client view, which takes care of the requisite efficiency. The query language EJB-QL in connection with select or finder methods is a possibility for optionally accessing particular instances of bound Enterprise Beans within the supercomponent. This problem can be solved elegantly and with relatively little programming effort on the server side with the aid of persistent relationships (in connection with the local client view), select and finder methods, and the query language EJB-QL. Here the deployment descriptor plays a central role. It contains parts of the implementation (EJB-QL queries) and lays the foundation for the linking of Enterprise Bean instances over persistent relationships. Thus changes can be made in this part of the application without the code of the Enterprise Beans having to be altered. Moreover, the solution should be able to be ported without difficulty to other (EJB 2.0 conforming) application servers and other databases.




Enterprise JavaBeans 2.1
Enterprise JavaBeans 2.1
ISBN: 1590590880
EAN: 2147483647
Year: 2006
Pages: 103

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net