Oracle9iAS Containers for J2EE Enterprise JavaBeans Developer's Guide Release 2 (9.0.3) Part Number A97677-01 |
|
This chapter discusses how to extend beyond the basics mentioned in each of the previous chapters. This chapter covers the following subjects:
To access an EJB from a client, you must do the following:
oc4j.jar
file. This JAR contains only the classes necessary for client interaction.
opmn.xml
file.
InitialContext
you will use for the connection.
These subjects are discussed in the following sections:
Within your client code, you 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.
In order to access EJBs, the client-side must download the oc4j.jar
file. This JAR contains only the classes necessary for client interaction. If you download this JAR into a browser, you must grant certain permissions. See <<<>>> for a list of these permissions.
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:
<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>
<local-home>employee.EmployeeLocalHome</local-home>
<local>employee.EmployeeLocal</local>
</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.
For more information and examples of the <ejb-ref>
element, see "Configuring Environment References".
If the client is collocated with the target, exists within the same application as the target, or the target exists within its parent, then 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:
To specify credentials within the JNDI properties, see "Specifying Credentials in EJB Clients".
A servlet that is collocated 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 the same application or an application that has been deployed as this application's parent. The default parent 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. See the Oracle9iAS Containers for J2EE User's Guide for directions on how to specify a parent 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 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, only 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://myhost/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);
OC4J is configured to assign an RMI or JMS port dynamically within set ranges. However, if you have a standalone EJB client, you must know an exact port number to direct your request.
opmn.xml
file within the Enterprise Manager Advanced Properties within the OPMN configuration. Change the RMI or JMS range to the specified port number. The following demonstrates setting the RMI port to 3202 in the opmn.xml
file:
<port ajp="..." jms="..." rmi="3202"/>
java.naming.provider.url=ormi://myhost:3202/myapp
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);
To use round-robin DNS for your incoming load balancing, you must do the following:
RMILBInitialContextFactory
as your initial context. Each client must use this initial context for DNS round-robin load balancing to work properly.
When you perform a successful host name lookup from the name server, the value is cached. DNS load balancing does not occur if every lookup returns the same value from the cache. When you use the RMILBInitialContextFactory
in the client, then a new context class is returned on each lookup.
java.naming.factory.initial= com.evermind.server.rmi.RMILBInitialContextFactory java.naming.provider.url=ormi://DNSserver:23792/applname java.naming.security.principal=admin java.naming.security.credentials=welcome dedicated.rmicontext=true
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 have an EJB or Web application that references other shared EJB classes, you should place the referenced classes in a shared JAR. In certain situations, if you copy the shared EJB classes into WAR file or another application that references them, you may receive a ClassCastException
because of a class loader issue. To be completely safe, never copy referenced EJB classes into the WAR file of its application or into another application.
Web application: The Web application copies referenced EJB classes in its WAR file in the same application. As described in the Oracle9iAS Containers for J2EE Servlet Developer's Guide, you can specify where to load the classes from in the <web-app-class-loader>
element. However, when executing, the Web application retrieves the EJB bean reference using JNDI, the following may occur:
ClassCastException
is thrown.
Separate application: A separate application copies referenced EJB classes into its EAR file. If both applications are executing within the same process and the bean reference is retrieved using JNDI lookup, one of the following occurs:
ClassCastException
is thrown.
To avoid this problem, do one of the following:
class-path
of the EJB JAR manifest.mf
file, as follows:
class-path:shared_classes.jar
The location of the shared_classes.jar
is relative to where the JAR that references it is located in the EAR file. In this example, the shared_classes.jar
file is at the same level as the EJB JAR.
home/lib
is a default shared library.
The default parent 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. See the Oracle9iAS Containers for J2EE User's Guide for directions on how to specify a parent application.
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>
disable-wrapper-cache
attribute disables the wrapper instance pool if true. The default is true. 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 8-1 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 8-2, 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 8-2, 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 8-3, 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 8-4, 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 8-5, 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();
EJB security involves two realms: granting permissions if you download into a browser and configuring your application for authentication and authorization. This section covers the following:
If you download the EJB application as a client where the security manager is active, you must grant the following permissions before you can execute:
permission java.net.SocketPermission "*:*", "connect,resolve"; permission java.lang.RuntimePermission "createClassLoader"; permission java.lang.RuntimePermission "getClassLoader"; permission java.util.PropertyPermission "*", "read"; permission java.util.PropertyPermission "LoadBalanceOnLookup",
"read,write";
For EJB authentication and authorization, you define the principals under which each method executes by configuring of the EJB deployment descriptor. The container enforces that the user who is trying to execute the method is the same as defined within the deployment descriptor.
The EJB deployment descriptor enables you to define security roles under which each method is allowed to execute. These methods are mapped to users or groups in the OC4J-specific deployment descriptor. The users and groups are defined within your designated security user managers, which uses either the JAZN or XML user manager. For a full description of security user managers, see the Oracle9iAS Containers for J2EE User's Guide and Oracle9iAS Containers for J2EE Services Guide.
For authentication and authorization, this section focuses on XML configuration within the EJB deployment descriptors. EJB authorization is specified within the EJB and OC4J-specific deployment descriptors. You can manage the authorization piece of your security within the deployment descriptors, as follows:
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.
Thus, the definition and mapping of roles is demonstrated in Figure 8-6.
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. You define shared or application-specific users and groups within either the JAZN or XML user managers. See the Oracle9iAS Containers for J2EE User's Guide and Oracle9iAS Containers for J2EE Services Guide. for directions.
As shown in Figure 8-7, you can use a logical name for a role within your bean implementation, and map this logical name to the correct database role or user. The mapping of the logical name to a database role is specified in the OC4J-specific deployment descriptor. See "Mapping Logical Roles to Users and Groups" for more information.
If you use a logical name for a database role within your bean implementation for methods such as isCallerInRole
, you can map the logical name to an actual database role by doing the following:
<enterprise-beans>
section <security-role-ref>
element. For example, to define a role used within the purchase order example, you may have checked, within the bean's implementation, to see if the caller had authorization to sign a purchase order. Thus, the caller would have to be signed in under a correct role. In order for the bean to not need to be aware of database roles, you can check isCallerInRole
on a logical name, such as POMgr
, since only purchase order managers can sign off on the order. Thus, you would define the logical security role, POMgr within the <security-role-ref><role-name>
element within the <enterprise-beans>
section, as follows:
<enterprise-beans> ... <security-role-ref> <role-name>POMgr</role-name> <role-link>myMgr</role-link> </security-role-ref> </enterprise-beans>
The <role-link>
element within the <security-role-ref>
element can be the actual database role, which is defined further within the <assembly-descriptor>
section. Alternatively, it can be another logical name, which is still defined more in the <assembly-descriptor>
section and is mapped to an actual database role within the Oracle-specific deployment descriptor.
PurchaseOrder
bean must have authorized itself as myMgr
. Note that PurchaseOrder
is the name declared in the <entity
| session><ejb-name>
element.
Thus, the following defines the role as myMgr
, the EJB as PurchaseOrder
, and all methods by denoting the '*' symbol.
<assembly-descriptor> <security-role> <description>Role needed purchase order authorization</description> <role-name>myMgr</role-name> </security-role> <method-permission> <role-name>myMgr</role-name> <method> <ejb-name>PurchaseOrder</ejb-name> <method-name>*</method-name> </method> </method-permission> ... </assembly-descriptor>
After performing both steps, you can refer to POMgr
within the bean's implementation and the container translates POMgr
to myMgr
.
The <method-permission><method>
element is used to specify the security role for one or more methods within an interface or implementation. According to the EJB specification, this definition can be of one of the following forms:
<method-permission> <role-name>myMgr</role-name> <method> <ejb-name>EJBNAME</ejb-name> <method-name>*</method-name> </method> </method-permission>
<method-permission> <role-name>myMgr</role-name> <method> <ejb-name>myBean</ejb-name> <method-name>myMethodInMyBean</method-name> </method> </method-permission>
<method-permission> <role-name>myMgr</role-name> <method> <ejb-name>myBean</ejb-name> <method-name>myMethod</method-name> <method-params> <method-param>javax.lang.String</method-param> <method-param>javax.lang.String</method-param> </method-params> </method> </method-permission>
The parameters are the fully-qualified Java types of the method's input parameters. If the method has no input arguments, the <method-params
> element contains no elements. Arrays are specified by the array element's type, followed by one or more pair of square brackets, such as int
[ ][ ].
If you want certain methods to not be checked for security roles, you define these methods as unchecked, as follows:
<method-permission> <unchecked/> <method> <ejb-name>EJBNAME</ejb-name> <method-name>*</method-name> </method> </method-permission>
Instead of a <role-name>
element defined, you define an <unchecked/>
element. When executing any methods in the EJBNAME
bean, the container does not check for security. Unchecked methods always override any other role definitions.
You can specify that all methods of an EJB execute under a specific identity. That is, the container does not check different roles for permission to run specific methods; instead, the container executes all of the EJB methods under the specified security identity. You can specify a particular role or the caller's identity as the security identity.
Specify the runAs security identity in the <security-identity>
element, which is contained in the <enterprise-beans>
section. The following XML demonstrates that the POMgr
is the role under which all the entity bean methods execute.
<enterprise-beans> <entity> ... <security-identity> <run-as> <role-name>POMgr</role-name> </run-as> </security-identity> ... </entity> </enterprise-beans>
Alternatively, the following XML example demonstrates how to specify that all methods of the bean execute under the identity of the caller:
<enterprise-beans> <entity> ... <security-identity> <use-caller-identity/> </security-identity> ... </entity> </enterprise-beans>
You can use logical roles or actual users and groups in the EJB deployment descriptor. However, if you use logical roles, you must map them to the actual users and groups defined either in the JAZN or XML User Managers.
Map the logical roles defined in the application deployment descriptors to JAZN or XML User Manager users or groups through the <security-role-mapping>
element in the OC4J-specific deployment descriptor.
name
attribute of this element defines the logical role that is to be mapped.
group
or user
element maps the logical role to a group or user name. This group or user must be defined in the JAZN or XML User Manager configuration. See Oracle9iAS Containers for J2EE User's Guide and Oracle9iAS Containers for J2EE Services Guide for a description of the JAZN and XML User Managers.
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 8-8, the logical role name for POMGR
defined in the EJB deployment descriptor is mapped to managers
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.
If any methods have not been associated with a role mapping, they are mapped to the default security role through the <default-method-access>
element in the orion-ejb-jar.xml
file. The following is the automatic mapping for any insecure methods:
<default-method-access> <security-role-mapping name="<default-ejb-caller-role>" impliesAll="true" /> </security-role-mapping> </default-method-access>
The default role is <default-ejb-caller-role>
and is defined in the name
attribute. You can replace this string with any name for the default role. The impliesAll
attribute indicates whether any security role checking occurs for these methods. This attribute defaults to true, which states that no security role checking occurs for these methods. If you set this attribute to false, the container will check for this default role on these methods.
If the impliesAll
attribute is false, you must map the default role defined in the name
attribute to a JAZN or XML user or group through the <user>
and <group>
elements. The following example shows how all methods not associated with a method permission are mapped to the "others
" group.
<default-method-access> <security-role-mapping name="default-role" impliesAll="false" /> <group name="others" /> </security-role-mapping> </default-method-access>
In order for the client to access methods that are protected by users and groups, the client must provide the correct user or group name with a password that the JAZN or XML User Manager recognizes. And the user or group must be the same one as designated in the security role for the intended method. See "Specifying Credentials in EJB Clients" for more information.
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")
Most performance settings are discussed in the Oracle9i Application Server Performance Guide. This section discusses other performance options.
You can manage these performance settings yourself from either the OC4J command-line option or by editing the appropriate XML file element.
Each -D
command-line option, except for the dedicated.rmicontext
option, defaults to the recommended setting. However, you can modify these options by providing each -D
command-line option as an OC4J option. See the Oracle9iAS Containers for J2EE User's Guide for an example.
dedicated.rmicontext=true/false
. The default value is false. This replaces the deprecated dedicated.connection
setting. When two or more clients in the same process retrieve an InitialContext
, OC4J returns a cached context. Thus, each client receives the same InitialContext
, which is assigned to the process. Server lookup, which results in server load balancing, happens only if the client retrieves its own InitialContext
. If you set dedicated.rmicontext=true
, then each client receives its own InitialContext
instead of a shared context. When each client has its own InitialContext
, then the clients can be load balanced.
This parameter is for the client. You can also set this in the JNDI properties. See Example 8-10 for an example.
oracle.dms.gate=true/false
. You can turn on and off collecting Oracle9iAS built-in performance metrics. The default value is true, which turns on the collection. To turn off the collection, set this option to false. This parameter should be set on the OC4J server.
DefineColumnType=true/false
. The default is true. If true, you avoid a round-trip when executing a select over the JDBC driver. You should be concerned with this flag only when you are using a non-Oracle JDBC driver. With a non-Oracle JDBC driver, you want to turn this flag to false. This parameter should be set on the OC4J server.
When you change the value of this option and restart OC4J, it is only valid for applications deployed after the change. Any applications deployed before the change are not affected.
The DefineColumnType
extension saves a round trip to the database that would otherwise be necessary to describe the table. When the Oracle JDBC driver performs a query, it first uses a round trip to an Oracle database to determine the types that it should use for the columns of the result set. Then, when JDBC receives data from the query, it converts the data, as necessary, as it populates the result set. When you specify column types for a query with the DefineColumnType
extension, you avoid the first round trip to the database. The server, which is optimized to do so, performs any necessary type conversions. If you want OC4J to perform this optimization for you, then set this option to true, which is the default. If you do not, then set this option to false.
You can specify one or two thread pools for an OC4J process through the global-thread-pool
element in the server.xml
file. If you do not specify this element, then an infinite number of threads can be created.
There are two types of threads in OC4J:
ApplicationServerThreadPool
.
ConnectionThreadPool
.
OC4J always maintains a certain amount of worker threads, so that any client connection traffic bursts can be handled.
If you specify a single thread pool, then both short and long lived threads exist in this pool. The risk is that all the available threads in the pool are one type of thread. Then, performance can be poor because of a lack of resources for the other type of thread. However, OC4J always guarantees a certain amount of worker threads, which are normally mapped to short lived threads. If a need for a worker thread arises and no short lived thread is available, the work is handled by a long lived thread.
If you specify two thread pools, then each pool contains one type of thread.
To create a single pool, configure the min
, max
, queue
, and keepAlive
attributes. To create two pools, configure the min
, max
, queue
, and keepAlive
attributes for the first pool and the cx-min
, cx-max
, cx-queue
, and cx-keepAlive
attributes for the second pool.
The global-thread-pool
element provides the following attributes:
Recommendations:
queue
attributes should be at least twice the size of the maximum number of threads.
cx-min
and cx-max
sets the thread pool size for the connection threads; thus, they are relative to the number of the physical connections you have at any point in time. The cx-queue
handles burst in connection traffic.
keepAlive
attribute to negative one.
The following example initializes two thread pools for the OC4J process. Each contains at minimum 10 threads and maximum of 100 threads. The number of requests outstanding in each queue can be 200 requests. Also, idle threads are kept alive for 700 seconds. The thread pool information is printed at startup.
<application-server ...> ... <global-thread-pool min="10" max="100" queue="200" keepAlive=700000" cx-min="10" cx-max="100" cx-queue="200" cx-keepAlive=700000" debug="true"/> ... </application-server>
You can cache database statements, which prevents the overhead of repeated cursor creation and repeated statement parsing and creation. In the DataSource
configuration, you enable JDBC statement caching, which caches executable statements that are used repeatedly. A JDBC statement cache is associated with a particular physical connection. See Oracle9i JDBC Developer's Guide and Reference for more information on statement caching.
You can dynamically enable and disable statement caching programmatically through the setStmtCacheSize() method of your connection object or through the stmt-cache-size
XML attribute in the DataSource
configuration. An integer value is expected with the size of the cache, which must be a value greater than 60. The cache size you specify is the maximum number of statements in the cache. The user determines how many distinct statements the application issues to the database. Then, the user sets the size of the cache to this number.
If you do not specify this element, this cache is disabled.
The following XML sets the statement cache size to 200 statements.
<data-source> ... stmt-cache-size="200" </data-source>
The task manager is a background process that performs cleanup. However, the task manager can be expensive. You can manage when the task manager performs its duties through the taskmanager-granularity
attribute in server.xml
. This element sets how often the task manager is kicked off for cleanup. Value is in milliseconds. Default is 1000 milliseconds.
<application-server ... taskmanager-granularity="60000" ...>
To use DNS for your incoming load balancing, you can do one of the following:
RMILBInitialContextFactory
object: If you use this initial context factory, the OC4J client selects a randomly chosen host from the configured machines.
RMIInitialContextFactory
object for DNS round-robin lookup, and turn off DNS caching: If you use this option, the OC4J client uses the DNS round-robin algorithm to choos between the configured IP hosts.
You must start each OC4J process that is involved in load balancing on separate IP addresses, but with the same port number. Each IP address used must be configured in the DNS server.
To retrieve a randomly selected machine from DNS, do the following:
RMILBInitialContextFactory
as your initial context.
Then, the incoming calls are randomly routed to one of the back-end machines.
java.naming.factory.initial= com.evermind.server.rmi.RMILBInitialContextFactory java.naming.provider.url=ormi://DNSserver:23792/applname java.naming.security.principal=admin java.naming.security.credentials=welcome dedicated.rmicontext=true
You can choose to use the RMIInitialContextFactory
object. In order for DNS round-robin to work properly, you must do the following:
The incoming calls are routed in a round-robin fashion to one of the back-end machines.
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.
When you have an EJB or Web application that references other shared EJB classes, you should place the referenced classes in a shared JAR. In certain situations, if you copy the shared EJB classes into WAR file or another application that references them, you may receive a ClassCastException
because of a class loader issue. To be completely safe, never copy referenced EJB classes into the WAR file of its application or into another application.
See "Packaging and Sharing Classes" for more information.
|
![]() Copyright © 2002 Oracle Corporation. All Rights Reserved. |
|