/** * The contents of this file are subject to the license and copyright * detailed in the LICENSE file at the root of the source * tree and available online at * * https://github.com/keeps/roda */ package org.roda.core.plugins.plugins.ingest; import java.io.IOException; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import org.roda.core.data.common.RodaConstants; import org.roda.core.data.exceptions.AlreadyExistsException; import org.roda.core.data.exceptions.AuthorizationDeniedException; import org.roda.core.data.exceptions.GenericException; import org.roda.core.data.exceptions.NotFoundException; import org.roda.core.data.exceptions.RequestNotValidException; import org.roda.core.data.v2.ip.AIP; import org.roda.core.data.v2.ip.AIPState; import org.roda.core.data.v2.ip.IndexedAIP; import org.roda.core.data.v2.ip.Permissions; import org.roda.core.data.v2.ip.Representation; import org.roda.core.data.v2.ip.metadata.PreservationMetadata.PreservationMetadataType; import org.roda.core.data.v2.validation.ValidationException; import org.roda.core.model.ModelService; import org.roda.core.storage.ContentPayload; import org.roda.core.storage.StorageService; import org.roda.core.storage.fs.FSPathContentPayload; import org.roda_project.commons_ip.model.IPDescriptiveMetadata; import org.roda_project.commons_ip.model.IPFile; import org.roda_project.commons_ip.model.IPMetadata; import org.roda_project.commons_ip.model.IPRepresentation; import org.roda_project.commons_ip.model.RepresentationStatus; import org.roda_project.commons_ip.model.SIP; public class EARKSIPToAIPPluginUtils { private EARKSIPToAIPPluginUtils() { // do nothing } public static AIP earkSIPToAIP(SIP sip, String username, Permissions fullPermissions, ModelService model, List<String> ingestSIPIds, String ingestJobId, Optional<String> parentId) throws RequestNotValidException, NotFoundException, GenericException, AlreadyExistsException, AuthorizationDeniedException, ValidationException, IOException { AIPState state = AIPState.INGEST_PROCESSING; Permissions permissions = new Permissions(); boolean notify = false; String aipType = IngestHelper.getType(sip); AIP aip = model.createAIP(state, parentId.orElse(null), aipType, permissions, ingestSIPIds, ingestJobId, notify, username); // process IP information processIPInformation(model, sip, aip.getId(), notify, false); // process IPRepresentation information for (IPRepresentation representation : sip.getRepresentations()) { processIPRepresentationInformation(model, representation, aip.getId(), notify, false); } model.notifyAipCreated(aip.getId()); AIP createdAIP = model.retrieveAIP(aip.getId()); // Set Permissions Permissions readPermissions = PermissionUtils.grantReadPermissionToUserGroup(model, createdAIP, aip.getPermissions()); Permissions finalPermissions = PermissionUtils.grantAllPermissions(username, readPermissions, fullPermissions); createdAIP.setPermissions(finalPermissions); model.updateAIP(createdAIP, username); return model.retrieveAIP(aip.getId()); } public static AIP earkSIPToAIPUpdate(SIP sip, IndexedAIP indexedAIP, ModelService model, StorageService storage, String username, String ingestJobId) throws RequestNotValidException, NotFoundException, GenericException, AlreadyExistsException, AuthorizationDeniedException, ValidationException { return earkSIPToAIPUpdate(sip, indexedAIP, model, username, Optional.empty(), ingestJobId); } public static AIP earkSIPToAIPUpdate(SIP sip, IndexedAIP indexedAIP, ModelService model, String username, Optional<String> searchScope, String ingestJobId) throws RequestNotValidException, NotFoundException, GenericException, AlreadyExistsException, AuthorizationDeniedException, ValidationException { boolean notify = false; // process IP information processIPInformation(model, sip, indexedAIP.getId(), notify, true); // process IPRepresentation information for (IPRepresentation representation : sip.getRepresentations()) { processIPRepresentationInformation(model, representation, indexedAIP.getId(), notify, true); } AIP aip = model.retrieveAIP(indexedAIP.getId()); aip.setGhost(false); if (searchScope.isPresent()) { aip.setParentId(searchScope.get()); } aip.addIngestUpdateJobId(ingestJobId); model.updateAIP(aip, username); return aip; } private static void processIPInformation(ModelService model, SIP sip, String aipId, boolean notify, boolean update) throws RequestNotValidException, GenericException, AlreadyExistsException, AuthorizationDeniedException, NotFoundException, ValidationException { // process descriptive metadata processDescriptiveMetadata(model, aipId, null, sip.getDescriptiveMetadata(), notify, update); // process other metadata processOtherMetadata(model, sip.getOtherMetadata(), aipId, Optional.empty(), notify); // process preservation metadata processPreservationMetadata(model, sip.getPreservationMetadata(), aipId, Optional.empty(), notify); // process documentation processDocumentation(model, sip.getDocumentation(), aipId, null, update); // process schemas processSchemas(model, sip.getSchemas(), aipId, null, update); } private static void processDescriptiveMetadata(ModelService model, String aipId, String representationId, List<IPDescriptiveMetadata> descriptiveMetadata, boolean notify, boolean update) throws RequestNotValidException, GenericException, AlreadyExistsException, AuthorizationDeniedException, NotFoundException, ValidationException { for (IPDescriptiveMetadata dm : descriptiveMetadata) { String descriptiveMetadataId = dm.getMetadata().getFileName(); ContentPayload payload = new FSPathContentPayload(dm.getMetadata().getPath()); String metadataType = IngestHelper.getMetadataType(dm); String metadataVersion = dm.getMetadataVersion(); try { model.createDescriptiveMetadata(aipId, representationId, descriptiveMetadataId, payload, metadataType, metadataVersion, notify); } catch (AlreadyExistsException e) { if (update) { Map<String, String> properties = new HashMap<>(); properties.put(RodaConstants.VERSION_ACTION, RodaConstants.VersionAction.UPDATE_FROM_SIP.toString()); model.updateDescriptiveMetadata(aipId, descriptiveMetadataId, payload, metadataType, metadataVersion, properties); } else { throw e; } } } } private static void processOtherMetadata(ModelService model, List<IPMetadata> otherMetadata, String aipId, Optional<String> representationId, boolean notify) throws GenericException, NotFoundException, RequestNotValidException, AuthorizationDeniedException, AlreadyExistsException { for (IPMetadata pm : otherMetadata) { IPFile file = pm.getMetadata(); ContentPayload fileContentPayload = new FSPathContentPayload(file.getPath()); model.createOrUpdateOtherMetadata(aipId, representationId.orElse(null), file.getRelativeFolders(), file.getFileName(), "", pm.getMetadataType().asString(), fileContentPayload, notify); } } private static void processPreservationMetadata(ModelService model, List<IPMetadata> preservationMetadata, String aipId, Optional<String> representationId, boolean notify) throws GenericException, NotFoundException, RequestNotValidException, AuthorizationDeniedException, AlreadyExistsException { for (IPMetadata pm : preservationMetadata) { IPFile file = pm.getMetadata(); ContentPayload fileContentPayload = new FSPathContentPayload(file.getPath()); if (representationId.isPresent()) { model.createPreservationMetadata(PreservationMetadataType.OTHER, aipId, representationId.get(), file.getRelativeFolders(), file.getFileName(), fileContentPayload, notify); } else { model.createPreservationMetadata(PreservationMetadataType.OTHER, aipId, file.getRelativeFolders(), file.getFileName(), fileContentPayload, notify); } } } private static void processDocumentation(ModelService model, List<IPFile> documentation, String aipId, String representationId, boolean update) throws RequestNotValidException, GenericException, AlreadyExistsException, AuthorizationDeniedException, NotFoundException { for (IPFile doc : documentation) { List<String> directoryPath = doc.getRelativeFolders(); String fileId = doc.getFileName(); ContentPayload payload = new FSPathContentPayload(doc.getPath()); try { model.createDocumentation(aipId, representationId, directoryPath, fileId, payload); } catch (AlreadyExistsException e) { // Tolerate duplicate documentation when updating if (!update) throw e; } } } private static void processSchemas(ModelService model, List<IPFile> schemas, String aipId, String representationId, boolean update) throws RequestNotValidException, GenericException, AlreadyExistsException, AuthorizationDeniedException, NotFoundException { for (IPFile schema : schemas) { List<String> directoryPath = schema.getRelativeFolders(); String fileId = schema.getFileName(); ContentPayload payload = new FSPathContentPayload(schema.getPath()); try { model.createSchema(aipId, representationId, directoryPath, fileId, payload); } catch (AlreadyExistsException e) { // Tolerate duplicate schemas when updating if (!update) throw e; } } } private static void processIPRepresentationInformation(ModelService model, IPRepresentation sr, String aipId, boolean notify, boolean update) throws RequestNotValidException, GenericException, AlreadyExistsException, AuthorizationDeniedException, NotFoundException, ValidationException { String representationType = IngestHelper.getType(sr); boolean isOriginal = RepresentationStatus.getORIGINAL().equals(sr.getStatus()); Representation representation = null; if (update) { try { representation = model.retrieveRepresentation(aipId, sr.getObjectID()); } catch (NotFoundException e) { // do nothing } } // Either we're not updating or the retrieve failed if (representation == null) { representation = model.createRepresentation(aipId, sr.getObjectID(), isOriginal, representationType, notify); } // process representation descriptive metadata processDescriptiveMetadata(model, aipId, representation.getId(), sr.getDescriptiveMetadata(), notify, update); // process other metadata processOtherMetadata(model, sr.getOtherMetadata(), aipId, Optional.ofNullable(representation.getId()), notify); // process representation preservation metadata processPreservationMetadata(model, sr.getPreservationMetadata(), aipId, Optional.ofNullable(representation.getId()), notify); // process representation files for (IPFile file : sr.getData()) { List<String> directoryPath = file.getRelativeFolders(); String fileId = file.getFileName(); ContentPayload payload = new FSPathContentPayload(file.getPath()); try { model.createFile(aipId, representation.getId(), directoryPath, fileId, payload, notify); } catch (AlreadyExistsException e) { if (update) { model.updateFile(aipId, representation.getId(), directoryPath, fileId, payload, true, notify); } else throw e; } } // process representation documentation processDocumentation(model, sr.getDocumentation(), aipId, representation.getId(), false); // process representation schemas processSchemas(model, sr.getSchemas(), aipId, representation.getId(), false); } }