/*
* This file is based on an exercise for the third GATE training course,
* Montreal, August/September 2010. It is released under the GNU Lesser
* General Public Licence version 3.0, a copy of which is available at
* http://gate.ac.uk/gate/licence.html
*
* Original code (c) 2010 The University of Sheffield.
*/
package ca.openlanguage.nlpgate;
import gate.Corpus;
import gate.CorpusController;
import gate.Document;
import gate.Factory;
import gate.Utils;
import gate.creole.ExecutionException;
import gate.creole.ResourceInstantiationException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.springframework.web.HttpRequestHandler;
/**
* Simple HttpRequestHandler that uses a GATE application to process
* some text as a GATE document and render the document's features as an
* HTML table.
*/
public class GateHandler implements HttpRequestHandler {
private static final Logger log = Logger.getLogger(GateHandler.class);
/**
* Atomic counter that we use to obtain a unique ID for each handler
* instance.
*/
private static AtomicInteger nextId = new AtomicInteger(1);
/**
* The ID of this handler instance.
*/
private int handlerId;
/**
* The application that will be run.
*/
private CorpusController application;
/**
* A corpus that will be used to hold the document being processed.
*/
private Corpus corpus;
/**
* Set the application that will be run over the documents.
*/
public void setApplication(CorpusController application) {
this.application = application;
}
/**
* Create the corpus. The PostConstruct annotation means that this
* method will be called by spring once the handler object has been
* constructed and its properties (i.e. the application) have been
* set.
*/
@PostConstruct
public void init() throws Exception {
handlerId = nextId.getAndIncrement();
log.info("init() for GateHandler " + handlerId);
// create a corpus and give it to the controller
corpus = Factory.newCorpus("webapp corpus");
application.setCorpus(corpus);
}
/**
* Clean-up method. The PreDestroy annotation means that Spring will
* call the method when the object is no longer required.
*/
@PreDestroy
public void cleanup() throws Exception {
log.info("cleanup() for GateHandler " + handlerId);
Factory.deleteResource(corpus);
Factory.deleteResource(application);
}
/**
* Handle a request.
*/
public void handleRequest(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
log.info("Handler " + handlerId + " handling request");
// we take the text to annotate from a form field
String text = request.getParameter("text");
// the form also allows you to provide a mime type
String mime = request.getParameter("mime");
// delay parameter to fake a long-running process
int delay = 0;
String delayParam = request.getParameter("delay");
if(delayParam != null) {
try {
delay = Integer.parseInt(delayParam);
}
catch(NumberFormatException e) {
log.warn("Failed to parse delay value " + delayParam + ", ignored", e);
}
}
Document doc = null;
try {
log.debug("Creating document");
doc = (Document)Factory.createResource("gate.corpora.DocumentImpl",
Utils.featureMap("stringContent", text, "mimeType", mime));
}
catch(ResourceInstantiationException e) {
failureMessage("Could not create GATE document for input text", e,
response);
return;
}
try {
corpus.add(doc);
log.info("Executing application");
application.execute();
// fake a long-running application by sleeping for delay seconds
try {
Thread.sleep(delay * 1000);
}
catch(InterruptedException e) {
// re-interrupt self
Thread.currentThread().interrupt();
}
log.info("Application completed \n\n");
successMessage(doc, response);
}
catch(ExecutionException e) {
failureMessage("Error occurred which executing GATE application", e,
response);
}
finally {
// remember to do the clean-up tasks in a finally
corpus.clear();
log.info("Deleting document");
Factory.deleteResource(doc);
}
}
/**
* Render the document's features in an HTML table.
*/
private void successMessage(Document doc, HttpServletResponse response)
throws IOException {
response.setContentType("text/html");
PrintWriter w = response.getWriter();
w.println("<html>");
w.println("<head>");
w.println("<title>Results - GATE handler " + handlerId + "</title>");
w.println("</head>");
w.println("<body>");
w.println("<h1>Document features: GATE handler " + handlerId + "</h1>");
w.println("<table border='1'>");
w.println("<tr><td><b>Name</b></td><td><b>Value</b></td></tr>");
for(Map.Entry<Object, Object> entry : doc.getFeatures().entrySet()) {
log.info("Document Features: "+entry.getKey()+" value: "+entry.getValue());
w.println("<tr><td>" + entry.getKey() + "</td><td>" + entry.getValue()
+ "</td></tr>");
}
w.println("</table>");
w.println("Anotationsets: "+doc.getAnnotations().get("SectionReference").toString() );
w.println("</body>");
w.println("</html>");
}
/**
* Simple error handler - you would obviously use something more
* sophisticated in a real application.
*/
private void failureMessage(String message, Exception e,
HttpServletResponse response) throws IOException {
response.setContentType("text/html");
PrintWriter w = response.getWriter();
w.println("<html>");
w.println("<head>");
w.println("<title>Error - GATE handler " + handlerId + "</title>");
w.println("</head>");
w.println("<body>");
w.println("<h1>Error in GATE handler " + handlerId + "</h1>");
w.println("<p>" + message + "</p>");
if(e != null) {
w.println("<pre>");
e.printStackTrace(w);
w.println("</pre>");
}
w.println("</body>");
w.println("</html>");
}
}