AutoTask Integration

The AutoTask integration project was started in response to an upgrade to the FSN application servers and a physical move of the data center from Phoenix, AZ to Chattanooga, TN. Concurrent with the move and upgrade of all the customer servers, we also moved to a new issue tracking system called AutoTask. AutoTask has a built in API that allows the auto generation of trouble tickets from emails sent to it's system. In addition, the new data center required the use of a new Microsoft Exchange server for email, instead of the standard vanilla SMTP email server that had been used by FSN for many years in the past. This project was started in conjunction with a major release to address both these issues.

Two action items were identified for this project:

  • TLS modifications to the existing email system were needed for all emails to work properly with the new Exchange server.
  • A loosely coupled AutoTask API needed to be created in FSN for feeds to utilize upon failure.

TLS Modifications

Emails in FSN were sent for various reasons such as quote letters, or alert emails to customers that their password needed to be reset, or alerts that some process had failed. Because we couldn't use the old SMTP server any longer (it was getting shut down), we were going to have to make some changes to how email was sent from FSN. One of the requirements of the new Microsoft SMTP server was that emails sent through it had to be sent using TLS (Transport Layer Security).

The original FSN email system used an older Java library to make the connection to the original SMTP server, which is why it didn't support TLS initially. To be able to support TLS, the first thing I had to do was download and integrate the newer JavaMail 1.4.3 library into the existing FSN library. Once that was done, I was able to start writing code that utilized TLS.

I located some examples of code that implemented TLS in Java, and spent some time researching it and found that it was pretty straightforward. The code change wasn't extensive - just changes to a dozen or so existing lines. It was just a matter of getting it to work with the new STMP server. I found the key to getting it working was to get the proper settings lined up on the FSN side so that the Exchange SMTP server would accept the connection properly. Once that was done and tested with some dummy emails, it was on to modifying the code to generate AutoTask tickets.

AutoTask Integration

The AutoTask integration was pretty straightforward, as the API was well documented. The API consisted of adding an XML footer to the email being sent to AutoTask that would identify things such as the account, customer and password. The ticket title and description were read from the subject and body of the email itself.

The first thing I did was create a class (AutoTaskXML) that had one static method, getAutoTaskTag, that would generate the AutoTask XML footer as needed. The reason for this design was that FSN still needed to be able to send emails without the XML tag and only use the tag when sending emails explicitly to AutoTask. There needed to be extremely loose coupling between the new and existing code.

Looking at the getAutoTaskTag method, the first thing it does is to create the empty XML document that's used to hold the XML tree that is subsequently created.

