Skip to content

Commit

Permalink
XML transformation and validation improvements in Dynamic API (#415)
Browse files Browse the repository at this point in the history
* model serialization implementation

* set trasformer factory implementation

* prepare xml stylesheets if provided on initialization

* prepare xml stylesheets if provided on initialization

* improve OperationalStep debug messages

---------

Co-authored-by: Georgy Litvinov <[email protected]>
  • Loading branch information
litvinovg and litvinovg authored Aug 18, 2023
1 parent a3722d8 commit 0784e2f
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Source;
import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
Expand All @@ -22,8 +25,10 @@
import edu.cornell.mannlib.vitro.webapp.dynapi.components.Parameter;
import edu.cornell.mannlib.vitro.webapp.dynapi.data.Data;
import edu.cornell.mannlib.vitro.webapp.dynapi.data.DataStore;
import edu.cornell.mannlib.vitro.webapp.dynapi.data.ModelView;
import edu.cornell.mannlib.vitro.webapp.dynapi.data.SimpleDataView;
import edu.cornell.mannlib.vitro.webapp.dynapi.data.conversion.InitializationException;
import edu.cornell.mannlib.vitro.webapp.dynapi.data.implementation.DynapiInMemoryOntModel;
import edu.cornell.mannlib.vitro.webapp.utils.configuration.Property;

public class XMLTransformation extends AbstractOperation {
Expand All @@ -32,11 +37,13 @@ public class XMLTransformation extends AbstractOperation {
private Parameter xsltParam;
private Parameter inputXmlParam;
private Parameter outputXmlParam;
private Templates transformTemplates;

@Property(uri = "https://vivoweb.org/ontology/vitro-dynamic-api#xslt", minOccurs = 1, maxOccurs = 1)
public void setXsltParam(Parameter xsltParam) throws InitializationException {
this.xsltParam = xsltParam;
inputParams.add(xsltParam);
prepareTransformTemplates();
}

@Property(uri = "https://vivoweb.org/ontology/vitro-dynamic-api#inputXml", minOccurs = 1, maxOccurs = 1)
Expand All @@ -53,7 +60,7 @@ public void setOutputXml(Parameter outputXmlParam) throws InitializationExceptio

@Override
public OperationResult runOperation(DataStore dataStore) throws Exception {
String is = SimpleDataView.getStringRepresentation(inputXmlParam.getName(), dataStore);
String is = getInputString(dataStore);
String styles = SimpleDataView.getStringRepresentation(xsltParam.getName(), dataStore);
ByteArrayOutputStream output = transform(is, styles);
Data outputData = new Data(outputXmlParam);
Expand All @@ -63,20 +70,55 @@ public OperationResult runOperation(DataStore dataStore) throws Exception {
return OperationResult.ok();
}

private String getInputString(DataStore dataStore) {
if (ModelView.isModel(inputXmlParam)) {
return ModelView.getModelRDFXmlRepresentation(dataStore, inputXmlParam);
}
return SimpleDataView.getStringRepresentation(inputXmlParam.getName(), dataStore);
}

private ByteArrayOutputStream transform(String input, String styles) throws Exception {
InputStream inputStream = IOUtils.toInputStream(input, StandardCharsets.UTF_8);
InputStream styleInputStream = IOUtils.toInputStream(styles, StandardCharsets.UTF_8);
Source stylesource = new StreamSource(styleInputStream);
ByteArrayOutputStream output = new ByteArrayOutputStream();
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer(stylesource);
Transformer transformer = getTransformer(styles);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(inputStream);
transformer.transform(new DOMSource(doc), new StreamResult(output));
return output;
}

private void prepareTransformTemplates() throws InitializationException{
try {
if (xsltParam.isInternal() && !xsltParam.isOptional()) {
String defaultValue = xsltParam.getDefaultValue();
if (defaultValue != null) {
InputStream styleInputStream = IOUtils.toInputStream(defaultValue, StandardCharsets.UTF_8);
Source stylesource = new StreamSource(styleInputStream);
TransformerFactory transformerFactory = TransformerFactory.newInstance("net.sf.saxon.TransformerFactoryImpl", null);
transformTemplates = transformerFactory.newTemplates(stylesource);
}
}
} catch (Exception e){
throw new InitializationException(e.getMessage());
}
}

private Transformer getTransformer(String styles)
throws TransformerFactoryConfigurationError, TransformerConfigurationException, Exception {
if (transformTemplates != null) {
return transformTemplates.newTransformer();
}
InputStream styleInputStream = IOUtils.toInputStream(styles, StandardCharsets.UTF_8);
Source stylesource = new StreamSource(styleInputStream);
TransformerFactory transformerFactory = TransformerFactory.newInstance("net.sf.saxon.TransformerFactoryImpl", null);
Transformer transformer = transformerFactory.newTransformer(stylesource);
if (transformer == null) {
throw new Exception("Failed to initialize transformer. Check styles.");
}
return transformer;
}

@Override
public boolean isInputValid(DataStore dataStore){
if (!super.isInputValid(dataStore)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.xml.sax.SAXException;

import edu.cornell.mannlib.vitro.webapp.dynapi.components.OperationResult;
import edu.cornell.mannlib.vitro.webapp.dynapi.components.Parameter;
Expand All @@ -32,12 +33,13 @@ public class XMLValidation extends AbstractOperation {
private Parameter inputXmlParam;
private Parameter validationResult;
private Parameter errorMessage;

private Schema defaultSchema;

@Property(uri = "https://vivoweb.org/ontology/vitro-dynamic-api#xsd", minOccurs = 1, maxOccurs = 1)
public void setSchemaParam(Parameter schemaParam) throws InitializationException {
this.schemaParam = schemaParam;
inputParams.add(schemaParam);
prepareSchema();
}

@Property(uri = "https://vivoweb.org/ontology/vitro-dynamic-api#inputXml", minOccurs = 1, maxOccurs = 1)
Expand Down Expand Up @@ -86,10 +88,7 @@ public OperationResult runOperation(DataStore dataStore) throws Exception {
private String validate(String input, String stringSchema) {
try {
InputStream inputStream = IOUtils.toInputStream(input, StandardCharsets.UTF_8);
InputStream schemaInputStream = IOUtils.toInputStream(stringSchema, StandardCharsets.UTF_8);
Source schemaSource = new StreamSource(schemaInputStream);
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = factory.newSchema(schemaSource);
Schema schema = getSchema(stringSchema);
Validator validator = schema.newValidator();
validator.validate(new StreamSource(inputStream));
} catch (Exception e) {
Expand All @@ -99,6 +98,30 @@ private String validate(String input, String stringSchema) {
return "";
}

private void prepareSchema() throws InitializationException{
try {
if (schemaParam.isInternal() && !schemaParam.isOptional()) {
String defaultValue = schemaParam.getDefaultValue();
if (defaultValue != null) {
defaultSchema = getSchema(defaultValue);
}
}
} catch (Exception e){
throw new InitializationException(e.getMessage());
}
}

private Schema getSchema(String stringSchema) throws SAXException {
if (defaultSchema != null) {
return defaultSchema;
}
InputStream schemaInputStream = IOUtils.toInputStream(stringSchema, StandardCharsets.UTF_8);
Source schemaSource = new StreamSource(schemaInputStream);
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = factory.newSchema(schemaSource);
return schema;
}

@Override
public boolean isInputValid(DataStore dataStore){
if (!super.isInputValid(dataStore)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,17 +66,25 @@ public void setOptional(boolean optional) {

public OperationResult run(DataStore data) {
OperationResult result = OperationResult.badRequest();
log.debug("Processing in STEP");
log.debug("Execution step is optional? " + optional);
long start = System.currentTimeMillis();
if (log.isDebugEnabled()) {
log.debug("Started execution in step.");
if (optional) {
log.debug("Operation step is optional.");
}
}
if (operation != null) {
log.debug("Operation not null");
ParameterSubstitutor.forwardSubstitution(substitutions, data);
result = operation.run(data);
ParameterSubstitutor.backwardSubstitution(substitutions, data);
if (!optional && result.hasError()) {
return result;
}
}
if (log.isDebugEnabled()) {
long time = System.currentTimeMillis() - start;
log.debug("Step execution time: " + time + "ms");
}
return nextStep.run(data);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import edu.cornell.mannlib.vitro.webapp.dynapi.components.Parameter;
import edu.cornell.mannlib.vitro.webapp.dynapi.components.Parameters;
import edu.cornell.mannlib.vitro.webapp.dynapi.data.implementation.DynapiInMemoryOntModel;
import edu.cornell.mannlib.vitro.webapp.dynapi.data.types.ImplementationType;
import edu.cornell.mannlib.vitro.webapp.dynapi.data.types.ParameterType;

Expand Down Expand Up @@ -64,6 +65,10 @@ public static List<Model> getExistingModels( Parameters params, DataStore dataSt
}
return list;
}

public static String getModelRDFXmlRepresentation(DataStore dataStore, Parameter param) {
return DynapiInMemoryOntModel.serialize(getModel(dataStore, param), "RDF/XML");
}

public static void addModel(DataStore dataStore, Model model, Parameter outputParam) {
Data modelData = new Data(outputParam);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
package edu.cornell.mannlib.vitro.webapp.dynapi.data.implementation;

import java.io.ByteArrayOutputStream;
import java.io.StringReader;

import org.apache.jena.ontology.OntModelSpec;
import org.apache.jena.ontology.impl.OntModelImpl;
import org.apache.jena.rdf.model.Model;
import org.apache.jena.riot.RDFDataMgr;
import org.apache.jena.riot.Lang;
import org.apache.jena.riot.RDFLanguages;

public class DynapiInMemoryOntModel {

public static String serialize(Model input, String lang){
ByteArrayOutputStream baos = new ByteArrayOutputStream();
RDFDataMgr.write(baos, input, RDFLanguages.nameToLang(lang)) ;
return baos.toString();
}

public static String serialize(Model input){
//TODO: implement
return "";
return serialize(input, "RDF/XML");
}

public static Model deserialize(String input){
Expand Down

0 comments on commit 0784e2f

Please sign in to comment.