Extending the Agency Case Study

As the final part of today's lesson, you will return to code written on Day 10, “Message-Driven Beans,” and amend the Agency application to handle messages received as XML. First refresh your memory by returning to Day 10 and looking back over the code for the MessageSender helper class in Listing 10.4, the ApplicantMatch Message-driven bean in Listing 10.5, and the code for the AgencyBean and RegisterBean Session beans. This code has also been reproduced in the Examples directory for Day 16 on the CD-ROM.

The MessageSender class will now be modified to create an XML document that contains the applicant's full details to send to the ApplicantMatch bean. To achieve this, the following changes to the Day 10 code will be made.

  1. Amend the AgencyBean and RegisterBean Session beans to pass the applicant's full details in the JMS message when an applicant is first registered or the applicant's location or skills are changed.

  2. Amend the MessageSender helper class to create an XML representation of the data and send this as a message to the jms/applicantQueue.

  3. Amend the ApplicantMatch Message-driven bean to parse the XML message instead of using Entity beans to look up the applicant's details.

The following XML schema represents the applicant's details.

<?xml version="1.0"?>
<xsd:schema>
  <xsd:element name="applicantSummary">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element name="applicant" type="applicantType" minOccurs="0"
 maxOccurs="unbounded"/>
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>

  <xsd:complexType name="applicantType">
    <xsd:sequence>
      <xsd:element name="name" type="xsd:string"/>
      <xsd:element name="email" type="xsd:string"/>
      <xsd:element name="summary" type="xsd:string"/>
      <xsd:element name="location" type="xsd:string"/>
      <xsd:element name="skill" type="xsd:string" minOccurs="1" maxOccurs="unbounded"/>
    </xsd:sequence>
      <xsd:attribute name="login" type="xsd:string" use="required"/>
      <xsd:attribute name="new" type="xsd:boolean" use="required"/>
  </xsd:complexType>
</xsd:schema>
					

For example the details for romeo would be constructed as follows:

<?xml version ="1.0"?>
<applicantSummary>
  <applicant login="romeo" new="false">
    <name>Romeo Montague</name>
    <email>[email protected]</email>
    <summary>Dutiful son</summary>
    <location>Wessex</location>
    <skill>Cook</skill>
    <skill>Bodyguard</skill>
  </applicant>
</applicantSummary>

Step 1—Change Session Beans

The following changes are required to AgencyBean. Replace the createApplicant() method with one that calls messageSender.sendApplicant() with all the applicants details. The following code shows how this is achieved.

public void createApplicant(String login, String name, String email) throws
 DuplicateException, CreateException{
    try {
        ApplicantLocal applicant = applicantHome.create(login,name,email); messageSender
.sendApplicant(applicant.getLogin(), applicant.getName(), applicant.getEmail(), applicant
.getSummary(), applicant.getLocation(). getName(), applicant.getSkills(), true);
    }
    catch (CreateException e) {
        error("Error creating applicant "+login,e);
    }
    catch (JMSException e) {
        error("Error sending applicant details to message bean "+login,e);
    }
}

Similarly, update RegisterBean to call the MessageSender.send() method with the applicant's full details when a new applicant is added or the details are changed. This time, the information can be obtained from private methods in the RegisterBean class.

Replace the messageSender method call:

