Describing Enterprise Beans

The enterprise beans contained in a JAR file are laid out within the deployment descriptor’s <enterprise-beans> element. So far, we have talked about deployment descriptors for a single enterprise bean, but it is possible to package several enterprise beans in a JAR file and describe them all within a single deployment descriptor. We could, for example, have deployed the TravelAgent, ProcessPayment, Cruise, Customer, Reservation, and ReservationProcessor EJBs in the same JAR file. The deployment descriptor would look something like this:

<?xml version="1.0" encoding="UTF-8"?>
...
<ejb-jar...>
    <description>
        This Deployment includes all the beans needed to make a reservation:
        TravelAgent, ProcessPayment, Reservation, Customer, Cruise, and Cabin.
    </description>
    <enterprise-beans>
        <session>
            <ejb-name>TravelAgentEJB</ejb-name>
            <remote>com.titan.travelagent.TravelAgentRemote</remote>
            ...
        </session>
        <entity>
            <ejb-name>CustomerEJB</ejb-name>
            <remote>com.titan.customer.CustomerRemote</remote>      
            ...
        </entity>
        <session>
            <ejb-name>ProcessPaymentEJB</ejb-name>
            <remote>com.titan.processpayment.ProcessPaymentRemote</remote>
            ...
        </session>
        <message-driven>
            <ejb-name>ReservationProcessorEJB</ejb-name>
            ...
        </message-driven>
        ...
    </enterprise-beans>
    <relationships>
        ...
    </relationships>
    <assembly-descriptor>
        ...
    </assembly-descriptor>
    ...
</ejb-jar>

In this descriptor, the <enterprise-beans> element contains two <session> elements, one <entity> element, and a <message-driven> element describing the enterprise beans. Other elements within the <entity>, <session>, and <message-driven> elements provide detailed information about the enterprise beans; as you can see, the <ejb-name> element defines the enterprise bean’s name. We will discuss all the things that can go into a bean’s description later.

When CMP entity beans are deployed, all the beans that have relationships must be deployed in the same EJB-JAR file, using the same deployment descriptor. The relationships are expressed in the <relationships> element, which follows the <enterprise-beans> element.

All types of EJBs share assembly information, which is defined in the <assembly-descriptor> element that follows the <relationships> element (if it’s present). In other words, beans can share security and transactional declarations, making it simpler to deploy them consistently. For example, deployment is easier if the same logical security roles control access to all the beans, and it is easiest to guarantee that the roles are defined consistently if they are defined in one place. This strategy also makes it easier to ensure that the transaction attributes are applied consistently to all the beans, because you can declare them all at once.

Session and Entity Beans

The <session> and <entity> elements, which describe session and entity beans, usually contain many nested elements. The lists of allowable subelements are similar, so we’ll discuss the <session> and <entity> elements together.

Like the <ejb-jar> element, a <session> or <entity> element can optionally contain <description>, <display-name>, <small-icon>, and <large-icon> elements. These are fairly self-explanatory and, in any case, have the same meanings as when they appear in the <ejb-jar> element. The <description> lets you provide a comment that describes the enterprise bean; the <display-name> is used by deployment tools to represent the enterprise bean; and the two icon elements are used to represent the enterprise bean in visual environments. The icon elements must point to JPEG or GIF images within the JAR file. The other elements are more interesting:

<ejb-name> (one required)

Specifies the name of the enterprise bean component. It is used in the <methodx> element to scope method declarations to the correct enterprise bean. Throughout this book, we use a name of the form “NameEJB” as the <ejb-name> for an enterprise bean. Other common conventions use names of the form “NameBean” or “TheName”.

<home> (optional)

Specifies the fully qualified class name of the enterprise bean’s remote home interface.

<remote> (optional)

Specifies the fully qualified class name of the enterprise bean’s remote interface.

<local-home> (optional)

Specifies the fully qualified class name of the enterprise bean’s local home interface.

<local> (optional)

Specifies the fully qualified class name of the enterprise bean’s local interface.

<service-endpoint> (EJB 2.1 only; optional)

Identifies the JAX-RPC endpoint interface used with stateless session beans that are deployed as EJB Endpoints. Web services and EJB are covered in detail in Chapter 14 and Chapter 15.

<ejb-class> (one required)

Specifies the fully qualified class name of the bean class.

<session-type> (one required; session beans only)

Declares that a session bean is either stateful or stateless. This element can have one of two values: Stateful or Stateless.

<primkey-field> (optional; entity beans only)

Specifies the primary key field for entity beans that use container-managed persistence. This element’s value is the name of the field that is used as the primary key. It is not used if the bean has a compound primary key or if the entity bean manages its own persistence. In the Cabin EJB, the <primkey-field> is the id CMP field. This element is discussed in more detail in Specifying Primary Keys later in this chapter.

<prim-key-class> (one required; entity beans only)

Specifies the class of the primary key for entity beans. This element’s value is the fully qualified name of the primary key class; it makes no difference whether you are using a custom compound primary key or a simple <primkey-field> such as an Integer, String, Date, etc. If you defer definition of the primary key class to the deployer, specify the type as java.lang.Object in this element.

<persistence-type> (one required; entity beans only)

Declares that the entity bean uses either container-managed persistence or bean-managed persistence. This element can have one of two values: Container or Bean.

<reentrant> (one required; entity beans only)

Declares that the bean either allows loopbacks (reentrant invocations) or does not. This element can have one of two values: True or False. True means that the bean allows loopbacks; False means that the bean throws an exception if a loopback occurs.

<cmp-version> (optional; entity beans only)

Describes the version of container-managed persistence for which the entity bean is deployed. EJB containers must support EJB 2.1 CMP, EJB 2.0 CMP, and even EJB 1.1 CMP for backward compatibility. This element may have one of two values: 2.x for EJB 2.1 and EJB 2.0 or 1.x for EJB 1.1.

<abstract-schema-name> (optional; entity beans only)

Uniquely identifies entity beans in a JAR file so that EJB QL statements can reference them. This method is described in more detail in the section “Declaring EJB QL Elements.”

<cmp-field> (zero or more; entity beans only)

Used in entity beans with container-managed persistence. A <cmp-field> element must exist for each container-managed field in the bean class. Each <cmp-field> element may include a <description> element and must include a <field-name> element. The <description> is an optional comment describing the field. The <field-name> is required and must be the name of one of the bean’s CMP fields. It must match the method name of the abstract accessor method (e.g., deckLevel for getDeckLevel( )/setDeckLevel( )). The following portion of a descriptor shows several <cmp-field> declarations for the Cabin EJB:

<cmp-field>
    <description>This is the primary key</description>
    <field-name>id</field-name>
</cmp-field>
<cmp-field>
    <field-name>name</field-name>
</cmp-field>
<cmp-field>
    <field-name>deckLevel</field-name>
</cmp-field>
<cmp-field>
    <field-name>shipId</field-name>
</cmp-field>
<cmp-field>
    <field-name>bedCount</field-name>
</cmp-field>
<env-entry> (zero or more)

Declares an environment entry that is available through the JNDI ENC. The use of environment entries in a bean and a deployment descriptor is discussed further in the “Environment Entries” section.

<ejb-ref> (zero or more)

Declares a remote enterprise bean reference that is available through the JNDI ENC. The mechanism for making bean references available through the ENC is described in more detail later, in References to Other Beans.

< ejb-local-ref> (zero or more)

Declares a local enterprise bean reference that is available through the JNDI ENC. The mechanism for making bean references available through the ENC is described in more detail later, in References to Other Beans.

<security-role-ref> (zero or more)

Used to declare security roles in the deployment descriptor and map them into the security roles in effect for the bean’s runtime environment. This method is described in more detail in the “Security Roles” section.

<security-identity> (optional)

Specifies security identity under which a method will run. This element is described in more detail in the “Specifying Security Roles and Method Permissions” section.

<resource-ref> (zero or more)

Declares a reference to a connection factory that is available through the JNDI ENC. An example of a resource factory is the javax.sql.DataSource, which is used to obtain a connection to a database. This element is discussed in detail in References to External Resources,

<resource-env-ref> (zero or more)

Describes additional “administered objects” required by the resource. The <resource-env-ref> element and administered objects are explained in more detail in the References to External Resources, later in this chapter.

<message-destination-ref> (EJB 2.1 only: optional)

The <message-destination-ref> element is new in EJB 2.1. It describes the type of destination the EJB will send messages to. The <message-destination-ref-name> declares the JNDI ENC lookup name used by the EJB to access the destination.

<transaction-type> (one required; session beans only)

Declares either that a session bean manages its own transactions or that the container manages its transactions. This element can have one of two values: Bean or Container. A bean that manages its own transactions will not have container-transaction declarations in the <assembly-descriptor> section of the deployment descriptor.

<query> (zero or more; entity beans only)

Contains an EJB QL statement that is bound to a find or a select method. The EJB QL statement defines how the find or select method should execute at runtime. This element is described in more detail later in Section 18.5.9

Message-Driven Beans

