-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'BezrukovM-jpylyzer-plugin'
- Loading branch information
Showing
4 changed files
with
350 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<parent> | ||
<artifactId>verapdf-library-samples</artifactId> | ||
<groupId>org.verapdf</groupId> | ||
<version>1.0-SNAPSHOT</version> | ||
</parent> | ||
<modelVersion>4.0.0</modelVersion> | ||
|
||
<artifactId>jpylyzer-plugin</artifactId> | ||
|
||
|
||
</project> |
134 changes: 134 additions & 0 deletions
134
jpylyzer-plugin/src/main/java/org/verapdf/JpylyzerConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
/** | ||
* | ||
*/ | ||
package org.verapdf; | ||
|
||
import javax.xml.bind.JAXBContext; | ||
import javax.xml.bind.JAXBException; | ||
import javax.xml.bind.Marshaller; | ||
import javax.xml.bind.Unmarshaller; | ||
import javax.xml.bind.annotation.XmlElement; | ||
import javax.xml.bind.annotation.XmlRootElement; | ||
import java.io.*; | ||
|
||
/** | ||
* @author Maksim Bezrukov | ||
*/ | ||
@XmlRootElement(namespace = "http://www.verapdf.org/JpylyzerConfig", name = "jpylyzerConfig") | ||
final class JpylyzerConfig { | ||
|
||
@XmlElement | ||
private final String cliPath; | ||
@XmlElement | ||
private final String outFolder; | ||
@XmlElement | ||
private final boolean isVerbose; | ||
|
||
private JpylyzerConfig() { | ||
this("", "", false); | ||
} | ||
|
||
private JpylyzerConfig(String outFolder, String cliPath, boolean isVerbose) { | ||
this.cliPath = cliPath; | ||
this.outFolder = outFolder; | ||
this.isVerbose = isVerbose; | ||
} | ||
|
||
public String getOutFolder() { | ||
return outFolder; | ||
} | ||
|
||
public boolean isVerbose() { | ||
return isVerbose; | ||
} | ||
|
||
public String getCliPath() { | ||
return cliPath; | ||
} | ||
|
||
@Override | ||
public boolean equals(Object o) { | ||
if (this == o) return true; | ||
if (o == null || getClass() != o.getClass()) return false; | ||
|
||
JpylyzerConfig config = (JpylyzerConfig) o; | ||
|
||
if (isVerbose != config.isVerbose) return false; | ||
if (cliPath != null ? !cliPath.equals(config.cliPath) : config.cliPath != null) return false; | ||
return outFolder != null ? outFolder.equals(config.outFolder) : config.outFolder == null; | ||
|
||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
int result = cliPath != null ? cliPath.hashCode() : 0; | ||
result = 31 * result + (outFolder != null ? outFolder.hashCode() : 0); | ||
result = 31 * result + (isVerbose ? 1 : 0); | ||
return result; | ||
} | ||
|
||
static JpylyzerConfig defaultInstance() { | ||
return new JpylyzerConfig(null, null, false); | ||
} | ||
|
||
static JpylyzerConfig fromValues(final String cliPath, final String outFolder, final boolean isVerbose) { | ||
return new JpylyzerConfig(cliPath, outFolder, isVerbose); | ||
} | ||
|
||
static String toXml(final JpylyzerConfig toConvert, Boolean prettyXml) | ||
throws JAXBException, IOException { | ||
String retVal = ""; | ||
try (StringWriter writer = new StringWriter()) { | ||
toXml(toConvert, writer, prettyXml); | ||
retVal = writer.toString(); | ||
return retVal; | ||
} | ||
} | ||
|
||
static JpylyzerConfig fromXml(final String toConvert) | ||
throws JAXBException { | ||
try (StringReader reader = new StringReader(toConvert)) { | ||
return fromXml(reader); | ||
} | ||
} | ||
|
||
static void toXml(final JpylyzerConfig toConvert, | ||
final OutputStream stream, Boolean prettyXml) throws JAXBException { | ||
Marshaller varMarshaller = getMarshaller(prettyXml); | ||
varMarshaller.marshal(toConvert, stream); | ||
} | ||
|
||
static JpylyzerConfig fromXml(final InputStream toConvert) | ||
throws JAXBException { | ||
Unmarshaller stringUnmarshaller = getUnmarshaller(); | ||
return (JpylyzerConfig) stringUnmarshaller.unmarshal(toConvert); | ||
} | ||
|
||
static void toXml(final JpylyzerConfig toConvert, final Writer writer, | ||
Boolean prettyXml) throws JAXBException { | ||
Marshaller varMarshaller = getMarshaller(prettyXml); | ||
varMarshaller.marshal(toConvert, writer); | ||
} | ||
|
||
static JpylyzerConfig fromXml(final Reader toConvert) | ||
throws JAXBException { | ||
Unmarshaller stringUnmarshaller = getUnmarshaller(); | ||
return (JpylyzerConfig) stringUnmarshaller.unmarshal(toConvert); | ||
} | ||
|
||
private static Unmarshaller getUnmarshaller() throws JAXBException { | ||
JAXBContext context = JAXBContext | ||
.newInstance(JpylyzerConfig.class); | ||
Unmarshaller unmarshaller = context.createUnmarshaller(); | ||
return unmarshaller; | ||
} | ||
|
||
private static Marshaller getMarshaller(Boolean setPretty) | ||
throws JAXBException { | ||
JAXBContext context = JAXBContext | ||
.newInstance(JpylyzerConfig.class); | ||
Marshaller marshaller = context.createMarshaller(); | ||
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, setPretty); | ||
return marshaller; | ||
} | ||
} |
199 changes: 199 additions & 0 deletions
199
jpylyzer-plugin/src/main/java/org/verapdf/JpylyzerExtractor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,199 @@ | ||
package org.verapdf; | ||
|
||
import org.verapdf.core.FeatureParsingException; | ||
import org.verapdf.features.AbstractImageFeaturesExtractor; | ||
import org.verapdf.features.ImageFeaturesData; | ||
import org.verapdf.features.tools.FeatureTreeNode; | ||
import org.w3c.dom.Document; | ||
import org.xml.sax.SAXException; | ||
|
||
import javax.xml.bind.JAXBException; | ||
import javax.xml.parsers.DocumentBuilder; | ||
import javax.xml.parsers.DocumentBuilderFactory; | ||
import javax.xml.parsers.ParserConfigurationException; | ||
import javax.xml.xpath.XPathExpression; | ||
import javax.xml.xpath.XPathExpressionException; | ||
import javax.xml.xpath.XPathFactory; | ||
import java.io.*; | ||
import java.net.URISyntaxException; | ||
import java.net.URL; | ||
import java.nio.file.*; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
/** | ||
* @author Maksim Bezrukov | ||
*/ | ||
public class JpylyzerExtractor extends AbstractImageFeaturesExtractor { | ||
|
||
@Override | ||
public List<FeatureTreeNode> getImageFeatures(ImageFeaturesData imageFeaturesData) { | ||
boolean doesContainsJPXFilter = false; | ||
for (ImageFeaturesData.Filter filter : imageFeaturesData.getFilters()) { | ||
if ("JPXDecode".equals(filter.getName())) { | ||
doesContainsJPXFilter = true; | ||
break; | ||
} | ||
} | ||
if (!doesContainsJPXFilter) { | ||
return null; | ||
} | ||
List<FeatureTreeNode> result = new ArrayList<>(); | ||
try { | ||
try { | ||
JpylyzerConfig config = getConfig(result); | ||
File temp = generateTempFile(imageFeaturesData.getStream(), "jpx"); | ||
exec(result, config, temp); | ||
} catch (IOException | InterruptedException | URISyntaxException e) { | ||
FeatureTreeNode node = FeatureTreeNode.createRootNode("error"); | ||
node.setValue("Error in execution. Error message: " + e.getMessage()); | ||
result.add(node); | ||
} | ||
} catch (FeatureParsingException e) { | ||
throw new IllegalStateException(e); | ||
} | ||
return result; | ||
} | ||
|
||
private File generateTempFile(byte[] stream, String name) throws IOException { | ||
File fold = getTempFolder(); | ||
File temp = File.createTempFile(name == null ? "" : name, "", fold); | ||
temp.deleteOnExit(); | ||
FileOutputStream out = new FileOutputStream(temp); | ||
out.write(stream); | ||
out.close(); | ||
return temp; | ||
} | ||
|
||
private void exec(List<FeatureTreeNode> nodes, JpylyzerConfig config, File temp) throws InterruptedException, FeatureParsingException, IOException, URISyntaxException { | ||
String scriptPath = getScriptPath(config); | ||
if (scriptPath == null) { | ||
FeatureTreeNode error = FeatureTreeNode.createRootNode("error"); | ||
error.setValue("Can not obtain jpylyzer script or binary"); | ||
nodes.add(error); | ||
return; | ||
} | ||
String[] args; | ||
if (config.isVerbose()) { | ||
args = new String[3]; | ||
args[0] = scriptPath; | ||
args[1] = "--verbose"; | ||
args[2] = temp.getCanonicalPath(); | ||
} else { | ||
args = new String[2]; | ||
args[0] = scriptPath; | ||
args[1] = temp.getCanonicalPath(); | ||
} | ||
Runtime rt = Runtime.getRuntime(); | ||
Process pr = rt.exec(args); | ||
File out = getOutFile(config, nodes); | ||
FileOutputStream outStream = new FileOutputStream(out); | ||
byte[] buffer = new byte[1024]; | ||
int bytesRead; | ||
while ((bytesRead = pr.getInputStream().read(buffer)) != -1) { | ||
outStream.write(buffer, 0, bytesRead); | ||
} | ||
pr.waitFor(); | ||
outStream.close(); | ||
FeatureTreeNode node = FeatureTreeNode.createRootNode("resultPath"); | ||
node.setValue(out.getCanonicalPath()); | ||
nodes.add(node); | ||
|
||
try { | ||
String isValidJP2Value = getXMLNodeValue("//jpylyzer/isValidJP2", out); | ||
FeatureTreeNode validationNode = FeatureTreeNode.createRootNode("isValidJP2"); | ||
validationNode.setValue(isValidJP2Value); | ||
nodes.add(validationNode); | ||
} catch (ParserConfigurationException | SAXException | XPathExpressionException e) { | ||
FeatureTreeNode error = FeatureTreeNode.createRootNode("error"); | ||
error.setValue("Error in obtaining validation result. Error message: " + e.getMessage()); | ||
nodes.add(error); | ||
} | ||
} | ||
|
||
private static String getXMLNodeValue(String xPath, File xml) throws ParserConfigurationException, IOException, SAXException, XPathExpressionException { | ||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); | ||
DocumentBuilder builder = factory.newDocumentBuilder(); | ||
Document document = builder.parse(xml); | ||
XPathExpression xp = XPathFactory.newInstance().newXPath().compile(xPath); | ||
return xp.evaluate(document); | ||
} | ||
|
||
private static File getOutFile(JpylyzerConfig config, List<FeatureTreeNode> nodes) throws FeatureParsingException, IOException { | ||
if (config.getOutFolder() == null) { | ||
File tempFolder = getTempFolder(); | ||
return getOutFileInFolder(tempFolder); | ||
} else { | ||
File outFolder = new File(config.getOutFolder()); | ||
if (outFolder.isDirectory()) { | ||
return getOutFileInFolder(outFolder); | ||
} else { | ||
FeatureTreeNode node = FeatureTreeNode.createRootNode("error"); | ||
node.setValue("Config file contains out folder path but it doesn't link a directory."); | ||
nodes.add(node); | ||
File tempFolder = getTempFolder(); | ||
return getOutFileInFolder(tempFolder); | ||
} | ||
} | ||
} | ||
|
||
private static File getTempFolder() { | ||
File tempDir = new File(System.getProperty("java.io.tmpdir")); | ||
File tempFolder = new File(tempDir, "veraPDFJpylyzerPluginTemp"); | ||
if (!tempFolder.exists()) { | ||
tempFolder.mkdir(); | ||
} | ||
tempFolder.deleteOnExit(); | ||
return tempFolder; | ||
} | ||
|
||
private static File getOutFileInFolder(File folder) throws IOException { | ||
File out = File.createTempFile("veraPDF_Jpylyzer_Plugin_out", ".xml", folder); | ||
out.deleteOnExit(); | ||
return out; | ||
} | ||
|
||
private JpylyzerConfig getConfig(List<FeatureTreeNode> nodes) throws FeatureParsingException { | ||
JpylyzerConfig config = JpylyzerConfig.defaultInstance(); | ||
File conf = getConfigFile(); | ||
if (conf.isFile() && conf.canRead()) { | ||
try { | ||
config = JpylyzerConfig.fromXml(new FileInputStream(conf)); | ||
} catch (JAXBException | FileNotFoundException e) { | ||
FeatureTreeNode node = FeatureTreeNode.createRootNode("error"); | ||
node.setValue("Config file contains wrong syntax. Error message: " + e.getMessage()); | ||
nodes.add(node); | ||
} | ||
} | ||
return config; | ||
} | ||
|
||
private File getConfigFile() { | ||
return new File(getFolderPath().toFile(), "config.xml"); | ||
} | ||
|
||
@Override | ||
public String getID() { | ||
return "3ee4e6b3-af6b-4510-8b95-1af29fc81629"; | ||
} | ||
|
||
@Override | ||
public String getDescription() { | ||
return "Extracts features of the Image using Jpylyzer"; | ||
} | ||
|
||
private String getScriptPath(JpylyzerConfig config) { | ||
String cliPath = config.getCliPath(); | ||
if (cliPath == null) { | ||
cliPath = getFolderPath().toString() + "/jpylyzer-master/jpylyzer/jpylyzer.py"; | ||
} | ||
|
||
File cli = new File(cliPath); | ||
if (!(cli.exists() && cli.isFile())) { | ||
return null; | ||
} | ||
return cliPath; | ||
} | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters