JavaMail

OC4J supports JavaMail 1.2, an API that allows you to send and receive mail through SMTP, IMAP, and POP servers. Since the JavaMail implementation is included on the server class- path , you can use it directly in any of your Java classes. However, to avoid hard-coding return addresses, hostnames, and other information, it's usually best to set up one or more JavaMail sessions, which can then be referenced logically and shared by your J2EE components .

This section walks you through setting up and using a simple SMTP mail session. For more details on individual classes and protocols, check out Sun's JavaMail documentation at http://java.sun.com/products/javamail .

Building an Application with JavaMail and JNDI

For both JavaMail and JNDI there's only so much that can be explained in writing. To get a fuller grasp of both topics let's build a sample application that leverages both technologies. The sample application you're going to build allows for an email to be sent to an arbitrary recipient from a web page.

Configuring a Mail Session

The first step when using JavaMail is configuring a mail session. A session is an instance of javax.mail.Session that has been initialized with certain default properties, such as the protocol, mail server, and from address. Each session is described in either orion-application.xml , or the global application.xml configuration file. When OC4J reads that file, it creates the session and makes it available in JNDI under the specified location.

To configure an SMTP mail session for the sample application, you need to add a <mail-session> tag to the orion-application.xml file, or to $J2EE_HOME/j2ee/home/config/application.xml:

 <?xml version="1.0"?> <!DOCTYPE orion-application PUBLIC "-//Evermind//DTD J2EE Application runtime 1.2//EN" "http://xmlns.oracle.com/ias/dtds/orion-application.dtd"> <orion-application deployment-version="1.0.2.2" default-data-source="jdbc/OracleDS">     <web-module id="javamail-web" path="javamail-web.war"/>     <persistence path="persistence"/>     <mail-session location="mail/SampleMail">         <property name="mail.transport.protocol" value="smtp"/>         <property name="mail.smtp.host" value="smtp.localdomain.com"/>         <property name="mail.from" value="default@apress.com"/>     </mail-session>     <log>         <file path="application.log"/>     </log> </orion-application> 

The important part here is of course the <mail-session> tag. The location attribute specifies the JNDI location to which the mail session will be bound and to which is a required parameter. Here you can see that the Session is bound to mail/SampleMail in the global JNDI namespace.

Tip 

OC4J doesn't include a mail server, so you'll need to specify an external SMTP, POP, or IMAP server in your mail-session attributes. The Apache James project ( http://james.apache.org ) is a 100 percent Java implementation of a mail server. Currently, James provides SMTP and POP implementations . James is a cinch to get up and running and provides an ideal solution for testing.

The <property> subelement is used to specify JavaMail properties, as described in the JavaMail specification. These properties aren't OC4J specific, but descriptions are included in Table 8-1 for your convenience.

Table 8-1: Common JavaMail Properties

Property Name

Allowed Values

Description

mail.debug

true false

Whether to print debug information. Default is false.

mail.from

String

The default sender email address to use if no "from address" is specified in a message.

mail.mime.address.strict

true false

Whether to use strict parsing on headers. Default is true.

mail.host

String

The default hostname if not specified for a particular protocol. Default is localhost .

mail. protocol .host

String

The default host name for the specified protocol. (Replace protocol with the name of a protocol, for example, SMTP, POP3, IMAP,)

mail.store.protocol

String

The default store protocol (for example, IMAP, POP3).

mail.transport.protocol

String

The default transport protocol (for example, SMTP).

mail. user

String

The default user to connect to the mail server as, if not specified for a particular protocol.

mail. protocol .user

String

The default user to connect to the mail server as, for the specified protocol. (Replace protocol with the name of a protocol, for example, SMTP, POP3, IMAP.)

mail. protocol .class

String

The fully qualified class name for the provider to be used for the specified protocol. (Replace protocol with the name of a protocol, for example, SMTP, POP3, IMAP.)

mail.protocol.port

String

The port number to be used for the specified protocol. Default depends on protocol. (Replace protocol with the name of a protocol, for example, SMTP, POP3, IMAP.)

In the previous example you can see that we've set the default transport protocol for this session to SMTP, the host to smtp.localdomain.com and the default from address to default@apress.com .

Creating a Local Resource Reference

In the previous section you created a global JNDI binding for the resource. Now you're going to bind this resource into the local namespace for the sample Servlet. JNDI resources are bound into the local component namespace using the web.xml file for Servlets and the ejb-jar.xml file for EJBs. Here's the complete web.xml file for the sample Servlet:

 <?xml version="1.0"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN" "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd"> <web-app>     <display-name>JavaMail Sample Application</display-name>     <distributable/>     <servlet>         <servlet-name>javamail</servlet-name>         <description>JavaMail Servlet</description>         <servlet-class>com.apress.oracle10g.javamail.JavaMailServlet         </servlet-class>     </servlet>     <servlet-mapping>         <servlet-name>javamail</servlet-name>         <url-pattern>/send</url-pattern>     </servlet-mapping>     <env-entry>         <env-entry-name>defaultSubject</env-entry-name>         <env-entry-value>This is the default subject</env-entry-value>         <env-entry-type>java.lang.String</env-entry-type>     </env-entry>     <resource-ref>         <res-ref-name>mail/SampleMail</res-ref-name>         <res-type>javax.mail.Session</res-type>         <res-auth>Container</res-auth>     </resource-ref> </web-app> 

The important parts here are the <resource-ref> and <env-entry> tags, along with their child tags. The <resource-ref> tag binds a resource from the global namespace, identified by the <res-ref-name> tag, into the local namespace. The <res-type> property specifies the type of object that's being bound and the <res-auth> tag specifies who is responsible for managing the security of this resource. In this case, the security will be managed by the container. The name given to this resource in the local tree is simply the global name, identified by the location attribute of the <mail-session> tag in the orion-application.xml file, prefixed with java:comp/env/ , in this case java:comp/env/mail/SampleMail.

The < env-entry> tag allows you to bind a simple value into the local JNDI namespace. The types of values available are any of the number wrapper classes ( Integer, Long , and so on), Boolean, Character , and String . In the preceding example you can see that we've created an entry for a default subject, something that isn't covered by the JavaMail configuration properties. Since this parameter is bound into the local JNDI namespace it can be accessed using java:comp/env/defaultSubject .

The Mail Form

In order to pass the appropriate parameters to the Servlet you need a simple JSP file that presents an HTML form, as follows :

 <html>     <head>         <title>JavaMail Sample Form</title>     </head>     <body>         form name="mailForm" action="send" method="post">             <table border="0">                 <tr>                     <td>From:</td>                     <td><input type="text" name="from"                     value="test@apress.com"></td>                 </tr>                 <tr>                     <td>To:</td>                     <td><input type="text" name="to" value="me@mydomain.com"></td>                 </tr>                 <tr>                     <td>Subject:</td>                     <td><input type="text" name="subject" value="Test"></td>                 </tr>                 <tr>                     <td>Body</td>                     <td><textarea name="body" rows="5"                     cols="50">Some Content</textarea></td>                 </tr>                 <tr>                     <td>JNDI Scope:</td>                     <td>                         <select name="jndiScope">                             <option value="local">Local</option>                             <option value="global">Global</option>                         </select>                     </td>                 </tr>                 <tr>                     <td colspan="2"><input type="submit" value="Send"></td>                 </tr>             </table>         </form>     </body> </html> 

You'll notice that we've added a drop-down box to allow the user to choose a JNDI scope. The mail session used by the Servlet will be obtained using the binding to the appropriate scope. This allows you to illustrate the use of the two different scopes.

Building the JavaMailServlet

The key class in this example is JavaMailServlet , which is responsible for processing the parameters submitted from the HTML form you've just seen, and creating and sending an e-mail using them. The class is quite large so we'll split it into sections and explain each one independently.

The first part of the class simply imports statements and a few constant declarations, as follows:

 package com.apress.oracle10g.javamail; import java.io.IOException; import javax.mail.Message; import javax.mail.MessagingException; import javax.mail.Session; import javax.mail.Transport; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class JavaMailServlet extends HttpServlet {     private static final String LOCAL_NAME = "java:comp/env/mail/SampleMail";     private static final String SUBJECT_NAME = "java:comp/env/defaultSubject";     private static final String GLOBAL_NAME = "mail/SampleMail"; 

Notice that we've created constants for the name of the mail session in both the local and global namespaces, along with the name of the default subject binding in the local namespace.

Next up is the doPost() method, which handles the request from the mail form, as shown here:

 protected void doPost(HttpServletRequest request, HttpServletResponse response)         throws ServletException, IOException {     // get the parameters     String jndiScope = request.getParameter("jndiScope");     String subject = request.getParameter("subject");     String to = request.getParameter("to");     String from = request.getParameter("from");     String body = request.getParameter("body"); 

You start by retrieving the parameters from the request. Next you grab the Session from the appropriate JNDI scope, as follows:

 // get the mail session Session session = null; if("local".equals(jndiScope)) {     session = getLocalMailSession(); } else {     session = getGlobalMailSession(); } 

Don't worry about the getLocalMailSession() and getGlobalMailSession() for now. It's enough to know that they return a mail session returned from the appropriate JNDI namespace. Next you create and send the mail message, as follows:

 // create the mail try {     Message mail = new MimeMessage(session);     if((subject != null) && (subject.length() > 0)) {         mail.setSubject(subject);     } else {         mail.setSubject(getDefaultSubject());     }     mail.setText(body);     if((from != null) && (from.length() > 0)) {         mail.setFrom(new InternetAddress(from));     }     mail.addRecipient(Message.RecipientType.TO, new InternetAddress(to));     // send     Transport.send(mail); } catch(MessagingException e) {     throw new ServletException(     "An error occured creating or sending the message", e); } 

If the from parameter isn't provided in the form, then you don't attempt to set it. This will cause the default value that was configured in the <mail-session> tag in orion-application.xml to be used. Also notice that if the subject parameter isn't supplied, you retrieve the default from JNDI with a call to getDefaultSubject() and use that.

Finally, for this method you redirect the user to the success.jsp file, which will display a nice message telling him that his mail has been sent, as shown here:

 // success!     RequestDispatcher rd = request.getRequestDispatcher("success.jsp");     rd.forward(request, response); } 

The next method is getGlobalMailSession() , which retrieves the mail Session bound to the global JNDI namespace (with the mail/SampleMail name), as follows:

 private Session getGlobalMailSession() throws ServletException {     try {         Context ctx = new InitialContext();         Session session = (Session)ctx.lookup(GLOBAL_NAME);         log("Obtained mail session from global context");         return session;     } catch(NamingException ex) {         throw new ServletException("Unable to locate mail session", ex);     } } 

As you can see, retrieving an object from JNDI is very simple. Once the InitialContext is created you simply call Context.lookup(), and pass in the resource name in order to retrieve the resource from the naming service. Since lookup() returns Object you need to cast the result of a call to lookup() to the appropriate type.

The remaining two methods are very similar to getGlobalMailSession() , as shown here:

 private Session getLocalMailSession() throws ServletException {         try {             Context ctx = new InitialContext();             Session session = (Session)ctx.lookup(LOCAL_NAME);             log("Obtained mail session from local context");             return session;         } catch(NamingException ex) {             throw new ServletException("Unable to locate mail session", ex);         }     }     private String getDefaultSubject() throws ServletException {         try {             Context ctx = new InitialContext();             String subject = (String)ctx.lookup(SUBJECT_NAME);             log("Obtained default subject " + subject + " from local context");             return subject;         } catch(NamingException ex) {             throw new ServletException("Unable to locate mail session", ex);         }     } } 

Notice that both of these methods use resource names that point to the local JNDI namespace. That is all there is to the process of creating and configuring the basic application. Before we continue the discussion of additional configuration options for this application, you should try out the application using both the locally and globally bound mail Session s. Also see what happens when you don't specify a from address or a subject.

Choosing Between Global and Local Namespaces

As you've seen from the sample application, there's very little difference between using a resource bound into the global scope and one that's bound into the local scope. So then, what is the benefit of using the local scope over the global scope? Simply put, there's no immediate benefit of doing so. However, consider a situation in which you have three applications running, each using a mail session bound into the global scope. What happens, then, when you wish to change the mail session in one application? You have to revisit the Java and code and recompile the application. Binding resources into the local tree provides a level of indirection for your application. However, when you create the new global Session and change the binding in the web.xml file, the name of the resource in the local namespace changes accordingly . What you need is the ability to retain the same name in the local namespace, but also to change the resource from the global tree that's bound to that reference. Enter logical references.

Using Logical References

Using logical references is very simple, but it's best demonstrated rather than explained. You can modify the sample application to use logical references to fully decouple the application from the global namespace.

The first step is a slight change to the orion-application.xml file, as shown here:

 <mail-session location="mail/SampleMail1">         <property name="mail.transport.protocol" value="smtp"/>         <property name="mail.smtp.host" value="mail.localdomain.com"/>         <property name="mail.from" value="default@apress.com"/>     </mail-session>     <mail-session location="mail/SampleMail2">         <property name="mail.transport.protocol" value="smtp"/>         <property name="mail.smtp.host" value=" mail.localdomain.com "/>         <property name="mail.from" value="default2@apress.com"/>     </mail-session> 

Notice that we've changed the name of the original mail session to mail/SampleMail1 and added a second session, mail/SampleMail2 , with a different "default from" address. If you tried to the run the application now, an error would occur during sending. The application is still looking to bind a resource with the name mail/SampleMail from the global namespace into the local scope. You could of course change the web.xml file for the application to look for one of these resources and then change the name used to look up the resource in the code. However, a better solution is to use logical references to link one of the resources in the global scope to the name that the application is looking to bind to its local namespace.

To do this, you need to create an orion-web .xml file and add it to the web application's WEB-INF directory, as follows:

 <?xml version="1.0"?> <!DOCTYPE orion-web-app PUBLIC "-//ORACLE//DTD OC4J Web Application 9.04//EN" "http://xmlns.oracle.com/ias/dtds/orion-web-9_04.dtd"> <orion-web-app>    <resource-ref-mapping name="mail/SampleMail" location="mail/SampleMail2">    </resource-ref-mapping> </orion-web-app> 

The important tag here is the <resource-ref-mapping> tag. The name attribute specifies the logical name you wish to associate with the resource, that is, the name used by the application. The location attribute specifies the location of the resource in the global namespace. Here you can see that we've associated the name mail/SampleMail with the resource bound to mail/SampleMail2 . No changes are required to the application code or to the web.xml file. You can redeploy the application and try it out again. You should note that the option to send using the global session won't work because there's no resource named mail/SampleMail bound to the global namespace. Try changing the location that the logical reference points to. You can tell the difference between the two by the "default from" address that's used when you don't specify one.



Oracle Application Server 10g. J2EE Deployment and Administration
Oracle Application Server 10g: J2EE Deployment and Administration
ISBN: 1590592352
EAN: 2147483647
Year: 2004
Pages: 150

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net