/** * P4SIP.java * Author: Francesco Rosso (rosso@eurix.it) * Contributors: Francesco Gallo (gallo@eurix.it) * * This file is part of PrestoPRIME Preservation Platform (P4). * * Copyright (C) 2009-2012 EURIX Srl, Torino, Italy * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package eu.prestoprime.datamanagement.impl; import it.eurix.archtools.data.model.DIP.DCField; import it.eurix.archtools.data.model.SIP; import it.eurix.archtools.persistence.DatabaseException; import it.eurix.archtools.tool.ToolException; import it.eurix.archtools.tool.ToolOutput; import it.eurix.archtools.tool.impl.MessageDigestExtractor; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Date; import java.util.GregorianCalendar; import java.util.List; import java.util.UUID; import javax.xml.bind.JAXBException; import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeFactory; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Node; import eu.prestoprime.conf.ConfigurationManager; import eu.prestoprime.conf.P4PropertyManager.P4Property; import eu.prestoprime.datamanagement.P4PersistenceManager; import eu.prestoprime.datamanagement.P4PersistenceManager.P4Collection; import eu.prestoprime.model.ModelUtils; import eu.prestoprime.model.ModelUtils.P4JAXBPackage; import eu.prestoprime.model.datatypes.Datatype; import eu.prestoprime.model.mets.AmdSecType; import eu.prestoprime.model.mets.FileType; import eu.prestoprime.model.mets.FileType.FLocat; import eu.prestoprime.model.mets.MdSecType; import eu.prestoprime.model.mets.MdSecType.MdRef; import eu.prestoprime.model.mets.MdSecType.MdWrap; import eu.prestoprime.model.mets.MdSecType.MdWrap.XmlData; import eu.prestoprime.model.mets.Mets; import eu.prestoprime.model.mets.MetsType.FileSec.FileGrp; import eu.prestoprime.model.mets.MetsType.MetsHdr; public class P4SIP extends P4RWInformationPackage implements SIP { private static final Logger logger = LoggerFactory.getLogger(P4SIP.class); public P4SIP(String id, Node content) { super(id, content); } @Override public synchronized void selfRelease() throws P4IPException { // store SIP try { P4PersistenceManager.getInstance().storeXMLResource(P4Collection.TEMP_COLLECTION, id, content); } catch (DatabaseException e) { e.printStackTrace(); logger.error("Unable to store SIP " + id + " on persistence DB..."); throw new P4IPException("Unable to store SIP " + id + " on persistence DB..."); } // store related resources for (P4Resource resource : this.resources) { try { P4PersistenceManager.getInstance().storeXMLResource(resource.getCollection(), resource.getResourceID(), resource.getResourceNode()); } catch (DatabaseException e) { e.printStackTrace(); logger.error("Unable to store P4Resource " + resource.getResourceID() + " on persistence DB..."); } } } @Override public synchronized String setRights(Node rights) throws P4IPException { if (rights != null) { // get rights datatype information Datatype rightsDT = ConfigurationManager.getDataTypesInstance().getDatatype("rights"); // get rights file size and checksum String md5 = null; Long size = null; try { File tmpUpdateFile = File.createTempFile("rights-", ".tmp"); TransformerFactory.newInstance().newTransformer().transform(new DOMSource(rights), new StreamResult(new FileOutputStream(tmpUpdateFile))); MessageDigestExtractor mde = new MessageDigestExtractor(); ToolOutput<MessageDigestExtractor.AttributeType> output = mde.extract(tmpUpdateFile.getAbsolutePath()); md5 = output.getAttribute(MessageDigestExtractor.AttributeType.MD5); size = tmpUpdateFile.length(); tmpUpdateFile.delete(); } catch (IOException | ToolException | TransformerException e) { e.printStackTrace(); throw new P4IPException("Unable to calculate size or checksum for rights file..."); } // add rights node to resources String rightsID = UUID.randomUUID().toString(); this.resources.add(new P4Resource(P4Collection.RIGHTSMD_COLLECTION, rightsID, rights)); // add MPEG-21 MCO as additional format List<String> formatList = this.getDCField(DCField.format); boolean hasMPEG21MCOFormat = false; for (String format : formatList) { if (format.contains("MPEG-21 MCO")) { hasMPEG21MCOFormat = true; break; } } if (!hasMPEG21MCOFormat) { formatList.add("MPEG-21 MCO (ISO/IEC 21000-21)"); this.setDCField(DCField.format, formatList); } // update rights reference in METS Mets mets = this.getContentAsMets(); List<MdSecType> rightsList = null; for (AmdSecType amdSecType : mets.getAmdSec()) { List<MdSecType> rightsMdList = amdSecType.getRightsMD(); if (rightsMdList.isEmpty()) continue; if (rightsMdList.size() != 1) throw new P4IPException("Multiple rights sections found..."); rightsMdList.remove(0); if (rightsList != null) throw new P4IPException("Multiple rights sections found..."); rightsList = rightsMdList; } // rights mdRef according to datatype MdRef mdRef = new MdRef(); mdRef.setLABEL(rightsDT.getRef().getLabel()); mdRef.setMDTYPE(rightsDT.getRef().getMdtype()); mdRef.setOTHERMDTYPE(rightsDT.getRef().getOthermdtype()); try { mdRef.setCREATED(ModelUtils.Date2XMLGC(new Date())); } catch (DatatypeConfigurationException e) { e.printStackTrace(); throw new P4IPException("Unable to assign new date to rights mdRef..."); } mdRef.setHref(ConfigurationManager.getPropertyInstance().getProperty(P4Property.P4_PLACEHOLDER) + "/access/resource/" + P4Collection.RIGHTSMD_COLLECTION + File.separator + rightsID); mdRef.setMIMETYPE("application/xml"); mdRef.setSIZE(size); mdRef.setCHECKSUM(md5); mdRef.setCHECKSUMTYPE("MD5"); // rights section according to datatype MdSecType rightsSecType = new MdSecType(); rightsSecType.setMdRef(mdRef); rightsSecType.setID(rightsDT.getSection().getId()); String status = rightsDT.getSection().getStatus(); if (status != null && !status.isEmpty()) rightsSecType.setSTATUS(status); rightsList.add(rightsSecType); // clean up identifiers of SIP sections for (MdSecType mdSecType : mets.getDmdSec()) mdSecType.setID("dmd-" + System.currentTimeMillis()); for (AmdSecType amdSecType : mets.getAmdSec()) amdSecType.setID("amd-" + System.currentTimeMillis()); this.setContent(mets); return rightsID; } else { throw new P4IPException("Unable to add rights to SIP..."); } } @Override public synchronized void addDNX(Object dnx, String id, boolean isMdRef) throws P4IPException { MdSecType techMdType = new MdSecType(); techMdType.setID(id); if (isMdRef) { MdRef mdRef = new MdRef(); mdRef.setMDTYPE("OTHER"); mdRef.setOTHERMDTYPE("DNX"); try { // add node to resources DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setNamespaceAware(true); Document dnxNode = dbf.newDocumentBuilder().newDocument(); ModelUtils.getMarshaller(P4JAXBPackage.DATA_MODEL).marshal(dnx, dnxNode); String dnxID = UUID.randomUUID().toString(); this.resources.add(new P4Resource(P4Collection.TECHMD_COLLECTION, dnxID, dnxNode)); mdRef.setHref(ConfigurationManager.getPropertyInstance().getProperty(P4Property.P4_PLACEHOLDER) + "/access/resource/" + P4Collection.TECHMD_COLLECTION + File.separator + dnxID); mdRef.setMIMETYPE("application/xml"); File tmpFile = File.createTempFile("dnx-", ".tmp"); TransformerFactory.newInstance().newTransformer().transform(new DOMSource(dnxNode), new StreamResult(new FileOutputStream(tmpFile))); MessageDigestExtractor mde = new MessageDigestExtractor(); ToolOutput<MessageDigestExtractor.AttributeType> output = mde.extract(tmpFile.getAbsolutePath()); mdRef.setCHECKSUMTYPE("MD5"); mdRef.setCHECKSUM(output.getAttribute(MessageDigestExtractor.AttributeType.MD5)); mdRef.setSIZE(tmpFile.length()); tmpFile.delete(); mdRef.setCREATED(ModelUtils.Date2XMLGC(new Date())); techMdType.setMdRef(mdRef); } catch (IOException | ToolException | TransformerException e) { e.printStackTrace(); throw new P4IPException("Unable to calculate size or checksum for dnx file..."); } catch (DatatypeConfigurationException e) { e.printStackTrace(); throw new P4IPException("Unable to assign new date to rights mdRef..."); } catch (ParserConfigurationException e) { e.printStackTrace(); throw new P4IPException("Unable to create DNX node in mdRef..."); } catch (JAXBException e) { e.printStackTrace(); throw new P4IPException("Unable to marshal DNX in mdRef..."); } } else { MdWrap mdWrap = new MdWrap(); mdWrap.setMDTYPE("OTHER"); mdWrap.setOTHERMDTYPE("DNX"); XmlData xmlData = new XmlData(); xmlData.getAny().add(dnx); mdWrap.setXmlData(xmlData); techMdType.setMdWrap(mdWrap); } AmdSecType amdSecType = new AmdSecType(); amdSecType.getTechMD().add(techMdType); amdSecType.setID("amd-" + System.currentTimeMillis()); Mets mets = this.getContentAsMets(); mets.getAmdSec().add(amdSecType); this.setContent(mets); } @Override public synchronized void setCreateDate(GregorianCalendar date) throws P4IPException { try { Mets mets = this.getContentAsMets(); if (mets.getMetsHdr() == null) mets.setMetsHdr(new MetsHdr()); mets.getMetsHdr().setCREATEDATE(DatatypeFactory.newInstance().newXMLGregorianCalendar(date)); this.setContent(mets); logger.debug("Assigned new METS to SIP... " + mets.getMetsHdr().getCREATEDATE()); } catch (DatatypeConfigurationException e) { e.printStackTrace(); throw new P4IPException("Unable to set SIP create date..."); } } @Override public synchronized void purgeFiles() throws P4IPException { Mets mets = this.getContentAsMets(); if (mets.getFileSec() != null) { for (FileGrp fileGroup : mets.getFileSec().getFileGrp()) { if (fileGroup != null) { for (FileType file : fileGroup.getFile()) { if (file != null) { List<FLocat> toBeRemoved = new ArrayList<>(); for (FLocat fLocat : file.getFLocat()) { String placeholder = ConfigurationManager.getPropertyInstance().getProperty(P4Property.P4_PLACEHOLDER); if (fLocat.getOTHERLOCTYPE().equals("FILE") && !fLocat.getHref().startsWith(placeholder)) { toBeRemoved.add(fLocat); } } for (FLocat fLocat : toBeRemoved) { file.getFLocat().remove(fLocat); } } if (file.getFLocat().size() == 0) { fileGroup.getFile().remove(file); } } if (fileGroup.getFile().size() == 0) { mets.getFileSec().getFileGrp().remove(fileGroup); } } } if (mets.getFileSec().getFileGrp().size() == 0) { mets.setFileSec(null); } } this.setContent(mets); } }