The <message-driven> element describes message-driven bean deployments. <message-driven> elements occur after <entity> and <session> elements within the <enterprise-bean> element. Like the <entity> and <session> elements, the <message-driven> element can optionally have <description>, <display-name>, <small-icon>, and <large-icon> elements. These elements are used primarily by visual deployment tools to represent the message-driven bean. The <message-driven> element also requires the declaration of the <ejb-name>, <ejb-class>, <transaction-type>, and <security-id-entity> elements. In addition, it contains the standard JNDI ENC elements <env-entry>, <ejb-ref>, <ejb-local-ref>, <resource-ref>, and <resource-env-ref>. These are fairly self-explanatory and have the same meaning as they did in the <entity> and <session> elements.

The elements specific to the message-driven bean are different in EJB 2.1 and EJB 2.0.

EJB 2.1 elements

EJB 2.0 defined a few JMS specific elements, which have been abandoned in EJB 2.1 so that the MDB deployment descriptor can represent JMS-based MDBs as well as Connector-based MDBs. The MDB elements and properties are covered in detail in Chapter 12.

<messaging-type>

Declares the messaging interfaces used by the MDB. For JMS-based MDBs, the messaging interface is always going to be javax.jms.MessageListener, but for other J2EE Connector-based MDBs it might be something different. If this element is omitted, the type is assumed to be javax.jms.MessageListener.

<message-destination-type>

Designates the type of destination from which the MDB receives messages. The allowed values for JMS-based MDBs are javax.jms.Queue and javax.jms.Topic. A J2EE Connector-based MDB might use some other type.

<activation-config>

Describes the messaging properties of the MDB. The property names and values used in <activation-config> depend on the type of message service used, but EJB 2.1 defines a set of fixed properties for JMS-based message-driven beans, including:

acknowledgeMode

The container considers this property only if the message-driven bean uses bean-managed transactions; with container-managed transactions, it is ignored. It determines which type of acknowledgment it uses; its value can be either Auto-acknowledge or Dups-ok-acknowledge. The first value acknowledges messages immediately; the second can delay acknowledgment to benefit performance but may result in duplicate or redelivered messages.

messageSelector

Message selectors allow an MDB to be more selective about the messages it receives from a particular topic or queue. Message selectors use Message properties as criteria in conditional expressions.[54] These conditional expressions use Boolean logic to declare which messages should be delivered to a client. The syntax of message selectors can cause problems with XML processing. See CDATA Sections later in this chapter.

destinationType

The <message-destination-type> and the destinationType activation configuration property are redundant for JMS-based MDBs—but not for other types of J2EE Connector-based MDBs. That’s because the activation configuration properties of Connector-based MDBs and JMS-based MDBs are completely different. It’s important that the <message-destination-type> be specified for both JMS-based and Connector-based MDBs.

subscriptionDurablity

When a JMS-based MDB uses a javax.jms.Topic, the subscription must be declared to be either Durable or NonDurable . A Durable subscription outlasts an MDB container’s connection to the JMS provider; if the EJB server suffers a partial failure, shuts down, or otherwise disconnects from the JMS provider, the messages that it would have received are not lost. A NonDurable subscription means that any messages the bean would have received while it was disconnected are lost.

EJB 2.0 elements

EJB 2.0 supports only one type of Message Driven Bean, the JMS-based MDB. Since only one messaging API is supported, EJB 2.0 defined JMS-specific elements, which were replaced in EJB 2.1 with JMS-specific properties.

<message-selector>

Message selectors allow an MDB to be more selective about the messages it receives from a particular topic or queue. Message selectors use Message properties as criteria in conditional expressions. These conditional expressions use Boolean logic to declare which messages should be delivered to a client. The syntax of message selectors can cause problems with XML processing. See the “CDATA Sections” sidebar later in this chapter.

<acknowledge-mode>

The container considers this element only if the message-driven bean uses bean-managed transactions; with container-managed transactions, it is ignored. It determines which type of acknowledgment it uses; its value can be either Auto-acknowledge or Dups-ok-acknowledge. The first acknowledges messages immediately; the second can delay acknowledgment to benefit performance, but may result in duplicate or redelivered messages.

<message-driven-destination>

This element designates the type of destination to which the MDB subscribes or listens. The allowed values for this element are javax.jms.Queue and javax.jms.Topic.

<subscription-durability>

When a MDB uses a javax.jms.Topic, the subscription must be declared to be either Durable or NonDurable . A Durable subscription outlasts an MDB container’s connection to the JMS provider; if the EJB server suffers a partial failure, shuts down, or otherwise disconnects from the JMS provider, the messages that it would have received are not lost. A NonDurable subscription means that any messages the bean would have received while it was disconnected are lost.