messageSender.sendApplicant(getLogin(), getName(), getEmail(), getSummary(),

with

messageSender.sendApplicant(applicant.getLogin(), applicant.getName(), applicant.getEmail
(), applicant.getSummary(), applicant.getLocation(). getName(), applicant.getSkills(), false);

Note that the final parameter to the sendApplicant() method indicates whether this is a new applicant or an updated one. It is set to true in AgencyBean (to indicate new applicant) and false in RegisterBean (to indicate that applicant details have been updated).

Step 2—Amend the MessageSender Helper Class

The MessageSender class now defines some extra methods that construct the XML document. For simplicity, these methods have been left in the MessageSender class, but they can be placed in their own helper class if desired.

The following two methods are used to create XML start and an end tags and append the tag to a StringBuffer object.

private void addStartTag (StringBuffer buf, String tag, String attributes) {
        buf.append("<");
        buf.append(tag);
        buf.append(attributes);
        buf.append(">");
    }
    private void addEndTag (StringBuffer buf, String tag) {
        buf.append("</");
        buf.append(tag);
        buf.append(">");
    }

The addElement() method constructs an entire XML element:

private void addElement (StringBuffer buf, String tag, String attributes, String contents) {
    addStartTag(buf, tag, attributes);
    buf.append (contents);
    addEndTag (buf, tag);
}

The applicant XML is created by the applicantXML() method:

private final String XMLVersion = "<?xml version ='1.0'?>";
private String applicantXML (String applicant, String name, String email, String summary,
 String location, String[] skills, boolean newApplicant) throws JMSException {
    StringBuffer xmlText = new StringBuffer(XMLVersion);
    addStartTag(xmlText, "applicantSummary", "");
    String newApplicantString = newApplicant?"true'":"false'";
    String attributes = " login='" + applicant + "' new='" + newApplicantString;
    addStartTag(xmlText, "applicant", attributes);
    addElement(xmlText, "name", "", name);
    addElement(xmlText, "email", "", email);
    addElement(xmlText, "summary", "", summary);
    addElement(xmlText, "location", "", location);
    Iterator it = skills.iterator();
        while (it.hasNext()){
            SkillLocal skill = (SkillLocal) it.next();
            addElement(xmlText, "skill", skill.getName());        }
    addEndTag(xmlText, "applicant");
    addEndTag (xmlText, "applicantSummary");
    return xmlText.toString();
}

Finally, the sendApplicant() method is changed to construct the XML document before embedding it in the JMS message body:

public void sendApplicant(String applicant, String name, String email,
String summary, String location, String[] skills, boolean newApplicant) throws JMSException {
    TextMessage message = queueSession.createTextMessage();
    String xml = applicantXML (applicant, name, email, summary, location, skills,
 newApplicant);
    message.setText(xml);
    queueSender.send(message);
}
						

Step 3—Amend the ApplicantMatch Message-Driven Bean

The ApplicantMatch bean now receives all the information required to perform a match between applicants and jobs in the JMS message. Instead of using the Agency Entity beans to obtain the location and skill, it parses the XML message. To do this, the onMessage() method has been changed to perform the following functions.

  1. Get the XML text out of the JMS message.

    xmlText = ((TextMessage)message).getText();
    
  2. Build a DOM tree from the XML.

    DocumentBuilder builder = factory.newDocumentBuilder();
    InputSource is = new InputSource (new StringReader(xmlText));
    document = builder.parse(is);
    document.getDocumentElement().normalize ();
    
  3. Get the applicant's login and newApplicant status from the applicant node.

    String login = getAttribute(document,"applicant", "login");
    String newApplicant = getAttribute (document,"applicant", "new");
        private String getAttribute (Document document, String tag, String attribute) {
            NodeList nodes = document.getElementsByTagName(tag);
            NamedNodeMap attrs = nodes.item(0).getAttributes();
            Node n = attrs.getNamedItem(attribute);
            if (n == null)
                return null;
            else
                return n.getNodeValue().trim();
        }
    
  4. If this is not a new applicant, make any old matches are removed from the Match table.

    if (newApplicant.equals("false")) {
        matchedHome.deleteByApplicant(login);
    }
    
  5. Get the applicant's skills and location from the XML elements.

    String location = getTagContents (document,"location");
    Collection appSkills = getMultipleContents (document,"skill");
    private String getTagContents (Document document, String tag) {
        NodeList nodes = document.getElementsByTagName(tag);
        NodeList contents = nodes.item(0).getChildNodes();
        int len = (contents != null) ? contents.getLength() : 0;
        Node text = contents.item(0);
        if (len != 1 || text.getNodeType() != Node.TEXT_NODE) {
            return null;
        }
        return text.getNodeValue().trim();
    }
    
    private Collection getMultipleContents (Document document, String tag) {
        Collection col = new ArrayList();
        NodeList nodes = document.getElementsByTagName(tag);
        int len = (nodes != null) ? nodes.getLength() : 0;
        for (int i = 0; i < len; i++) {
            NodeList contents = nodes.item(i).getChildNodes();
            Node text = contents.item(0);
            if (text.getNodeType() == Node.TEXT_NODE) {
                col.add(text.getNodeValue().trim());
            }
        }
        return col;
    }
    

    This replaces the previous code

    ApplicantLocal applicant = applicantHome.findByPrimaryKey(login);
    String location = applicant.getLocation().getName();
    Collection skills = applicant.getSkills();
    Collection appSkills = new ArrayList();
    Iterator appIt = skills.iterator();
    while (appIt.hasNext()) {
        SkillLocal as = (SkillLocal)appIt.next();
        appSkills.add(as.getName());
    }
    

As before, deploy this code and test by creating new applicants or updating existing applicants. Use the table.jsp created on Day 13, “JavaServer Pages,”, or any other method you choose, to display the contents of the matched table.

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

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