au.edu.ausstage.mobile.GathererManager.java Source code

Java tutorial

Introduction

Here is the source code for au.edu.ausstage.mobile.GathererManager.java

Source

/*
 * This file is part of the AusStage Mobile Service
 *
 * The AusStage Mobile Service is free software: you can redistribute
 * it and/or modify it under the terms of the GNU General Public License 
 * as published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * The AusStage Mobile Service is distributed in the hope that it will 
 * be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 
 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with the AusStage Mobile Service.  
 * If not, see <http://www.gnu.org/licenses/>.
 */

package au.edu.ausstage.mobile;

// import additional AusStage libraries
import au.edu.ausstage.utils.*;

// import the twitter-text-java library
import com.twitter.Extractor;

// import the Joda Time library
import org.joda.time.DateTime;
import org.joda.time.LocalDateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

// import other java libraries
import java.util.List;
import java.util.ListIterator;
import java.sql.ResultSet;
import javax.servlet.ServletConfig;
import org.json.simple.*;

/**
 * A class used to compile the marker data which is used to build
 * maps on web pages
 */
public class GathererManager {

    // declare private class variables
    private DbManager database;

    // declare class level constants
    private static final String SOURCE_ID = "2";
    public static final String SMS_SOURCE_ID = SOURCE_ID;
    public static final String MOBILE_WEB_SOURCE_ID = "3";

    // date related constants
    private final String DB_DATE_TIME_FORMAT = "DD-MON-YYYY HH24:MI:SS";
    private final String JODA_DATE_TIME_FORMAT = "dd-MMM-YYYY HH:mm:ss";
    private final String JODA_INPUT_DATE_TIME_FORMAT = "YY.MM.dd HH:mm:ss";
    private DateTimeFormatter dateTimeFormat = null;
    private DateTimeFormatter inputDateTimeFormat = null;

    // email related variables
    private EmailOptions emailOptions = null;
    private EmailManager emailManager = null;
    private final String EMAIL_SUBJECT = "[AusStage Feedback Gatherer] Message Processing Error";
    private final String EMAIL_MESSAGE = "Exception Report: The Feedback Gatherer experienced an error while processing a message. Details Follow:\n";

    /**
     * Constructor for this class
     *
     * @param database a valid DbManager object
     * @param servletConfig a valid ServletConfig object
     */
    public GathererManager(DbManager database, ServletConfig servletConfig) {

        // double check the parameter
        if (database == null || servletConfig == null) {
            throw new IllegalArgumentException("All parameters to this constructor are required");
        }

        // store a reference to the database object locally
        this.database = database;

        // instantiate the email processing objects
        emailOptions = new EmailOptions();
        try {

            // set the options for sending email
            emailOptions.setHost(servletConfig.getServletContext().getInitParameter("mailHost"));

            if (InputUtils.isValid(servletConfig.getServletContext().getInitParameter("mailUser")) == true) {
                emailOptions.setUser(servletConfig.getServletContext().getInitParameter("mailUser"));
                emailOptions.setPassword(servletConfig.getServletContext().getInitParameter("mailPassword"));
            }

            // use security?
            if (InputUtils.isValid(servletConfig.getServletContext().getInitParameter("mailSsl")) == true) {
                // double check the value of this parameter
                if (servletConfig.getServletContext().getInitParameter("mailSsl").equals("yes") == true
                        || servletConfig.getServletContext().getInitParameter("mailSsl").equals("true") == true) {
                    emailOptions.setSSL(true);
                } else {
                    emailOptions.setSSL(false);
                }
            }

            if (InputUtils.isValid(servletConfig.getServletContext().getInitParameter("mailTls")) == true) {
                // double check the value of this parameter
                if (servletConfig.getServletContext().getInitParameter("mailTls").equals("yes") == true
                        || servletConfig.getServletContext().getInitParameter("mailTls").equals("true") == true) {
                    emailOptions.setTLS(true);
                } else {
                    emailOptions.setTLS(false);
                }
            }

            emailOptions.setPort(servletConfig.getServletContext().getInitParameter("mailPort"));
            emailOptions.setFromAddress(servletConfig.getServletContext().getInitParameter("mailFrom"));
            emailOptions.setToAddress(servletConfig.getServletContext().getInitParameter("mailTo"));

        } catch (IllegalArgumentException ex) {
            throw new IllegalArgumentException("Unable to construct the email options class", ex);
        }

        // instantiate the email manager class
        emailManager = new EmailManager(emailOptions);

        // instantiate the date time helper variables variables
        dateTimeFormat = DateTimeFormat.forPattern(JODA_DATE_TIME_FORMAT);
        inputDateTimeFormat = DateTimeFormat.forPattern(JODA_INPUT_DATE_TIME_FORMAT);
    }