Specifying Primary Keys

If a single field in the bean can serve naturally as a unique identifier, you can use that field as the primary key. Optionally, a custom primary key can be used as a compound primary key. In the Cabin EJB, for example, the primary key type could be the CabinPK, which is mapped to the bean class fields id and name, as shown here (the CabinBean is using bean-managed persistence to better illustrate):

public class CabinBean implements javax.ejb.EntityBean {

    public int id;
    public String name;
    public int deckLevel;
    public int ship;
    public int bedCount;
 
    public CabinPK ejbCreate(int id, String name) {
        this.id = id;
        this.name = name;
        return null;
    }
    ...
}

In Chapter 4, we used the appropriate primitive wrapper, java.lang.Integer, instead of the custom CabinPK class, and defined the CabinBean as:

public class CabinBean implements javax.ejb.EntityBean {

    public int id;
    public String name;
    public int deckLevel;
    public int ship;
    public int bedCount;
 
    public Integer ejbCreate(int id) {
        this.id = id;
        return null;
    }
    ...
}

This simplifies things a lot. Instead of taking the time to define a custom primary key like CabinPK, we simply use the appropriate wrapper. To do this, we need to add a <primkey-field> element to the Cabin EJB’s deployment descriptor, so it knows which field to use as the primary key. We also need to change the <prim-key-class> element to state that the Integer class is being used to represent the primary key. Here’s how the Cabin EJB’s deployment descriptor would need to change to use Integer as the primary key field:

<entity>
    <description>
        This Cabin enterprise bean entity represents a cabin on 
        a cruise ship.
    </description>
    <ejb-name>CabinEJB</ejb-name>
    <home>com.titan.cabin.CabinHome</home>
    <remote>com.titan.cabin.Cabin</remote>
    <ejb-class>com.titan.cabin.CabinBean</ejb-class>
    <persistence-type>Bean</persistence-type>
    <prim-key-class>java.lang.Integer</prim-key-class>
    <reentrant>False</reentrant>

    <cmp-field><field-name>id</field-name></cmp-field>
    <cmp-field><field-name>name</field-name></cmp-field>
    <cmp-field><field-name>deckLevel</field-name></cmp-field>
    <cmp-field><field-name>ship</field-name></cmp-field>
    <cmp-field><field-name>bedCount</field-name></cmp-field>
    <primkey-field>id</primkey-field>
</entity>

Simple primary key fields are not limited to the primitive wrapper classes (Byte, Boolean, Integer, and so on); any container-managed field can be used as a primary key, as long as it is serializable. String types are probably the most common, but other types, such as java.lang.StringBuffer, java.util.Date, or even java.util.Hashtable are also valid. Custom types can also be primary keys, provided they are serializable. Use common sense when choosing a primary key: since it is used as an index to the data in the database, it should be lightweight.

Deferring primary key definition

Container-managed persistence makes it possible for the bean developer to defer defining the primary key, leaving key definition to the bean deployer. This feature might be needed if, for example, the primary key is generated by the database and is not a container-managed field in the bean class. Containers that have a tight integration with database or legacy systems that automatically generate primary keys might use this approach. It is also an attractive approach for vendors that sell shrink-wrapped beans, because it makes the bean more portable. Here’s how an entity bean using container-managed persistence defers the definition of the primary key to the deployer:

// bean class for bean that uses a deferred primary key 
public class HypotheticalBean implements javax.ejb.EntityBean {
    ...
    public java.lang.Object ejbCreate( ) {
        ...
        return null;
    }
    ...
}

// home interface for bean with deferred primary key
public interface HypotheticalHome extends javax.ejb.EJBHome {
    public Hypothetical create( ) throws ...;
    public Hypothetical findByPrimaryKey(java.lang.Object key) throws ...;
}

Here’s the relevant portion of the deployment descriptor:

// primkey-field declaration for the Hypothetical bean
...
<entity>
    <ejb-name>HypotheticalEJB</ejb-name>
    ...
    <persistence-type>Container</persistence-type>
    <prim-key-class>java.lang.Object</prim-key-class>
    <reentrant>False</reentrant>
    <cmp-field><field-name>creationDate</field-name></cmp-field>
    ...
</entity>

Because the primary key is of type java.lang.Object, the client application’s interaction with the bean’s key is limited to the Object type and its methods.

Environment Entries

