package edu.isi.karma.linkedapi.server;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.Resource;
import edu.isi.karma.model.serialization.MimeType;
import edu.isi.karma.model.serialization.SerializationLang;
import edu.isi.karma.model.serialization.WebServiceLoader;
import edu.isi.karma.modeling.Namespaces;
import edu.isi.karma.modeling.Prefixes;
import edu.isi.karma.rep.model.Atom;
import edu.isi.karma.rep.model.ClassAtom;
import edu.isi.karma.rep.model.IndividualPropertyAtom;
import edu.isi.karma.rep.sources.Attribute;
import edu.isi.karma.rep.sources.InvocationManager;
import edu.isi.karma.rep.sources.Table;
import edu.isi.karma.rep.sources.WebService;
import edu.isi.karma.webserver.KarmaException;
public class PostRequestManager extends LinkedApiRequestManager {
static Logger logger = Logger.getLogger(PostRequestManager.class);
private InputStream inputStream;
private String inputLang;
private Model inputJenaModel;
private Model outputJenaModel;
private WebService service;
private List<Map<String, String>> listOfInputAttValues;
public PostRequestManager(String serviceId,
InputStream inputStream,
String inputLang,
String returnType,
HttpServletResponse response) throws IOException {
super(serviceId, null, returnType, response);
this.inputStream = inputStream;
this.inputLang = inputLang;
this.inputJenaModel = ModelFactory.createDefaultModel();
}
/**
* checks whether the input has correct RDf syntax or not
* @return
*/
private boolean validateInputSyntax() {
try {
this.inputJenaModel.read(this.inputStream, null, this.inputLang);
} catch (Exception e) {
logger.error("Exception in creating the jena model from the input data.");
return false;
}
if (this.inputJenaModel == null) {
logger.error("Could not create a jena model from the input data.");
return false;
}
return true;
}
private boolean loadService() {
service = WebServiceLoader.getInstance().getSourceByUri(getServiceUri());
if (service == null) {
return false;
}
return true;
}
/**
* checks if the input data satisfies the service input graph
* (if the service input contained in the input data or not)
* @return
* @throws IOException
*/
private boolean validateInputSemantic() throws IOException {
PrintWriter pw = getResponse().getWriter();
edu.isi.karma.rep.model.Model serviceInputModel = service.getInputModel();
if (serviceInputModel == null) {
getResponse().setContentType(MimeType.TEXT_PLAIN);
pw.write("The service input model is null.");
return false;
}
listOfInputAttValues = serviceInputModel.findModelDataInJenaData(this.inputJenaModel, null);
if (listOfInputAttValues == null)
return false;
for (Map<String, String> m : listOfInputAttValues)
for (String s : m.keySet())
logger.debug(s + "-->" + m.get(s));
//for (String s : serviceIdsAndMappings.)
return true;
}
private String getUrlString(WebService service, Map<String, String> inputAttValues) {
List<Attribute> missingAttributes= null;
missingAttributes = new ArrayList<Attribute>();
String url = service.getPopulatedAddress(inputAttValues, missingAttributes);
//FIXME: Authentication Data
url = url.replaceAll("\\{p3\\}", "karma");
logger.debug(url);
for (Attribute att : missingAttributes)
logger.debug("missing: " + att.getName() + ", grounded in:" + att.getGroundedIn());
return url;
}
private Table invokeWebAPI(String requestURLString) {
InvocationManager invocatioManager;
try {
invocatioManager = new InvocationManager(null, requestURLString);
logger.info("Requesting data with includeURL=" + true + ",includeInput=" + true + ",includeOutput=" + true);
Table serviceTable = invocatioManager.getServiceData(false, false, true);
logger.debug(serviceTable.getPrintInfo());
logger.info("The service " + service.getUri() + " has been invoked successfully.");
return serviceTable;
} catch (MalformedURLException e) {
logger.error("Malformed service request URL.");
return null;
} catch (KarmaException e) {
logger.error(e.getMessage());
return null;
}
}
public void addStatementsToJenaModel(WebService service, Model model,
Map<String, String> inputAttValues, Map<String, String> outputAttValues) {
edu.isi.karma.rep.model.Model outputModel = service.getOutputModel();
if (outputModel == null) {
logger.info("The service output model is null.");
return;
}
Resource r;
model.setNsPrefix(Prefixes.RDF, Namespaces.RDF);
model.setNsPrefix(Prefixes.RDFS, Namespaces.RDFS);
Property rdf_type = model.createProperty(Namespaces.RDF , "type");
Map<String, Resource> outputVariablesToResource = new HashMap<String, Resource>();
String predicateUri = "";
String argument1 = "";
String argument2 = "";
for (Atom atom : outputModel.getAtoms()) {
if (atom instanceof ClassAtom) {
ClassAtom classAtom = (ClassAtom)atom;
// creating a blank node
r = model.createResource();
if (classAtom.getClassPredicate().getPrefix() != null && classAtom.getClassPredicate().getNs() != null)
model.setNsPrefix(classAtom.getClassPredicate().getPrefix(), classAtom.getClassPredicate().getNs());
predicateUri = classAtom.getClassPredicate().getUri();
// creating the class resource
Resource classResource = model.getResource(predicateUri);
if (classResource == null)
classResource = model.createResource(predicateUri);
argument1 = classAtom.getArgument1().getId();
outputVariablesToResource.put(argument1, r);
r.addProperty(rdf_type, classResource);
}
}
for (Atom atom : outputModel.getAtoms()) {
if (atom instanceof IndividualPropertyAtom) {
IndividualPropertyAtom propertyAtom = (IndividualPropertyAtom)atom;
if (propertyAtom.getPropertyPredicate().getPrefix() != null && propertyAtom.getPropertyPredicate().getNs() != null)
model.setNsPrefix(propertyAtom.getPropertyPredicate().getPrefix(), propertyAtom.getPropertyPredicate().getNs());
predicateUri = propertyAtom.getPropertyPredicate().getUri();
// creating the property resource
Property propertyResource = model.getProperty(predicateUri);
if (propertyResource == null)
propertyResource = model.createProperty(predicateUri);
argument1 = propertyAtom.getArgument1().getId();
argument2 = propertyAtom.getArgument2().getId();
Resource subjectResource = outputVariablesToResource.get(argument1);
// maybe this variable is defined in input rdf
if (subjectResource == null) {
String subjectUri = inputAttValues.get(argument1);
if (subjectUri != null) {
subjectResource = model.getResource(subjectUri);
}
}
if (subjectResource == null) {
logger.error("Could not find the corresponding resource of " + argument1 + " variable.");
continue;
}
String attValue = outputAttValues.get(argument2);
// the object of this predicate is a literal
if (attValue != null) {
subjectResource.addProperty(propertyResource, attValue);
} else { // object is a resource
Resource objectResource = outputVariablesToResource.get(argument2);
if (objectResource == null) { // this is not a variable created by output model, but it might exist in input model
String objectUri = inputAttValues.get(argument2);
if (objectUri != null) {
objectResource = model.getResource(objectUri);
}
}
if (objectResource == null) {
logger.error("Could not find the corresponding resource of " + argument2 + " variable.");
continue;
}
subjectResource.addProperty(propertyResource, objectResource);
}
}
}
}
public void HandleRequest() throws IOException {
// printing the input data (just fo debug)
// InputStreamReader is = new InputStreamReader(inputStream);
// BufferedReader br = new BufferedReader(is);
// String read = br.readLine();
// System.out.println("START");
// while(read != null) {
// System.out.println(read);
// read = br.readLine();
// }
// System.out.println("END");
boolean blankInput = false;
PrintWriter pw = getResponse().getWriter();
if (!loadService()) {
getResponse().setContentType(MimeType.TEXT_PLAIN);
pw.write("Could not find the service " + getServiceId() + " in service repository");
return;
}
if (this.service.getInputAttributes() == null ||
this.service.getInputAttributes().size() == 0) {
blankInput = true;
} else {
if (!validateInputSyntax()) {
getResponse().setContentType(MimeType.TEXT_PLAIN);
pw.write("Could not validate the syntax of input RDF.");
return;
}
if (!blankInput && !validateInputSemantic()) {
getResponse().setContentType(MimeType.TEXT_PLAIN);
pw.write("The input RDF does not have a matching pattern for service input model. ");
return;
}
}
// including the statements of the input model in the output model
this.outputJenaModel = ModelFactory.createDefaultModel();
if (this.inputJenaModel != null) {
this.outputJenaModel.add(this.inputJenaModel);
this.outputJenaModel.setNsPrefixes(this.inputJenaModel.getNsPrefixMap());
}
Map<String, String> outputAttNameToAttIds = new HashMap<String, String>();
Map<String, String> outputAttValues = new HashMap<String, String>();
if (blankInput) { // service without input parameter
String invocationURL = getUrlString(service, new HashMap<String, String>());
Table table = invokeWebAPI(invocationURL);
if (table == null || table.getHeaders() == null) {
logger.info("Error in invoking " + invocationURL);
} else {
// creating a mapping from attribute names (table headers) to attribute Ids
outputAttNameToAttIds.clear();
for (Attribute header : table.getHeaders()) {
String name = header.getName();
Attribute serviceAtt = service.getOutputAttributeByName(name);
if (serviceAtt == null) {
logger.info("Could not find the attribute " + name + " in service output attributes.");
continue;
}
outputAttNameToAttIds.put(name, serviceAtt.getId());
}
// iterating over the rows to create the output RDF
outputAttValues.clear();
for (List<String> values : table.getValues()) {
for (int i = 0; i < table.getColumnsCount(); i++) {
String attId = outputAttNameToAttIds.get(table.getHeaders().get(i).getName());
if (attId == null) continue;
String value = values.get(i);
outputAttValues.put(attId, value);
}
addStatementsToJenaModel(this.service, this.outputJenaModel, new HashMap<String, String>(), outputAttValues);
}
}
} else if (listOfInputAttValues == null) {
getResponse().setContentType(MimeType.TEXT_PLAIN);
pw.write("Cannot extract the input values from the service input model. ");
return;
} else {
for (Map<String,String> inputAttValues : listOfInputAttValues) {
// invoking the Web API and load the response in a table
String invocationURL = getUrlString(service, inputAttValues);
Table table = invokeWebAPI(invocationURL);
if (table == null || table.getHeaders() == null) {
logger.info("Error in invoking " + invocationURL);
continue;
}
// creating a mapping from attribute names (table headers) to attribute Ids
outputAttNameToAttIds.clear();
for (Attribute header : table.getHeaders()) {
String name = header.getName();
Attribute serviceAtt = service.getOutputAttributeByName(name);
if (serviceAtt == null) {
logger.info("Could not find the attribute " + name + " in service output attributes.");
continue;
}
outputAttNameToAttIds.put(name, serviceAtt.getId());
}
// iterating over the rows to create the output RDF
outputAttValues.clear();
for (List<String> values : table.getValues()) {
for (int i = 0; i < table.getColumnsCount(); i++) {
String attId = outputAttNameToAttIds.get(table.getHeaders().get(i).getName());
if (attId == null) continue;
String value = values.get(i);
outputAttValues.put(attId, value);
}
addStatementsToJenaModel(this.service, this.outputJenaModel, inputAttValues, outputAttValues);
}
}
}
if (getFormat().equalsIgnoreCase(SerializationLang.XML))
getResponse().setContentType(MimeType.APPLICATION_XML);
else if (getFormat().equalsIgnoreCase(SerializationLang.XML_ABBREV))
getResponse().setContentType(MimeType.APPLICATION_XML);
else
getResponse().setContentType(MimeType.TEXT_PLAIN);
// getResponse().setContentType(MimeType.TEXT_PLAIN);
// pw.write("Success.");
getResponse().setContentType(MimeType.TEXT_PLAIN);
this.outputJenaModel.write(pw, getFormat());
}
}