    /**
     * A method to process an SMS message
     *
     * @param callerId the id of the caller, typically the mobile device / mobile phone number
     * @param time     the time that the message was sent
     * @param date     the date that the message was sent
     * @param message  the content of the message 
     *
     * @return         the message in response to the input
     */
    public String processSMS(String callerId, String time, String date, String message) {

        // check on the parameters
        if (InputUtils.isValid(callerId) == false || InputUtils.isValid(time) == false
                || InputUtils.isValid(date) == false || InputUtils.isValid(message) == false) {
            return null;
        }

        // url decode the message
        try {
            String tmp = java.net.URLDecoder.decode(message, "UTF-8");
            message = tmp;
        } catch (java.io.UnsupportedEncodingException ex) {
        }

        // define helper variables
        Extractor extractHashTags = new Extractor();

        // get the date and time that the message was recieved
        time = time.split(" ")[0];
        if (time == null) {
            emailManager.sendSimpleMessage(EMAIL_SUBJECT, EMAIL_MESSAGE
                    + "\nDetails: Incompatible time format detected\n" + buildException(callerId, null, message));
            return "Error";
        }

        DateTime messageReceived = inputDateTimeFormat.parseDateTime(date + " " + time);
        LocalDateTime localMessageReceived = messageReceived.toLocalDateTime();

        // get a santised version of the callerId
        callerId = HashUtils.hashValue(callerId);

        // get the list of hash tags from the tweet
        List<String> hashtags = extractHashTags.extractHashtags(message);

        // check on what was returned
        if (hashtags.isEmpty() == true) {
            // no hashtags were found
            // send an exception report
            emailManager.sendSimpleMessage(EMAIL_SUBJECT,
                    EMAIL_MESSAGE + "\nDetails: No hashtags found in the message\n"
                            + buildException(callerId, localMessageReceived, message));
            return "Error";
        }

        // convert all of the found hash tags to lower case
        ListIterator<String> hashtagsIterator = hashtags.listIterator();

        while (hashtagsIterator.hasNext() == true) {

            // get the next tage in the list
            String tmp = (String) hashtagsIterator.next();

            tmp = tmp.toLowerCase();

            // replace the value we retrieved with this updated one
            hashtagsIterator.set(tmp);
        }

        // see if this is a company performance
        if (isCompanyPerformance(hashtags, callerId, message, localMessageReceived) == false) {
            // this isn't a company performance
            // is it using a performance specific id?
            if (isPerformance(hashtags, callerId, message, localMessageReceived) == false) {
                // send an exception report
                emailManager.sendSimpleMessage(EMAIL_SUBJECT,
                        EMAIL_MESSAGE + "\nDetails: Unable to find a matching performance\n"
                                + buildException(callerId, localMessageReceived, message));
                return "ERROR";
            }
        }

        // if we get this far everything is ok
        return "OK";

    }

    /**
     * A private method to process an incoming message using company specific tags
     *
     * @param hashtags a list of hashtags retrieved from the message
     * @param callerId the hash of the mobile device number
     * @param message  the text of the message
     * @param localMessageRecieved the date and time that the message was receieved
     */
    private boolean isCompanyPerformance(List<String> hashtags, String callerId, String message,
            LocalDateTime localMessageReceived) {

        /*
         * get the performance and question id
         */
        String performanceId = null;
        String questionId = null;

        // define the sql            
        String selectSql = "SELECT performance_id, question_id, SUBSTR(twitter_hash_tag, 2) "
                + "FROM mob_performances, mob_organisations, orgevlink "
                + "WHERE mob_performances.event_id = orgevlink.eventid "
                + "AND mob_organisations.organisation_id = orgevlink.organisationid "
                + "AND start_date_time < TO_DATE(?, '" + DB_DATE_TIME_FORMAT + "') "
                + "AND end_date_time + 1/12 > TO_DATE(?, '" + DB_DATE_TIME_FORMAT + "') ";

        // define the parameters array
        String[] sqlParameters = new String[2];
        sqlParameters[0] = dateTimeFormat.print(localMessageReceived);
        sqlParameters[1] = dateTimeFormat.print(localMessageReceived);

        // get the data
        DbObjects results = database.executePreparedStatement(selectSql, sqlParameters);

        // check on what is returned
        if (results == null) {
            emailManager.sendSimpleMessage(EMAIL_SUBJECT,
                    EMAIL_MESSAGE + "\nDetails: Unable to lookup performance information\n"
                            + buildException(callerId, localMessageReceived, message));
            return false;
        } else {

            // look for performances matching the hash tag from the message
            ResultSet resultSet = results.getResultSet();

            // loop through the resultset
            boolean found = false; // exit the loop early

            // reset the sql parameters
            sqlParameters = new String[6];

            try {

                while (resultSet.next() && found == false) {

                    // see if the hashtags in the message match one in the DB
                    if (hashtags.contains(resultSet.getString(3)) == true) {
                        // yep
                        sqlParameters[0] = resultSet.getString(1);
                        sqlParameters[1] = resultSet.getString(2);
                        found = true;
                    }
                }
            } catch (java.sql.SQLException ex) {
                found = false;
            }

            if (found == true) {

                /*
                 * write the message to the database
                 */

                // define the sql
                String insertSql = "INSERT INTO mob_feedback "
                        + "(performance_id, question_id, source_type, received_date_time, received_from, short_content) "
                        + "VALUES (?,?,?, TO_DATE(?, '" + DB_DATE_TIME_FORMAT + "'),?,?)";

                // build the remaining parameters

                // use the source id from the constant
                sqlParameters[2] = SOURCE_ID;

                // add the date and time
                sqlParameters[3] = dateTimeFormat.print(localMessageReceived);

                // add the user id
                sqlParameters[4] = callerId;

                // add the message
                sqlParameters[5] = message;

                // insert the data
                if (database.executePreparedInsertStatement(insertSql, sqlParameters) == false) {
                    emailManager.sendSimpleMessage(EMAIL_SUBJECT,
                            EMAIL_MESSAGE + "\nDetails: Unable to add information to the database"
                                    + buildException(callerId, localMessageReceived, message));
                    return false;
                }
            } else {
                return false;
            }
        } // end performance check

        // if we get this far everything went OK
        return true;
    }