A deployment descriptor can define environment entries, values similar to properties the bean can read when it is running. The bean can use environment entries to customize its behavior, find out about how it is deployed, and so on.

The <env-entry> element is used to define environment entries. This element contains the subelements <description> (optional), <env-entry-name> (required), <env-entry-type> (required), and <env-entry-value> (optional). Here is a typical <env-entry> declaration:

<env-entry>
    <env-entry-name>minCheckNumber</env-entry-name>
    <env-entry-type>java.lang.Integer</env-entry-type>
    <env-entry-value>2000</env-entry-value>
</env-entry>

The <env-entry-name> is relative to the "java:comp/env" context. For example, the minCheckNumber entry can be accessed using the path "java:comp/env/minCheckNumber" in a JNDI ENC lookup:

InitialContext jndiContext = new InitialContext( );
Integer miniumValue = (Integer)
    jndiContext.lookup("java:comp/env/minCheckNumber");

The <env-entry-type> can be of type String or one of several primitive wrapper types, including Integer, Long, Double, Float, Byte, Boolean, and Short.

The <env-entry-value> is optional. The value can be specified by the bean developer or deferred to the application assembler or deployer.

References to Other Beans

In EJB, references to other beans can be local or remote. In EJB 2.1 you can also reference a web Service object that provides access to an EJB endpoint (see Chapter 15 to learn more about EJB endpoints).

Remote references

The <env-ref> element defines references to other beans within the JNDI ENC. This makes it much easier for beans to reference other beans; a bean can use JNDI to look up a reference to the home interface for any bean in which it is interested.

The <env-ref> element contains the subelements <description> (optional), <ejb-ref-name> (required), <ejb-ref-type> (required), <remote> (required), <home> (required), and <ejb-link> (optional). Here is a typical <env-ref> declaration:

<ejb-ref>
    <ejb-ref-name>ejb/ProcessPaymentHomeRemote</ejb-ref-name>
    <ejb-ref-type>Session</ejb-ref-type>
    <home>com.titan.processpayment.ProcessPaymentHomeRemote</home>
    <remote>com.titan.processpayment.ProcessPaymentHomeRemote</remote>
</ejb-ref>

The <ejb-ref-name> is relative to the "java:comp/env" context. It is recommended but not required that the name be placed under a subcontext of ejb/. Following this convention, the path used to access the ProcessPayment EJB’s home would be "java:comp/env/ejb/ProcessPaymentHomeRemote“. Here’s how a client bean would use this context to look up a reference to the ProcessPayment EJB:

InitialContext jndiContext = new InititalContext( );
Object ref = jndiContext.lookup("java:comp/env/ejb/ProcessPaymentHomeRemote");
ProcessPaymentHomeRemote home = (ProcessPaymentHomeRemote)
    PortableRemoteObject.narrow(ref, ProcessPaymentHomeRemote.class);

The <ejb-ref-type> can have one of two values, Entity or Session, according to whether it is an entity or a session bean.

The <home> element specifies the fully qualified class name of the bean’s home interface; the <remote> element specifies the fully qualified class name of the bean’s remote interface.

If the bean referenced by the <ejb-ref> element is deployed in the same deployment descriptor (i.e., it is defined under the same <ejb-jar> element), the <ejb-ref> element can be linked to the bean’s declaration using the <ejb-link> element. If, for example, the TravelAgent bean uses a reference to the ProcessPayment EJB that is declared in the same deployment descriptor, the <ejb-ref> elements for the TravelAgent bean can use an <ejb-link> element to map its <ejb-ref> elements to the ProcessPayment EJB. The <ejb-link> value must match one of the <ejb-name> values declared in the same deployment descriptor. Here’s a portion of a deployment descriptor that uses the <ejb-link> element:

<ejb-jar>
    <enterprise-beans>
        <session>
            <ejb-name>TravelAgentEJB</ejb-name>
            <remote>com.titan.travelagent.TravelAgentRemote</remote>
            ...
            <ejb-ref>
                <ejb-ref-name>ejb/ProcessPaymentHome</ejb-ref-name>
                <ejb-ref-type>Session</ejb-ref-type>
                <home>com.titan.processpayment.ProcessPaymentHomeRemote</home>
                <remote>com.titan.processpayment.ProcessPaymentRemote</remote>
                <ejb-link>ProcessPaymentEJB</ejb-link>
            </ejb-ref>
            ...
        </session>

        <session>
            <ejb-name>ProcessPaymentEJB</ejb-name>
            <remote>com.titan.processpayment.ProcessPaymentRemote</remote>
            ...
        </session>
        ...
    </enterprise-beans>
    ...
