Package org.dtk.util

Source Code of org.dtk.util.Feedback

package org.dtk.util;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Formatter;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.ServletContext;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.dtk.resources.exceptions.IncorrectParameterException;

import com.sun.syndication.feed.atom.Feed;
import com.sun.syndication.feed.synd.SyndContent;
import com.sun.syndication.feed.synd.SyndContentImpl;
import com.sun.syndication.feed.synd.SyndEntry;
import com.sun.syndication.feed.synd.SyndEntryImpl;
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.feed.synd.SyndFeedImpl;
import com.sun.syndication.io.FeedException;
import com.sun.syndication.io.SyndFeedOutput;

/***
* Tiny utility class to log all feedback submissions from the front-end
* application. Handles AJAX submissions of JSON fields. Possible fields
* include "name", "email address", "category" & "description". We simply
* turn all submissions into log lines.
*
* Also produces an RSS 2.0 feed for all existing log entries, updated as new entries
* are received.
*
* @author James Thomas
*/

@Path("/feedback")
public class Feedback {
 
  /**
   * RSS 2.0 feed for the Feedback submissions
   */
  protected FeedbackRssFeed logEntriesRssFeed;
 
  /**
   * Simple log formatter, used to construct log entries.
   */
  protected static final Formatter logFormatter = new SimpleFormatter();   
 
  /**
   * Expected feedback form parameters. Only mandatory parameter
   * is "details", without that feedback is useless.
   */   
  protected static final String EMAIL_ADDRESS = "email";
  protected static final String CONTACT_NAME = "name";
  protected static final String FEEDBACK_CATEGORY = "category";
  protected static final String FEEDBACK_DETAILS = "details";
 
  /**
   * Regular expression used to differentiate log entries in the
   * existing feedback logs.
   */
  protected static final Pattern NEW_LOG_ENTRY_PATTERN
    = Pattern.compile("(.*) org.dtk.util.Feedback submitFeedback$");
 
  /**
   * Error message when the user has submitted feedback without
   * the mandatory details parameter.
   */
  protected static final String MISSING_FEEDBACK_DETAILS = "Unable to process " +
    "feedback submission, missing mandatory parameter 'details'.";
 
  /**
   * Log message generated for each feedback submission
   */
  protected static final String FEEDBACK_MSG_FORMAT = "Feedback submission, category " +
    "%1$s, submitted by %2$s (%3$s): %4$s";
 
  /**
   * All feedback is sent straight to this logging instance.
   */
  private static Logger logger = Logger.getLogger(Feedback.class.getName());
 
  /**
   * On instantiation, read all existing feedback entries and used to
   * construct the RSS feed for feedback submissions.
   */
  public Feedback() {
    initialiseLogFeed();
  }
 
  /**
   * API call to allow feedback submission, must contain
   * mandatory feedback parameter, details. Valid submissions are sent
   * through to the logging service and added to the RSS feed generated.
   *
   * @param feedbackSubmission - JSON object containing feedback details
   */
  @POST
  @Consumes(MediaType.APPLICATION_JSON)
  public void submitFeedback(HashMap<String, Object> feedbackSubmission) {
    if (feedbackSubmission.containsKey(FEEDBACK_DETAILS)) {     
      addFeedbackFeedEntry(feedbackSubmission);
      logger.log(Level.INFO, constructLogMessage(feedbackSubmission));
    } else {
      throw new IncorrectParameterException(MISSING_FEEDBACK_DETAILS);
    }
  } 
 
  /**
   * Return feedback submissions formatted into a valid
   * RSS 2.0 feed. All submission entries are included as
   * individual feed items.
   *
   * @return RSS 2.0 feed for feedback entries
   * @throws FeedException - Unable to create output feed
   */
  @GET
  @Produces(MediaType.APPLICATION_XML)
  public String getFeedbackFeed() throws FeedException {   
        SyndFeedOutput output = new SyndFeedOutput();
        return output.outputString(logEntriesRssFeed);       
  }
 
  /**
   * Read existing feedback log file, if it exists, turning
   * into a series of log entries submitted. Use these to instantiate
   * the RSS feed to be served up.
   */
  protected void initialiseLogFeed() {
    String existingFeedbackLogs = getExistingFeedbackLogs();   
    List<String> logEntries = parseLogFileIntoEntries(existingFeedbackLogs);   
    logEntriesRssFeed = new FeedbackRssFeed(logEntries);
  }
   