    /**
     * A private method to process an incoming message using company specific tags
     *
     * @param hashtags a list of hashtags retrieved from the message
     * @param callerId the hash of the mobile device number
     * @param message  the text of the message
     * @param localMessageRecieved the date and time that the message was receieved
     */
    private boolean isPerformance(List<String> hashtags, String callerId, String message,
            LocalDateTime localMessageReceived) {

        /*
         * get the performance and question id
         */
        String performanceId = null;
        String questionId = null;

        String selectSql = "SELECT performance_id, question_id, hash_tag " + "FROM mob_performances "
                + "WHERE deprecated_hash_tag = 'N'";

        // get the data
        DbObjects results = database.executeStatement(selectSql);

        // double check the results
        if (results == null) {
            emailManager.sendSimpleMessage(EMAIL_SUBJECT,
                    EMAIL_MESSAGE + "\nDetails: Unable to lookup performance specific hash tags\n"
                            + buildException(callerId, localMessageReceived, message));
            return false;

        } else {
            // look for performances matching the hash tag from the message
            ResultSet resultSet = results.getResultSet();

            // loop through the resultset
            boolean found = false; // exit the loop early
            String[] sqlParameters = new String[6]; // store the parameters

            try {

                while (resultSet.next() && found == false) {

                    // see if the hashtags in the message match one in the DB
                    if (hashtags.contains(resultSet.getString(3)) == true) {
                        // yep
                        sqlParameters[0] = resultSet.getString(1);
                        sqlParameters[1] = resultSet.getString(2);
                        found = true;
                    }
                }
            } catch (java.sql.SQLException ex) {
                found = false;
            }

            if (found == false) {
                // no performance with a matching company id was found
                return false;
            } else {

                /*
                 * write the message to the database
                 */

                // define the sql
                String insertSql = "INSERT INTO mob_feedback "
                        + "(performance_id, question_id, source_type, received_date_time, received_from, short_content) "
                        + "VALUES (?,?,?, TO_DATE(?, '" + DB_DATE_TIME_FORMAT + "'),?,?)";

                // use the source id from the constant
                sqlParameters[2] = SOURCE_ID;

                // add the date and time
                sqlParameters[3] = dateTimeFormat.print(localMessageReceived);

                // add the user id
                sqlParameters[4] = callerId;

                // add the message
                sqlParameters[5] = message;

                // insert the data
                if (database.executePreparedInsertStatement(insertSql, sqlParameters) == false) {

                    emailManager.sendSimpleMessage(EMAIL_SUBJECT,
                            EMAIL_MESSAGE + "\nDetails: Unable to add the feedback to the database\n"
                                    + buildException(callerId, localMessageReceived, message));
                    return false;
                } else {
                    return true;
                }
            }
        } // end performance check   
    }

