com.okworx.ilcd.validation.XSLTStylesheetValidator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ilcd-validation Show documentation
Show all versions of ilcd-validation Show documentation
A Java library for performing technical validation of data in ILCD data format.
package com.okworx.ilcd.validation;
import java.io.File;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.apache.commons.io.output.NullOutputStream;
import com.okworx.ilcd.validation.common.DatasetType;
import com.okworx.ilcd.validation.events.IValidationEvent;
import com.okworx.ilcd.validation.events.Severity;
import com.okworx.ilcd.validation.events.ValidationEvent;
import com.okworx.ilcd.validation.profile.Profile;
import com.okworx.ilcd.validation.profile.ProfileManager;
import com.okworx.ilcd.validation.reference.IDatasetReference;
import com.okworx.ilcd.validation.util.AbstractDatasetsTask;
import com.okworx.ilcd.validation.util.CURIResolver;
import com.okworx.ilcd.validation.util.PartitionedList;
import com.okworx.ilcd.validation.util.PrefixBuilder;
import com.okworx.ilcd.validation.util.TaskResult;
import com.okworx.ilcd.validation.util.ValidatorListener;
import net.java.truevfs.access.TFile;
import net.java.truevfs.access.TFileInputStream;
/**
* Validates a set of given datasets against an XSLT Stylesheet.
*
* @author oliver.kusche
* @version $Id: $Id
*/
public class XSLTStylesheetValidator extends AbstractReferenceObjectsAwareValidator implements IValidator {
private String aspectName = "Profile specific rules";
private String aspectDescription = "Checks against a custom XSLT stylesheet.";
protected Profile.Bundle[] stylesheetBundles = null;
protected Map transformationParameters = new HashMap<>();
protected Map resolverMappings = new HashMap<>();
/**
* setTransformationParameter.
*
* @param string a {@link java.lang.String} object.
* @param object a {@link java.lang.Object} object.
*/
public void setTransformationParameter(String string, Object object) {
this.transformationParameters.put(string, object);
}
/**
* Constructor for XSLTStylesheetValidator.
*/
public XSLTStylesheetValidator() {
super();
this.setProfile(ProfileManager.getInstance().getDefaultProfile());
}
/**
* {@inheritDoc}
*/
@Override
public String getAspectName() {
return this.aspectName;
}
/**
* {@inheritDoc}
*/
@Override
public String getAspectDescription() {
return this.aspectDescription;
}
/**
* {@inheritDoc}
*/
@Override
public void setProfile(Profile profile) {
super.setProfile(profile);
if (profile != null) {
this.stylesheetBundles = profile.getStylesheetBundles();
this.aspectDescription = profile.getDescription();
}
}
/**
* registerStylesheet.
*
* @param pathToJar a {@link java.lang.String} object.
* @param stylesheetsDir a {@link java.lang.String} object.
* @param stylesheetName a {@link java.lang.String} object.
*/
public void registerStylesheet(String pathToJar, String stylesheetsDir, String stylesheetName) {
this.stylesheetBundles = new Profile.Bundle[]{new Profile.Bundle<>(pathToJar, stylesheetsDir, stylesheetName)};
}
/**
* validate.
*
* @return a boolean indicating whether validation succeeded or not
* @throws java.lang.InterruptedException if any.
*/
public boolean validate() throws InterruptedException {
updateStatusSetup();
super.validate();
if (this.stylesheetBundles == null)
throw new IllegalArgumentException("no stylesheet bundle");
this.unitsTotal = this.objectsToValidate.size();
PartitionedList partList = new PartitionedList<>(
this.objectsToValidate.values());
Collection> tasks = new ArrayList<>();
for (List refList : partList.getPartitions()) {
for (Profile.Bundle bundle : stylesheetBundles) {
try {
String absoluteUrlPrefix = PrefixBuilder.buildPrefix(bundle.getJarPath(), bundle.getUrlPrefix());
tasks.add(new ValidateTask(this, refList, bundle.getDescription(), absoluteUrlPrefix, bundle.getResource(), this.resolverMappings));
} catch (TransformerConfigurationException e) {
raiseApplicationError("error configuring transformer", e);
return false;
} catch (TransformerFactoryConfigurationError e) {
raiseApplicationError("error configuring transformer factory", e);
return false;
}
}
}
ExecutorService executor = Executors.newFixedThreadPool(partList.getNumThreads());
updateStatusValidating();
try {
List> taskResults = executor.invokeAll(tasks);
for (Future taskResult : taskResults) {
if (taskResult.get() != null) {
TaskResult res = taskResult.get();
this.eventsList.addAll(res.getValidationEvents());
this.statistics.add(res.getStatistics());
}
}
executor.shutdown();
} catch (InterruptedException e) {
executor.shutdown();
interrupted(e);
} catch (Exception e) {
raiseApplicationError("an error ocurred during processing", e);
return false;
}
log.info(this.eventsList.getEvents().size() + " events ");
updateProgress(1);
updateStatusDone();
return this.getEventsList().isPositive();
}
private javax.xml.transform.Transformer setupTransformer(ValidatorListener listener, String urlPrefix, String stylesheetName)
throws TransformerFactoryConfigurationError, TransformerConfigurationException {
TransformerFactory tFactory = TransformerFactory.newInstance();
// CURIResolver resolver = new CURIResolver(this.urlPrefix);
// for (String key : this.resolverMappings.keySet())
// resolver.registerMapping(key, this.resolverMappings.get(key));
// tFactory.setURIResolver(resolver);
javax.xml.transform.Transformer transformer = tFactory.newTransformer(new StreamSource(urlPrefix + stylesheetName));
transformer.setErrorListener(listener);
for (String key : this.transformationParameters.keySet()) {
if (log.isDebugEnabled())
log.debug("setting transformer variable '" + key + "' to " + this.transformationParameters.get(key));
transformer.setParameter(key, this.transformationParameters.get(key));
}
return transformer;
}
/**
* Setter for the field aspectName
.
*
* @param aspectName a {@link java.lang.String} object.
*/
public void setAspectName(String aspectName) {
this.aspectName = aspectName;
this.eventsList.setAspectName(aspectName);
}
final class ValidateTask extends AbstractDatasetsTask implements Callable {
private final String description;
private final String urlPrefix;
private final ValidatorListener vListener;
private final Transformer transformer;
private final Map resolverMappings;
ValidateTask(AbstractDatasetsValidator validator, Collection files, String description, String urlPrefix, String stylesheetName, Map resolverMappings) throws TransformerConfigurationException, TransformerFactoryConfigurationError {
this.files = files;
this.description = description;
this.validator = validator;
this.urlPrefix = urlPrefix;
this.resolverMappings = resolverMappings;
this.vListener = new ValidatorListener();
this.transformer = setupTransformer(this.vListener, urlPrefix, stylesheetName);
}
public TaskResult call() throws Exception {
return new TaskResult(validate(files), this.statistics);
}
private Collection validate(Collection files) throws Exception {
InputStream is;
Collection events = new ArrayList<>();
int count = 0;
for (IDatasetReference ref : files) {
if (Thread.currentThread().isInterrupted()) {
log.info("operation was interrupted, aborting");
updateStatusCancelled();
throw new InterruptedException();
}
if (ref.getDatasetType().equals(DatasetType.EXTERNAL_FILE)) {
this.statistics.update(ref, true);
continue;
}
is = wrapInputStream(new TFileInputStream(ref.getAbsoluteFileName()));
try {
String path = new TFile(ref.getAbsoluteFileName()).getParent().concat(File.separator);
transformer.setURIResolver(new CURIResolver(this.urlPrefix, path, this.resolverMappings));
transformer.setParameter("pathPrefix", URLEncoder.encode(path, "UTF-8"));
transformer.transform(new StreamSource(is), new StreamResult(NullOutputStream.NULL_OUTPUT_STREAM));
} catch (Exception e) {
String message = e.getMessage().replaceAll("com.sun.org.apache.xalan.internal.xsltc.TransletException:", "").replaceAll("java.io.FileNotFoundException", "File not found");
Severity severity = (message.trim().startsWith("File not found") ? Severity.WARNING : Severity.ERROR);
events.add(new ValidationEvent(XSLTStylesheetValidator.this.getAspectName(), this.description, severity, ref, message));
}
boolean success = (vListener.getResults().isEmpty());
this.statistics.update(ref, success);
if (success && XSLTStylesheetValidator.this.reportSuccesses)
events.add(new ValidationEvent(XSLTStylesheetValidator.this.getAspectName(), this.description, Severity.SUCCESS, ref, ValidationEvent.SUCCESS_MESSAGE));
count = updateChunkCount(count);
if (log.isDebugEnabled())
log.debug(ref.getUuid() + ": " + vListener.getResults().size() + " events occurred");
// extract message
for (String rawMessage : vListener.getResults()) {
if (rawMessage.startsWith("Validation error: ")) {
rawMessage = rawMessage.split("Validation error: ")[1];
events.add(new ValidationEvent(XSLTStylesheetValidator.this.getAspectName(), this.description, Severity.ERROR, ref, rawMessage));
} else if (rawMessage.startsWith("Validation warning: ")) {
rawMessage = rawMessage.split("Validation warning: ")[1];
events.add(new ValidationEvent(XSLTStylesheetValidator.this.getAspectName(), this.description, Severity.WARNING, ref, rawMessage));
}
}
vListener.getResults().clear();
}
return events;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy