
de.unirostock.sems.cbarchive.meta.MetaDataFile Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of CombineArchive Show documentation
Show all versions of CombineArchive Show documentation
Library to read/create/write/manipulate/... COMBINE archives
The newest version!
/**
* CombineArchive - a JAVA library to read/write/create/... CombineArchives
* Copyright (c) 2014, Martin Scharm
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
package de.unirostock.sems.cbarchive.meta;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import javax.xml.transform.TransformerException;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import de.binfalse.bflog.LOGGER;
import de.unirostock.sems.cbarchive.ArchiveEntry;
import de.unirostock.sems.cbarchive.CombineArchive;
import de.unirostock.sems.cbarchive.CombineArchiveException;
import de.unirostock.sems.cbarchive.Utils;
/**
* The Class MetaDataFile providing some static functions to read and write meta
* data files.
*
* @author Martin Scharm
*/
public class MetaDataFile
extends MetaDataHolder
{
/**
* Read a meta data file containing descriptions about the
* {@link CombineArchive archive} and/or its {@link ArchiveEntry
* entries} given in entries
.
*
* @param file
* the file containing meta data
* @param entries
* the entries available in the corresponding archive
* @param archive
* the archive which contains this file
* @param metaMetaHolder
* the meta data of meta data
* @param metaDataFiles
* the meta data file to evaluate
* @param continueOnError
* ignore errors and continue (as far as possible)
* @param errors
* the list of occurred errors
* @throws ParseException
* the parse exception
* @throws JDOMException
* the jDOM exception
* @throws IOException
* Signals that an I/O exception has occurred.
* @throws CombineArchiveException
* the combine archive exception
*/
public static void readFile (Path file, HashMap entries,
CombineArchive archive, MetaDataHolder metaMetaHolder,
List metaDataFiles, boolean continueOnError, List errors)
throws ParseException,
JDOMException,
IOException,
CombineArchiveException
{
Document doc = null;
try
{
doc = Utils.readXmlDocument (file);
}
catch (JDOMException e)
{
LOGGER.error (e, "cannot read manifest of archive");
errors.add ("cannot read manifest of archive. xml seems to be invalid.");
if (!continueOnError)
throw e;
return;
}
catch (IOException e)
{
LOGGER.error (e, "cannot read manifest of archive.");
errors.add ("cannot read manifest of archive. io error.");
if (!continueOnError)
throw e;
return;
}
List nl = Utils.getElementsByTagName (doc.getRootElement (),
"Description", Utils.rdfNS);
for (int i = 0; i < nl.size (); i++)
{
Element current = nl.get (i);
String about = current.getAttributeValue ("about", Utils.rdfNS);
if (about == null)
{
LOGGER.error ("meta description " + i + " in " + file
+ " does not contain an `about` value. so we cannot assign it to an entity.");
errors.add ("meta description " + i + " in " + file
+ " does not contain an `about` value. so we cannot assign it to an entity.");
if (!continueOnError)
throw new CombineArchiveException ("meta description " + i + " in "
+ file
+ " does not contain an `about` value. so we cannot assign it to an entity.");
continue;
}
if (about.equals (".") || about.equals ("/"))
{
// this entry describes the archive itself
if (!addMetaToEntry (archive, current, null))
LOGGER.warn ("could not parse description for ", about);
continue;
}
if (about.startsWith ("./"))
about = about.substring (2);
while (about.startsWith ("/"))
about = about.substring (1);
about = "/" + about;
MetaDataHolder currentEntry = null;
String fragmentIdentifier = null;
about = Utils.pathFixer (Paths.get (about).normalize ().toString ());
// try to find the corresponding entry
for (ArchiveEntry entry : entries.values ())
{
if (about.startsWith (entry.getFilePath ())
&& (about.length () == entry.getFilePath ().length ()
|| about.charAt (entry.getFilePath ().length ()) == '#'))
{
currentEntry = entry;
if (about.length () > entry.getFilePath ().length ()
&& about.charAt (entry.getFilePath ().length ()) == '#')
fragmentIdentifier = about
.substring (entry.getFilePath ().length () - 1);
break;
}
}
if (currentEntry == null && metaDataFiles != null)
{
for (Path p : metaDataFiles)
{
String path = p.toString ();
if (about.startsWith (path) && (about.length () == path.length ()
|| about.charAt (path.length ()) == '#'))
{
currentEntry = metaMetaHolder;
if (about.length () > path.length ()
&& about.charAt (path.length ()) == '#')
fragmentIdentifier = about.substring (path.length () - 1);
break;
}
}
}
if (currentEntry == null)
{
LOGGER.error ("found no entry for description ", i, " in ", file,
" (about=", about, ").");
errors.add ("found no entry for description " + i + " in " + file
+ " (about=" + about + ").");
if (!continueOnError)
throw new CombineArchiveException ("found no entry for description "
+ current + "(" + i + ") in " + file + " (about=" + about + ").");
continue;
}
if (!addMetaToEntry (currentEntry, current, fragmentIdentifier))
LOGGER.warn ("could not parse description for ", about);
}
}
/**
* Adds all descriptions of a file to a single entry, assuming all are about this file (ignoring the actual about!).
*
* @param file
* the file containing the meta data
* @param entry
* the entry in the archive
* @return the number of descriptions added to entry
* @throws JDOMException
* the jDOM exception
* @throws IOException
* Signals that an I/O exception has occurred.
*/
public static int addAllMetaToEntry (Path file, ArchiveEntry entry)
throws JDOMException,
IOException
{
int added = 0;
Document doc = Utils.readXmlDocument (file);
List nl = Utils.getElementsByTagName (doc.getRootElement (),
"Description", Utils.rdfNS);
for (int i = 0; i < nl.size (); i++)
{
Element current = nl.get (i);
String fragmentIdentifier = null;
String about = current.getAttributeValue ("about", Utils.rdfNS);
if (about != null)
{
// is there a fragment identifier
int p = about.indexOf ("#");
if (p >= 0 && about.length () > p + 1)
fragmentIdentifier = about.substring (p + 1);
}
if (fragmentIdentifier != null)
current.setAttribute ("about", entry.getEntityPath () + "#" + fragmentIdentifier, Utils.rdfNS);
else
current.setAttribute ("about", entry.getEntityPath (), Utils.rdfNS);
if (!addMetaToEntry (entry, current, fragmentIdentifier))
LOGGER.warn ("could not parse description for ", about);
else
added++;
}
return added;
}
/**
* Associates some meta data to a file.
*
* This function won't associate the same meta data twice to the same object.
*
* @param entity
* the entity that is described by subtree
* @param subtree
* the current xml subtree which describes entry
* @param fragmentIdentifier
* the fragment identifier
* @return true, if successful
*/
private static boolean addMetaToEntry (MetaDataHolder entity, Element subtree,
String fragmentIdentifier)
{
if (entity == null)
return false;
MetaDataObject object = null;
// is that omex?
object = OmexMetaDataObject.tryToRead (subtree);
/*
* ···································
* optional: other meta data formats..
* ···································
*/
if (object == null)
{
// is it default?
object = DefaultMetaDataObject.tryToRead (subtree);
}
if (object != null)
{
object.setAbout (entity, fragmentIdentifier);
// do not add the same meta twice...
for (MetaDataObject obj : entity.getDescriptions ())
if (object.equals (obj))
return true;
entity.addDescription (fragmentIdentifier, object);
}
else
return false;
return true;
}
/**
* Write the meta data about the {@link CombineArchive archive} and its
* {@link ArchiveEntry entries} given in archive
and
* entries
to a single meta data files.
*
*
* This method will create one meta data file per entry. Meta data files will
* be named baseDir/metadata(-[-0-9a-f]+)?.rdf
. See
* {@link #writeFile(File,HashMap,CombineArchive,MetaDataHolder)} if you want
* to
* store all meta data in a single file.
*
*
* @param baseDir
* the base directory to store the files
* @param entries
* the archive entries
* @param archive
* the archive which will contain the files
* @param metaMetaHolder
* the meta data of meta data
* @return the list of files that were created
* @throws IOException
* Signals that an I/O exception has occurred.
* @throws TransformerException
* the transformer exception
*/
public static List writeFiles (File baseDir,
HashMap entries, CombineArchive archive,
MetaDataHolder metaMetaHolder) throws IOException, TransformerException
{
List outputs = new ArrayList ();
// archive itself
File output = getMetaOutputFile (baseDir);
Document xmlDoc = new Document ();
Element rdf = new Element ("RDF", Utils.rdfNS);
xmlDoc.addContent (rdf);
rdf.addNamespaceDeclaration (Utils.dcNS);
rdf.addNamespaceDeclaration (Utils.vcNS);
exportMetaData (archive, rdf);
// meta of meta
exportMetaData (metaMetaHolder, rdf);
try (BufferedWriter bw = new BufferedWriter (new FileWriter (output)))
{
bw.write (Utils.prettyPrintDocument (xmlDoc));
}
catch (IOException | TransformerException e)
{
LOGGER.error (e, "cannot write omex descriptions to ", output);
throw e;
}
outputs.add (output);
// all entries
for (ArchiveEntry e : entries.values ())
{
output = getMetaOutputFile (baseDir);
xmlDoc = new Document ();
rdf = new Element ("RDF", Utils.rdfNS);
xmlDoc.addContent (rdf);
rdf.addNamespaceDeclaration (Utils.dcNS);
rdf.addNamespaceDeclaration (Utils.vcNS);
exportMetaData (e, rdf);
try (BufferedWriter bw = new BufferedWriter (new FileWriter (output)))
{
bw.write (Utils.prettyPrintDocument (xmlDoc));
}
catch (IOException | TransformerException ex)
{
LOGGER.error (ex, "cannot write omex descriptions to ", output);
throw ex;
}
outputs.add (output);
}
return outputs;
}
/**
* Write the meta data about the {@link CombineArchive archive} and its
* {@link ArchiveEntry entries} given in archive
and
* entries
to a single meta data file.
*
*
* This method will create one meta data file for all description. Thus, the
* returned list of files will be of size one. The meta data file will be
* named baseDir/metadata(-[-0-9a-f]+)?.rdf
. See
* {@link #writeFiles(File,HashMap,CombineArchive,MetaDataHolder)} if you want
* to store the
* meta data in a multiple files, one for each entry.
*
*
* @param baseDir
* the base directory to store the file
* @param entries
* the archive entries
* @param archive
* the archive which will contain the files
* @param metaMetaHolder
* the meta data of meta data
* @return the list of files th
* the meta data of meta dataat were created (should be always of size
* one)
* @throws IOException
* Signals that an I/O exception has occurred.
* @throws TransformerException
* the transformer exception
*/
public static List writeFile (File baseDir,
HashMap entries, CombineArchive archive,
MetaDataHolder metaMetaHolder) throws IOException, TransformerException
{
File output = getMetaOutputFile (baseDir);
Document xmlDoc = new Document ();
Element rdf = new Element ("RDF", Utils.rdfNS);
xmlDoc.addContent (rdf);
rdf.addNamespaceDeclaration (Utils.dcNS);
rdf.addNamespaceDeclaration (Utils.vcNS);
// archive itself
exportMetaData (archive, rdf);
// meta of meta
exportMetaData (metaMetaHolder, rdf);
// all entries
for (ArchiveEntry e : entries.values ())
exportMetaData (e, rdf);
try (BufferedWriter bw = new BufferedWriter (new FileWriter (output)))
{
bw.write (Utils.prettyPrintDocument (xmlDoc));
}
catch (IOException | TransformerException e)
{
LOGGER.error (e, "cannot write omex descriptions to ", output);
throw e;
}
List outputs = new ArrayList ();
outputs.add (output);
return outputs;
}
/**
* Find a file to write the meta data to.
*
* @param baseDir
* the base directory
* @return the output file
*/
private static File getMetaOutputFile (File baseDir)
{
File output = new File (
baseDir.getAbsolutePath () + File.separator + "metadata.rdf");
int it = 0;
while (output.exists ())
output = new File (baseDir.getAbsolutePath () + File.separator
+ "metadata-" + ++it + ".rdf");
return output;
}
/**
* Export the meta data of an entity.
*
* @param entity
* the entity
* @param rdf
* the RDF node which will host the description
*/
private static void exportMetaData (MetaDataHolder entity, Element rdf)
{
for (MetaDataObject meta : entity.getDescriptions ())
{
Element Description = new Element ("Description", Utils.rdfNS);
String about = meta.getAbout ();
if (!about.startsWith("."))
about = "." + about;
Description.setAttribute ("about", about, Utils.rdfNS);
rdf.addContent (Description);
meta.injectDescription (Description);
}
}
@Override
public String getEntityPath ()
{
return "/metadata.rdf";
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy