/*******************************************************************************
* Copyright 2012 University of Southern California
*
* Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
*
* 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.
*
* This code was developed by the Information Integration Group as part
* of the Karma project at the Information Sciences Institute of the
* University of Southern California. For more information, publications,
* and related projects, please see: http://www.isi.edu/integration
******************************************************************************/
package edu.isi.karma.kr2rml;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.eclipse.jetty.http.HttpMethods;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.openrdf.OpenRDFException;
import org.openrdf.model.BNode;
import org.openrdf.model.Resource;
import org.openrdf.model.URI;
import org.openrdf.model.Value;
import org.openrdf.model.ValueFactory;
import org.openrdf.model.vocabulary.RDF;
import org.openrdf.repository.Repository;
import org.openrdf.repository.RepositoryConnection;
import org.openrdf.repository.RepositoryException;
import org.openrdf.repository.sail.SailRepository;
import org.openrdf.rio.RDFHandler;
import org.openrdf.rio.turtle.TurtleWriter;
import org.openrdf.sail.memory.MemoryStore;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import edu.isi.karma.modeling.Namespaces;
import edu.isi.karma.modeling.Prefixes;
import edu.isi.karma.modeling.Uris;
import edu.isi.karma.modeling.ontology.OntologyManager;
import edu.isi.karma.rep.HNode;
import edu.isi.karma.rep.RepFactory;
import edu.isi.karma.rep.Worksheet;
import edu.isi.karma.rep.metadata.WorksheetProperties;
import edu.isi.karma.rep.metadata.WorksheetProperties.Property;
import edu.isi.karma.util.FileUtil;
public class WorksheetModelWriter {
private PrintWriter writer;
private RepFactory factory;
private OntologyManager ontMgr;
private String worksheetName;
private Repository myRepository;
// Internal instance variables
private RepositoryConnection con;
private ValueFactory f;
// Add a blank node of R2RML mapping
private Resource mappingRes;
private static Logger logger = LoggerFactory
.getLogger(WorksheetModelWriter.class);
public WorksheetModelWriter(PrintWriter writer, RepFactory factory, OntologyManager ontMgr,
String worksheetName)
throws RepositoryException {
this.writer = writer;
this.factory = factory;
this.ontMgr = ontMgr;
/** Initialize an in-memory sesame triple store **/
myRepository = new SailRepository(new MemoryStore());
myRepository.initialize();
con = myRepository.getConnection();
f = myRepository.getValueFactory();
/** Create resource for the mapping as a blank node **/
URI r2rmlMapUri = f.createURI(Uris.KM_R2RML_MAPPING_URI);
URI sourceNameUri = f.createURI(Uris.KM_SOURCE_NAME_URI);
mappingRes = f.createBNode();
con.add(mappingRes, RDF.TYPE, r2rmlMapUri);
this.worksheetName = worksheetName;
Value srcNameVal = f.createLiteral(worksheetName);
con.add(mappingRes, sourceNameUri, srcNameVal);
// Add the timestamp
URI pubTime = f.createURI(Uris.KM_MODEL_PUBLICATION_TIME_URI);
con.add(mappingRes, pubTime, f.createLiteral(new Date().getTime()));
}
public boolean writeR2RMLMapping(OntologyManager ontManager, KR2RMLMappingGenerator mappingGen)
throws RepositoryException, JSONException {
/** Get the required data structures of R2RML **/
R2RMLMapping mapping = mappingGen.getR2RMLMapping();
KR2RMLMappingAuxillaryInformation auxInfo = mappingGen.getMappingAuxillaryInformation();
List<TriplesMap> triplesMapList = mapping.getTriplesMapList();
try {
URI trTypeUri = f.createURI(Uris.RR_TRIPLESMAP_CLASS_URI);
URI templateUri = f.createURI(Uris.RR_TEMPLATE_URI);
URI subjMapUri = f.createURI(Uris.RR_SUBJECTMAP_URI);
URI predUri = f.createURI(Uris.RR_PREDICATE_URI);
URI objectMapUri = f.createURI(Uris.RR_OBJECTMAP_URI);
URI columnUri = f.createURI(Uris.RR_COLUMN_URI);
URI rfObjClassUri = f.createURI(Uris.RR_REF_OBJECT_MAP_URI);
URI parentTriplesMapUri = f.createURI(Uris.RR_PARENT_TRIPLE_MAP_URI);
URI predObjMapMapUri = f.createURI(Uris.RR_PRED_OBJ_MAP_URI);
URI blankNodeUri = f.createURI(Uris.RR_BLANK_NODE_URI);
URI termTypeUri = f.createURI(Uris.RR_TERM_TYPE_URI);
URI logicalTableUri = f.createURI(Uris.RR_LOGICAL_TABLE_URI);
URI tableNameUri = f.createURI(Uris.RR_TABLENAME_URI);
URI classUri = f.createURI(Uris.RR_CLASS_URI);
URI coversColUri = f.createURI(Uris.KM_BLANK_NODE_COVERS_COLUMN_URI);
URI bnNamePrefixUri = f.createURI(Uris.KM_BLANK_NODE_PREFIX_URI);
URI nodeIdUri = f.createURI(Uris.KM_NODE_ID_URI);
URI steinerTreeRootNodeUri = f.createURI(Uris.KM_STEINER_TREE_ROOT_NODE);
URI hasTrMapUri = f.createURI(Uris.KM_HAS_TRIPLES_MAP_URI);
/** Add all the triple maps **/
for (TriplesMap trMap:triplesMapList) {
URI trMapUri = f.createURI(Namespaces.KARMA_DEV + trMap.getId());
// Add the triples map type statement
con.add(trMapUri, RDF.TYPE, trTypeUri);
// Associate it with the source mapping URI
con.add(mappingRes, hasTrMapUri, trMapUri);
// Add the Logical table information
BNode logTableBNode = f.createBNode();
con.add(logTableBNode, tableNameUri, f.createLiteral(worksheetName));
con.add(trMapUri, logicalTableUri, logTableBNode);
// Add the subject map statements
SubjectMap sjMap = trMap.getSubject();
BNode sjBlankNode = f.createBNode();
Value templVal = f.createLiteral(sjMap.getTemplate()
.getR2rmlTemplateString(factory));
con.add(sjBlankNode, templateUri, templVal);
con.add(trMapUri, subjMapUri, sjBlankNode);
// Add the node id for the subject
Value nodeIdVal = f.createLiteral(sjMap.getId());
con.add(sjBlankNode, nodeIdUri, nodeIdVal);
// Add the type for subject maps
List<TemplateTermSet> rdfsTypes = sjMap.getRdfsType();
for (TemplateTermSet typeTermSet:rdfsTypes) {
if (typeTermSet.isSingleUriString()) {
URI sjTypeUri = f.createURI(typeTermSet.getR2rmlTemplateString(factory));
con.add(sjBlankNode, classUri, sjTypeUri);
} else {
if (typeTermSet.isSingleColumnTerm()) {
BNode typeBlankNode = f.createBNode();
String colRepr = typeTermSet.getR2rmlTemplateString(factory);
con.add(typeBlankNode, templateUri, f.createLiteral(colRepr));
con.add(sjBlankNode, classUri, typeBlankNode);
}
}
}
// Check if the subject map is a blank node
if (sjMap.isBlankNode()) {
con.add(sjBlankNode, termTypeUri, blankNodeUri);
// Add the information about the columns that it covers.
// This info is used in constructing the blank node's URI.
List<String> columnsCovered = auxInfo.getBlankNodesColumnCoverage().
get(sjMap.getId());
for (String colHnodeId:columnsCovered) {
HNode hNode = factory.getHNode(colHnodeId);
if (hNode != null) {
Value colNameVal = f.createLiteral(getR2RMLColNameRepresentation(hNode));
con.add(sjBlankNode, coversColUri, colNameVal);
}
}
// Add the prefix name for the blank node
String prefix = auxInfo.getBlankNodesUriPrefixMap().get(sjMap.getId());
Value prefixVal = f.createLiteral(prefix);
con.add(sjBlankNode, bnNamePrefixUri, prefixVal);
}
// Mark as Steiner tree root node if required
if (sjMap.isSteinerTreeRootNode()) {
con.add(sjBlankNode, RDF.TYPE, steinerTreeRootNodeUri);
}
// Add the predicate object maps
for (PredicateObjectMap pom:trMap.getPredicateObjectMaps()) {
BNode pomBlankNode = f.createBNode();
// Add the predicate
TemplateTermSet predTermSet = pom.getPredicate().getTemplate();
if (predTermSet.isSingleUriString()) {
URI predValUri = f.createURI(predTermSet
.getR2rmlTemplateString(factory));
// Skip the class instance special meta property
if (predValUri.stringValue().equals(Uris.CLASS_INSTANCE_LINK_URI)) continue;
con.add(pomBlankNode, predUri, predValUri);
} else {
Value predValLiteratl = f.createLiteral(predTermSet.
getR2rmlTemplateString(factory));
con.add(pomBlankNode, predUri, predValLiteratl);
}
// Add the object: Could be RefObjectMap or simple object with column values
if (pom.getObject().hasRefObjectMap()) {
RefObjectMap rfMap = pom.getObject().getRefObjectMap();
URI rfUri = f.createURI(Namespaces.KARMA_DEV + rfMap.getId());
con.add(rfUri, RDF.TYPE, rfObjClassUri);
TriplesMap prMap = rfMap.getParentTriplesMap();
URI prMapUri = f.createURI(Namespaces.KARMA_DEV + prMap.getId());
con.add(rfUri, parentTriplesMapUri, prMapUri);
// Add the RefObjectMap as the object map of current POMap
con.add(pomBlankNode, objectMapUri, rfUri);
} else {
TemplateTermSet objTermSet = pom.getObject().getTemplate();
if (objTermSet.isSingleColumnTerm()) {
BNode cnBnode = f.createBNode();
Value cnVal = f.createLiteral(objTermSet.
getColumnNameR2RMLRepresentation(factory));
con.add(cnBnode, columnUri, cnVal);
// Add the link b/w blank node and object map
con.add(pomBlankNode, objectMapUri, cnBnode);
}
}
con.add(trMapUri, predObjMapMapUri, pomBlankNode);
}
}
Map<String, String> prefixMap = ontMgr.getPrefixMap();
for (String ns:prefixMap.keySet()) {
String prefix = prefixMap.get(ns);
con.setNamespace(prefix, ns);
}
con.setNamespace(Prefixes.RR, Namespaces.RR);
con.setNamespace(Prefixes.KARMA_DEV, Namespaces.KARMA_DEV);
RDFHandler rdfxmlWriter = new TurtleWriter(writer);
con.export(rdfxmlWriter);
} catch (OpenRDFException e) {
logger.error("Error occured while generating RDF representation of R2RML data " +
"structures.", e);
} finally {
con.close();
}
return true;
}
private String getR2RMLColNameRepresentation(HNode hNode) throws JSONException {
String colNameStr = "";
JSONArray colNameArr = hNode.getJSONArrayRepresentation(factory);
if (colNameArr.length() == 1) {
colNameStr = (String)
(((JSONObject)colNameArr.get(0)).get("columnName"));
} else {
JSONArray colNames = new JSONArray();
for (int i=0; i<colNameArr.length();i++) {
colNames.put((String)
(((JSONObject)colNameArr.get(i)).get("columnName")));
}
colNameStr = colNames.toString();
}
return colNameStr;
}
public boolean writeTransformationHistory(List<String> commandsJSON) throws RepositoryException {
URI hasTransformationUri = f.createURI(Uris.KM_HAS_TRANSFORMATION_URI);
for (String commandJson : commandsJSON) {
Value commandLiteral = f.createLiteral(commandJson);
con.add(mappingRes, hasTransformationUri, commandLiteral);
}
return true;
}
public void close() throws RepositoryException {
con.close();
myRepository.shutDown();
}
public void writeCompleteWorksheetHistory(String historyFilePath)
throws RepositoryException {
File historyFile = new File(historyFilePath);
URI hasWorksheetHistoryUri = f.createURI(Uris.KM_HAS_WORKSHEET_HISTORY_URI);
if (!historyFile.exists()) {
logger.error("Worksheet history file not found! Can't write worksheet history " +
"into R2RML model. Path:" + historyFile.getAbsolutePath());
return;
}
try {
String historyJsonStr = FileUtil.readFileContentsToString(historyFile);
Value historyLiteral = f.createLiteral(historyJsonStr);
con.add(mappingRes, hasWorksheetHistoryUri, historyLiteral);
} catch (IOException e) {
logger.error("IO Exception occured while writing worksheet history into R2RML model", e);
return;
}
}
public void writeWorksheetProperties(Worksheet worksheet) throws RepositoryException {
WorksheetProperties props = worksheet.getMetadataContainer().getWorksheetProperties();
if (props == null) {
return;
}
// Service options (if present)
if (props.hasServiceProperties()) {
if (props.getPropertyValue(Property.serviceUrl) == null) {
return;
}
// Request method triple
URI reqMethodUri = f.createURI(Uris.KM_SERVICE_REQ_METHOD_URI);
Value method = f.createLiteral(props.getPropertyValue(Property.serviceRequestMethod));
con.add(mappingRes, reqMethodUri, method);
// Service Url triple
URI serUrlUri = f.createURI(Uris.KM_SERVICE_URL_URI);
Value servUrl = f.createLiteral(props.getPropertyValue(Property.serviceUrl));
con.add(mappingRes, serUrlUri, servUrl);
if (props.getPropertyValue(Property.serviceRequestMethod).equals(HttpMethods.POST)) {
// POST method related option triple
URI postMethodUri = f.createURI(Uris.KM_SERVICE_POST_METHOD_TYPE_URI);
Value methodUrl = f.createLiteral(props.getPropertyValue(Property.serviceDataPostMethod));
con.add(mappingRes, postMethodUri, methodUrl);
}
}
}
}