/*
* Copyright (C) 2010 Interactive Media Management
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package dk.i2m.converge.web.servlets;
import dk.i2m.spellchecker.LanguageNotSupportedException;
import dk.i2m.spellchecker.SpellChecker;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.richfaces.json.JSONArray;
import org.richfaces.json.JSONException;
import org.richfaces.json.JSONObject;
/**
* {@link HttpServlet} implementing the TinyMCE spellchecking plug-in protocol.
* The servlet receives and responds with JSON messages.
* <p>The incoming message must have a <code>method</code> parameter and
* <code>params</code> array. The <code>method</code> must be either
* <code>checkWords</code> or <code>getSuggestions</code>. The
* <code>params</code> array must contain the language identifier as the first
* entry and the second entry must be an array of the words to check.<p>
*
* @author Allan Lykke Christensen
*/
public class SpellCheckerServlet extends HttpServlet {
private static final String DEFAULT_LANGUAGE = "en";
private static final String METHOD = "method";
private static final String METHOD_CHECK_WORDS = "checkWords";
private static final String METHOD_GET_SUGGESTIONS = "getSuggestions";
private static final String PARAMS = "params";
private static final String RESPONSE_ID = "id";
private static final String RESPONSE_RESULT = "result";
private static final String RESPONSE_ERROR = "error";
/** Application logger. */
private static final Logger LOG = Logger.getLogger(SpellCheckerServlet.class.getName());
/**
* Processes the JSON request received.
*
* @param request
* Request to process
* @return Response to the request
* @throws org.richfaces.json.JSONException
* If the request is not valid JSON
*/
public JSONObject process(JSONObject request) throws JSONException {
JSONObject response = new JSONObject();
String cmd = request.getString(METHOD);
String lang = request.getJSONArray(PARAMS).getString(0);
if (lang == null) {
lang = DEFAULT_LANGUAGE;
}
SpellChecker sc;
try {
String textToCheck;
sc = SpellChecker.getInstance(lang);
String[] output;
if (METHOD_CHECK_WORDS.equalsIgnoreCase(cmd)) {
JSONArray words = request.getJSONArray(PARAMS).getJSONArray(1);
textToCheck = words.join(" ").replaceAll("\"", "");
output = sc.getMisspelledWords(textToCheck);
// If there are no spelling mistakes, TinyMCE pops up a lame
// dialog that blocks for entry on Safari - therefore add a
// dummy misspelledword
} else if (METHOD_GET_SUGGESTIONS.equalsIgnoreCase(cmd)) {
textToCheck = request.getJSONArray(PARAMS).getString(1);
output = sc.getSuggestions(textToCheck);
} else {
output = new String[0];
}
response.put(RESPONSE_ID, JSONObject.NULL);
response.put(RESPONSE_RESULT, Arrays.asList(output));
response.put(RESPONSE_ERROR, JSONObject.NULL);
} catch (LanguageNotSupportedException ex) {
response.put(RESPONSE_ERROR, ex.getMessage());
}
return response;
}
/**
* Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.
* @param request servlet request
* @param response servlet response
* @throws ServletException if a servlet-specific error occurs
* @throws IOException if an I/O error occurs
*/
protected void processRequest(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
try {
JSONObject requestJSONdata = decode(request.getInputStream());
LOG.log(Level.FINE, "Received request: {0}", requestJSONdata.toString());
JSONObject jsonResponse = process(requestJSONdata);
LOG.log(Level.FINE, "Generated response: {0}", jsonResponse.toString());
response.getOutputStream().print(jsonResponse.toString());
} catch (JSONException ex) {
LOG.log(Level.SEVERE, ex.getMessage());
LOG.log(Level.FINEST, null, ex);
}
}
/**
* Decodes the content from the given {@link InputStream} to a
* {@link JSONObject}.
*
* @param is
* {@link InputStream} to decode
* @return {@link JSONObject} containing the content from the
* {@link InputStream}
* @throws java.io.IOException
* If the content could not be read from the {@link InputStream}
* @throws org.richfaces.json.JSONException
* If the content is not valid JSON
*/
private JSONObject decode(InputStream is) throws IOException, JSONException {
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String jsonString;
StringBuilder jsonStringBuffer = new StringBuilder();
while ((jsonString = br.readLine()) != null) {
jsonStringBuffer.append(jsonString);
}
return new JSONObject(jsonStringBuffer.toString());
}
/**
* Handles the HTTP <code>GET</code> method.
*
* @param request
* servlet request
* @param response
* servlet response
* @throws ServletException
* if a servlet-specific error occurs
* @throws IOException
* if an I/O error occurs
*/
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
processRequest(request, response);
}
/**
* Handles the HTTP <code>POST</code> method.
*
* @param request
* servlet request
* @param response
* servlet response
* @throws ServletException
* if a servlet-specific error occurs
* @throws IOException
* if an I/O error occurs
*/
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
processRequest(request, response);
}
/**
* Returns a short description of the servlet.
*
* @return String containing servlet description
*/
@Override
public String getServletInfo() {
return "Spellchecker Servlet for TinyMCE";
}
}