EJB Call Builder
In this topic ...
Related Topics ...
Use the EJB Call builder to create a link to an Enterprise Java™ Bean (EJB). Once a link is established, your model will have access to the methods associated with the bean's home and remote interfaces.
The EJB Call builder is similar in function to the Linked Java Object builder. Both give you access to the methods of an external Java object. When you link to an EJB, you gain access to the bean's home and remote interfaces. The home interface includes methods for finding and creating the bean object, and the remote interface includes methods that implement the bean's business logic.
With the Linked Java Object builder, you only need to specify where its class file is located, relative to the WEB-INF\classes directory. Linking to an EJB, however, is more complicated. Beans are deployed in an application server known as the EJB container. When you configure the EJB Call builder specify the location of the application server and how it should look up the bean.
Before you try to use the EJB Call builder, verify that your system is configured properly. The EJB should be properly deployed. Please refer to you application server documentation for instructions on deploying a bean.
The EJB Call Builder generates three objects: the EJB Home Interface reference, EJB Remote Interface reference, and a builder-specific helper object. These objects are all put into the model as linked objects with the following names:
- EJB Home Interface: <BuilderName>HomeEJB
- Remote Interface: <BuilderName>
- Builder specific helper object: <BuilderName>Util
Note that the EJB Home Interface and Builder specific helper object are hidden. They will not be displayed in Action list choosers. However, we can use the WebAppAccess API to access them. For example, the following method will support this access: webAppAccess.getVariables().getObject("<BuilderName>HomeEJB");.
Quick Tips
- The data that a bean returns must be serialized. String objects may be used since they are serializable. If we need to return an XML object, create an object that implements Serializable or just return a String object. We can call toString() on your XML object, return that, and then recreate the XML object from the String.
- Make sure the Factory is configured to communicate with the application server. To successfully link to an EJB, the Factory must be configured to communicate with the application server in which EJBs are deployed. The Factory class path must include:
- Location of the library of classes required by the application server to access the beans
- Location of the home and remote interfaces of each deployed bean
- For successful linking and bean access, the EJB must be running concurrently with the Factory.
Specifying Inputs
The EJB Call builder takes the inputs described in the table below. For help on inputs common to many or all builders such as those in the Properties and HTML Attributes input groups, see "Using the Builder Call Editor."
Input name Description Name Enter a name for this builder call. The designer tool displays this name in the builder call list. EJB to call Select an EJB from the drop-down list. EJBs displayed in the list result from introspecting the ejb-jar.xml files found in any available EJB jars.
Cache Home Interface Enable to turn on caching and improve performance. This check box determines whether or not the EJB Home interface is cached or looked up for each client. Disabling caching often degrades performance since a look-up is required for each client.
Remote JNDI Server Definitions JNDI Context Factory Select the appropriate Context Factory class based on the type of remote JNDI server. This corresponds to the environment property Context.INITIAL_CONTEXT_FACTORY.
The syntax of this entry depends on the application server or JNDI server you are using. For example,
- WebSphere: com.ibm.ws.naming.util.WsnInitCtxFactory
JNDI URL Select the URL of the remote JNDI server. This entry corresponds to the environment property Context.PROVIDER_URL required for creating an initial naming context.For example:
- WebSphere: iiop://host_name:9001
Principal The principal name to be used in binding to the JNDI Server that specifies the identity of the user for authentication to the remote JNDI server. This value is typically a user name or ID. We can also type a reference to a variable, such as ${Variables/principal}.
Each EJB server has its own way of specifying which roles and users have access to certain bean methods. For more information, refer to the documentation accompanying your EJB server.
Application servers handle this input in different ways. For example:
On WebSphere - The Principal and credentials inputs you provide in this builder will override the ones provided by the datasource on the application server.
Credentials Password of the user for authentication to the remote JNDI server. This value is typically the password associated with the user name entered in the previous step. Constructor Constructor Source Select one of the following constructor operations:
- Create - Select to generate a constructor by filling in the appropriate information and then pressing the "Generate" button.
- Specify - Select to use a method or method call in your model as the method which creates an EJB reference. The selected method must return an EJB remote interface, or a collection containing EJB remote interfaces.
Instantiate Method (Available when Constructor Source is "Specify.") Choose the method or method call in your model to use to create an EJB reference.
The method must return an EJB remote interface, or a collection containing EJB remote interfaces.
Create Method Select a value from the list of create methods available in the EJB home interface. Create Arguments Arguments used Should present a list of the argument types from the selected create method. Finder Method (Entity EJBs only) For an entity EJB, select a finder method from the EJB Home Interface. This method will be used to locate the entity bean. See note below.
Finder Method Arguments Provide values for any arguments associated with the finder method selected above. Generate Button After filling in the appropriate information in the rest of the Constructor group inputs, press "Generate" to generate the constructor used to create the EJB Remote Interface. Constructor Use the reference chooser to select a constructor. If you prefer, we can write your own EJB Constructor by entering constructor code directly into the input area..
If this input is left blank, the builder will try to use a no-argument create() call on the EJB Home Interface to create the EJB Remote Interface.
EJB Info EJB name (Normally provided automatically by this builder.) Name of the EJB s specified in ejb-jar.xml file.
JNDI Name (Normally provided automatically by this builder.) EJB JNDI Name
Remote Interface (Normally provided automatically by this builder.) Fully-qualified Remote Interface Name
Home Interface (Normally provided automatically by this builder.) Fully-qualified Home Interface Name
Setting up your EJB environment
Before using this builder, copy the EJB client jar into <project root>/WEB-INF/work/classes (or directory defined by property bowstreet.dynamic.class.load.path in bowstreet.properties if not /work/classes) and into <project root>/WEB-INF/lib. This copy operation will make the EJB classes available to both the Designer and the Factory servlet. ( In a non-development environment, when it is not necessary to have the EJB classes available for the Designer, it is only necessary to put the jar into <project root>/WEB-INF/lib.) For more about working with jar files see, Adding JARs to Factory Environments.
It is also necessary to put the JNDI client classes into the Factory class path if the application server hosting the EJBs and the application server hosting the Factory are running in different JVMs. For example, if the Factory is hosted on one application server and the EJBs are running on a second application server, you will need to put the second application server's JNDI client JAR file into <project root>/WEB-INF/lib.
Steps to link to an EJB
You generally follow these steps to link an EJB into a model:
- Open a new EJB Call builder and give it a name.
- Select the desired EJB from the EJB drop-down list.
This list should be populated by the EJB s available in the jars which were put into <project root>/WEB-INF/work/classes. Note that the list will not include EJBs which have only a local home interface, since it would not be appropriate to try to call local interfaces in EJBs outside of the Factory .ear file.
- Open the "EJB Info" input group, and check the information. In most cases, the appropriate values will be filled in for you. In some cases, if the EJB builder does not recognize the deployment specific descriptor, or if the deployment specific descriptor is not available, you might need to fill in the EJB JNDI name with the appropriate value.
- Check the "Cache Home Interface" checkbox if you want to cache home interfaces. (This will provide significantly better performance).
- Fill in the JNDI information if the EJB is not located on the same application server as the Factory.
- Open the Constructor input group. In the simplest case, if the EJB being called is a Session bean with a no-arg create() method, leave all of the inputs blank; otherwise:
a. Select a create() method for the bean. The dropdown list should be populated based on the create() methods available in the EJB.
b. For each of the arguments to the create() method, select the appropriate value in the argument table. The inputs can be either literal values, or indirect values.
c. If the EJB is an entity bean, you will also select a Finder method, and Finder method arguments. Note that the dropdown list is only populated by the Finder methods which return a single bean, and not ones which return a collection of beans.
d. Click the "Generate" button. This will generate a constructor for the Remote Interface. This constructor should work in most cases. We can make changes by hand if you want a different constructor.
- Click "Apply" or "OK."
Working with Linked Objects
To use the EJB Call builder effectively, be familiar with standard Factory techniques for dealing with linked objects. For example, there are two ways of calling a method of the linked Account EJB from within a script. You might use:
Object o =webAppAccess.getVariables().getObject("Account");
examples.ejb.basic.beanManaged.Account account = (examples.ejb.basic.beanManaged.Account)o;
balance = account.getBalance();
or
Double balance = (Double)webAppAccess.callMethod("Account.balance");
For most purposes these approaches are equivalent.
When you call a method of the remote interface, the Factory first verifies if it has already instantiated that object. If not, it calls the constructor method (default or custom) to do so. Once the object is instantiated, its object reference will exist until you explicitly destroy the object, by calling (for example):
webAppAccess.getVariables().setObject("Account", null);
An example custom constructor for the account bean might look as follows:
1 String accountID = webAppAccess.getVariables().getString("accountID");
2 Variable home = webAppAccess.getVariables().getVariable("AccountHome");
3 examples.ejb.basic.beanManaged.AccountHome accountHome =
4 (examples.ejb.basic.beanManaged.AccountHome)home.getValue();
5 Object account = null;
6 try {
7 account = accountHome.findByPrimaryKey(accountID);
8 } catch(Exception error) {
9 try {
10 account = accountHome.create(accountID, 0);
11 } catch(Exception e) {}
12 webAppAccess.getVariables().setString("accountBalance","");
}
13 return account;
The line-by-line action in this code sample is as follows: (1) Get the user's account ID from a text input field. (2-5) Fetch the home object, which is used to create and find remote objects. (6,7) Try to find an account with the given ID number. (8) If no account with that ID is found, some sort of "ObjectNotFound" exception is thrown, which we can catch, (9-12) If exception occurs, create a new account with the given ID and starting balance. (13) Return this information.
Class Cast Exceptions When Accessing objects in a Collection of Entity Beans
If a class cast exception such as this
com.bowstreet.util.WrappedException: java.lang.ClassCastException:
org.omg.stub.javax.ejb._EJBObject_Stub
at genjava._dd.Employee_getAttributeValue(_dd.java:322)
at java.lang.reflect.Method.invoke(Native Method)
is encountered when accessing the beans in a returned Collection (if a "findAll" type method has been executed), an EntityBean Remote Interface was expected, but a generic object stub was returned.
It is likely that the objects in the returned collection need to be narrowed to the correct type. For example, if the EJB Call set up an employees Variable for the Collection being returned, you could convert the objects in that Collection as follows:
{
java.util.Collection c =
(java.util.Collection)webAppAccess.getVariables().getObject("employees");
java.util.Iterator iter = c.iterator();
java.util.Collection c2 = new java.util.Vector();
while (iter.hasNext())
{
Object o = iter.next();
o = javax.rmi.PortableRemoteObject.narrow(o, com.bowstreet.ejb.Employee.class);
c2.add(o);
}
webAppAccess.getVariables().setObject("employees", c2);
}
You would substitute your variable for "employees" and the class name you expect for "com.bowstreet.ejb.Employee" in the example.
Advanced Use of this Builder
The EJB Call builder supports some advanced operations. The following sections discuss some of these techniques.
Generating Constructors for the EJB
We can leave blank either the Create Method and Create Method Arguments, and/or the Finder Method and Finder Method Arguments (in the case of an entity EJB) blank. When these inputs are empty, the builder will generate a method that generally based on what information is provided. If no method is specified, and no method is generated, the builder will default to using a default no-arg "create()" call on the EJB home interface.
Dealing with Collections of EJBs
In the case of entity beans, we can specify a finder method that returns a collection of EJBs. In this case, the EJB LJO variable reference will contain the collection object instead of an EJB remote interface object. It is up to you to know what object is in the variable, and to deal with it appropriately.
Clearing a Reference to the Current EJB Object
There are two ways we can clear an EJB object reference:
- <EJB builder name>ClearRemoteReference - This method sets the EJB LJO variable reference in the Webapp to null, which will force the EJB builder to recreate the EJB remote reference. This technique might be useful if you want to use a single EJB builder to reference multiple entity EJBs.
In this case we can specify a finder method which takes a variable as the input to the finder method, then when you want to reference the EJB set the variable to the appropriate value and call the xxxClearRemoteReference method before calling methods on the EJB remote variable.
- <EJB builder name>Util.flushHomeCache - This is the utility class created by each EJB builder. This class is hidden in the method chooser widget in the builder call UI, but we can access the class using the following method: webAppAccess.getVariables().getObject()