Oracle® Containers for J2EE Servlet Developer's Guide 10g (10.1.3.1.0) Part Number B28959-01 |
|
|
View PDF |
OC4J supports annotations that the servlet 2.5 specification describes, by injecting resource references before a component instance is made available to an application. The following sections describe how to use annotations in OC4J:
In J2SE 5.0 or greater, you can specify configuration data and dependency on external resources in Java code as metadata, also referred to as annotations. You can define such data in configuration files or in annotations for services, such as EJBs or Web services, and for resource references, such as data sources and JMS destinations.
For example, in J2EE 1.4, before a servlet can refer to an EJB, the developer must define an ejb-local-ref
element, like this one:
<ejb-local-ref> <ejb-ref-name>ejb/HelloWorld</ejb-ref-name> <local>oracle.ejb.HelloWorld</local> </ejb-local-ref>
Then, to refer to the EJB in code, the developer has to use JNDI, as in this code fragment:
Context ic = new InitialContext(); HelloWorld helloWorld = (HelloWorld)ic.lookup("java:comp/env/ejb/HelloWorld"); helloWorld.greet(ÒHello!Ó);
In servlet 2.5, the client code is simplified and OC4J injects the correct resource or service. The client only needs to specify the resource or service in an annotation, such as this one:
@EJB private HelloWorld helloWorld; helloWorld.greet("Hello!");
The metadata-complete
attribute of the web-app
element in a Web application's deployment descriptor specifies whether the Web descriptor and other related deployment descriptors for this module (such as Web service descriptors) are complete. If the web.xml
file uses servlet 2.5 by setting version="2.5"
or points to the servlet 2.5 schema namespace, the OC4J servlet container will check the metadata-complete
flag to determine whether or not to process annotations. If version
is set to 2.4
or an earlier version, the servlet container does not process any annotations.
If metadata-complete
is set to true
, the default value for Servlet 2.4, the servlet container ignores any servlet annotations that are in the class files of the application. If the metadata-complete
attribute is missing or is set to false
, the default value for Servlet 2.5, and version
is set to 2.5
, the servlet container examines the class files of the application for servlet annotations and supports the annotations as follows:
The OC4J servlet container inspects resource or service references for annotation references for classes of a Web application that are located in the WEB-INF/
directory or in a JAR file under the WEB-INF/lib/
directory.
The servlet container also provides annotation support for jar files listed in MANIFEST.MF
.
The OC4J servlet container provides annotation support for managed component classes that are declared in the Web application deployment descriptor and that implement the following interfaces:
javax.servlet.Servlet
javax.servlet.Filter
javax.servlet.ServletContextListener
javax.servlet.ServletContextAttributeListencer
javax.servlet.ServletRequestListener
javax.servlet.ServletRequestAttributeListener
javax.servlet.http.HttpSessionListener
javax.servlet.http.HttpSessionAttributeListener
The OC4J servlet container injects resource or service references before any lifecycle methods are called on the instance.
(init()
for javax.servlet.Servlet
and javax.servlet.Filter
contextInitialized()
for javax.servlet.ServletContextListener
requestInitialized()
for javax.servlet.ServletRequestListener
If both an annotation and a deployment descriptor entry declare an environment entry, information in the deployment descriptor entry can override some of the information in a Resource
, EJB
, or WebServiceRef
annotation.
The following specifications describe the rules for using a deployment descriptor entry to override annotation information:
For rules to override Resource
annotations, see the Java EE 5 specification.
For rules to override EJB
annotations, see the EJB specification.
For rules to override WebServiceRef
annotations, see the Web Services specification.
If the OC4J servlet container cannot find a resource or service that it needs to inject for a class, the initialization of the class fails and OC4J issues this warning message:
Some resource(s) and/or service(s) to be injected cannot be found for class name. class name will not be put to service.
After all the resource or service references have been injected, and before any lifecycle methods are called on the instance, the method marked with the PostConstruct
annotation, if any, must be invoked to give the servlet a chance to initialize the injected resources. See "PostConstruct Annotation".
Before the servlet is taken out of service, the method marked with a PreDestroy
annotation, if any, must be invoked to give the servlet a chance to release the injected resources. See "PreDestroy Annotation".
This section describes the annotations that OC4J supports:
PersistenceContext(s) Annotation
An EJB
annotation on a field or method of an application component is equivalent to an ejb-ref
or ejb-local-ref
element in the deployment descriptor. If a field has an EJB
annotation, OC4J injects the field with a reference to the corresponding EJB component.
In an EJB
annotation, you can refer to the local or remote home interface of the bean or to the business interface of an EJB 3 bean. If the reference is to the EJB 3 business interface, OC4J injects a reference to an instance of the enterprise bean.
The following example shows a short EJB
annotation:
@EJB private ShoppingCart myCart;
The next example shows a longer EJB
annotation, which uses all of the annotation fields:
@EJB( name = "ejb/shopping-cart", beanName = "Cart1", beanInterface = ShoppingCart.class, description = "Items for purchase" ) private ShoppingCart myCart;
For more details about the EJB
annotation, see the EJB specification.
The example set in the "Annotation Example" section includes EJB annotation.
Use the Resource
annotation to declare a reference to a resource such as a data source, JMS destination, or environment entry. If you use this annotation, you do not need to declare the reference in a <resource-ref>
, <message-destination-ref>
, <env-ref>,
or <resource-env-ref>
element in the deployment descriptor.
When a Resource
annotation is applied on a field or a setter method, OC4J injects a reference to the resource declared by the annotation and maps the references to the JNDI name for the resource. When the annotation is applied to a class, the annotation declares a resource that the application will look up at runtime.
Each injection corresponds to a JNDI lookup. If the annotation does not explicitly specify the JNDI name, the name of the field combined with the fully qualified name of the class is used as the JNDI name. For example, the default JNDI name of a field named myDb
in a class MyApp
in the package com.example
would be java:comp/env/com.example.MyApp/myDb
. All JNDI names are relative to java:comp/env/
. If the annotation is applied on a setter method, the default is the JavaBeans property name corresponding to the method qualified by the class name. When the annotation is applied to a class, there is no default and the name must be specified.
The following example does not specify the JNDI name, so OC4J would use the default JNDI name:
@Resource private DataSource myDB;
The next example explicitly specifies the JNDI name:
@Resource(name="customerDB") private DataSource myDB;
For general information about annotations, see the Java EE 5 specification.
The example set in the "Annotation Example" section includes resource annotation.
Repeated annotations are not allowed, so the Resources
annotation acts as a container for multiple Resource
annotations, in this format:
public @interface Resources { Resource[] value; } // value – Array of multiple resources.
The following example shows a Resources
annotation that contains two Resource
annotations on a class, for a data source and a connection factory:
@Resources ({ @Resource (name = "myDB", type=javax.sql.DataSource), @Resource (name = "myCF", type=javax.jms.ConnectionFactory) ) public class MulResClass { //... }
OC4J invokes the method with the PostConstruct
annotation after all other resource injections have been completed and before any lifecycle methods on a component is called. This allows the component to do post-create processing. OC4J invokes this method even if the class has no other annotations.
The following example shows a PostConstruct
annotation:
@PostConstruct void doPostInjectionProcessing { //...
Note: ThePostConstruct annotation lets an arbitrary method of a servlet act as the init() method. |
OC4J invokes the method with the PreDestroy
annotation before taking the servlet out of service. This allows the servlet to release the injected resources. OC4J invokes this method even if the class has no other annotations.
The following example shows a PreDestroy
annotation:
@PreDestroy void doPreDestroyProcessing { //... }
Note: ThePreDestroy annotation lets an arbitrary method of a servlet act as the destroy() method. |
A PersistenceUnit
annotation is required for using EJB 3.0 persistence. A persistence unit has configuration details about entity managers (persistence contexts) that manage a set of related entity beans. "PersistenceContext(s) Annotation" describes the annotation for persistence contexts.
You can annotate a field or a method of a servlet with a PersistenceUnit annotation. A logical persistent unit reference refers to an entity manager factory for a persistence unit.
The following example declares a single persistence unit:
@PersistenceUnit EntityManagerFactory emf;
If you declare multiple persistence units in a servlet, you must specify an explicit unitName for each unit, as follows:
@PersistenceUnit(unitName=ÓInventoryManagementÓ) EntityManagerFactory emf;
A PersistenceUnit
annotation is equivalent to a persistence-unit-ref
element in persistence.xml
.
For more information about persistence unit references, see the Java EE 5 specification.
A PersistenceContext
annotation is required for using EJB 3.0 persistence. A persistence context is an entity manager that manages a set of related entity beans. A persistence unit has configuration details about a persistence context. "PersistenceUnit(s) Annotation" describes the annotation for persistence units. An example of a PersistenceContext
annotation follows:
@PersistenceContext EntityManager em;
If multiple persistence units are declared in the servlet, an explicit unit name must be specified in the unitName
attribute, as follows:
@PersistenceContext(unitName=ÓInventoryManagementÓ) EntityManager em;
This annotation is equivalent to a persistence-context-ref
element in persistence.xml
.
For more information about persistence context references, see the Java EE 5 specification.
Annotating with the WebServiceRef
annotation is equivalent to declaring a <resource-ref>
element in the deployment descriptor that would provide a reference to a Web service.
This annotation has two main uses:
Define a reference whose type is a generated service interface
Define a reference whose type is a service endpoint interface (SEI
)
An example of a WebServiceRef
annotation follows:
// Generated Service Interface @WebServiceRef private StockQuoteService stockQuoteService; // SEI @WebServiceRef(StockQuoteService.class) private StockQuoteProvider stockQuoteProvider;
For more details about the WebServiceRef
annotation, see Java API for XML-Based Web Services, 2.0 (JSR 224).
The DeclaresRoles
annotation defines all the security roles that compose the security model of an application. You can specify this annotation on a class, defining roles that you can test from within the methods of the annotated class, by calling isCallerInRole
.
The following example shows a DeclaresRoles
annotation:
@DeclaresRoles("Manager") public class CorporationServlet { //... }
This annotation is equivalent to the following code in a web.xml
file:
<web-app> <security-role> <role-name>Manager</role-name> </security-role> </web-app>
For more details about the DeclaresRoles
annotation, see Common Annotations for the JavaTM Platform (JSR 250)
The RunAs
annotation is equivalent to the <run-as>
element in the deployment descriptor. This annotation can only be used in classes that implement the javax.servlet.Servlet
interface or a subclass of it.
The following example shows a RunAs
annotation:
@RunAs("Admin") public class CorporationServlet { //... }
This annotation is equivalent to the following code in a web.xml
file:
<servlet> <servlet-name>CorporationServlet</servlet-name> <run-as>Admin</run-as> </servlet>
For more details about the RunAs
annotation, see Common Annotations for the JavaTM Platform (JSR 250)
Here are some rules for using annotations. For more information on general annotation guidelines, see the Java EE 5 specification.
A field or a method of the following container-managed component classes can be annotated to request that an entry from the component's environment be injected into the class:
javax.servlet.Servlet
javax.servlet.Filter
javax.servlet.ServletContextListener
javax.servlet.ServletContextAttributeListencer
javax.servlet.ServletRequestListener
javax.servlet.ServletRequestAttributeListener
javax.servlet.http.HttpSessionListener
javax.servlet.http.HttpSessionAttributeListener
A field or method can have any access qualifier (such as public
or private
).
A field or method cannot be static, except for the fields or methods of the application client main class that have been annotated for injection. These fields or methods must be static.
Any violation of the preceding rules is an error that will result in a message or messages being logged. The violating class will not be put in service.
Annotations applied on a class do not cause resource injections. Instead, they declare an entry in an application component's environment that the application component can look up through JNDI or the component context lookup method.
Resource annotations can be specified in any of the classes in the first item of this list or on any of their superclasses, as the following example shows. Injection of resources follows the Java language overriding rules for visibility of fields and methods.
Class A { @Resource private DataSource myDS; // Injected resource not visible in class B //... } Class B extends Class A { public DataSource myDS; // Not a resource, needs to do JNDI lookup //... }
Whether or not annotations are used for Web applications with servlet version 2.5, if the metadata-complete
attribute of <web-app>
is missing from the deployment descriptor or is set to false
(the servlet 2.5 default value), OC4J needs to load all the classes under WEB-INF/
and WEB-INF/lib
to look for annotations. This loading can have some impact on Oracle Application Server performance at startup. When you are not using annotations, you can avoid this performance impact by specifying metadata-complete="true"
.
This startup performance impact is applicable only for Web applications with servlet version 2.5. For Web applications with servlet version 2.4 or lower, there will be no performance impact.
This section contains an example of a servlet using annotations and the corresponding web.xml
file.
The servlet illustrates the Servlet 2.5 way of doing things and then commented out is the Servlet 2.4 way of doing things as a comparison. The servlet demonstrates one @EJB
annotation and two @Resource
annotations.
The web.xml
file illustrates the version=
and metadata-complete
settings required to enable annotations to be used:
<web-app version="2.5" metadata-complete="false"> ... </web-app>
For additional information, see the document "How-To: Using Dependency Injection In Web Module" on the following site:
http://www.oracle.com/technology/tech/java/oc4j/10131/how_to/index.html
Here is the web.xml file example.
<?xml version="1.0"?> <web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.5" metadata-complete="false" > <display-name>Annotation Example</display-name> <description>A few examples of Servlet 2.5 Annotation and Resource Injection</description> <servlet> <display-name>hello</display-name> <servlet-name>HelloServlet</servlet-name> <servlet-class>HelloServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>HelloServlet</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping> <env-entry> <env-entry-name>EmpNo</env-entry-name> <env-entry-type>java.lang.Integer</env-entry-type> <env-entry-value>15</env-entry-value> </env-entry> </web-app>
Here is the HelloServlet.java servlet example.
import java.io.*; import javax.servlet.*; import javax.servlet.http.*; import javax.annotation.Resource; import javax.sql.*; import java.sql.*; import javax.naming.*; import org.acme.*; import javax.rmi.*; import javax.ejb.*; public class HelloServlet extends HttpServlet { @EJB HelloObject bean; @Resource(name="EmpNo") int empNo; @Resource(name="jdbc/OracleDS") private DataSource db; public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.setContentType("text/html"); PrintWriter writer = res.getWriter(); // ejb invocation writer.println(bean.sayHello()+"<br>"); // fetch value set by deployer writer.println("EmpNo="+empNo+"<br>"); // make a db connection writer.println("db="+getConnection()+"<br>"); } public Connection getConnection() { Connection conn = null; try { if (db != null) { conn = db.getConnection(); } } catch (Exception e) { e.printStackTrace(); } return conn; } // The following is the pre-2.5 way to do it. /* public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.setContentType("text/html"); PrintWriter writer = res.getWriter(); InitialContext ctx = new InitialContext(); Object obj = ctx.lookup("java:comp/env/ejb/Hello"); HelloHome ejbHome = (HelloHome) PortableRemoteObject.narrow(obj,HelloHome.class); HelloObject bean = ejbHome.create(); // ejb invocation writer.println(bean.sayHello()+"<br>"); // fetch value set by deployer Context myEnv = (Context) ctx.lookup("java:comp/env"); Integer empNoInteger = (Integer) myEnv.lookup("EmpNo"); int empNo = empNoInteger.intValue(); writer.println("EmpNo="+empNo+"<br>"); // make a db connection writer.println("db="+getConnection()+"<br>"); } public Connection getConnection() { Context initCtx = new InitialContext(); javax.sql.DataSource db = (javax.sql.DataSource) initCtx.lookup("java:comp/env/jdbc/OracleDS"); Connection conn = null; try { if (db != null) { conn = db.getConnection(); } } catch (Exception e) { e.printStackTrace(); } return conn; } */ }