  /**
   * Add new feedback entry into the currently RSS feed. Format as an existing
   * log line and then add directly into the feed stream. 
   *
   * @param feedbackSubmission - JSON object containing feed details.
   */
  protected void addFeedbackFeedEntry(HashMap<String, Object> feedbackSubmission) {   
    String formattedLogEntry = logFormatter.format(new LogRecord(Level.INFO, constructLogMessage(feedbackSubmission)));
    logEntriesRssFeed.addLogEntry(formattedLogEntry);   
  }
 
  /**
   * Return contents of the feedback log file used to store submission entries.
   * If there is a problem reading the file, return an empty string.
   *
   * @return Log file contents
   */
  protected String getExistingFeedbackLogs() {
    String existingFeedbackLog = "";
    String logFile = String.format(ContextListener.LOG_FILE_FORMAT, Feedback.class.getName());
   
    try {   
      File file = new File(logFile);
      if (file.exists()) {
        existingFeedbackLog = FileUtils.readFileToString(file);         
      } else {
        logger.warning("Unable to read existing feedback log file, " + logFile);
      }     
    } catch (IOException e) {
      logger.warning("Unable to read existing feedback log file, " + logFile);
    }
   
    return existingFeedbackLog;   
  }
 
  /**
   * Parse through existing log file contents, pulling out
   * individual log entries as separate strings. Returns a list
   * of those entries as single strings.
   *
   * @param logFileContents - Existing log file contents
   * @return List of log entry strings
   */
  protected List<String> parseLogFileIntoEntries(String logFileContents) {
    List<String> logEntries = new ArrayList<String>();   
    String[] logFileLines = logFileContents.split("\n");
    StringBuffer logEntryBuffer = new StringBuffer();
   
    for(String line: logFileLines) {     
      Matcher matcher =  NEW_LOG_ENTRY_PATTERN.matcher(line);
     
      if (matcher.find() ) {
        storeAndClearBuffer(logEntryBuffer, logEntries);                 
      }
     
      logEntryBuffer.append(line + "\n");     
    }   
 
    storeAndClearBuffer(logEntryBuffer, logEntries);
   
    return logEntries;
  }
 
  /**
   * Add StringBuffer contents as a new List<String> entry, ignoring
   * if the contents are empty, following by reseting the buffer to
   * empty afterwards.
   *
   * @param logEntryBuffer - String buffer 
   * @param logEntries - List of strings
   */
  protected void storeAndClearBuffer(StringBuffer logEntryBuffer, List<String> logEntries) {
    if (logEntryBuffer.length() > 0) {
      logEntries.add(logEntryBuffer.toString());
      logEntryBuffer.delete(0, logEntryBuffer.length());
    }   
  }
 
  /**
   * Turn feedback submission into a human-readable log string containing all
   * the parameter values. 
   *
   * @param feedbackSubmission - Feedback parameters submitted
   * @return Human readable log message string
   */
  protected String constructLogMessage(HashMap<String, Object> feedbackSubmission) {
    // Access all parameters, optional parameters default to "unknown" if missing
    String details = getFeedbackParam(feedbackSubmission, FEEDBACK_DETAILS),
      contactName = getFeedbackParam(feedbackSubmission, CONTACT_NAME),
      emailAddress = getFeedbackParam(feedbackSubmission, EMAIL_ADDRESS),
      feedbackCategory = getFeedbackParam(feedbackSubmission, FEEDBACK_CATEGORY);
   
    return String.format(FEEDBACK_MSG_FORMAT, feedbackCategory, contactName, emailAddress, details);
  }
 
  /**
   * Extract feedback parameter from user submission, default to "unknown"
   * when no key is found.
   *
   * @param feedbackSubmission - JSON details with feedback parameters
   * @param parameterKey - Feedback parameter we want
   * @return Feedback parameter value
   */
  protected String getFeedbackParam(HashMap<String, Object> feedbackSubmission, String parameterKey) {
    String parameterValue = "Unknown";
   
    if (feedbackSubmission.containsKey(parameterKey)) {
      parameterValue = (String) feedbackSubmission.get(parameterKey);
    }
   
    return parameterValue;
  }
}
TOP

Related Classes of org.dtk.util.Feedback

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.