Using JavaMail Within J2EE Components

The only complication to using JavaMail within a J2EE component is the restriction that EJBs should not do direct file or network I/O. An EJB relies on the J2EE container to provide required I/O services through objects registered with the name service. You have already seen this in practice with the use of DataSource objects discussed on Day 4, “Introduction to Enterprise JavaBeans.”

To support JavaMail, a J2EE container provides support for resource references to javax.mail.Session objects. Figure 11.4 shows the Admin Console screen for the J2EE RI with a Mail Session object called mail/James representing James email server running on the local workstation.

Figure 11.4. Defining a J2EE RI JavaMail Resource.


You can create JavaMail resources using the asadmin command line interface or the Admin Console. For the Agency case study you can create the JavaMail resources using this asant command provided on the Web site:

asant create-mail

This asant target uses asadmin to define the mail/James resource.

Using JavaMail requires your EJB code to look up the Session object using JNDI as follows:

try {
    javax.mail.Session session = (javax.mail.Session)ic.lookup("java:comp/env/mail/James"));
}
catch (NamingException ex) { ... }

Once you have obtained a Session object, sending and retrieving email is no different to working with JavaMail from J2SE (as discussed in today's exercise).

The Agency case study in the Day11/exercise directory has been augmented to send an email to an applicant whenever an applicant registers with the agency or updates their details. The email includes a list of all matched jobs. To add this extra functionality a new class called EmailApplicant has been created to send the email. This new class is shown in Listing 11.10.

Listing 11.10. EmailApplicant.java Full Listing
package data;

import java.util.*;
import javax.ejb.*;
import java.util.Properties;
import javax.mail.*;
import javax.naming.*;
import javax.mail.internet.*;

public class EmailApplicant  {

    private Set jobs = new HashSet();
    private Session session;

    public EmailApplicant (Session session)  {
        this.session = session;
    }

    public void addJob (JobPK job) {
        jobs.add(job);
    }

    public void newMessage () {
        jobs.clear();
    }

    public void sendMail (String recipient) throws MessagingException {
        System.out.println("emailApplicant: "+recipient+" - "+jobs);
        MimeMessage message = new MimeMessage(session);

        if (jobs.size() == 0)
            message.setText("Sorry, there are no jobs that currently match your skills and
 location.
");
        else {
            StringBuffer msg = new StringBuffer();
            msg.append("The following is a list of the jobs that match your skills and
 location.
");
            Iterator jobsIter = jobs.iterator();
            while (jobsIter.hasNext()) {
                JobPK job = (JobPK)jobsIter.next();
                msg.append (job.getCustomer() + "/" + job.getRef() + "
");
            }
            message.setText(msg.toString());
        }

        message.setSubject("Email from the Agency Case Study");
        message.setFrom(new InternetAddress("agency@localhost"));
        message.addRecipient(Message.RecipientType.TO, new InternetAddress(recipient));

        Transport.send(message);
    }
}

The example in Listing 11.10 is given a reference to the Session object when it is constructed and maintains a list of matched jobs for the applicant. When the message is sent the body is simply a list of the matched jobs. The recipient's email address is passed as a parameter to the sendMail() method and the sender's email address is hard coded as agency@localhost.

In Listing 11.10 the sendMail() method throws any JavaMail exceptions back to the caller. This is the correct design approach as it is the responsibility of the caller, rather than EmailApplicant, to handle and possibly recover from exceptions.

The ApplicantMatch MDB has been updated to add jobs to the EmailApplicant object and then call the sendMail() method. The following code shows the changes to ApplicantMatch to send the email:

private EmailApplicant emailApplicant;

public void onMessage(Message message) {
...
    try {
...
        emailApplicant.newMessage();
        Collection col = jobHome.findByLocation(location);
        Iterator jobsIter = col.iterator();
        while (jobsIter.hasNext()) {
            JobLocal job = (JobLocal)jobsIter.next();
...
            MatchedPK key = new MatchedPK(login,job.getRef(),job.getCustomer());
            try {
                matchedHome.create(key.getApplicant(),key.getJob(),key.getCustomer(), exact);
                emailApplicant.addJob(new JobPK(job.getRef(),job.getCustomer()));
            }
            catch (CreateException ex) {
                System.out.println("ApplicantMatch: failed to create matched entry: "+key);
            }
        }
        emailApplicant.sendMail(applicant.getEmail());
    catch (javax.mail.MessagingException me) {
        System.err.println("ApplicantMatch: mail error "+me);
    }
...
}

public void setMessageDrivenContext(MessageDrivenContext ctx) {
    this.ctx = ctx;
    InitialContext ic = null;
    try {
        ic = new InitialContext();
...
    try {
        emailApplicant = new EmailApplicant((javax.mail.Session)ic.lookup("java:comp/env
/mail/James"));
    }
    catch (NamingException ex) {
        error("Error connecting to java:comp/env/mail/James:",ex);
    }
}

Note that the MessageException object is referenced by its full package name because the javax.mail package is not imported. If the class had imported javax.mail as well as javax.jms there would have been name conflicts for several classes such as Session and Message.

When building the Agency application EAR file the deployment descriptor for the ApplicantMatch class must include a resource reference for the JavaMail Session object. This is shown in the deploytool Resource Refs dialog shown in Figure 11.5.

Figure 11.5. Defining a JavaMail Resource Reference.


Adding this JavaMail resource adds the following entry to the ejb-jar.xml deployment descriptor:

<ejb-jar>
  <display-name>Entity</display-name>
  <enterprise-beans>
    <message-driven>
      <ejb-name>ApplicantMatch</ejb-name>
...
      <resource-ref>
        <res-ref-name>mail/James</res-ref-name>
        <res-type>javax.mail.Session</res-type>
        <res-auth>Container</res-auth>
        <res-sharing-scope>Shareable</res-sharing-scope>
      </resource-ref>
    </message-driven>
...
  </enterprise-beans>
...
</ejb-jar>

The following Sun-specific entry is added to the sun-ejb-jar.xml deployment descriptor to map the resource reference onto the actual resource:

<sun-ejb-jar>
  <enterprise-beans>
...
    <ejb>
      <ejb-name>ApplicantMatch</ejb-name>
      <jndi-name>jms/applicantQueue</jndi-name>
      <resource-ref>
        <res-ref-name>mail/James</res-ref-name>
        <jndi-name>mail/James</jndi-name>
        <default-resource-principal>
          <name>agency</name>
          <password>agency</password>
        </default-resource-principal>
      </resource-ref>
...
    </ejb>
  </enterprise-beans>
</sun-ejb-jar>

To deploy and run this example enter the following command from within the Day11/exercise directory:

asant build deploy run

Make sure you are running the James email server on the local workstation before running the following test. Remember that matching applicants to jobs requires that the applicant's location match the job's location and there must be at least one skill match.

To test this example, log in as the applicant juliet and add the critic skill; her skills will now partly match the Cigar Maker job advertised by winston (assuming the sample data has not been changed during previous exercises). When you click on the Update button a new message is sent to the ApplicantMatch MDB, which in turn will generate an email to send to juliet.

The Agency case study as it stands is incomplete, as it does not email customers when new applicants match advertised jobs. Adding this functionality is an optional part of today's exercise.

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

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