/** * P4AIP.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.AIP; 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.Date; import java.util.List; import java.util.UUID; import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.TransformerFactoryConfigurationError; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; 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.datatypes.Datatype; import eu.prestoprime.model.mets.AmdSecType; 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.premis.Event; import eu.prestoprime.model.premis.Event.EventIdentifier; import eu.prestoprime.model.premis.Event.LinkingAgentIdentifier; public class P4AIP extends P4RWInformationPackage implements AIP { public P4AIP(String id, Node content) { super(id, content); } @Override public void selfRelease() throws P4IPException { 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..."); throw new P4IPException("Unable to store P4Resource " + resource.getResourceID() + " on persistence DB..."); } } try { P4PersistenceManager.getInstance().storeXMLResource(P4Collection.AIP_COLLECTION, id, content); } catch (DatabaseException e) { e.printStackTrace(); logger.error("Unable to store AIP " + id + " on persistence DB..."); throw new P4IPException("Unable to store AIP " + id + " on persistence DB..."); } } @Override public synchronized String updateSection(Node resultNode, String updateType) throws P4IPException { String resourceId = null; try { Datatype datatype = ConfigurationManager.getDataTypesInstance().getDatatype(updateType); String secType = datatype.getSection().getType(); String mdLabel = datatype.getRef().getLabel(); String multiple = datatype.getMultiple(); logger.debug("Retrieved datatype: " + datatype.getName() + " " + secType + " " + mdLabel + " " + multiple); Mets mets = this.getContentAsMets(); logger.debug("Unmarshalled METS: " + mets.getOBJID()); P4Collection updateCollection = null; MdSecType updateMdSec = null; AmdSecType updateAmdSec = null; if (secType.equals("dmdSec")) { logger.debug("Updating dmdSec"); if (multiple.equalsIgnoreCase("true")) { logger.debug("Multiple..."); updateMdSec = new MdSecType(); updateMdSec.setID(datatype.getSection().getId() + "-" + System.currentTimeMillis()); mets.getDmdSec().add(updateMdSec); updateMdSec.setMdRef(new MdRef()); updateCollection = P4Collection.DMD_COLLECTION; } else { logger.debug("Not multiple..."); if (mets.getDmdSec().size() == 0) { logger.debug("Creating new dmdSec"); updateMdSec = new MdSecType(); updateMdSec.setID(datatype.getSection().getId() + "-" + System.currentTimeMillis()); mets.getDmdSec().add(updateMdSec); } List<MdSecType> mdSecList = mets.getDmdSec(); updateCollection = P4Collection.DMD_COLLECTION; for (MdSecType mdSecType : mdSecList) { if (mdSecType.getMdRef() != null && mdSecType.getMdRef().getMDTYPE() != null && mdSecType.getMdRef().getLABEL().equals(mdLabel)) { updateMdSec = mdSecType; updateMdSec.setID(datatype.getSection().getId() + "-" + System.currentTimeMillis()); logger.debug("Found existing mdSectype: " + updateMdSec.getID()); break; } } } } else { if (multiple.equalsIgnoreCase("true")) { logger.debug("Multiple..."); updateAmdSec = new AmdSecType(); updateAmdSec.setID("amd-" + System.currentTimeMillis()); mets.getAmdSec().add(updateAmdSec); updateMdSec = new MdSecType(); updateMdSec.setID(datatype.getSection().getId()); updateMdSec.setMdRef(new MdRef()); switch (secType) { case ("techMD"): updateAmdSec.getTechMD().add(updateMdSec); updateCollection = P4Collection.TECHMD_COLLECTION; break; case ("rightsMD"): updateAmdSec.getRightsMD().add(updateMdSec); updateCollection = P4Collection.RIGHTSMD_COLLECTION; break; case ("sourceMD"): updateAmdSec.getSourceMD().add(updateMdSec); updateCollection = P4Collection.SOURCEMD_COLLECTION; break; case ("digiprovMD"): updateAmdSec.getDigiprovMD().add(updateMdSec); updateCollection = P4Collection.DIGIPROVMD_COLLECTION; break; } logger.debug("Added new MdSec to new AmdSec"); } else { logger.debug("Not multiple..."); if (mets.getAmdSec().size() == 0) { updateAmdSec = new AmdSecType(); updateAmdSec.setID("amd-" + System.currentTimeMillis()); mets.getAmdSec().add(updateAmdSec); logger.debug("Created new AmdSec"); } main: for (AmdSecType amdSecType : mets.getAmdSec()) { List<MdSecType> mdSecList = null; switch (secType) { case ("techMD"): mdSecList = amdSecType.getTechMD(); updateCollection = P4Collection.TECHMD_COLLECTION; break; case ("rightsMD"): mdSecList = amdSecType.getRightsMD(); updateCollection = P4Collection.RIGHTSMD_COLLECTION; break; case ("sourceMD"): mdSecList = amdSecType.getSourceMD(); updateCollection = P4Collection.SOURCEMD_COLLECTION; break; case ("digiprovMD"): mdSecList = amdSecType.getDigiprovMD(); updateCollection = P4Collection.DIGIPROVMD_COLLECTION; break; } logger.debug("Looping on mdSecList for type: " + secType); for (MdSecType mdSecType : mdSecList) { logger.debug("mdSecType " + mdSecType.getID()); if (mdSecType.getMdRef() != null && mdSecType.getMdRef().getMDTYPE() != null && mdSecType.getMdRef().getLABEL() != null && mdSecType.getMdRef().getLABEL().equals(mdLabel)) { updateMdSec = mdSecType; updateAmdSec = amdSecType; updateMdSec.setID(datatype.getSection().getId()); updateAmdSec.setID("amd-" + System.currentTimeMillis()); logger.debug("Found updateMdSec: " + updateMdSec); break main; } } } } } if (updateMdSec == null || updateMdSec.getMdRef() == null) { logger.debug("MdSecType to be updated not found... creating a new one"); updateMdSec = new MdSecType(); updateMdSec.setMdRef(new MdRef()); updateMdSec.setID(datatype.getSection().getId()); if (secType.equals("dmdSec")) { updateMdSec.setID(datatype.getSection().getId() + "-" + System.currentTimeMillis()); mets.getDmdSec().add(updateMdSec); logger.debug("Added new empty update sec in dmdSec"); } else { updateAmdSec = new AmdSecType(); updateAmdSec.setID("amd-" + System.currentTimeMillis()); mets.getAmdSec().add(updateAmdSec); logger.debug("Added new empty update amd sec in mets"); switch (secType) { case ("techMD"): updateAmdSec.getTechMD().add(updateMdSec); break; case ("rightsMD"): updateAmdSec.getRightsMD().add(updateMdSec); break; case ("sourceMD"): updateAmdSec.getSourceMD().add(updateMdSec); break; case ("digiprovMD"): updateAmdSec.getDigiprovMD().add(updateMdSec); break; } logger.debug("Added new empty update sec in amdSec"); } } String status = datatype.getSection().getStatus(); if (status != null && !status.isEmpty()) updateMdSec.setSTATUS(status); updateMdSec.getMdRef().setLABEL(datatype.getRef().getLabel()); updateMdSec.getMdRef().setMDTYPE(datatype.getRef().getMdtype()); updateMdSec.getMdRef().setOTHERMDTYPE(datatype.getRef().getOthermdtype()); updateMdSec.getMdRef().setCREATED(ModelUtils.Date2XMLGC(new Date())); logger.debug("Updated references in update mdSec..."); UUID resourceUUID = UUID.randomUUID(); resourceId = resourceUUID.toString(); // FIXME dynamic URL String upPermURL = ConfigurationManager.getPropertyInstance().getProperty(P4Property.P4_PLACEHOLDER) + "/access/resource/" + updateCollection + "/" + resourceId; File tmpUpdateFile = File.createTempFile("update-", ".tmp"); TransformerFactory.newInstance().newTransformer().transform(new DOMSource(resultNode), new StreamResult(new FileOutputStream(tmpUpdateFile))); MessageDigestExtractor mde = new MessageDigestExtractor(); ToolOutput<MessageDigestExtractor.AttributeType> output = mde.extract(tmpUpdateFile.getAbsolutePath()); String md5 = output.getAttribute(MessageDigestExtractor.AttributeType.MD5); Long size = tmpUpdateFile.length(); tmpUpdateFile.delete(); updateMdSec.getMdRef().setHref(upPermURL); updateMdSec.getMdRef().setLOCTYPE("URL"); updateMdSec.getMdRef().setMIMETYPE("application/xml"); updateMdSec.getMdRef().setSIZE(size); updateMdSec.getMdRef().setCHECKSUM(md5); updateMdSec.getMdRef().setCHECKSUMTYPE("MD5"); logger.debug("Updated resource references in update mdSec..."); this.setContent(mets); this.resources.add(new P4Resource(updateCollection, resourceId.toString(), resultNode)); logger.debug("Updated AIP " + id + " for datatype " + datatype.getName()); return resourceId.toString(); } catch (ToolException e) { logger.error("Error in computing checksum..."); throw new P4IPException("Error in computing checksum..."); } catch (DatatypeConfigurationException e) { logger.error("Error in datatypeConfiguration..."); throw new P4IPException("Error in datatypeConfiguration..."); } catch (IOException e) { logger.error("Error in IO..."); throw new P4IPException("Error in IO..."); } catch (TransformerConfigurationException e) { e.printStackTrace(); } catch (TransformerException e) { e.printStackTrace(); } catch (TransformerFactoryConfigurationError e) { e.printStackTrace(); } return updateType; } @Override public synchronized void addPreservationEvent(String type, String info) throws P4IPException { try { Event event = new Event(); event.setEventType(type); event.setEventDetail(info); event.setEventDateTime(ModelUtils.Date2XMLGC(new Date()).toString()); EventIdentifier eventIdentifier = new EventIdentifier(); eventIdentifier.setEventIdentifierType("UUID"); eventIdentifier.setEventIdentifierValue(UUID.randomUUID().toString()); event.setEventIdentifier(eventIdentifier); LinkingAgentIdentifier agentIdentifier = new LinkingAgentIdentifier(); agentIdentifier.setLinkingAgentIdentifierType("Preservation System"); agentIdentifier.setLinkingAgentIdentifierValue("P4"); Mets mets = this.getContentAsMets(); List<AmdSecType> amdSecList = mets.getAmdSec(); AmdSecType premisSec = null; for (AmdSecType amdSecType : amdSecList) { if (amdSecType.getID() != null && amdSecType.getID().equalsIgnoreCase("AMD-PREMIS")) { premisSec = amdSecType; break; } } if (premisSec == null) { premisSec = new AmdSecType(); premisSec.setID("AMD-PREMIS"); mets.getAmdSec().add(premisSec); } List<MdSecType> digiprovSecList = premisSec.getDigiprovMD(); String digiprovSecID = "PREMIS-" + type.toUpperCase(); MdSecType digiprovSec = null; for (MdSecType mdSec : digiprovSecList) { if (mdSec.getID().equalsIgnoreCase(digiprovSecID)) { digiprovSec = mdSec; break; } } if (digiprovSec == null) { digiprovSec = new MdSecType(); digiprovSec.setID(digiprovSecID); digiprovSecList.add(digiprovSec); } digiprovSec.setCREATED(ModelUtils.Date2XMLGC(new Date())); MdWrap mdWrap = new MdWrap(); mdWrap.setMDTYPE("PREMIS"); digiprovSec.setMdWrap(mdWrap); XmlData xmlData = new XmlData(); mdWrap.setXmlData(xmlData); xmlData.getAny().add(event); logger.debug("Updated digital provenance MD for event " + type); this.setContent(mets); } catch (DatatypeConfigurationException e) { logger.error("Error in setting digiprovMD CREATED time"); throw new P4IPException("Error in setting digiprovMD CREATED time"); } } }