</ejb-jar>

In most cases, you are better off using the <ejb-local-ref> element to obtain references to beans in the same JAR file, unless the referenced enterprise bean does not have a set of local component interfaces. If that’s the situation, use the <ejb-link> element with the <ejb-ref> element to get a remote reference to the enterprise bean.

Local references

The deployment descriptor also provides a special set of tags, the <ejb-local-ref> elements, to declare local EJB references, i.e., references to enterprise beans that are co-located in the same container and deployed in the same EJB JAR file. The <ejb-local-ref> elements are declared immediately after the <ejb-ref> elements:

<ejb-local-ref>
    <ejb-ref-name>ejb/CruiseHomeLocal</ejb-ref-name>
    <ejb-ref-type>Entity</ejb-ref-type>
    <local-home>com.titan.cruise.CruiseHomeLocal</local-home>
    <local>com.titan.cruise.CruiseLocal</local>
    <ejb-link>CruiseEJB</ejb-link>
</ejb-local-ref>
<ejb-local-ref>
    <ejb-ref-name>ejb/CabinHomeLocal</ejb-ref-name>
    <ejb-ref-type>Entity</ejb-ref-type>
    <local-home>com.titan.cabin.CabinHomeLocal</local-home>
    <local>com.titan.cabin.CabinLocal</local>
    <ejb-link>CabinEJB</ejb-link>
</ejb-local-ref>

The <ejb-local-ref> element defines a name for the bean within the ENC, declares the bean’s type, and gives the names of its local component interfaces. These elements should be linked explicitly to other co-located beans using the <ejb-link> element, but it’s not required—the application assembler or deployer can do it later. The value of the <ejb-link> element within the <ejb-local-ref> must equal the <ejb-name> of the appropriate bean in the same JAR file.

At deployment time, the EJB container’s tools map the local references declared in the <ejb-local-ref> elements to entity beans that are co-located in the same container system.

Enterprise beans declared in the <ejb-local-ref> elements are local enterprise beans and so do not require the use of the PortableRemoteObject.narrow( ) method to narrow the reference. Instead, you can use a simple native cast operation:

InitialContext jndiContext = new InititalContext( );
CabinHome home = (CabinHome)
    jndiContext.lookup("java:comp/env/ejb/CabinHomeLocal");

References to External Resources

Enterprise beans also use the JNDI ENC to look up external resources, such as database connections, that they need to access. The mechanism for doing this is similar to the mechanism used for referencing other beans and environment entries: the external resources are mapped into a name within the JNDI ENC namespace. For external resources, the mapping is performed by the <resource-ref> element.

The <resource-ref> element contains the <description> (optional), <res-ref-name> (required), <res-type> (required), and <res-auth> (required) subelements.

Here is a <resource-ref> declaration used for a DataSource connection factory:

<resource-ref>
    <description>DataSource for the Titan database</description>
    <res-ref-name>jdbc/titanDB</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
</resource-ref>

The <res-ref-name> is relative to the "java:comp/env" context. Although not a requirement, it is a good idea to place connection factories under a subcontext that describes the resource type. For example:

  • jdbc/ for a JDBC DataSource factory

  • jms/ for a JMS QueueConnectionFactory or TopicConnectionFactory factory

  • mail/ for a JavaMail session factory

  • url/ for a javax.net.URL factory

Here is how a bean would use JNDI to look up a resource—in this case, a DataSource:

InitialContext jndiContext = new InitialContext( );
DataSource source = (DataSource)
    jndiContext.lookup("java:comp/env/jdbc/titanDB");

The <res-type> element declares the fully qualified class name of the connection factory. In this example, the <res-type> is javax.sql.DataSource.

The <res-auth> element tells the server who is responsible for authentication. It can have one of two values: Container or Application. If Container is specified, the container will automatically perform authentication (sign-on or login) to use the resource, as specified at deployment time. If Application is specified, the bean itself must perform authentication before using the resource. Here’s how a bean might sign on to a connection factory when Application is specified for <res-auth>:

InitialContext jndiContext = new InitialContext( );
DataSource source = (DataSource)
    jndiContext.lookup("java:comp/env/jdbc/titanDB");

String loginName = ejbContext.getCallerPrincipal( ).getName( );
String password = ...; // get password from somewhere

// use login name and password to obtain a database connection
java.sql.Connection con = source.getConnection(loginName, password);

Additional administered objects

In addition to the resource factory described in the <resource-ref> element, some resources may have other administered objects that need to be obtained from the JNDI ENC. An administered object is a resource that is configured at deployment time and managed by the EJB container at runtime. For example, to use JMS, the bean developer must obtain both a JMS factory object and a destination object:

