/* LanguageTool, a natural language style checker
* Copyright (C) 2014 Daniel Naber (http://www.danielnaber.de)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
package org.languagetool.dev.eval;
import org.languagetool.AnalyzedSentence;
import org.languagetool.markup.AnnotatedText;
import org.languagetool.rules.Rule;
import org.languagetool.rules.RuleMatch;
import org.languagetool.tools.StringTools;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
/**
* Check text against AtD via HTTP. Comment in in {@link RealWordCorpusEvaluator}.
* @since 2.7
*/
class AtDEvaluator implements Evaluator {
private static final int WAIT_MILLIS = 1500;
private final String urlPrefix;
/**
* @param urlPrefix e.g. {@code http://de.service.afterthedeadline.com/checkDocument?key=test&data=}
*/
AtDEvaluator(String urlPrefix) {
this.urlPrefix = urlPrefix;
}
@Override
public List<RuleMatch> check(AnnotatedText annotatedText) {
try {
String text = annotatedText.getPlainText();
String xml = queryAtDServer(text);
return getRuleMatches(xml, annotatedText);
} catch (XPathExpressionException e) {
throw new RuntimeException(e);
}
}
@Override
public void close() {
}
private String queryAtDServer(String text) {
try {
System.out.println("Sleeping " + WAIT_MILLIS + " before connecting " + urlPrefix + "...");
Thread.sleep(WAIT_MILLIS);
URL url = new URL(urlPrefix + URLEncoder.encode(text, "UTF-8"));
URLConnection conn = url.openConnection();
String atSign = "@";
conn.setRequestProperty("User-Agent", "AtDEvalChecker, contact daniel.naber " + atSign + " languagetool.org");
InputStream contentStream = (InputStream) conn.getContent();
return StringTools.streamToString(contentStream, "UTF-8");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private List<RuleMatch> getRuleMatches(String resultXml, AnnotatedText text) throws XPathExpressionException {
List<RuleMatch> matches = new ArrayList<>();
Document document = getDocument(resultXml);
XPath xPath = XPathFactory.newInstance().newXPath();
NodeList errors = (NodeList)xPath.evaluate("//error", document, XPathConstants.NODESET);
for (int i = 0; i < errors.getLength(); i++) {
Node error = errors.item(i);
String string = xPath.evaluate("string", error);
String description = xPath.evaluate("description", error);
String preContext = xPath.evaluate("precontext", error);
String errorText = preContext + " " + string;
int fromPos = text.getPlainText().indexOf(errorText) + preContext.length() + 1;
int toPos = fromPos + string.length();
NodeList suggestions = (NodeList)xPath.evaluate("suggestions", error, XPathConstants.NODESET);
RuleMatch ruleMatch = new RuleMatch(new AtdRule(),
text.getOriginalTextPositionFor(fromPos), text.getOriginalTextPositionFor(toPos), description);
for (int j = 0; j < suggestions.getLength(); j++) {
Node option = suggestions.item(j);
String optionStr = xPath.evaluate("option", option);
ruleMatch.setSuggestedReplacement(optionStr);
}
matches.add(ruleMatch);
}
return matches;
}
private Document getDocument(String xml) {
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
InputSource inputSource = new InputSource(new StringReader(xml));
return builder.parse(inputSource);
} catch (Exception e) {
throw new RuntimeException("Could not parse XML: " + xml);
}
}
class AtdRule extends Rule {
@Override
public String getId() {
return "ATD_RULE";
}
@Override
public String getDescription() {
return "Result from remote After The Deadline server";
}
@Override
public RuleMatch[] match(AnalyzedSentence sentence) throws IOException {
throw new RuntimeException("not implemented");
}
}
}