diff --git a/.gitignore b/.gitignore
index 16006d3..ce9a994 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,6 +7,7 @@
# Package Files #
*.jar
+!/metsMetadata-plugin/src/main/resources/mets-api.jar
*.war
*.ear
diff --git a/iccdump-plugin/pom.xml b/iccdump-plugin/pom.xml
index 65b9d40..d3f3e94 100644
--- a/iccdump-plugin/pom.xml
+++ b/iccdump-plugin/pom.xml
@@ -11,5 +11,4 @@
iccdump-plugin
-
\ No newline at end of file
diff --git a/mediaconch/pom.xml b/mediaconch/pom.xml
new file mode 100644
index 0000000..bd1430a
--- /dev/null
+++ b/mediaconch/pom.xml
@@ -0,0 +1,15 @@
+
+
+
+ verapdf-library-samples
+ org.verapdf
+ 1.0-SNAPSHOT
+
+ 4.0.0
+
+ mediaconch-plugin
+
+
+
\ No newline at end of file
diff --git a/mediaconch/src/main/java/org/verapdf/MediaConchConfig.java b/mediaconch/src/main/java/org/verapdf/MediaConchConfig.java
new file mode 100644
index 0000000..970455c
--- /dev/null
+++ b/mediaconch/src/main/java/org/verapdf/MediaConchConfig.java
@@ -0,0 +1,125 @@
+/**
+ *
+ */
+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/MediaConchConfig", name = "mediaconchConfig")
+final class MediaConchConfig {
+
+ @XmlElement
+ private final String cliPath;
+ @XmlElement
+ private final String outFolder;
+
+ private MediaConchConfig() {
+ this("", "");
+ }
+
+ private MediaConchConfig(String outFolder, String cliPath) {
+ this.outFolder = outFolder;
+ this.cliPath = cliPath;
+ }
+
+ public String getCliPath() {
+ return cliPath;
+ }
+
+ public String getOutFolder() {
+ return outFolder;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ MediaConchConfig that = (MediaConchConfig) o;
+
+ if (cliPath != null ? !cliPath.equals(that.cliPath) : that.cliPath != null) return false;
+ return !(outFolder != null ? !outFolder.equals(that.outFolder) : that.outFolder != null);
+
+ }
+
+ @Override
+ public int hashCode() {
+ int result = cliPath != null ? cliPath.hashCode() : 0;
+ result = 31 * result + (outFolder != null ? outFolder.hashCode() : 0);
+ return result;
+ }
+
+ static MediaConchConfig defaultInstance() {
+ return new MediaConchConfig("mediaconch", null);
+ }
+
+ static MediaConchConfig fromValues(final String cliPath, final String outFolder) {
+ return new MediaConchConfig(cliPath, outFolder);
+ }
+
+ static String toXml(final MediaConchConfig toConvert, Boolean prettyXml)
+ throws JAXBException, IOException {
+ String retVal = "";
+ try (StringWriter writer = new StringWriter()) {
+ toXml(toConvert, writer, prettyXml);
+ retVal = writer.toString();
+ return retVal;
+ }
+ }
+
+ static MediaConchConfig fromXml(final String toConvert)
+ throws JAXBException {
+ try (StringReader reader = new StringReader(toConvert)) {
+ return fromXml(reader);
+ }
+ }
+
+ static void toXml(final MediaConchConfig toConvert,
+ final OutputStream stream, Boolean prettyXml) throws JAXBException {
+ Marshaller varMarshaller = getMarshaller(prettyXml);
+ varMarshaller.marshal(toConvert, stream);
+ }
+
+ static MediaConchConfig fromXml(final InputStream toConvert)
+ throws JAXBException {
+ Unmarshaller stringUnmarshaller = getUnmarshaller();
+ return (MediaConchConfig) stringUnmarshaller.unmarshal(toConvert);
+ }
+
+ static void toXml(final MediaConchConfig toConvert, final Writer writer,
+ Boolean prettyXml) throws JAXBException {
+ Marshaller varMarshaller = getMarshaller(prettyXml);
+ varMarshaller.marshal(toConvert, writer);
+ }
+
+ static MediaConchConfig fromXml(final Reader toConvert)
+ throws JAXBException {
+ Unmarshaller stringUnmarshaller = getUnmarshaller();
+ return (MediaConchConfig) stringUnmarshaller.unmarshal(toConvert);
+ }
+
+ private static Unmarshaller getUnmarshaller() throws JAXBException {
+ JAXBContext context = JAXBContext
+ .newInstance(MediaConchConfig.class);
+ Unmarshaller unmarshaller = context.createUnmarshaller();
+ return unmarshaller;
+ }
+
+ private static Marshaller getMarshaller(Boolean setPretty)
+ throws JAXBException {
+ JAXBContext context = JAXBContext
+ .newInstance(MediaConchConfig.class);
+ Marshaller marshaller = context.createMarshaller();
+ marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, setPretty);
+ return marshaller;
+ }
+}
diff --git a/mediaconch/src/main/java/org/verapdf/MediaConchExtractor.java b/mediaconch/src/main/java/org/verapdf/MediaConchExtractor.java
new file mode 100644
index 0000000..40a54b8
--- /dev/null
+++ b/mediaconch/src/main/java/org/verapdf/MediaConchExtractor.java
@@ -0,0 +1,144 @@
+package org.verapdf;
+
+import org.verapdf.core.FeatureParsingException;
+import org.verapdf.features.AbstractEmbeddedFileFeaturesExtractor;
+import org.verapdf.features.EmbeddedFileFeaturesData;
+import org.verapdf.features.tools.FeatureTreeNode;
+
+import javax.xml.bind.JAXBException;
+import java.io.*;
+import java.util.*;
+
+/**
+ * @author Maksim Bezrukov
+ */
+public class MediaConchExtractor extends AbstractEmbeddedFileFeaturesExtractor {
+
+ @Override
+ public List getEmbeddedFileFeatures(EmbeddedFileFeaturesData embeddedFileFeaturesData) {
+ if (!isValidType(embeddedFileFeaturesData.getSubtype())) {
+ return null;
+ }
+ List result = new ArrayList<>();
+ try {
+ try {
+ MediaConchConfig config = getConfig(result);
+ File temp = generateTempFile(embeddedFileFeaturesData.getStream(), embeddedFileFeaturesData.getName());
+ execCLI(result, config, temp);
+ } catch (IOException | InterruptedException 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 execCLI(List nodes, MediaConchConfig config, File temp) throws InterruptedException, FeatureParsingException, IOException {
+ List res = new ArrayList<>();
+ Runtime rt = Runtime.getRuntime();
+ String cliPath;
+ String configCliPath = config.getCliPath();
+ if (configCliPath == null || configCliPath.isEmpty()) {
+ cliPath = "mediaconch";
+ } else {
+ cliPath = configCliPath;
+ }
+ File out = getOutFile(config, nodes);
+ String[] str = new String[]{cliPath, "-mc", "-fx", temp.getCanonicalPath()};
+ Process pr = rt.exec(str);
+ 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();
+ FeatureTreeNode node = FeatureTreeNode.createRootNode("resultPath");
+ node.setValue(out.getCanonicalPath());
+ nodes.add(node);
+
+ }
+
+ private File getOutFile(MediaConchConfig config, List nodes) throws FeatureParsingException, IOException {
+ if (config.getOutFolder() == null) {
+ File tempFolder = getTempFolder();
+ File res = getOutFileInFolder(tempFolder);
+ return res;
+ } else {
+ File outFolder = new File(config.getOutFolder());
+ if (outFolder.isDirectory()) {
+ File res = getOutFileInFolder(outFolder);
+ return res;
+ } 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();
+ File res = getOutFileInFolder(tempFolder);
+ return res;
+ }
+ }
+ }
+
+ private File getTempFolder() {
+ File tempDir = new File(System.getProperty("java.io.tmpdir"));
+ File tempFolder = new File(tempDir, "veraPDFMediaConchPluginTemp");
+ if (!tempFolder.exists()) {
+ tempFolder.mkdir();
+ }
+ return tempFolder;
+ }
+
+ private File getOutFileInFolder(File folder) throws IOException {
+ File out = File.createTempFile("veraPDF_MediaConch_Plugin_out", ".xml", folder);
+ return out;
+ }
+
+ private MediaConchConfig getConfig(List nodes) throws FeatureParsingException {
+ MediaConchConfig config = MediaConchConfig.defaultInstance();
+ File conf = getConfigFile();
+ if (conf.isFile() && conf.canRead()) {
+ try {
+ config = MediaConchConfig.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");
+ }
+
+ private boolean isValidType(String type) {
+ return type.toLowerCase().startsWith("video/");
+ }
+
+ @Override
+ public String getID() {
+ return "8725b233-1597-490e-9b45-b989303d2c5b";
+ }
+
+ @Override
+ public String getDescription() {
+ //TODO: check this description
+ return "Generates mediaconch report of the given embedded video file";
+ }
+}
diff --git a/metsMetadata-plugin/pom.xml b/metsMetadata-plugin/pom.xml
new file mode 100644
index 0000000..b25000d
--- /dev/null
+++ b/metsMetadata-plugin/pom.xml
@@ -0,0 +1,34 @@
+
+
+
+ verapdf-library-samples
+ org.verapdf
+ 1.0-SNAPSHOT
+
+ 4.0.0
+
+ metsMetadata-plugin
+
+
+
+ au.edu.apsr.mtk
+ mets
+ 1.0
+ system
+ ${project.basedir}/src/main/resources/mets-api.jar
+
+
+ org.verapdf
+ feature-report
+ [0.11.0,0.12.0)
+
+
+ org.verapdf
+ verapdf-xmp-core
+ [0.11.0,0.12.0)
+
+
+
+
\ No newline at end of file
diff --git a/metsMetadata-plugin/src/main/java/org/verapdf/METSConfig.java b/metsMetadata-plugin/src/main/java/org/verapdf/METSConfig.java
new file mode 100644
index 0000000..ae3c374
--- /dev/null
+++ b/metsMetadata-plugin/src/main/java/org/verapdf/METSConfig.java
@@ -0,0 +1,112 @@
+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/METSConfig", name = "metsConfig")
+final class METSConfig {
+
+ @XmlElement
+ private final String outFolder;
+
+ private METSConfig() {
+ this("");
+ }
+
+ private METSConfig(String outFolder) {
+ this.outFolder = outFolder;
+ }
+
+ public String getOutFolder() {
+ return outFolder;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ METSConfig that = (METSConfig) o;
+
+ return !(outFolder != null ? !outFolder.equals(that.outFolder) : that.outFolder != null);
+
+ }
+
+ @Override
+ public int hashCode() {
+ return outFolder != null ? outFolder.hashCode() : 0;
+ }
+
+ static METSConfig defaultInstance() {
+ return new METSConfig(null);
+ }
+
+ static METSConfig fromValues(final String outFolder) {
+ return new METSConfig(outFolder);
+ }
+
+ static String toXml(final METSConfig toConvert, Boolean prettyXml)
+ throws JAXBException, IOException {
+ String retVal = "";
+ try (StringWriter writer = new StringWriter()) {
+ toXml(toConvert, writer, prettyXml);
+ retVal = writer.toString();
+ return retVal;
+ }
+ }
+
+ static METSConfig fromXml(final String toConvert)
+ throws JAXBException {
+ try (StringReader reader = new StringReader(toConvert)) {
+ return fromXml(reader);
+ }
+ }
+
+ static void toXml(final METSConfig toConvert,
+ final OutputStream stream, Boolean prettyXml) throws JAXBException {
+ Marshaller varMarshaller = getMarshaller(prettyXml);
+ varMarshaller.marshal(toConvert, stream);
+ }
+
+ static METSConfig fromXml(final InputStream toConvert)
+ throws JAXBException {
+ Unmarshaller stringUnmarshaller = getUnmarshaller();
+ return (METSConfig) stringUnmarshaller.unmarshal(toConvert);
+ }
+
+ static void toXml(final METSConfig toConvert, final Writer writer,
+ Boolean prettyXml) throws JAXBException {
+ Marshaller varMarshaller = getMarshaller(prettyXml);
+ varMarshaller.marshal(toConvert, writer);
+ }
+
+ static METSConfig fromXml(final Reader toConvert)
+ throws JAXBException {
+ Unmarshaller stringUnmarshaller = getUnmarshaller();
+ return (METSConfig) stringUnmarshaller.unmarshal(toConvert);
+ }
+
+ private static Unmarshaller getUnmarshaller() throws JAXBException {
+ JAXBContext context = JAXBContext
+ .newInstance(METSConfig.class);
+ Unmarshaller unmarshaller = context.createUnmarshaller();
+ return unmarshaller;
+ }
+
+ private static Marshaller getMarshaller(Boolean setPretty)
+ throws JAXBException {
+ JAXBContext context = JAXBContext
+ .newInstance(METSConfig.class);
+ Marshaller marshaller = context.createMarshaller();
+ marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, setPretty);
+ return marshaller;
+ }
+}
diff --git a/metsMetadata-plugin/src/main/java/org/verapdf/METSMetadataExtractor.java b/metsMetadata-plugin/src/main/java/org/verapdf/METSMetadataExtractor.java
new file mode 100644
index 0000000..0d623e6
--- /dev/null
+++ b/metsMetadata-plugin/src/main/java/org/verapdf/METSMetadataExtractor.java
@@ -0,0 +1,284 @@
+package org.verapdf;
+
+import au.edu.apsr.mtk.base.*;
+import com.adobe.xmp.XMPException;
+import com.adobe.xmp.XMPMeta;
+import com.adobe.xmp.XMPMetaFactory;
+import com.adobe.xmp.impl.VeraPDFMeta;
+import com.adobe.xmp.impl.VeraPDFXMPNode;
+import com.adobe.xmp.impl.XMPSchemaRegistryImpl;
+import org.verapdf.core.FeatureParsingException;
+import org.verapdf.features.AbstractMetadataFeaturesExtractor;
+import org.verapdf.features.MetadataFeaturesData;
+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 java.io.*;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Maksim Bezrukov
+ */
+public class METSMetadataExtractor extends AbstractMetadataFeaturesExtractor {
+
+ private XMPMeta dmdMeta = null;
+ private XMPMeta rightsMeta = null;
+ private XMPMeta techMeta = null;
+ private XMPMeta sourceMeta = null;
+ private XMPMeta digiprovMeta = null;
+
+ @Override
+ public List getMetadataFeatures(MetadataFeaturesData metadataFeaturesData) {
+ List result = new ArrayList<>(1);
+ try {
+ File outFile = getOutFile(result);
+ byte[] bytes = metadataFeaturesData.getStream();
+ convertXMPToMETS(new ByteArrayInputStream(bytes), new FileOutputStream(outFile));
+ FeatureTreeNode node = FeatureTreeNode.createRootNode("resultFile");
+ node.setValue(outFile.getCanonicalPath());
+ result.add(node);
+ } catch (XMPException | METSException | IOException | SAXException | FeatureParsingException | ParserConfigurationException e) {
+ try {
+ result.clear();
+ FeatureTreeNode node = FeatureTreeNode.createRootNode("error");
+ node.setValue(e.getMessage());
+ result.add(node);
+ } catch (FeatureParsingException e1) {
+ throw new IllegalStateException(e1);
+ }
+ }
+ return result;
+ }
+
+ private void convertXMPToMETS(InputStream toConvert, OutputStream out) throws XMPException, METSException, IOException, SAXException, ParserConfigurationException {
+ VeraPDFMeta meta = VeraPDFMeta.parse(toConvert);
+ divideMetas(meta);
+ METSWrapper metsWrapper = new METSWrapper();
+ createMETS(metsWrapper);
+ //TODO: fix mets creation in such way that validating will not generate any exceptions
+// metsWrapper.validate();
+ metsWrapper.write(out);
+ }
+
+ private void createMETS(METSWrapper metsWrapper) throws METSException, SAXException, ParserConfigurationException, XMPException, IOException {
+ METS mets = metsWrapper.getMETSObject();
+
+ if (this.dmdMeta != null) {
+ DmdSec dmd = mets.newDmdSec();
+ dmd.setID("DMD_ID_1");
+ MdWrap dmdWrap = dmd.newMdWrap();
+ addXMPTreeToMdWrap(dmdWrap, this.dmdMeta);
+ dmd.setMdWrap(dmdWrap);
+ mets.addDmdSec(dmd);
+ }
+
+ if (this.rightsMeta != null || this.techMeta != null || this.sourceMeta != null || this.digiprovMeta != null) {
+ AmdSec amd = mets.newAmdSec();
+
+ if (this.rightsMeta != null) {
+ RightsMD rightsMD = amd.newRightsMD();
+ rightsMD.setID("RIGHTSMD_ID_1");
+ MdWrap rightsWrap = rightsMD.newMdWrap();
+ addXMPTreeToMdWrap(rightsWrap, this.rightsMeta);
+ rightsMD.setMdWrap(rightsWrap);
+ amd.addRightsMD(rightsMD);
+ }
+
+ if (this.techMeta != null) {
+ TechMD techMD = amd.newTechMD();
+ techMD.setID("TECHMD_ID_1");
+ MdWrap techWrap = techMD.newMdWrap();
+ addXMPTreeToMdWrap(techWrap, this.techMeta);
+ techMD.setMdWrap(techWrap);
+ amd.addTechMD(techMD);
+ }
+
+ if (this.sourceMeta != null) {
+ SourceMD sourceMD = amd.newSourceMD();
+ sourceMD.setID("SOURCEMD_ID_1");
+ MdWrap sourceWrap = sourceMD.newMdWrap();
+ addXMPTreeToMdWrap(sourceWrap, this.sourceMeta);
+ sourceMD.setMdWrap(sourceWrap);
+ amd.addSourceMD(sourceMD);
+ }
+
+ if (this.digiprovMeta != null) {
+ DigiprovMD digiprovMD = amd.newDigiprovMD();
+ digiprovMD.setID("DIGIPROVMD_ID_1");
+ MdWrap digiprovWrap = digiprovMD.newMdWrap();
+ addXMPTreeToMdWrap(digiprovWrap, this.digiprovMeta);
+ digiprovMD.setMdWrap(digiprovWrap);
+ amd.addDigiprovMD(digiprovMD);
+ }
+
+ mets.addAmdSec(amd);
+ }
+ }
+
+ private void addXMPTreeToMdWrap(MdWrap wrap, XMPMeta meta) throws XMPException, ParserConfigurationException, IOException, SAXException {
+ ByteArrayOutputStream bstream = new ByteArrayOutputStream();
+ XMPMetaFactory.serialize(meta, bstream);
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ Document doc = builder.parse(new ByteArrayInputStream(bstream.toByteArray()));
+ wrap.setXmlData(doc.getDocumentElement());
+ wrap.setMDType("OTHER");
+ wrap.setOtherMDType("XMP");
+ }
+
+ private void divideMetas(VeraPDFMeta meta) {
+
+ List xmpProps = meta.getProperties();
+ List properties;
+
+ if (meta.getExtensionSchemasNode() != null) {
+ properties = new ArrayList<>(xmpProps.size() + 1);
+ properties.add(new String[]{XMPSchemaRegistryImpl.NS_PDFA_EXTENSION, "schemas"});
+ } else {
+ properties = new ArrayList<>(xmpProps.size());
+ }
+
+ for (VeraPDFXMPNode node : xmpProps) {
+ properties.add(new String[]{node.getNamespaceURI(), node.getName()});
+ }
+
+ this.dmdMeta = meta.getCloneOfInitialMeta();
+ this.rightsMeta = meta.getCloneOfInitialMeta();
+ this.techMeta = meta.getCloneOfInitialMeta();
+ this.sourceMeta = meta.getCloneOfInitialMeta();
+ this.digiprovMeta = meta.getCloneOfInitialMeta();
+
+ boolean isDMDEmpty = true;
+ boolean isRightsEmpty = true;
+ boolean isTechEmpty = true;
+ boolean isSourceEmpty = true;
+ boolean isDIGIPROVEmpty = true;
+
+ for (String[] el : properties) {
+ switch (METSTypeRegistry.getTypeForProperty(el[0], el[1])) {
+ case DMD_SEC:
+ isDMDEmpty = false;
+ rightsMeta.deleteProperty(el[0], el[1]);
+ techMeta.deleteProperty(el[0], el[1]);
+ sourceMeta.deleteProperty(el[0], el[1]);
+ digiprovMeta.deleteProperty(el[0], el[1]);
+ break;
+ case RIGHTS_MD:
+ isRightsEmpty = false;
+ dmdMeta.deleteProperty(el[0], el[1]);
+ techMeta.deleteProperty(el[0], el[1]);
+ sourceMeta.deleteProperty(el[0], el[1]);
+ digiprovMeta.deleteProperty(el[0], el[1]);
+ break;
+ case TECH_MD:
+ isTechEmpty = false;
+ dmdMeta.deleteProperty(el[0], el[1]);
+ rightsMeta.deleteProperty(el[0], el[1]);
+ sourceMeta.deleteProperty(el[0], el[1]);
+ digiprovMeta.deleteProperty(el[0], el[1]);
+ break;
+ case SOURCE_MD:
+ isSourceEmpty = false;
+ dmdMeta.deleteProperty(el[0], el[1]);
+ rightsMeta.deleteProperty(el[0], el[1]);
+ techMeta.deleteProperty(el[0], el[1]);
+ digiprovMeta.deleteProperty(el[0], el[1]);
+ break;
+ case DIGIPROV_MD:
+ isDIGIPROVEmpty = false;
+ dmdMeta.deleteProperty(el[0], el[1]);
+ rightsMeta.deleteProperty(el[0], el[1]);
+ techMeta.deleteProperty(el[0], el[1]);
+ sourceMeta.deleteProperty(el[0], el[1]);
+ break;
+ }
+ }
+
+ if (isDMDEmpty) {
+ this.dmdMeta = null;
+ }
+ if (isRightsEmpty) {
+ this.rightsMeta = null;
+ }
+ if (isTechEmpty) {
+ this.techMeta = null;
+ }
+ if (isSourceEmpty) {
+ this.sourceMeta = null;
+ }
+ if (isDIGIPROVEmpty) {
+ this.digiprovMeta = null;
+ }
+ }
+
+ private File getOutFile(List nodes) throws FeatureParsingException, IOException {
+ METSConfig config = getConfig(nodes);
+ if (config.getOutFolder() == null) {
+ File tempFolder = getTempFolder();
+ File res = getOutFileInFolder(tempFolder);
+ return res;
+ } else {
+ File outFolder = new File(config.getOutFolder());
+ if (outFolder.isDirectory()) {
+ File res = getOutFileInFolder(outFolder);
+ return res;
+ } 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();
+ File res = getOutFileInFolder(tempFolder);
+ return res;
+ }
+ }
+ }
+
+ private File getTempFolder() {
+ File tempDir = new File(System.getProperty("java.io.tmpdir"));
+ File tempFolder = new File(tempDir, "veraPDFMETSPluginTemp");
+ if (!tempFolder.exists()) {
+ tempFolder.mkdir();
+ }
+ return tempFolder;
+ }
+
+ private File getOutFileInFolder(File folder) throws IOException {
+ return File.createTempFile("veraPDF_METS_Plugin_out", ".xml", folder);
+ }
+
+ private METSConfig getConfig(List nodes) throws FeatureParsingException {
+ METSConfig config = METSConfig.defaultInstance();
+ File conf = getConfigFile();
+ if (conf.isFile() && conf.canRead()) {
+ try {
+ config = METSConfig.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 "63f0a295-587b-4e50-909c-4b47e02f64f7";
+ }
+
+ @Override
+ public String getDescription() {
+ return "This extractor generates METS file based on XMP package.";
+ }
+}
diff --git a/metsMetadata-plugin/src/main/java/org/verapdf/METSTypeRegistry.java b/metsMetadata-plugin/src/main/java/org/verapdf/METSTypeRegistry.java
new file mode 100644
index 0000000..cfbe451
--- /dev/null
+++ b/metsMetadata-plugin/src/main/java/org/verapdf/METSTypeRegistry.java
@@ -0,0 +1,139 @@
+package org.verapdf;
+
+import com.adobe.xmp.impl.XMPSchemaRegistryImpl;
+
+/**
+ * @author Maksim Bezrukov
+ */
+public class METSTypeRegistry {
+
+ public enum METSType {
+ DMD_SEC,
+ RIGHTS_MD,
+ TECH_MD,
+ SOURCE_MD,
+ DIGIPROV_MD
+ }
+
+ public static METSType getTypeForProperty(String namespace, String name) {
+
+ switch (namespace) {
+ case XMPSchemaRegistryImpl.NS_DC:
+ return getDCType(name);
+ case XMPSchemaRegistryImpl.NS_XMP:
+ return getXMPType(name);
+ case XMPSchemaRegistryImpl.TYPE_IDENTIFIERQUAL:
+ return METSType.TECH_MD;
+ case XMPSchemaRegistryImpl.NS_XMP_RIGHTS:
+ return METSType.RIGHTS_MD;
+ case XMPSchemaRegistryImpl.NS_XMP_MM:
+ return METSType.DIGIPROV_MD;
+ case XMPSchemaRegistryImpl.NS_XMP_BJ:
+ case XMPSchemaRegistryImpl.TYPE_PAGEDFILE:
+ case XMPSchemaRegistryImpl.NS_PHOTOSHOP:
+ case XMPSchemaRegistryImpl.NS_CAMERARAW:
+ case XMPSchemaRegistryImpl.NS_EXIF:
+ case XMPSchemaRegistryImpl.NS_EXIF_AUX:
+ return METSType.TECH_MD;
+ case XMPSchemaRegistryImpl.NS_DM:
+ return getDMType(name);
+ case XMPSchemaRegistryImpl.NS_PDF:
+ return getPDFType(name);
+ case XMPSchemaRegistryImpl.NS_TIFF:
+ return getTIFFType(name);
+ default:
+ return METSType.TECH_MD;
+ }
+ }
+
+ private static METSType getDCType(String name) {
+ switch (name) {
+ case "description":
+ case "language":
+ case "relation":
+ case "source":
+ case "subject":
+ case "title":
+ case "type":
+ return METSType.DMD_SEC;
+ case "contributor":
+ case "creator":
+ case "publisher":
+ case "rights":
+ return METSType.RIGHTS_MD;
+ case "coverage":
+ case "format":
+ case "identifier":
+ return METSType.TECH_MD;
+ case "date":
+ return METSType.DIGIPROV_MD;
+ default:
+ return METSType.TECH_MD;
+ }
+ }
+
+ private static METSType getXMPType(String name) {
+ switch (name) {
+ case "Nickname":
+ return METSType.DMD_SEC;
+ case "BaseURL":
+ case "Identifier":
+ case "Label":
+ case "Rating":
+ case "Thumbnails":
+ return METSType.TECH_MD;
+ case "CreatorTool":
+ return METSType.SOURCE_MD;
+ case "Advisory":
+ case "CreateDate":
+ case "MetadataDate":
+ case "ModifyDate":
+ return METSType.DIGIPROV_MD;
+ default:
+ return METSType.TECH_MD;
+ }
+ }
+
+ private static METSType getDMType(String name) {
+ switch (name) {
+ case "copyright":
+ return METSType.RIGHTS_MD;
+ case "projectRef":
+ return METSType.SOURCE_MD;
+ case "videoModDate":
+ case "audioModDate":
+ case "metadataModDate":
+ return METSType.DIGIPROV_MD;
+ default:
+ return METSType.TECH_MD;
+ }
+ }
+
+ private static METSType getPDFType(String name) {
+ switch (name) {
+ case "Keywords":
+ case "PDFVersion":
+ return METSType.TECH_MD;
+ case "Producer":
+ return METSType.SOURCE_MD;
+ default:
+ return METSType.TECH_MD;
+ }
+ }
+
+ private static METSType getTIFFType(String name) {
+ switch (name) {
+ case "ImageDescription":
+ return METSType.DMD_SEC;
+ case "Artist":
+ case "Copyright":
+ return METSType.RIGHTS_MD;
+ case "Software":
+ return METSType.SOURCE_MD;
+ case "DateTime":
+ return METSType.DIGIPROV_MD;
+ default:
+ return METSType.TECH_MD;
+ }
+ }
+}
diff --git a/metsMetadata-plugin/src/main/resources/mets-api.jar b/metsMetadata-plugin/src/main/resources/mets-api.jar
new file mode 100644
index 0000000..3efe6b4
Binary files /dev/null and b/metsMetadata-plugin/src/main/resources/mets-api.jar differ
diff --git a/pom.xml b/pom.xml
index 362d999..da94c37 100644
--- a/pom.xml
+++ b/pom.xml
@@ -27,6 +27,8 @@
fontSample-plugin
embeddedfileSample-plugin
imageSample-plugin
+ metsMetadata-plugin
+ mediaconch