TopicConnectionFactory factory = (TopicConnectionFactory)
    jndiContext.lookup("java:comp/env/jms/TopicFactory");
        
Topic topic = (Topic)
    jndiContext.lookup("java:comp/env/ejb/TicketTopic");

Both the JMS factory and destination are administered objects that must be obtained from the JNDI ENC. The <resource-ref> element declares the JMS factory, while the <resource-env-ref> element declares the destination:

<resource-ref>
    <res-ref-name>jms/TopicFactory</res-ref-name>
    <res-type>javax.jms.TopicConnectionFactory</res-type>
    <res-auth>Container</res-auth>
</resource-ref>
<resource-ref>
    <res-ref-name>jdbc/titanDB</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
</resource-ref>
<resource-env-ref>
    <resource-env-ref-name>jms/TicketTopic</resource-env-ref-name>
    <resource-env-ref-type>javax.jms.Topic</resource-env-ref-type>
</resource-env-ref>

At deployment time, the deployer maps the JMS TopicConnectionFactory or QueueConnectionFactory and the Topic or Queue declared by the <resource-ref> and <resource-env-ref> elements to a JMS factory and topic.

Shareable resources

When several enterprise beans in a unit-of-work or transaction all use the same resource, you will want to configure your EJB server to share that resource. Sharing a resource means that each enterprise bean will use the same connection to access the resource (e.g., database or JMS provider), a strategy that is more efficient than using separate resource connections.

In the TravelAgent EJB, the bookPassage( ) method uses the ProcessPayment EJB and the Reservation EJB to book a passenger on a cruise. If the enterprise beans use the same database, they should share their resource connection for efficiency. Enterprise JavaBeans containers share resources by default, but resource sharing can be turned on or off explicitly with the <resource-ref> element:

<resource-ref>
    <res-ref-name>jdbc/titanDB</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
   <res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>

<res-sharing-scope> is an optional element that may be declared as either Shareable, indicating that connections should be shared in local transactions, or Unshareable, indicating that they should not. If it is not specified, the default is Shareable.

Occasionally, advanced developers may run into situations where resource sharing is not desirable, and having the option to turn off resource sharing is beneficial. Unless you have a good reason for turning off resource sharing, I recommend that you use Shareable resources.

The <service-ref> Deployment Element (EJB 2.1)

EJB 2.1 includes a new element, <service-ref>, that is used to bind a JAX-RPC Service to the JNDI ENC. The modified TravelAgent EJB declares a <service-ref> element that looks like this:

<ejb-jar 
 xmlns="http://java.sun.com/xml/ns/j2ee"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

                      xmlns:chargeIt="http://charge-it.com/Processor"
 xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
                    http://java.sun.com/xml/ns/j2ee/ejb-jar_2_1.xsd"
 version="2.1">
   <enterprise-beans>
     <session>
       <ejb-name>TravelAgentEJB</ejb-name>
       ...
       <service-ref>
                  <service-ref-name>service/ChargeItProcessorService</service-ref-name>
                  <service-interface>com.charge_it.ProcessorService</service-interface>
                  <wsdl-file>META-INF/wsdl/ChargeItProcessor.wsdl</wsdl-file>
                  <jaxrpc-mapping-file>META-INF/mapping.xml</jaxrpc-mapping-file>
                  <service-qname>chargeIt:ProcessorService</service-qname>
                         </service-ref>
      ...
    </session>
  </enterprise-beans>
  ...
</ejb-jar>

The <service-ref-name> element declares the JNDI ENC lookup name of the JAX-RPC Service: it is always relative to the "java:comp/env" context. For more details about various web service deployment descriptors, see Chapter 15.

Security Roles

The <security-role-ref> element defines the security roles that are used by a bean and maps them into the security roles that are in effect for the runtime environment. It can contain three subelements: an optional <description>, a <role-name> (required), and an optional <role-link>.

Here’s how security roles are defined. When a role name is used in the EJBContext.isCallerInRole(String roleName) method, the role name must be statically defined (it cannot be derived at runtime) and it must be declared in the deployment descriptor using the <security-role-ref> element:

<-- security-role-ref declaration for Account bean -->
<entity>
    <ejb-name>AccountEJB</ejb-name>
    ...
    <security-role-ref>
        <description>
            The caller must be a member of this role in 
            order to withdraw over $10,000
        </description>
        <role-name>Manager</role-name>
        <role-link>Administrator</role-link>
    </security-role-ref>
    ...