public static String getAutoTaskTag() {
    Logger log = Logger.getLogger(AutoTaskXML.class.getName());
    log.info("Creating AutoTask XML...");

    /*
        Creating an empty XML Document
    */
    DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
    DocumentBuilder docBuilder = null;
    try {
        docBuilder = dbfac.newDocumentBuilder();
    } catch (ParserConfigurationException e) {
        log.log(Level.SEVERE, "Error creating AutoTask XML", e);
    }
    Document doc = docBuilder.newDocument();
    

The next thing that's done is to read the AutoTask configuration settings from the configuration file. The Prefs object in the code below is used to read in the XML configuration file that holds all the settings.

    /*
        Reading configuration from XML configuration file
    */
    Prefs autoTaskPrefs = Prefs.ROOT.getChild("fw").getChild("messaging").getChild("autoTask");
    String IDName = autoTaskPrefs.getString("ID");
    String PWName = autoTaskPrefs.getString("PW");
    String CustomerName = autoTaskPrefs.getString("Customer");
    String EmailName = autoTaskPrefs.getString("Email");
    String ContactName = autoTaskPrefs.getString("Contact");
    String SubIssueName = autoTaskPrefs.getString("SubIssue");
    String TicketNumber = autoTaskPrefs.getString("TicketNumber");
    
 

The new XML nodes that match the XML pattern in the AutoTask API are then created and populated with the values pulled from the XML configuration file.

    // Create the root AutoTask element
    Element root = doc.createElement("Autotask");
    doc.appendChild(root);

    // Create ID element
    Element childID = doc.createElement("ID");
    childID.setAttribute("name", IDName);
    root.appendChild(childID);

    // Create PW element
    Element childPW = doc.createElement("PW");
    childPW.setAttribute("name", PWName);
    root.appendChild(childPW);

    // Create Customer element
    if (CustomerName != null && CustomerName != "") {
        Element childCustomer = doc.createElement("Customer");
        childCustomer.setAttribute("name", CustomerName);
        root.appendChild(childCustomer);
    }

    // Create Email element
    if (EmailName != null && EmailName != "") {
        Element childEmail = doc.createElement("Email");
        childEmail.setAttribute("name", EmailName);
        root.appendChild(childEmail);
    }

    // Create Contact element
    if (ContactName != null && ContactName != "") {
        Element childContact = doc.createElement("Contact");
        childContact.setAttribute("name", ContactName);
        root.appendChild(childContact);
    }

    // Create SubIssue element
    if (SubIssueName != null && SubIssueName != "") {
        Element childSubIssue = doc.createElement("SubIssue");
        childSubIssue.setAttribute("name", SubIssueName);
        root.appendChild(childSubIssue);
    }

    // Create TicketNumber element
    if (TicketNumber != null && TicketNumber != "") {
        Element childTicketNumber = doc.createElement("TicketNumber");
        childTicketNumber.setAttribute("name", TicketNumber);
        root.appendChild(childTicketNumber);
    }
    

The last thing that's done is to create a String from the XML document that represents the XML footer and return that String to the class that's calling it.

    /*
       The next section outputs a String representing the AutoTask XML footer
    */

    // Set up a transformer
    TransformerFactory transfac = TransformerFactory.newInstance();
    Transformer trans = null;
    try {
        trans = transfac.newTransformer();
    } catch (TransformerConfigurationException e) {
        log.log(Level.SEVERE, "Error creating AutoTask XML", e);
    }

    if (trans != null) {
        trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
        trans.setOutputProperty(OutputKeys.INDENT, "yes");
    }

    // Create String from XML tree
    StringWriter sw = new StringWriter();
    StreamResult result = new StreamResult(sw);
    DOMSource source = new DOMSource(doc);

    try {
        trans.transform(source, result);
    } catch (TransformerException e) {
        log.log(Level.SEVERE, "Error creating AutoTask XML", e);
    } catch (NullPointerException npe) {
        log.log(Level.SEVERE, "Error creating AutoTask XML", npe);
    }

    // Return XML String
    log.log(Level.INFO, "Autotask XML:\n" + sw.toString());
    return sw.toString();
}

The String is then appended to the original email.

The New FSN Email

The new FSN email API operated similar to the old email client, except that it now uses TLS when connecting to the email server. Everything else about the operation of the email client remained the same. A process could create an email and send it the same way it did before. The changes were transparent to the rest of the application because all of the changes were implemented either in the library code upgrade, or directly in the FSN Email API itself. This design was necessary to avoid extensive re-testing of all processes that used email if it were coupled directly to the Email API. Since the TLS changes only dealt with the connection itself, it was decided that extensive testing of the Email API was not needed beyond sending a few test emails and verifying a connection to the email server.

The biggest change was seen when an AutoTask ticket needed to be generated by a process because of an error condition. In this case, the AutoTask API was called instead of the Email API - a slight code change in the process was needed. The AutoTask API would then call the appropriate methods in the Email API, while appending the AutoTask XML to the original email. Once the AutoTask API sent the email through the Email API, the process was the same as a regular email.

The send method from the AutoTask Email API below shows how it uses the existing Email API to create and send an email to AutoTask so a ticket may be generated. All a process needs to do is supply the error message and subject when instantiating the AutoTaskEmail class and a ticket can be created. This is usually done in the catch block during error or exception trapping.

public void send() {

    // Get AutoTask ticket email address from prefs
    Prefs autoTaskPrefs = Prefs.ROOT.getChild("fw").getChild("messaging").getChild("autoTask");
    String autoTaskTicketEmail = autoTaskPrefs.getString("autoTaskTicketEmail");

    if (autoTaskTicketEmail == null || autoTaskTicketEmail.equals("")) {
        autoTaskTicketEmail = this.autoTaskTicketEmail;
    }

    // Add XML tag to message.
    this.message += AutoTaskXML.getAutoTaskTag();

    // Create email.
    EmailMessage autoTaskEmail = 
         new EmailMessage(null, autoTaskTicketEmail, this.subject, this.message);

    // Send email.
    try {
        autoTaskEmail.send(false);
    } catch (GeneralSecurityException gse) {
        String errmsg = gse.getMessage();
        log.log(Level.WARNING, errmsg);
    }
}

Once AutoTask receives the email, workflow rules route it to the person it needs to go to based on client and keywords in the email.