/******************************************************************************
*
* Copyright 2014 Paphus Solutions Inc.
*
* Licensed under the Eclipse Public License, Version 1.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
package org.botlibre.sense.service;
import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.net.URL;
import java.util.HashMap;
import java.util.logging.Level;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import net.sf.json.JSONSerializer;
import org.botlibre.api.knowledge.Network;
import org.botlibre.api.knowledge.Vertex;
import org.botlibre.knowledge.Primitive;
import org.botlibre.sense.BasicSense;
import org.botlibre.sense.http.Freebase;
import org.botlibre.sense.http.Http;
import org.botlibre.sense.http.Wiktionary;
import org.botlibre.sense.wikidata.Wikidata;
import org.botlibre.util.TextStream;
import org.botlibre.util.Utils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
/**
* Process remote service requests, such as SRAIX, Pannous, BotBots, Freebase, Wikidata, HTML, XML, Twiter, Facebook, RSS.
*/
public class RemoteService extends BasicSense {
public static String PANNOUS = "http://weannie.pannous.com";
public static String SERVER = "http://www.botlibre.com";
protected ThreadLocal<DocumentBuilder> parser = new ThreadLocal<DocumentBuilder>();
public RemoteService() {
}
/**
* Invoke the remote service request, and return the result.
*/
public String request(String message, String bot, String botid, String server, Primitive service, String apikey, int limit, String hint, Network network) throws Exception {
if (!isEnabled()) {
return null;
}
try {
log("Request", Level.INFO, message);
if (service != null) {
if (service.equals(Primitive.PANNOUS)) {
return requestPannous(message, botid, server, apikey, limit);
} else if (service.equals(Primitive.BOTLIBRE)) {
server = SERVER;
} else if (service.equals(Primitive.BOTLIBRETWITTER)) {
server = "http://twitter.botlibre.com";
} else if (service.equals(Primitive.PAPHUS)) {
server = "http://www.botlibre.biz";
} else if (service.equals(Primitive.WIKIDATA)) {
return requestWikidata(message, botid, server, apikey, limit, hint, network);
} else if (service.equals(Primitive.FREEBASE)) {
return requestFreebase(message, botid, server, apikey, limit, hint, network);
} else if (service.equals(Primitive.WIKTIONARY)) {
return requestWiktionary(message, botid, server, apikey, limit, hint, network);
} else if (service.equals(Primitive.XML)) {
return requestXML(message, botid, server, apikey, limit, hint, network);
} else if (service.equals(Primitive.JSON)) {
return requestJSON(message, botid, server, apikey, limit, hint, network);
} else if (service.equals(Primitive.HTML)) {
return requestHTML(message, botid, server, apikey, limit, hint, network);
} else if (service.equals(Primitive.FORGE)) {
return requestFORGE(message, botid, server, apikey, limit, hint, network);
}
}
if ((server == null || server.isEmpty()) && (botid == null || botid.isEmpty()) && (bot == null || bot.isEmpty())) {
return requestPannous(message, botid, server, apikey, limit);
}
if (server != null && !server.isEmpty()) {
server = server.toLowerCase();
if (!server.startsWith("http")) {
server = "http://" + server;
}
} else {
server = SERVER;
}
String url = server + "/pandora/talk-xml?";
if (botid != null && !botid.isEmpty()) {
url = url + "botid=" + botid;
} else if (bot != null && !bot.isEmpty()) {
url = url + "botid=" + Utils.encodeURL(bot);
}
if (apikey != null && !apikey.isEmpty()) {
url = url + "&custid=" + apikey;
}
url = url + "&input=" + Utils.encodeURL(message);
log("SERVICE", Level.INFO, url);
InputStream stream = Utils.openStream(new URL(url), 20000);
String result = Utils.loadTextFile(stream, "UTF-8", 1000000);
log("Response", Level.FINE, result);
Element dom = parseXML(result);
log("Response", Level.FINE, result);
if (result == null) {
return null;
}
NodeList thats = dom.getElementsByTagName("that");
if (thats == null || thats.getLength() == 0) {
return null;
}
String text = thats.item(0).getTextContent().trim();
if (limit > 0) {
StringWriter writer = new StringWriter();
TextStream textStream = new TextStream(text);
for (int index = 0; index < limit; index++) {
if (textStream.atEnd()) {
break;
}
writer.write(textStream.nextSentence());
}
text = writer.toString();
}
return text;
} catch (Exception exception) {
log(exception);
return null;
}
}
/**
* Invoke the Wikidata sense.
*/
public String requestWikidata(String message, String botid, String server, String apikey, int limit, String hint, Network network) throws Exception {
try {
log("WIKIDATA", Level.INFO, message);
Vertex result = getBot().awareness().getSense(Wikidata.class).processSearch(message, -1, false, hint, network, new HashMap<String, Vertex>());
if (result != null) {
if (hint != null && !hint.isEmpty()) {
Vertex value = result.getRelationship(network.createPrimitive(hint));
if (value != null) {
Vertex word = value.getRelationship(Primitive.WORD);
return word.printString();
}
} else {
Vertex description = result.getRelationship(Primitive.SENTENCE);
if (description != null) {
return description.printString();
}
}
}
} catch (Exception exception) {
log(exception);
}
return null;
}
/**
* Invoke the XML HTTP request.
*/
public String requestXML(String message, String botid, String server, String apikey, int limit, String hint, Network network) throws Exception {
try {
log("XML", Level.INFO, message);
Vertex result = null;
if (hint != null && !hint.isEmpty()) {
result = getBot().awareness().getSense(Http.class).requestXML(message, hint, network);
} else {
result = getBot().awareness().getSense(Http.class).requestXML(message, network);
}
if (result == null) {
return null;
}
return result.printString();
} catch (Exception exception) {
log(exception);
}
return null;
}
/**
* Invoke the XML HTTP request.
*/
public String requestJSON(String message, String botid, String server, String apikey, int limit, String hint, Network network) throws Exception {
try {
log("JSON", Level.INFO, message);
Vertex result = null;
if (hint != null && !hint.isEmpty()) {
result = getBot().awareness().getSense(Http.class).requestJSON(message, hint, network);
if (result == null) {
return null;
}
} else {
result = getBot().awareness().getSense(Http.class).requestJSON(message, network);
}
if (result == null) {
return null;
}
return result.printString();
} catch (Exception exception) {
log(exception);
}
return null;
}
/**
* Invoke the XML HTTP request.
*/
public String requestFORGE(String message, String botid, String server, String apikey, int limit, String hint, Network network) throws Exception {
try {
log("FORGE", Level.INFO, message);
String url = "";
if (server == null || server.isEmpty()) {
server = "http://www.personalityforge.com";
} else {
server = server.toLowerCase();
if (!server.startsWith("http")) {
server = "http://" + server;
}
}
url = server + "/api/chat/?apiKey=" + apikey + "&chatBotID=" + botid + "&message=" + message + "&externalID=123";
String json = Utils.httpGET(url);
JSONObject root = (JSONObject)JSONSerializer.toJSON(json);
if (root == null) {
return null;
}
Object response = root.get("message");
if (!(response instanceof JSONObject)) {
return null;
}
response = ((JSONObject)response).get("message");
if (!(response instanceof String)) {
return null;
}
return (String)response;
} catch (Exception exception) {
log(exception);
}
return null;
}
/**
* Invoke the HTML HTTP request.
*/
public String requestHTML(String message, String botid, String server, String apikey, int limit, String hint, Network network) throws Exception {
try {
log("HTML", Level.INFO, message);
Vertex result = null;
if (hint != null && !hint.isEmpty()) {
result = getBot().awareness().getSense(Http.class).requestHTML(message, hint, network);
}
if (result == null) {
return null;
}
return result.printString();
} catch (Exception exception) {
log(exception);
}
return null;
}
/**
* Invoke the Freebase sense.
*/
public String requestFreebase(String message, String botid, String server, String apikey, int limit, String hint, Network network) throws Exception {
try {
log("FREEBASE", Level.INFO, message);
Vertex result = getBot().awareness().getSense(Freebase.class).processSearch(message, -1, false, hint, network, new HashMap<String, Vertex>());
if (result != null) {
if (hint != null && !hint.isEmpty()) {
Vertex value = result.getRelationship(network.createPrimitive(hint));
if (value != null) {
Vertex word = value.getRelationship(Primitive.WORD);
return word.printString();
}
} else {
Vertex description = result.getRelationship(Primitive.SENTENCE);
if (description != null) {
return description.printString();
}
}
}
} catch (Exception exception) {
log(exception);
}
return null;
}
/**
* Invoke the Wiktionary sense.
*/
public String requestWiktionary(String message, String botid, String server, String apikey, int limit, String hint, Network network) throws Exception {
try {
log("WIKTIONARY", Level.INFO, message);
Vertex word = network.createWord(message);
Vertex result = getBot().awareness().getSense(Wiktionary.class).define(word, word);
if (result != null) {
Vertex description = result.getRelationship(Primitive.SENTENCE);
if (description != null) {
return description.printString();
}
}
} catch (Exception exception) {
log(exception);
}
return null;
}
/**
* Invoke the Pannous service.
*/
public String requestPannous(String message, String botid, String server, String apikey, int limit) throws Exception {
try {
if (server != null && !server.isEmpty()) {
server = server.toLowerCase();
if (!server.startsWith("http")) {
server = "http://" + server;
}
} else {
server = PANNOUS;
}
String url = server + "/api?input=" + Utils.encodeURL(message);
log("PANNOUS", Level.INFO, url);
InputStream stream = Utils.openStream(new URL(url));
String result = Utils.loadTextFile(stream, "UTF-8", MAX_FILE_SIZE);
log("Response", Level.INFO, result);
JSONObject json = (JSONObject)JSONSerializer.toJSON(result);
if (json == null || json.isNullObject()) {
return null;
}
JSONArray outputs = json.getJSONArray("output");
if (outputs == null || outputs.isEmpty()) {
return null;
}
JSONObject output = (JSONObject)outputs.get(0);
if (output == null || output.isNullObject()) {
return null;
}
JSONObject actions = output.getJSONObject("actions");
if (actions == null || actions.isNullObject()) {
return null;
}
JSONObject value = actions.getJSONObject("say");
if (value == null || value.isNullObject()) {
return null;
}
String text = value.getString("text");
if (text == null) {
return null;
}
if (limit > 0) {
StringWriter writer = new StringWriter();
TextStream textStream = new TextStream(text);
for (int index = 0; index < limit; index++) {
if (textStream.atEnd()) {
break;
}
writer.write(textStream.nextSentence());
}
text = writer.toString();
}
return text;
} catch (Exception exception) {
log(exception);
return null;
}
}
/**
* Stop sensing.
*/
@Override
public void shutdown() {
super.shutdown();
disconnect();
}
/**
* Reset state when instance is pooled.
*/
@Override
public void pool() {
disconnect();
}
public void disconnect() {
this.parser.remove();
}
public DocumentBuilder getParser() throws Exception {
if (this.parser.get() == null) {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
this.parser.set(factory.newDocumentBuilder());
}
return this.parser.get();
}
/**
* Parse the input XML stream into a DOM.
*/
public Element parseXML(String xml) throws Exception {
InputSource input = new InputSource();
input.setCharacterStream(new StringReader(xml));
Document document = getParser().parse(input);
return document.getDocumentElement();
}
/**
* Post, process the post request.
*/
@Override
public void output(Vertex output) {
}
}