</entity>

The <role-name> defined in the deployment descriptor must match the role name used in the EJBContext.isCallerInRole( ) method. Here is how the role name is used in the bean’s code:

// Account bean uses the isCallerInRole( ) method
public class AccountBean implements EntityBean {
    int id;
    double balance;
    EntityContext context;

    public void withdraw(Double withdraw) throws AccessDeniedException {
        
        if (withdraw.doubleValue( ) > 10000) {
            boolean isManager = context.isCallerInRole("Manager");
            if (!isManager) {
                // only Managers can withdraw more than 10k
                throw new AccessDeniedException( );
            }
        }
        balance = balance - withdraw.doubleValue( );
    }
    ...
}

The <role-link> element is optional; it can be used to map the role name used in the bean to a logical role defined in a <security-role> element in the <assembly-descriptor> section of the deployment descriptor. If no <role-link> is specified, the deployer must map the <security-role-ref> to an existing security role in the target environment.

Declaring EJB QL Elements

EJB QL statements are declared in <query> elements in an entity bean’s deployment descriptor. In the following listing, you can see that findByName( ) and ejbSelectShips( ) methods were declared in the <query> elements of the Cruise EJB deployment descriptor:

<ejb-jar>
    <enterprise-beans>
        <entity>
            <ejb-name>ShipEJB</ejb-name>
            ...
            <abstract-schema-name>Ship</abstract-schema-name>
            ...
        </entity>
        <entity>
            <ejb-name>CruiseEJB</ejb-name>
            ...
            <reentrant>False</reentrant>
            <abstract-schema-name>Cruise</abstract-schema-name>
            <cmp-version>2.x</cmp-version>
            <cmp-field>
                <field-name>name</field-name>
            </cmp-field>
            <primkey-field>id</primkey-field>
            <query>
                <query-method>
                    <method-name>findByName</method-name>
                    <method-params> 
                  <mehod-param>java.lang.String</method-param>
                    </method-params>
                </query-method>
                <ejb-ql>
                  SELECT OBJECT(c) FROM Cruise c WHERE c.name = ?1
                </ejb-ql>
            </query>
            <query>
                <query-method>
                    <method-name>ejbSelectShips</method-name>
                    <method-params></method-params>
                </query-method>
                <result-type-mapping>Remote</result-type-mapping>
                <ejb-ql>
                    SELECT OBJECT(s) FROM Ship AS s
                </ejb-ql>
            </query>
        </entity>
    </enterprise-beans>
</ejb-jar>

The <query> element contains two primary elements; the <query-method> element identifies the find method of the remote or local home interface, and the <ejb-ql> element declares the EJB QL statement. The <query> element binds the EJB QL statement to the proper find method. The syntax of EJB QL may cause problems for the XML parser; you may need to wrap the query in a CDATA section. See the sidebar “CDATA Sections” for more details.

When two find methods in the local and remote home interfaces have the same method name and parameters, the query declaration applies to both methods. The container returns the proper type for each query method: queries that use the remote home return one or more remote EJB objects, and queries that use the local home return one or more local EJB objects. This feature allows you to define the behavior of both the local and remote home find methods using a single <query> element—which is convenient if you want local clients to have access to the same find methods as remote clients.

The <result-type-mapping> element can be used to declare whether a select method should return local or remote EJB objects. The value Local indicates that a method should return local EJB objects; Remote indicates remote EJB objects. If the <result-type-mapping> element is not declared, the default is Local. In the <query> element for the ejbSelectShips( ) method, the <result-type-mapping> is declared as Remote, which means the query should return remote EJB object types (i.e., remote references to the Ship EJB).

Every entity bean that is referenced in an EJB QL statement must have an abstract schema name , which is declared by the <abstract-schema-name> element. No two entity beans may have the same abstract schema name. In the entity element that describes the Cruise EJB, the abstract schema name is Cruise, while the Ship EJB’s abstract schema name is Ship. The <ejb-ql> element contains an EJB QL statement that uses this identifier in its FROM clause.

In Chapter 7, you learned that the abstract persistence schema of an entity bean is defined by its <cmp-field> and <cmr-field> elements. The abstract schema name is also an important part of the abstract persistence schema. EJB QL statements are always expressed in terms of the abstract persistence schemas of entity beans. EJB QL uses the abstract schema names to identify entity bean types, the container-managed persistence (CMP) fields to identify specific entity bean data, and the container-managed relationship (CMR) fields to create paths for navigating from one entity bean to another.



[54] Message selectors are also based on message headers, which are outside the scope of this chapter.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.221.126.56