424 WebSphere Studio Application Developer Version 5 Programming Guide account.withdraw(amount); getTransRecordHome().create("D", amount, account); return account.getBalance(); } public BigDecimal transfer(String account1, String account2, BigDecimal amount) throws InsufficientFundsException, AccountDoesNotExistException, CreateException { BigDecimal balance = withdraw(account1, amount); deposit (account2, amount); return balance; } public Customer getCustomer(String customerID) throws CustomerDoesNotExistException { CustomerLocal customer = getCustomerLocal(customerID); Customer customerDTO = new Customer(); customerDTO.setId(customerID); customerDTO.setFirstName(customer.getFirstName()); customerDTO.setLastName(customer.getLastName()); customerDTO.setTitle(customer.getTitle()); return customerDTO; } public Account getAccount(String accountID) throws AccountDoesNotExistException { AccountLocal account = getAccountLocal(accountID); Account accountDTO = new Account(); accountDTO.setId(accountID); accountDTO.setType(account.getType()); accountDTO.setBalance(account.getBalance()); return accountDTO; } public Account[] getAccounts(String customerID) throws CustomerDoesNotExistException { CustomerLocal customer = getCustomerLocal(customerID); Collection accounts = customer.getAccounts(); Iterator i = accounts.iterator(); SortedSet dtoset = new TreeSet(); while ( i.hasNext() ) { AccountLocal account = (AccountLocal) i.next(); Account accountDTO = new Account(); accountDTO.setId(account.getId()); accountDTO.setType(account.getType()); accountDTO.setBalance(account.getBalance()); dtoset.add(accountDTO); } return (Account[])dtoset.toArray( new Account[dtoset.size()] ); } public TransRecord[] getTransactions(String accountID) throws AccountDoesNotExistException { AccountLocal account = getAccountLocal(accountID); Chapter 12. Developing EJB applications 425 Collection transactions = account.getTransRecords(); Iterator i = transactions.iterator(); SortedSet dtoset = new TreeSet(); while ( i.hasNext() ) { TransRecordLocal tr = (TransRecordLocal) i.next(); TransRecord trDTO = new TransRecord(); trDTO.setTimeStamp(tr.getTimeStamp()); trDTO.setTransType(tr.getTransType()); trDTO.setTransAmt(tr.getTransAmt()); dtoset.add(trDTO); } return (TransRecord[])dtoset.toArray( new TransRecord[dtoset.size()] ); } Again, you might have to organize the import statements to correct the errors. Promote the business methods to the remote interface Add all seven methods to the bean’s remote interface by selecting the methods in the Outline view and Enterprise Bean -> Promote to Remote Interface (context). Save your changes and close the editor. Notes: As you can see by the code that you just typed in, the session facade cannot return references of the entity beans. What it does is build data transfer objects based on the entity data and return these objects instead. There are many reasons for this, among which are the facts that these entity beans do not expose a remote view, and that even if they did, it would be terrible practice to have the control and view layers make multiple remote calls to the model to carry on their responsibilities. The building process of the transfer objects is inlined in the session bean code, making it a little bit cluttered. We did it this way for simplicity. An alternative would have been to use builder objects. The getAccounts and getTransactions methods use the generated relationship methods to retrieve a collection of related objects. The collection is iterated and converted into an array of transfer objects. This is done using a SortedSet to produce the result array in ascending order of account IDs or transaction IDs. To use a SortedSet both Account and TransRecord transfer objects implement the compareTo method of the Comparable interface. 426 WebSphere Studio Application Developer Version 5 Programming Guide Generating the deployed code If written according to the specification, EJBs can be run on any compliant server. But for the server to be able to provide the enterprise services the bean needs to fulfill its responsibilities, it must have generated what is called the deploy code. This code provides the logic that connects the server-independent deployable bean to the server-dependent implementation of the standard services. The name comes from the fact that this step is normally done at deploy time, when all the definitions are complete, such as: Life-cycle and finder method(s) defined and promoted to the home interface Business logic methods defined and promoted to the component interface(s) Object-relational mapping completed for CMP entity beans. Before you can successfully run your enterprise beans on either the test environment or production server, you need to generate deployed code for the beans. If your EJB project contains CMP beans that have not been mapped, a default top-down mapping is created when you generate the deployment code. To generate deploy code for our sample EJB project, switch to the J2EE Hierarchy view and select the EJB module (ItsoProGuideEJB). Now select Generate > Deploy and RMIC code from the context menu. The Generate Deploy and RMIC Code wizard appears (Figure 12-49). Figure 12-49 Generating the deploy code Chapter 12. Developing EJB applications 427 By default, only those enterprise beans that have changed and require updated deployment code are selected in the wizard. Make sure all are selected and click Finish . Code is generated into the folder where your enterprise beans are located. If there is a problem with the generation of RMIC code, a window appears where you can read any error messages that are associated with the problem. You should not see any error messages during the deployment process if your Tasks view does not show any errors. Completing the EJB deployment descriptor Before we can test the entity beans, we have to update the deployment descriptor with WebSphere specific binding information. Open the deployment descriptor of the ItsoProGuideEJB EJB module. In the Overview page (Figure 12-50) add two values for the CMP Factory Connection Binding: For the JNDI name enter jdbc/ejbbank. This is the JNDI name we used for the data source definition during the setup of the WebSphere Test Environment (see “Defining a data source in the server” on page 256). For the Container authorization type select Per_Connection_Factory . This results in authorization by enterprise application. The other choice, Container , results in authorization by the EJB container. Also, check that the correct current Backend ID is selected (DB2UDBNT_V72_1). Figure 12-50 WebSphere bindings in deployment descriptor Save your changes and close the editor. 428 WebSphere Studio Application Developer Version 5 Programming Guide Changing the data source for EJB access A data source that is used to access EJBs must be specified in a specific way. Open the Server perspective and then open the server configuration of the ItsoServer and go to the Data source page: Select the Default DB2 JDBC Provider . Select the EJBBANK data source and click Edit . Select Use this data source in container managed persistence (see Figure 8-11 on page 257). Click Finish . Save the configuration. Testing the EJBs Start the ItsoServer in the Servers view. Application Developer automatically publishes your projects to the server. The Console view opens and you should see that the data source is allocated, the Web and EJB modules are loaded, and the message Server server1 open for e-business is displayed. That means that the server is now ready to serve client requests. Select the ItsoProGuideEJB EJB module and select Run on Server from the selection’s context menu. If the Server Selection dialog appears, make sure that the existing ItsoServer is selected. Select Set this server as project default (do not prompt) and click Finish . The universal test client launches and we can test our EJBs. Universal test client In this section we describe some of the operations you can perform with the universal test client (UTC). We will use the test client to find the Customer EJB home, find and create instances of the Customer bean, and send messages to those instances. Home page Figure 12-51 shows the home page of the test client as it appears in a browser window after selecting an EJB project and Run on Server : Chapter 12. Developing EJB applications 429 Figure 12-51 Universal test client: home page The test client can also be started from the Servers view by selecting a server and then Run universal test client from the server’s context menu. The two main pages to work with are the JNDI Explorer and the Bean page. The JNDI Explorer is used to locate EJBs and the Bean page is used to work with EJBs and JavaBeans. JNDI Explorer The JNDI Explorer allows you to browse or search for distributed objects (like EJBs and data sources) deployed in the server. If a distributed object cannot be found through the JNDI Explorer, it is because it was not deployed to the server successfully. Click JNDI Explorer to display the JNDI Explorer page (Figure 12-52). Tip: The default URL of the test client is http://localhost:9080/UTC/, so you can also access it through an external browser. If you want to access it from another machine, just substitute localhost with the real hostname or IP address. 430 WebSphere Studio Application Developer Version 5 Programming Guide Figure 12-52 Universal test client: JNDI Explorer After expanding the [Local EJB beans], ejb and jdbc groups all the way you can see: AccountLocalHome, CustomerLocalHome, and TransRecordLocalHome—The local home interfaces to our entity beans. BankEJBHome—The remote home interface to our session bean. jdbc/ejbbank—The data source to the EJBBANK database. To work with the Customer EJB, we click the CustomerLocalHome link, which brings us to the Beans page. Beans page The Beans page shows EJB references (homes and components), object references (any objects that are used and kept during the session), class references (classes that are loaded explicitly), and utilities (which provides various functions, such as the ability to load a class and cast an instance). In the JNDI explorer, we selected the CustomerLocalHome and therefore it shows up under EJB References once we expand that section (Figure 12-53). Chapter 12. Developing EJB applications 431 Figure 12-53 Universal test client: references on bean page The create and findByPrimaryKey methods of the home interface are visible under the CustomerLocal home. In addition, findCustomerByAccountsKey_Local and remove methods are visible as well. The finder method was automatically generated to support the customer-account relationship. Click Method Visibility and you can see from which superclasses and interfaces methods are inherited, and which ones are selected to be displayed for the customer home. To find an EJB instance by its primary key, select the findByPrimaryKey method. Note that, in this case, the method parameter type is an object type, and a non-literal one. This means that we first have to create an instance of that type to be able to call the finder method. Click findByPrimaryKey to display the method in the Parameters pane (Figure 12-54): We have to select values for two different list boxes. The first one lets you specify whether you want to pass an object as a parameter, or just a null reference instead. Select Objects. The second list then lets you select which constructor to use. Select CustomerKey(int). Note: Objects of non-literal types have to be constructed through an explicit use of the new operator. Objects of literal types, such as java.lang.String, may be constructed without using the new operator (i.e. “I am a String object”). In Java, the only literal object types are string and arrays. 432 WebSphere Studio Application Developer Version 5 Programming Guide Figure 12-54 Universal Test Client: non-literal object parameter (1) After you do that, expand the CustomerKey tree and enter a customer ID (for example, 102) and click Invoke . A CustomerLocal object is retrieved. Click Work with Object to add the result to the EJB references (Figure 12-55). Figure 12-55 Universal Test Client: findByPrimaryKey Chapter 12. Developing EJB applications 433 Expand the CustomerLocal reference and run some of the methods. For example, select the getLastName method and click Invoke to display the customer’s last name (Figure 12-56). Figure 12-56 Universal Test Client: run customer methods To remove unwanted objects from the universal test client pane, click the scissor icon that is displayed next to the object name. Working with the session bean Select the BankEJBHome in the JNDI Explorer. A session bean must be created first. Expand the home reference, select the create method and click Invoke . Click Work with Object to add a session bean reference. Select the withdraw method, enter 102-2001 as account number and 375.26 as amount. Click Invoke (Figure 12-57). Tip: If you know which EJB you would like to test and want to skip having to browse for the bean using the JNDI Explorer, you can select the bean in the EJB module and select Run on Server from its context menu. The UTC will automatically switch to the Bean page, where a home reference to the selected bean is instantiated. . substitute localhost with the real hostname or IP address. 430 WebSphere Studio Application Developer Version 5 Programming Guide Figure 12 -52 Universal test client: JNDI Explorer After expanding the. the only literal object types are string and arrays. 432 WebSphere Studio Application Developer Version 5 Programming Guide Figure 12 -54 Universal Test Client: non-literal object parameter (1) After. deployment descriptor Save your changes and close the editor. 428 WebSphere Studio Application Developer Version 5 Programming Guide Changing the data source for EJB access A data source that