Oracle9iAS Containers for J2EE Enterprise JavaBeans Developer's Guide and Reference Release 2 (9.0.2) Part Number A95881-01 |
|
This chapter discusses how to extend beyond the basics mentioned in each of the previous chapters. This chapter covers the following subjects:
You must retrieve an EJB reference to the target bean in order to execute methods on that bean. In OC4J, you use JNDI to retrieve this reference. Most of the time, you must specify the target bean in an <ejb-ref
> element in the originator's XML configuration file that is used in the java:comp/env
logical name to designate the target bean to JNDI.
The method for accessing EJBs depends on where your client is located relative to the bean it wants to invoke. Consider the following when implementing the JNDI retrieval of the EJB reference of the bean:
<ejb-ref>
element with the target bean information. The logical name specified in the <ejb-ref-name>
element is used in the JNDI lookup.
<ejb-name>
element.
Specify the EJB reference information for the remote EJB in the <ejb-ref>
element in the application-client.xml
, ejb-jar.xml
, or web.xml
files. A full description or how to set up the <ejb-ref>
element is given in "Configuring Environment References".
For example, the following specifies the reference information for the employee example:
<?xml version="1.0"?>
<!DOCTYPE application-client PUBLIC "-//Sun Microsystems, Inc.//DTD J2EE Application Client 1.2//EN" "http://java.sun.com/j2ee/dtds/application-client_1_2.dtd">
<application-client>
<display-name>EmployeeBean</display-name>
<ejb-ref>
<ejb-ref-name>EmployeeBean</ejb-ref-name>
<ejb-ref-type>Session</ejb-ref-type>
<home>employee.EmployeeHome</home>
<remote>employee.Employee</remote>
</ejb-ref>
</application-client>
OC4J maps the logical name to the actual JNDI name on the client-side. The server-side receives the JNDI name and resolves it within its JNDI tree.
If the client exists within the same application as the target or the target exists within its parent, you do not need a JNDI properties file. If not, you must initialize your JNDI properties either within a jndi.properties
file, in the system properties, or within your implementation, before the JNDI call. The following sections discuss these three options:
A servlet that exists in the same application with the target bean automatically accesses the JNDI properties for the node. Thus, accessing the EJB is simple: no JNDI properties are required.
//Get the Initial Context for the JNDI lookup for a local EJB InitialContext ic = new InitialContext(); //Retrieve the Home interface using JNDI lookup Object empObject = ic.lookup("java:comp/env/employeeBean");
This is also true if the target bean is in an application that has been deployed as this application's parent. To specify parents, use the -parent
option of the admin.jar command when deploying the originating application.
If setting the JNDI properties within the jndi.properties
file, set the properties as follows. Make sure that this file is accessible from the CLASSPATH
.
java.naming.factory.initial=
com.evermind.server.ApplicationClientInitialContextFactory
The ORMI default port number is 23791, which can be modified in config/rmi.xml
. Thus, set the URL in the jndi.properties
, in one of the two ways:
java.naming.provider.url=ormi://<hostname>/<application-name>
or
java.naming.provider.url=ormi://<hostname>:23791/<application-name>
When you access EJBs in a remote container, you must pass valid credentials to this container. Stand-alone clients define their credentials in the jndi.properties
file deployed with the client's code.
java.naming.security.principal=<username> java.naming.security.credentials=<password>
Set the properties with the same values, just with different syntax. For example, JavaBeans running within the container pass their credentials within the InitialContext
, which is created to look up the remote EJBs.
To pass JNDI properties within the Hashtable
environment, set these as shown below:
Hashtable env = new Hashtable();
env.put("java.naming.provider.url", "ormi://localhost/ejbsamples");
env.put("java.naming.factory.initial",
"com.evermind.server.ApplicationClientInitialContextFactory");
env.put(Context.SECURITY_PRINCIPAL, "guest");
env.put(Context.SECURITY_CREDENTIALS, "welcome");
Context ic = new InitialContext (env);
Object homeObject = ic.lookup("java:comp/env/employeeBean");
// Narrow the reference to a TemplateHome.
EmployeeHome empHome =
(EmployeeHome) PortableRemoteObject.narrow(homeObject,
EmployeeHome.class);
For most clients, set the initial context factory class to ApplicationClientInitialContextFactory
. If you are not using a logical name defined in the <ejb-ref>
in your XML configuration file, then you must provide the actual JNDI name of the target bean. In this instance, you must use a different initial context factory class, the com.evermind.server.RMIInitialContextFactory
class.
The following servlet uses the JNDI name for the target bean: /cmpapp/employeeBean
. Thus, this servlet may provide the JNDI properties in an RMIInitialContext
object, instead of the ApplicationClientInitialContext
object. The environment is initialized as follows:
INITIAL_CONTEXT_FACTORY
is initialized to a RMIInitialContextFactory
.
InitialContext
, it is retrieved. '
Hashtable env = new Hashtable(); env.put(Context.PROVIDER_URL, "ormi://localhost/cmpapp"); env.put(Context.SECURITY_PRINCIPAL, "admin"); env.put(Context.SECURITY_CREDENTIALS, "welcome"); env.put(Context.INITIAL_CONTEXT_FACTORY,"com.evermind.server.rmi.RMIInitialContextFactory
");Context ic =
Object homeObject = ic.lookup("/cmpapp/employeeBean"); // Narrow the reference to a TemplateHome. EmployeeHome empHome = (EmployeeHome) PortableRemoteObject.narrow(homeObject, EmployeeHome.class);
new com.evermind.server.rmi.RMIInitialContextFactory().
getInitialContext(env);
If an application is installed in the OC4J server with a JSP or servlet that wants to invoke an EJB in a remote server, do the following:
remote=true
" attribute in the <ejb-module>
element in orion-application.xml
for the EJB module deployed in the local application. The local EJB will be ignored.
<server>
element in rmi.xml
. You provide the hostname, port number, username, and password, as follows:
<server host=<remote_host> port=<remote_port> user=<username> password=<password>
If multiple servers are configured, the OC4J container will search all remote servers for the intended EJB application. Thus, the JSP or servlet in one OC4J container will invoke an EJB deployed in another OC4J container.
When you execute a JNDI lookup, you retrieve a connection to the server. Each subsequent JNDI lookup for this same server uses the connection returned on the first JNDI lookup. That is, all requests are forwarded over and share the same connection. However, if you want to use a dedicated connection for each connection, specify the "dedicated.connection
" JNDI property to be true before you retrieve the InitialContext
, as follows:
env.put("dedicated.connection", "true");
One of the reasons for using this is if you need to retrieve multiple connections, where each uses a different username/password. If dedicated.connection
is false (which is the default), the first username/password is used for all subsequent connections, even if an alternate username/password is supplied. If you want to connect using a different username/password for each connection, you must set dedicated.connection
to true. Thus, you will retrieve a separate physical connection, each with its own designated username/password. It opens a new connection instead of reusing a cached connection.
If you have classes that can be used by more than one EJB, you can centralize these classes in one of the following ways:
$J2EE_HOME/lib
directory. Then, all classes deployed in OC4J can use these supporting classes.
<application>
element in the server.xml
file as follows:
<application ... parent="applicationWithCommonClasses" .../>
The parent
attribute defines an optional 'parent' application, where the default is the global application. The children see the namespace of its parent application. This is used in order to share services such as EJBs among multiple applications.
Whenever you deploy an application, OC4J automatically generates the OC4J-specific XML files with the default elements. If you want to change these files or add to the existing XML files, you must copy the XML files to where your original development directory for the application and change it in this location. If you change the XML file within the deployed location, OC4J simply overwrites these changes when the application is deployed again. The changes only stay constant when changed in the development directories.
For all OC4J-specific XML files, you can add these files within the recommended development structure as shown in Figure 6-1.
In order to avoid resource contention and overwriting each others changes to database tables while allowing concurrent execution, entity bean concurrency and database isolation modes are provided.
The java.sql.Connection
object represents a connection to a specific database. Database isolation modes are provided to define protection against resource contention. When two or more users try to update the same resource, a lost update can occur. That is, one user can overwrite the other user's data without realizing it. The java.sql.Connection
standard provides four isolation modes, of which Oracle only supports two of these modes. These are as follows:
TRANSACTION_READ_COMMITTED
: Dirty reads are prevented; non-repeatable reads and phantom reads can occur. This level only prohibits a transaction from reading a row with uncommitted changes in it.
TRANSACTION_SERIALIZABLE
: Dirty reads, non-repeatable reads and phantom reads are prevented. This level includes the prohibitions in TRANSACTION_REPEATABLE_READ
and further prohibits the situation where one transaction reads all rows that satisfy a WHERE condition, a second transaction inserts a row that satisfies that WHERE condition, and the first transaction rereads for the same condition, retrieving the additional "phantom" row in the second read.
You can configure one of these database isolation modes for a specific bean. That is, you can specify that when the bean starts a transaction, the database isolation mode for this bean be what is specified in the OC4J-specific deployment descriptor. Specify the isolation mode on what is important for the bean: parallel execution or data consistency. The isolation mode for this bean is set for the entire transaction.
The isolation mode can be set for each entity bean in the <entity-deployment>
element in the isolation
attribute. The values can be committed
or serializable
. The default is committed
. To change it to serializable
, configure the following in the orion-ejb-jar.xml
for the intended bean:
<entity-deployment ... isolation="serializable" ... </entity-deployment>
There is always a trade-off between performance and data consistency. The serializable
isolation mode provides data consistency; the committed
isolation mode provides for parallel execution.
If you do not set an isolation mode, you receive the mode that is configured in the database. Setting the isolation mode within the OC4J-specific deployment descriptor temporarily overrides the database configured isolation mode for the life of the global transaction for this bean. That is, if you define the bean to use the serializable
mode, then the OC4J container will force the database to be serializable
for this bean only until the end of the transaction.
OC4J also provides concurrency modes for handling resource contention and parallel execution within container-managed persistence (CMP) entity beans. Bean-managed persistence entity beans manage the resource locking within the bean implementation themselves. The concurrency modes configure when to block to manage resource contention or when to execute in parallel.
The concurrency modes are as follows:
PESSIMISTIC
: This manages resource contention and does not allow parallel execution. Only one user at a time is allowed to execute the entity bean at a single time.
OPTIMISTIC
: Multiple users can execute the entity bean in parallel. It does not monitor resource contention; thus, the burden of the data consistency is placed on the database isolation modes.
READ-ONLY
: Multiple users can execute the entity bean in parallel. The container does not allow any updates to the bean's state.
To enable the CMP entity bean concurrency mode, add the appropriate concurrency value of "pessimistic
", "optimistic
", or "read-only
" to the locking-mode
attribute of the <entity-deployment>
element in the OC4J-specific deployment descriptor (orion-ejb-jar.xml
). The default is "optimistic
". To modify the concurrency mode to pessimistic
, do the following:
<entity-deployment ... locking-mode="pessimistic" ... </entity-deployment>
These concurrency modes are defined per bean and the effects of locking apply on the transaction boundaries.
Parallel execution requires that the pool size for wrapper and bean instances are set correctly. For more information on how to configure the pool sizes, see "Configuring Pool Sizes For Entity Beans".
The exclusive-write-access
attribute of the <entity-deployment>
element states that this is the only bean that accesses its table in the database and that no external methods are used to update the resource. It informs the OC4J instance that any cache maintained for this bean will only be dirtied by this bean. Essentially, if you set this attribute to true, you are assuring the container that this is the only bean that will update the tables used within this bean. Thus, any cache maintained for the bean does not need to constantly update from the back-end database.
This flag does not prevent you from updating the table; that is, it does not actually lock the table. However, if you update the table from another bean or manually, the results are not automatically updated within this bean.
The default for this attribute is false. Because of the effects of the entity bean concurrency modes, this element is only allowed to be set to true for a read-only
entity bean. OC4J will always reset this attribute to false for pessimistic
and optimistic
concurrency modes.
<entity-deployment ... exclusive-write-access="true" ... </entity-deployment>
For the pessimistic
and read-only
concurrency modes, the setting of the database isolation mode does not matter. These isolation modes only matter if an external source is modifying the database.
If you choose optimistic
with committed
, you have the potential to lose an update. If you choose optimistic
with serializable
, you will never lose an update. Thus, your data will always be consistent. However, you can receive an ORA-8177
exception as a resource contention error.
An entity bean with the pessimistic
concurrency mode does not allow multiple clients to execute the bean instance. Only one client is allowed to execute the instance at any one moment. An entity bean with the optimistic
concurrency mode allows multiple instances of the bean implementation to execute in parallel. Setting the database isolation mode to serializable
does not allow these multiple bean implementation instances to update the same row at the same time. Thus, the only difference between a pessimistic
concurrency bean and an optimistic
/serializable
bean is where the blocking occurs. A pessimistic
bean blocks at the bean instance; the other blocks at the database row.
All concurrency modes behave in a similar manner whether they are used within a standalone or a clustered environment. This is because the concurrency modes are locked at the database level. Thus, even if a pessimistic bean instance is clustered across nodes, the instant one instance tries to execute, the database locks out all other instances.
You can set the minimum and maximum number of both the following instance pools:
You can set the pool number of each instance type with the following attributes of the <entity-deployment>
element.
max-instances
attribute sets the maximum entity bean instances to be allowed in the pool. An entity bean is set to a pooled state if not associated with a wrapper instance. Thus, it is generic.
The default is 10. Set the maximum bean implementation instances as follows:
<entity-deployment ... max-instances="20" ... </entity-deployment>
Or the minimum number allowed in the pool as follows:
<entity-deployment ... min-instances="2" ... </entity-deployment>
max-instances-per-pk
attribute sets the maximum entity bean wrapper instances allowed in its pool for a given primary key. An entity bean's wrapper code can be pooled if it is not used by a client.
The default maximum value is 50. Set the maximum wrapper instances as follows:
<entity-deployment ... max-instances-per-pk="20" ... </entity-deployment>
Set the minimum wrapper instances as follows:
<entity-deployment ... min-instances-per-pk="2" ... </entity-deployment>
disable-wrapper-cache
attribute disables the wrapper instance pool if true. The default is false. If it is better to create the wrapper instances on demand, then set this attribute to true. To do so, configure the following:
<entity-deployment ... disable-wrapper-cache="true" ... </entity-deployment>
By default, the container persists only the modified fields in the bean. At the end of each call, a SQL command is created to update these fields. However, if you want to have all of your persistence fields updated, set the following attribute to false:
<entity-deployment ... update-changed-fields-only="false" ... </entity-deployment>
If you choose to have all fields updated, the SQL parsing cache is used. The same SQL command is used for each update.
You can create three types of environment elements that are accessible to your bean during runtime: environment variables, EJB references, and resource managers. These environment elements are static and can not be changed by the bean.
ISVs typically develop EJBs that are independent from the EJB container. In order to distance the bean implementation from the container specifics, you can create environment elements that map to one of the following: defined variables, entity beans, or resource managers. This indirection enables the bean developer to refer to existing variables, EJBs, and a JDBC DataSource
without specifying the actual name. These names are defined in the deployment descriptor and are linked to the actual names within the OC4J-specific deployment descriptor.
You can create environment variables that your bean accesses through a lookup on the InitialContext
. These variables are defined within an <env-entry>
element and can be of the following types: String
, Integer
, Boolean
, Double
, Byte
, Short
, Long
, and Float
. The name of the environment variable is defined within <env-entry-name>
, the type is defined in <env-entry-type>
, and its initialized value is defined in <env-entry-value>
. The <env-entry-name>
is relative to the "java:comp/env"
context.
For example, the following two environment variables are declared within the XML deployment descriptor for java:comp/env/minBalance
and java:comp/env/maxCreditBalance
.
<env-entry> <env-entry-name>minBalance</env-entry-name> <env-entry-type>java.lang.Integer</env-entry-type> <env-entry-value>500</env-entry-value> </env-entry> <env-entry> <env-entry-name>maxCreditBalance</env-entry-name> <env-entry-type>java.lang.Integer</env-entry-type> <env-entry-value>10000</env-entry-value> </env-entry>
Within the bean's code, you would access these environment variables through the InitialContext
, as follows:
InitialContext ic = new InitialContext(); Integer min = (Integer)ic.lookup("java:comp/env/minBalance"); Integer max = (Integer) ic.lookup("java:comp/env/maxCreditBalance"));
Notice that to retrieve the values of the environment variables, you prefix each environment element with "java:comp/env/
", which is the location that the container stored the environment variable.
If you wanted the value of the environment variable to be defined in the OC4J-specific deployment descriptor, you can map the <env-entry-name>
to the <env-entry-mapping>
element in the OC4J-specific deployment descriptor. This means that the value specified in the orion-ejb-jar.xml
file overrides any value that may be specified in the ejb-jar.xml
file. The type specified in the EJB deployment descriptor stays the same.
Figure 6-2 shows how the minBalance
environment variable is defined as 500 within the OC4J-specific deployment descriptor.
You can define an environment reference to an EJB within the deployment descriptor. If your bean calls out to another bean, you can enable your bean to invoke the second bean using a reference defined within the deployment descriptors. You create a logical name within the EJB deployment descriptor, which is mapped to the concrete name of the bean within the OC4J-specific deployment descriptor.
Declaring the target bean as an environment reference provides a level of indirection: the originating bean can refer to the target bean with a logical name.
To define a reference to another EJB within the JAR or in a bean declared as a parent, you provide the following:
ejb/
", such as "ejb/myEmployee
", and will be available within the "java:comp/env/ejb
" context.
<ejb-name>
element in the <session>
or <entity>
elements.
<ejb-link>
element in this <ejb-ref>
element or in the <ejb-ref-mapping>
element in the OC4J-specific deployment descriptor.
These options are discussed below.
Session
" or "Entity
".
If you have two beans in the JAR: BeanA
and BeanB
. If BeanB
creates a reference to BeanA
, you can define this reference in one of three methods:
BeanB
would define the following <ejb-ref>
within its definition:
<ejb-ref> <ejb-ref-name>myBeans/BeanA</ejb-ref-name> <ejb-ref-type>Session</ejb-ref-type> <home>myBeans.BeanAHome</home> <remote>myBeans.BeanA</remote> </ejb-ref>
No <ejb-link>
is necessary for this method. However, the BeanB
implementation must refer to BeanA
in the JNDI retrieval, which would use java:comp/env/myBeans/BeanA
for retrieval within an EJB or Java client and use "myBeans/BeanA
" within a Servlet.
<ejb-link>
element. This method allows you to use any logical name in your bean implementation for the JNDI retrieval:
<ejb-ref> <ejb-ref-name>ejb/nextVal</ejb-ref-name> <ejb-ref-type>Session</ejb-ref-type> <home>myBeans.BeanAHome</home> <remote>myBeans.BeanA</remote> <ejb-link>myBeans/BeanA</ejb-link> </ejb-ref>
BeanB
would use java:comp/env/ejb/nextVal
in the JNDI retrieval of BeanA
.
<ejb-ref-name>
and the actual name of the bean in the <ejb-ref-mapping>
element in the OC4J-specific deployment descriptor.
The reference in the EJB deployment descriptor would be as follows:
<ejb-ref> <ejb-ref-name>ejb/nextVal</ejb-ref-name> <ejb-ref-type>Session</ejb-ref-type> <home>myBeans.BeanAHome</home> <remote>myBeans.BeanA</remote> </ejb-ref>
The "ejb/nextVal
" logical name is mapped to an actual name in the OC4J-deployment descriptor as follows:
<ejb-ref-mapping name="ejb/nextVal" location="myBeans/BeanA"/>
BeanB
would use java:comp/env/ejb/nextVal
in the JNDI retrieval of BeanA
.
As shown in Figure 6-3, the logical name for the bean is mapped to the JNDI name by providing the same name, "ejb/nextVal
", in both the <ejb-ref-name>
in the EJB deployment descriptor and the name
attribute within the <ejb-ref-mapping>
element in the OC4J-specific deployment descriptor.
The following example defines a reference to the Hello
bean, as follows:
java:comp/env/ejb/HelloWorld
".
hello.HelloHome
; its remote interface is hello.Hello
.
HelloWorldBean
" name.
As shown in Figure 6-3, the <ejb-link>
is mapped to the name
attribute within the <ejb-ref-mapping>
element in the OC4J-specific deployment descriptor by providing the same logical name in both elements. The Oracle-specific deployment descriptor would have the following definition to map the logical bean name of "java:comp/env/ejb/HelloWorld
" to the JNDI URL "/test/myHello
".
To invoke this bean from within your implementation, you use the <ejb-ref-name
> defined in the EJB deployment descriptor. In EJB or pure Java clients, you prefix this name with "java:comp/env/ejb/
", which is where the container places the EJB references defined in the deployment descriptor. Servlets only require the logical name defined in the <ejb-ref-name>
.
The following is a lookup from an EJB client:
InitialContext ic = new InitialContext(); HelloHome hh = (HelloHome)ic.lookup("java:comp/env/ejb/HelloWorld");
The following is a lookup from a Servlet, if the Servlet defines the logical name of "ejb/HelloWorld
" in <ejb-ref>
in its web.xml
file and maps it to the actual name of "/test/myHello
" within the orion-web.xml
file.
InitialContext ic = new InitialContext(); HelloHome hh = (HelloHome)ic.lookup("ejb/HelloWorld");
The resource manager connection factory references can include resource managers such as JMS, Java mail, URL, and JDBC DataSource
objects. Similar to the EJB references, you can access these objects from JNDI by creating an environment element for each object reference. However, these references can only be used for retrieving the object within the bean that defines these references. Each is fully described in the following sections:
You can access a database through JDBC either using the traditional method or by creating an environment element for a JDBC DataSource
. In order to create an environment element for your JDBC DataSource
, you must do the following:
DataSource
in the data-sources.xml
file.
<res-ref-name>
element in the EJB deployment descriptor. This name should always start with "jdbc
". In the bean code, the lookup of this reference is always prefaced by "java:comp/env/jdbc
".
java:comp/env/jdbc
" preface and the logical name defined in the EJB deployment descriptor.
As shown in Figure 6-4, the JDBC DataSource
uses the JNDI name "test/OrderDataSource
". The logical name that the bean knows this resource as is "jdbc/OrderDB
". These names are mapped together within the OC4J-specific deployment descriptor. Thus, within the bean's implementation, the bean can retrieve the connection to OrderDataSource
by using the "java:comp/env/jdbc/OrderDB
" environment element.
The environment element is defined within the EJB deployment descriptor by providing the logical name, "jdbc/OrderDB
", its type of javax.sql.DataSource
, and the authenticator of "Application
".
The environment element of "jdbc/OrderDB
" is mapped to the JNDI bound name for the connection, "test/OrderDataSource
" within the Oracle-specific deployment descriptor.
Once deployed, the bean can retrieve the JDBC DataSource
as follows:
javax.sql.DataSource db; java.sql.Connection conn; . . . db = (javax.sql.DataSource) initCtx.lookup("java:comp/env/jdbc/OrderDB"); conn = db.getConnection();
You can create an environment element for a Java mail Session
object through the following:
javax.mail.Session
reference within the JNDI name space in the application.xml
file using the <mail-session>
element, as follows:
<mail-session location="mail/MailSession" smtp-host="mysmtp.oraclecorp.com"> <property name="mail.transport.protocol" value="smtp"/> <property name="mail.smtp.from" value="emailaddress@oracle.com"/> </mail-session>
The location attribute contains the JNDI name specified in the location attribute of the <resource-ref-mapping>
element in the OC4J-specific deployment descriptor.
<res-ref-name>
element in the EJB deployment descriptor. This name should always start with "mail
". In the bean code, the lookup of this reference is always prefaced by "java:comp/env/mail
".
java:comp/env/mail
" preface and the logical name defined in the EJB deployment descriptor.
As shown in Figure 6-5, the Session
object was bound to the JNDI name "/test/myMailSession
". The logical name that the bean knows this resource as is "mail/testMailSession
". These names are mapped together within the OC4J-specific deployment descriptor. Thus, within the bean's implementation, the bean can retrieve the connection to the bound Session
object by using the "java:comp/env/mail/testMailSession
" environment element.
This environment element is defined with the following information:
The environment element is defined within the EJB deployment descriptor by providing the logical name, "mail/testMailSession
", its type of javax.mail.Session
, and the authenticator of "Application
".
The environment element of "mail/testMailSession
" is mapped to the JNDI bound name for the connection, "test/myMailSession
" within the OC4J-specific deployment descriptor.
Once deployed, the bean can retrieve the Session
object reference as follows:
InitialContext ic = new InitialContext(); Session session = (Session) ic.lookup("java:comp/env/mail/testMailSession"); //The following uses the mail session object //Create a message object MimeMessage msg = new MimeMessage(session); //Construct an address array String mailTo = "whosit@oracle.com"; InternetAddress addr = new InternetAddress(mailto); InternetAddress addrs[] = new InternetAddress[1]; addrs[0] = addr; //set the message parameters msg.setRecipients(Message.RecipientType.TO, addrs); msg.setSubject("testSend()" + new Date()); msg.setContent(msgText, "text/plain"); //send the mail message Transport.send(msg);
You can create an environment element for a Java URL
object through the following:
<res-ref-name>
element in the EJB deployment descriptor. This name should always start with "url
". In the bean code, the lookup of this reference is always prefaced by "java:comp/env/url
".
java:comp/env/url
" preface and the logical name defined in the EJB deployment descriptor.
As shown in Figure 6-6, the URL
object was bound to the URL "www.myURL
.com". The logical name that the bean knows this resource as is "url/testURL
". These names are mapped together within the OC4J-specific deployment descriptor. Thus, within the bean's implementation, the bean can retrieve the connection to the bound Session
object by using the "java:comp/env/url/testURL
" environment element.
This environment element is defined with the following information:
The environment element is defined within the EJB deployment descriptor by providing the logical name, "url/testURL
", its type of java.net.URL
, and the authenticator of "Application
".
The environment element of "url/testURL
" is mapped to the URL "www.myURL.com
" within the OC4J-specific deployment descriptor.
Once deployed, the bean can retrieve the URL
object reference as follows:
InitialContext ic = new InitialContext(); URL url = (URL) ic.lookup("java:comp/env/url/testURL"); //The following uses the URL object URLConection conn = url.openConnection();
Choosing what security to use is a subject that involves more than the authorization details that we discuss in this section. For a full description of security, see the OC4J Services Guide.
This book focuses on EJBs and any XML configuration that belongs within the EJB deployment descriptors. Within the security spectrum, EJB authorization is specified within the EJB and OC4J-specific deployment descriptors. It involves assigning roles that are attached to EJBs to users and groups that are defined in the principals.xml
file. Thus, this section describes assigning roles to EJBs and mapping these roles to specific users or groups.
You can manage the authorization piece of your security within the deployment descriptors, as follows:
principals.xml
.
Users and groups are identities known by the container. Roles are the logical identities each application uses to indicate access rights to its different objects. The username/passwords can be digital certificates and, in the case of SSL, private key pairs. The EJB deployment descriptor indicates what roles are needed to access the different parts of the application. The OC4J-specific deployment descriptor provides a mapping between the logical roles and the users/groups known by the container.
Defining users, groups, and roles are discussed in the following sections:
OC4J supports the definition of users and groups--either shared by all deployed applications or specific to given applications.
config/principals.xml
file.
principals.xml
, which path is indicated in the orion-application.xml
file of that application.
The following excerpt from the principals.xml
file shows how to define a group named managers
and a user named guest
with password, welcome
.
<principals> <groups><group name="managers">
<description>Group for all managerial users</description> <permission name="rmi:login" /> <permission name="com.evermind.server.rmi.RMIPermission" /> </group> ....other groups... </groups> <users><user username="guest" password="welcome">
<description>purchase order manager</description><group-membership group="managers" />
</user> </users> </principals>
For a full description of the principals.xml
file and how to specify users and groups, see the OC4J Services Guide.
Specify the logical roles that your application uses in the EJB deployment descriptor. The roles are defined within the element named <security-role>
.
This example creates a logical role named POMGR in the ejb-jar.xml
deployment descriptor.
<security-role>
element.
<security-role> <description>Purchase Order Manager</description> <role-name>POMGR</role-name> </security-role>
<method-permission>
element.
<method-permission> <role-name>POMGR</role-name> <method> <ejb-name>PurchaseOrderBean</ejb-name> <method-name>*</method-name> </method> </method-permission>
Map the logical roles defined in the application deployment descriptors to concrete users or groups through the <security-role-mapping>
element in the OC4J-specific deployment descriptor.
This example maps the logical role POMGR
to the managers
group in the orion-ejb-jar.xml
file. Any user that can log in as part of this group is considered to have the POMGR
role; thus, it can execute the methods of PurchaseOrderBean
.
<security-role-mapping name="POMGR"> <group name="managers" /> </security-role-mapping>
To map this role to a specific user, do the following:
<security-role-mapping name="POMGR"> <user name="guest" /> </security-role-mapping>
Lastly, you can map a role to a specific user within a specific group, as follows:
<security-role-mapping name="POMGR"> <group name="managers" /> <user name="guest" /> </security-role-mapping>
As shown in Figure 6-7, the logical role name for POMGR
defined in the EJB deployment descriptor is mapped to SCOTT within the OC4J-specific deployment descriptor in the <security-role-mapping>
element.
Notice that the <role-name>
in the EJB deployment descriptor is the same as the name attribute in the <security-role-mapping>
element in the OC4J-specific deployment descriptor. This is what identifies the mapping.
Thus, the definition and mapping of roles is demonstrated in Figure 6-8.
To default all methods in EJBs that have not been associated with a method permission to a security role, use the <default-method-access>
element.
The following example shows how all methods not associated with a method permission are mapped to the "managers
" group:
<default-method-access> <security-role-mapping name="users" impliesAll="true" /> <group name="managers" /> </security-role-mapping> </default-method-access>
The impliesAll
attribute specifies that this includes all users.
When you access EJBs in a remote container, you must pass valid credentials to this container.
jndi.properties
file deployed with the EAR file.
InitialContext
, which is created to look up the remote EJBs.
Indicate the username (principal) and password (credentials) to use when looking up remote EJBs in the jndi.properties
file.
For example, if you want to access remote EJBs as POMGR/welcome
, define the following properties. The factory.initial
property indicates that you will use the Oracle JNDI implementation:
java.naming.security.principal=POMGR java.naming.security.credentials=welcome java.naming.factory.initial=
com.evermind.server.ApplicationClientInitialContextFactory java.naming.provider.url=ormi://localhost/ejbsamples
In your application program, authenticate and access the remote EJBs, as shown below:
InitialContext ic = new InitialContext(); CustomerHome = (CustomerHome)ic.lookup("java:comp/env/purchaseOrderBean");
To access remote EJBs from a servlet or JavaBean, pass the credentials in the InitialContext
object, as follows:
Hashtable env = new Hashtable(); env.put("java.naming.provider.url", "ormi://localhost/ejbsamples"); env.put("java.naming.factory.initial", "com.evermind.server.ApplicationClientInitialContextFactory"); env.put(Context.SECURITY_PRINCIPAL, "POMGR"); env.put(Context.SECURITY_CREDENTIALS, "welcome"); Context ic = new InitialContext (env); CustomerHome = (CustomerHome)ic.lookup("java:comp/env/purchaseOrderBean")
The following are common errors that may occur when executing EJBs:
If you are trying to remotely access an EJB and you receive an javax.naming.NamingException
error, your JNDI properties are probably not initialized properly. See "Accessing EJBs" for a discussion on setting up JNDI properties when accessing an EJB from a remote object or remote servlet.
If the call sequence of several beans cause a deadlock scenario, the OC4J container notices the deadlock condition and throws a Remote exception that details the deadlock condition in one of the offending beans.
|
Copyright © 2002 Oracle Corporation. All Rights Reserved. |
|