    /**
     * A private method to build an error message
     * 
     * @param callerId the callerId
     * @param date     the date of the message
     * @param time     the time of the message
     * @param message  the feedback meessage
     *
     * @return         a string representation of the message to use in the exception report
     */
    private String buildException(String callerId, LocalDateTime localMessageReceived, String message) {

        StringBuilder builder = new StringBuilder("\n******************************************\n");
        builder.append("Caller ID: " + callerId + "\n");
        if (localMessageReceived != null) {
            builder.append("Date & Time: " + dateTimeFormat.print(localMessageReceived) + "\n");
        } else {
            builder.append("Date & Time: Unavailable");
        }
        builder.append("Message: " + message + "\n");

        return builder.toString();
    }

    /**
     * A public method to process a new mobile web message
     * 
     * @param performance the unique performance identifier
     * @param message     the content of the feedback message
     * @param remoteAddr  the remote IP address of the client
     *
     * @return            a list of feedback already recieved, same content as the FeedbackManager.getInitialFeedback() method
     */
    public String processMobileWeb(String performance, String message, String remoteAddr) {

        // check on the parameters
        if (InputUtils.isValidInt(performance) == false || InputUtils.isValid(message) == false) {
            throw new IllegalArgumentException("All parameters are required to be valid");
        }

        // declare helper variables
        JSONArray jsonArray = new JSONArray();
        String question = null;

        // check to see if the performance id is valid
        String sql = "SELECT performance_id, question_id " + "FROM mob_performances " + "WHERE performance_id = ?";

        // declare the parameters
        String[] sqlParameters = { performance };

        // get the data
        DbObjects results = database.executePreparedStatement(sql, sqlParameters);

        // check on what is returned
        if (results == null) {
            emailManager.sendSimpleMessage(EMAIL_SUBJECT, EMAIL_MESSAGE
                    + "\nDetails: Unable to lookup performance information\n"
                    + buildMobileWebExceptionReport(performance, DateUtils.getCurrentDateAndTime(), message));
            return jsonArray.toString();
        }

        // get the data
        ResultSet resultSet = results.getResultSet();

        // check to see that data was returned
        if (results == null) {
            emailManager.sendSimpleMessage(EMAIL_SUBJECT, EMAIL_MESSAGE
                    + "\nDetails: No matching performance found\n"
                    + buildMobileWebExceptionReport(performance, DateUtils.getCurrentDateAndTime(), message));
            return jsonArray.toString();
        }

        // get the question id
        try {
            resultSet.next();
            question = resultSet.getString(2);
        } catch (java.sql.SQLException ex) {
            emailManager.sendSimpleMessage(EMAIL_SUBJECT, EMAIL_MESSAGE
                    + "\nDetails: SQL Error caused by looking up performance information\n"
                    + buildMobileWebExceptionReport(performance, DateUtils.getCurrentDateAndTime(), message));
            return jsonArray.toString();
        }

        // play nice and tidy up
        resultSet = null;
        results.tidyUp();
        results = null;

        // get the hash 
        String receivedFrom = null;
        if (InputUtils.isValid(remoteAddr) == true) {
            receivedFrom = HashUtils.hashValue(remoteAddr + performance);
        } else {
            receivedFrom = HashUtils.hashValue(Long.toHexString(Double.doubleToLongBits(Math.random())));
        }

        // define new sql
        sql = "INSERT INTO mob_feedback "
                + "(performance_id, question_id, source_type, short_content, received_from) "
                + "VALUES (?,?,?,?,?)";

        // define new parameters   
        sqlParameters = new String[5]; // store the parameters
        sqlParameters[0] = performance;
        sqlParameters[1] = question;
        sqlParameters[2] = MOBILE_WEB_SOURCE_ID;
        sqlParameters[3] = message;
        sqlParameters[4] = receivedFrom;

        // insert the data
        if (database.executePreparedInsertStatement(sql, sqlParameters) == false) {
            emailManager.sendSimpleMessage(EMAIL_SUBJECT, EMAIL_MESSAGE + "\nDetails: Error inserting feedback \n"
                    + buildMobileWebExceptionReport(performance, DateUtils.getCurrentDateAndTime(), message));
            return jsonArray.toString();
        }

        // get the feedback
        FeedbackManager feedback = new FeedbackManager(database);
        return feedback.getInitialFeedback(performance);
    }

    /**
     * A private method to build an exception report for a mobile web transaction
     *
     * @param performance the unique performance identifier
     * @param date        the date that the message was sent
     * @param time        the time that the message was sent
     * @param message     the content of the feedback message
     * 
     * @return            the text of the exception report
     */
    private String buildMobileWebExceptionReport(String performance, String date, String message) {

        StringBuilder builder = new StringBuilder("\n******************************************\n");
        builder.append("Performance ID" + performance + "\n");
        builder.append("Date / Time: " + date + "\n");
        builder.append("Message: " + message + "\n");

        return builder.toString();
    }
}