/******************************************************************************* * Copyright French Prime minister Office/SGMAP/DINSIC/Vitam Program (2015-2019) * * contact.vitam@culture.gouv.fr * * This software is a computer program whose purpose is to implement a digital archiving back-office system managing * high volumetry securely and efficiently. * * This software is governed by the CeCILL 2.1 license under French law and abiding by the rules of distribution of free * software. You can use, modify and/ or redistribute the software under the terms of the CeCILL 2.1 license as * circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". * * As a counterpart to the access to the source code and rights to copy, modify and redistribute granted by the license, * users are provided only with a limited warranty and the software's author, the holder of the economic rights, and the * successive licensors have only limited liability. * * In this respect, the user's attention is drawn to the risks associated with loading, using, modifying and/or * developing or reproducing the software by the user in light of its specific status of free software, that may mean * that it is complicated to manipulate, and that also therefore means that it is reserved for developers and * experienced professionals having in-depth computer knowledge. Users are therefore encouraged to load and test the * software's suitability as regards their requirements in conditions enabling the security of their systems and/or data * to be ensured and, more generally, to use and operate it in the same conditions as regards security. * * The fact that you are presently reading this means that you have had knowledge of the CeCILL 2.1 license and that you * accept its terms. *******************************************************************************/ package fr.gouv.vitam.worker.core.handler; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.net.URISyntaxException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.xml.bind.JAXBException; import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; import org.bson.Document; import com.fasterxml.jackson.databind.JsonNode; import fr.gouv.vitam.common.VitamConfiguration; import fr.gouv.vitam.common.client.VitamRequestIterator; import fr.gouv.vitam.common.database.builder.query.QueryHelper; import fr.gouv.vitam.common.database.builder.request.exception.InvalidCreateOperationException; import fr.gouv.vitam.common.database.builder.request.single.Select; import fr.gouv.vitam.common.digest.Digest; import fr.gouv.vitam.common.exception.InvalidParseOperationException; import fr.gouv.vitam.common.i18n.VitamLogbookMessages; import fr.gouv.vitam.common.json.JsonHandler; import fr.gouv.vitam.common.logging.VitamLogger; import fr.gouv.vitam.common.logging.VitamLoggerFactory; import fr.gouv.vitam.common.model.ItemStatus; import fr.gouv.vitam.common.model.LifeCycleStatusCode; import fr.gouv.vitam.common.model.StatusCode; import fr.gouv.vitam.common.parameter.ParameterHelper; import fr.gouv.vitam.logbook.common.exception.LogbookClientException; import fr.gouv.vitam.logbook.common.parameters.LogbookParameterName; import fr.gouv.vitam.logbook.common.parameters.LogbookTypeProcess; import fr.gouv.vitam.logbook.common.server.database.collections.LogbookDocument; import fr.gouv.vitam.logbook.common.server.database.collections.LogbookLifeCycleObjectGroupInProcess; import fr.gouv.vitam.logbook.common.server.database.collections.LogbookLifeCycleUnitInProcess; import fr.gouv.vitam.logbook.common.server.database.collections.LogbookMongoDbName; import fr.gouv.vitam.logbook.common.server.database.collections.LogbookOperation; import fr.gouv.vitam.logbook.lifecycles.client.LogbookLifeCyclesClient; import fr.gouv.vitam.logbook.lifecycles.client.LogbookLifeCyclesClientFactory; import fr.gouv.vitam.logbook.operations.client.LogbookOperationsClient; import fr.gouv.vitam.logbook.operations.client.LogbookOperationsClientFactory; import fr.gouv.vitam.processing.common.exception.ProcessingException; import fr.gouv.vitam.processing.common.parameter.WorkerParameterName; import fr.gouv.vitam.processing.common.parameter.WorkerParameters; import fr.gouv.vitam.storage.engine.client.StorageClient; import fr.gouv.vitam.storage.engine.client.StorageClientFactory; import fr.gouv.vitam.storage.engine.client.exception.StorageClientException; import fr.gouv.vitam.storage.engine.common.model.StorageCollectionType; import fr.gouv.vitam.storage.engine.common.model.request.ObjectDescription; import fr.gouv.vitam.worker.common.HandlerIO; import fr.gouv.vitam.worker.common.utils.IngestWorkflowConstants; import fr.gouv.vitam.worker.common.utils.SedaConstants; import fr.gouv.vitam.worker.core.MarshallerObjectCache; import fr.gouv.vitam.worker.core.impl.HandlerIOImpl; import fr.gouv.vitam.worker.model.ArchiveUnitReplyTypeRoot; import fr.gouv.vitam.worker.model.DataObjectTypeRoot; import fr.gouv.vitam.workspace.api.exception.ContentAddressableStorageException; import fr.gouv.vitam.workspace.api.exception.ContentAddressableStorageNotFoundException; import fr.gouv.vitam.workspace.api.exception.ContentAddressableStorageServerException; /** * Transfer notification reply handler */ public class TransferNotificationActionHandler extends ActionHandler { private static final VitamLogger LOGGER = VitamLoggerFactory.getInstance(TransferNotificationActionHandler.class); private static final int ATR_RESULT_OUT_RANK = 0; private static final int ARCHIVE_UNIT_MAP_RANK = 0; private static final int BINARY_DATAOBJECT_MAP_RANK = 1; private static final int BDO_OG_STORED_MAP_RANK = 2; private static final int BINARYDATAOBJECT_ID_TO_VERSION_DATAOBJECT_MAP_RANK = 3; private static final int SEDA_PARAMETERS_RANK = 4; private static final int OBJECT_GROUP_ID_TO_GUID_MAP_RANK = 5; static final int HANDLER_IO_PARAMETER_NUMBER = 6; private static final String XML = ".xml"; private static final String HANDLER_ID = "ATR_NOTIFICATION"; private static final String NAMESPACE_URI = "fr:gouv:culture:archivesdefrance:seda:v2.0"; private static final String XLINK_URI = "http://www.w3.org/1999/xlink"; private static final String PREMIS_URI = "info:lc/xmlns/premis-v2"; private static final String XSI_URI = "http://www.w3.org/2001/XMLSchema-instance"; private static final String XSD_VERSION = " seda-2.0-main.xsd"; private HandlerIO handlerIO; private static final String DEFAULT_STRATEGY = "default"; private static final String EVENT_ID_PROCESS = "evIdProc"; private final List<Class<?>> handlerInitialIOList = new ArrayList<>(); private final MarshallerObjectCache marshallerObjectCache = new MarshallerObjectCache(); private StatusCode workflowStatus = StatusCode.UNKNOWN; private boolean isBlankTestWorkflow = false; private static final String TEST_STATUS_PREFIX = "Test "; private String statusPrefix = ""; /** * Constructor TransferNotificationActionHandler * * @throws IOException * */ public TransferNotificationActionHandler() { for (int i = 0; i < HANDLER_IO_PARAMETER_NUMBER; i++) { handlerInitialIOList.add(File.class); } } /** * @return HANDLER_ID */ public static final String getId() { return HANDLER_ID; } @Override public ItemStatus execute(WorkerParameters params, HandlerIO handler) { checkMandatoryParameters(params); final StorageClientFactory storageClientFactory = StorageClientFactory.getInstance(); String eventDetailData; final ItemStatus itemStatus = new ItemStatus(HANDLER_ID); handlerIO = handler; try { workflowStatus = StatusCode.valueOf(params.getMapParameters().get(WorkerParameterName.workflowStatusKo)); LogbookTypeProcess logbookTypeProcess = params.getLogbookTypeProcess(); if (logbookTypeProcess != null && LogbookTypeProcess.INGEST_TEST.equals(logbookTypeProcess)) { isBlankTestWorkflow = true; statusPrefix = TEST_STATUS_PREFIX; } File atrFile; if (workflowStatus.isGreaterOrEqualToKo()) { atrFile = createATRKO(params, handlerIO); } else { // CHeck is only done in OK mode since all parameters are optional checkMandatoryIOParameter(handler); atrFile = createATROK(params, handlerIO); } // calculate digest by vitam alog final Digest vitamDigest = new Digest(VitamConfiguration.getDefaultDigestType()); final String vitamDigestString = vitamDigest.update(atrFile).digestHex(); LOGGER.debug( "DEBUG: \n\t" + vitamDigestString); // define eventDetailData eventDetailData = "{" + "\"FileName\":\"" + "ATR_" + params.getContainerName() + "\", \"MessageDigest\": \"" + vitamDigestString + "\", \"Algorithm\": \"" + VitamConfiguration.getDefaultDigestType() + "\"}"; itemStatus.getData().put(LogbookParameterName.eventDetailData.name(), eventDetailData); // FIXME P1 : Fix bug on jenkin org.xml.sax.SAXParseException: src-resolve: Cannot resolve the name // 'xml:id' to a(n) 'attribute declaration' component. // Actually cannot reproduce but get another SAX exception on the seda-vitam-2.0-main.xsd file (and its // imports, it seems). // if (new ValidationXsdUtils().checkWithXSD(new FileInputStream(atrFile), SEDA_VALIDATION_FILE)) { handler.addOuputResult(ATR_RESULT_OUT_RANK, atrFile, true); // store binary data object final ObjectDescription description = new ObjectDescription(); description.setWorkspaceContainerGUID(params.getContainerName()); description.setWorkspaceObjectURI(handler.getOutput(ATR_RESULT_OUT_RANK).getPath()); try (final StorageClient storageClient = storageClientFactory.getClient()) { storageClient.storeFileFromWorkspace( DEFAULT_STRATEGY, StorageCollectionType.REPORTS, params.getContainerName() + XML, description); if (!workflowStatus.isGreaterOrEqualToKo()) { description.setWorkspaceObjectURI( IngestWorkflowConstants.SEDA_FOLDER + "/" + IngestWorkflowConstants.SEDA_FILE); storageClient.storeFileFromWorkspace( DEFAULT_STRATEGY, StorageCollectionType.MANIFESTS, params.getContainerName() + XML, description); } } // } itemStatus.increment(StatusCode.OK); } catch (ProcessingException | ContentAddressableStorageException e) { LOGGER.error(e); itemStatus.increment(StatusCode.KO); } catch (URISyntaxException | InvalidParseOperationException | StorageClientException | IOException e) { LOGGER.error(e); itemStatus.increment(StatusCode.FATAL); // } catch (SAXException | XMLStreamException e) { // LOGGER.error(e); // itemStatus.increment(new WorkflowStatusCode(StatusCode.FATAL)); } return new ItemStatus(HANDLER_ID).setItemsStatus(HANDLER_ID, itemStatus); } /** * Serialize a Jaxb POJO object in the current XML stream * * @param jaxbPOJO * @throws ProcessingException */ private void writeXMLFragment(Object jaxbPOJO, XMLStreamWriter xmlsw) throws ProcessingException { try { marshallerObjectCache.getMarshaller(jaxbPOJO.getClass()).marshal(jaxbPOJO, xmlsw); } catch (final JAXBException e) { throw new ProcessingException("Error on writing " + jaxbPOJO + "object", e); } } /** * @param params of type WorkerParameters * @param ioParam of type HandlerIO * @throws ProcessingException when execute process failed * @throws ContentAddressableStorageNotFoundException * @throws ContentAddressableStorageServerException * @throws URISyntaxException * @throws ContentAddressableStorageException * @throws IOException * @throws InvalidParseOperationException */ private File createATROK(WorkerParameters params, HandlerIO ioParam) throws ProcessingException, ContentAddressableStorageNotFoundException, ContentAddressableStorageServerException, URISyntaxException, ContentAddressableStorageException, IOException, InvalidParseOperationException { ParameterHelper.checkNullOrEmptyParameters(params); final File atrTmpFile = handlerIO.getNewLocalFile(handlerIO.getOutput(ATR_RESULT_OUT_RANK).getPath()); // Pre-actions final InputStream archiveUnitMapTmpFile = new FileInputStream((File) handlerIO.getInput(ARCHIVE_UNIT_MAP_RANK)); final Map<String, Object> archiveUnitSystemGuid = JsonHandler.getMapFromInputStream(archiveUnitMapTmpFile); final InputStream binaryDataObjectMapTmpFile = new FileInputStream((File) handlerIO.getInput(BINARY_DATAOBJECT_MAP_RANK)); final Map<String, Object> binaryDataObjectSystemGuid = JsonHandler.getMapFromInputStream(binaryDataObjectMapTmpFile); final InputStream bdoObjectGroupStoredMapTmpFile = new FileInputStream((File) handlerIO.getInput(BDO_OG_STORED_MAP_RANK)); final Map<String, Object> bdoObjectGroupSystemGuid = JsonHandler.getMapFromInputStream(bdoObjectGroupStoredMapTmpFile); final InputStream binaryDataObjectIdToVersionDataObjectMapTmpFile = new FileInputStream((File) handlerIO.getInput(BINARYDATAOBJECT_ID_TO_VERSION_DATAOBJECT_MAP_RANK)); final Map<String, Object> bdoVersionDataObject = JsonHandler.getMapFromInputStream(binaryDataObjectIdToVersionDataObjectMapTmpFile); final InputStream objectGroupSystemGuidTmpFile = new FileInputStream((File) handlerIO.getInput(OBJECT_GROUP_ID_TO_GUID_MAP_RANK)); final Map<String, Object> objectGroupSystemGuid = JsonHandler.getMapFromInputStream(objectGroupSystemGuidTmpFile); final SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX"); final JsonNode sedaParameters = JsonHandler.getFromFile((File) handlerIO.getInput(SEDA_PARAMETERS_RANK)); final JsonNode infoATR = sedaParameters.get(SedaConstants.TAG_ARCHIVE_TRANSFER); final String messageIdentifier = infoATR.get(SedaConstants.TAG_MESSAGE_IDENTIFIER).asText(); // creation of ATR report try (FileWriter artTmpFileWriter = new FileWriter(atrTmpFile)) { final XMLOutputFactory outputFactory = XMLOutputFactory.newInstance(); final XMLStreamWriter xmlsw = outputFactory.createXMLStreamWriter(artTmpFileWriter); xmlsw.writeStartDocument(); xmlsw.writeStartElement(SedaConstants.TAG_ARCHIVE_TRANSFER_REPLY); xmlsw.writeNamespace(SedaConstants.NAMESPACE_XLINK, XLINK_URI); xmlsw.writeNamespace(SedaConstants.NAMESPACE_PR, PREMIS_URI); xmlsw.writeDefaultNamespace(NAMESPACE_URI); xmlsw.writeNamespace(SedaConstants.NAMESPACE_XSI, XSI_URI); xmlsw.writeAttribute(SedaConstants.NAMESPACE_XSI, XSI_URI, SedaConstants.ATTRIBUTE_SCHEMA_LOCATION, NAMESPACE_URI + XSD_VERSION); writeAttributeValue(xmlsw, SedaConstants.TAG_DATE, sdfDate.format(new Date())); writeAttributeValue(xmlsw, SedaConstants.TAG_MESSAGE_IDENTIFIER, params.getContainerName()); writeAttributeValue(xmlsw, SedaConstants.TAG_ARCHIVAL_AGREEMENT, (infoATR.get(SedaConstants.TAG_ARCHIVAL_AGREEMENT) != null) ? infoATR.get(SedaConstants.TAG_ARCHIVAL_AGREEMENT).textValue() : ""); xmlsw.writeStartElement(SedaConstants.TAG_CODE_LIST_VERSIONS); if (infoATR.get(SedaConstants.TAG_CODE_LIST_VERSIONS) != null) { writeAttributeValue(xmlsw, SedaConstants.TAG_REPLY_CODE_LIST_VERSION, (infoATR.get(SedaConstants.TAG_CODE_LIST_VERSIONS) .get(SedaConstants.TAG_REPLY_CODE_LIST_VERSION) != null) ? infoATR.get(SedaConstants.TAG_CODE_LIST_VERSIONS) .get(SedaConstants.TAG_REPLY_CODE_LIST_VERSION) .textValue() : ""); writeAttributeValue(xmlsw, SedaConstants.TAG_MESSAGE_DIGEST_ALGORITHM_CODE_LIST_VERSION, (infoATR.get(SedaConstants.TAG_CODE_LIST_VERSIONS) .get(SedaConstants.TAG_MESSAGE_DIGEST_ALGORITHM_CODE_LIST_VERSION) != null) ? infoATR.get(SedaConstants.TAG_CODE_LIST_VERSIONS) .get(SedaConstants.TAG_MESSAGE_DIGEST_ALGORITHM_CODE_LIST_VERSION).textValue() : ""); writeAttributeValue(xmlsw, SedaConstants.TAG_FILE_FORMAT_CODE_LIST_VERSION, (infoATR.get(SedaConstants.TAG_CODE_LIST_VERSIONS) .get(SedaConstants.TAG_FILE_FORMAT_CODE_LIST_VERSION) != null) ? infoATR.get(SedaConstants.TAG_CODE_LIST_VERSIONS) .get(SedaConstants.TAG_FILE_FORMAT_CODE_LIST_VERSION) .textValue() : ""); } xmlsw.writeEndElement(); // END SedaConstants.TAG_CODE_LIST_VERSIONS xmlsw.writeStartElement(SedaConstants.TAG_DATA_OBJECT_PACKAGE); writeAttributeValue(xmlsw, SedaConstants.TAG_DESCRIPTIVE_METADATA, null); xmlsw.writeStartElement(SedaConstants.TAG_MANAGEMENT_METADATA); xmlsw.writeStartElement(SedaConstants.TAG_REPLY_OUTCOME); xmlsw.writeStartElement(SedaConstants.TAG_ARCHIVE_UNIT_LIST); if (archiveUnitSystemGuid != null) { for (final Map.Entry<String, Object> entry : archiveUnitSystemGuid.entrySet()) { final ArchiveUnitReplyTypeRoot au = new ArchiveUnitReplyTypeRoot(); au.setId(entry.getKey()); au.setSystemId(entry.getValue().toString()); writeXMLFragment(au, xmlsw); } } xmlsw.writeEndElement(); // END ARCHIVE_UNIT_LIST xmlsw.writeStartElement(SedaConstants.TAG_DATA_OBJECT_LIST); // Set to known which DOGIG has already be used in the XML final Set<String> usedDataObjectGroup = new HashSet<>(); if (binaryDataObjectSystemGuid != null) { for (final Map.Entry<String, Object> entry : binaryDataObjectSystemGuid.entrySet()) { final String dataOGID = bdoObjectGroupSystemGuid.get(entry.getKey()).toString(); final String dataBDOVersion = bdoVersionDataObject.get(entry.getKey()).toString(); final DataObjectTypeRoot dotr = new DataObjectTypeRoot(); dotr.setId(entry.getKey()); // Test if the DOGID has already be used . If so, use DOGRefID, else DOGID in the SEDA XML if (usedDataObjectGroup.contains(dataOGID)) { dotr.setDataObjectGroupRefId(dataOGID); } else { dotr.setDataObjectGroupId(dataOGID); usedDataObjectGroup.add(dataOGID); } dotr.setDataObjectVersion(dataBDOVersion); dotr.setDataObjectGroupSystemId(objectGroupSystemGuid.get(dataOGID).toString()); writeXMLFragment(dotr, xmlsw); } } xmlsw.writeEndElement();// END DATA_OBJECT_LIST xmlsw.writeEndElement(); // END ARCHIVE_UNIT_LIST xmlsw.writeEndElement(); // END REPLY_OUTCOME xmlsw.writeEndElement(); // END MANAGEMENT_METADATA writeAttributeValue(xmlsw, SedaConstants.TAG_REPLY_CODE, statusPrefix + workflowStatus.name()); writeAttributeValue(xmlsw, SedaConstants.TAG_MESSAGE_REQUEST_IDENTIFIER, messageIdentifier); if (!isBlankTestWorkflow) { writeAttributeValue(xmlsw, SedaConstants.TAG_GRANT_DATE, sdfDate.format(new Date())); } xmlsw.writeStartElement(SedaConstants.TAG_ARCHIVAL_AGENCY); if (infoATR.get(SedaConstants.TAG_ARCHIVAL_AGENCY) != null) { writeAttributeValue(xmlsw, SedaConstants.TAG_IDENTIFIER, (infoATR.get(SedaConstants.TAG_ARCHIVAL_AGENCY).get(SedaConstants.TAG_IDENTIFIER) != null) ? infoATR.get(SedaConstants.TAG_ARCHIVAL_AGENCY).get(SedaConstants.TAG_IDENTIFIER).textValue() : ""); } xmlsw.writeEndElement(); // END SedaConstants.TAG_ARCHIVAL_AGENCY xmlsw.writeStartElement(SedaConstants.TAG_TRANSFERRING_AGENCY); if (infoATR.get(SedaConstants.TAG_TRANSFERRING_AGENCY) != null) { writeAttributeValue(xmlsw, SedaConstants.TAG_IDENTIFIER, (infoATR.get(SedaConstants.TAG_TRANSFERRING_AGENCY).get(SedaConstants.TAG_IDENTIFIER) != null) ? infoATR.get(SedaConstants.TAG_TRANSFERRING_AGENCY).get(SedaConstants.TAG_IDENTIFIER) .textValue() : ""); } xmlsw.writeEndElement(); // END SedaConstants.TAG_TRANSFERRING_AGENCY xmlsw.writeEndElement(); xmlsw.writeEndDocument(); xmlsw.flush(); xmlsw.close(); } catch (XMLStreamException | IOException e) { LOGGER.error("Error of response generation"); throw new ProcessingException(e); } return atrTmpFile; } /** * @param params of type WorkerParameters * @param ioParam of type HandlerIO * @throws ProcessingException when execute process failed * @throws ContentAddressableStorageNotFoundException * @throws ContentAddressableStorageServerException * @throws URISyntaxException * @throws ContentAddressableStorageException * @throws IOException * @throws InvalidParseOperationException */ private File createATRKO(WorkerParameters params, HandlerIO ioParam) throws ProcessingException, ContentAddressableStorageNotFoundException, ContentAddressableStorageServerException, URISyntaxException, ContentAddressableStorageException, IOException, InvalidParseOperationException { ParameterHelper.checkNullOrEmptyParameters(params); final File atrTmpFile = handlerIO.getNewLocalFile(handlerIO.getOutput(ATR_RESULT_OUT_RANK).getPath()); // Pre-actions final SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX"); JsonNode infoATR = null; String messageIdentifier = ""; if (handlerIO.getInput(SEDA_PARAMETERS_RANK) != null) { final JsonNode sedaParameters = JsonHandler.getFromFile((File) handlerIO.getInput(SEDA_PARAMETERS_RANK)); infoATR = sedaParameters.get(SedaConstants.TAG_ARCHIVE_TRANSFER); if (infoATR != null && infoATR.get(SedaConstants.TAG_MESSAGE_IDENTIFIER) != null) { messageIdentifier = infoATR.get(SedaConstants.TAG_MESSAGE_IDENTIFIER).asText(); } } // creation of ATR report try (FileWriter artTmpFileWriter = new FileWriter(atrTmpFile);) { final XMLOutputFactory outputFactory = XMLOutputFactory.newInstance(); final XMLStreamWriter xmlsw = outputFactory.createXMLStreamWriter(artTmpFileWriter); xmlsw.writeStartDocument(); xmlsw.writeStartElement(SedaConstants.TAG_ARCHIVE_TRANSFER_REPLY); xmlsw.writeNamespace(SedaConstants.NAMESPACE_XLINK, XLINK_URI); xmlsw.writeNamespace(SedaConstants.NAMESPACE_PR, PREMIS_URI); xmlsw.writeDefaultNamespace(NAMESPACE_URI); xmlsw.writeNamespace(SedaConstants.NAMESPACE_XSI, XSI_URI); xmlsw.writeAttribute(SedaConstants.NAMESPACE_XSI, XSI_URI, SedaConstants.ATTRIBUTE_SCHEMA_LOCATION, NAMESPACE_URI + XSD_VERSION); writeAttributeValue(xmlsw, SedaConstants.TAG_DATE, sdfDate.format(new Date())); writeAttributeValue(xmlsw, SedaConstants.TAG_MESSAGE_IDENTIFIER, params.getContainerName()); if (infoATR != null) { writeAttributeValue(xmlsw, SedaConstants.TAG_ARCHIVAL_AGREEMENT, (infoATR.get(SedaConstants.TAG_ARCHIVAL_AGREEMENT) != null) ? infoATR.get(SedaConstants.TAG_ARCHIVAL_AGREEMENT).textValue() : ""); xmlsw.writeStartElement(SedaConstants.TAG_CODE_LIST_VERSIONS); if (infoATR.get(SedaConstants.TAG_CODE_LIST_VERSIONS) != null) { writeAttributeValue(xmlsw, SedaConstants.TAG_REPLY_CODE_LIST_VERSION, (infoATR.get(SedaConstants.TAG_CODE_LIST_VERSIONS) .get(SedaConstants.TAG_REPLY_CODE_LIST_VERSION) != null) ? infoATR.get(SedaConstants.TAG_CODE_LIST_VERSIONS) .get(SedaConstants.TAG_REPLY_CODE_LIST_VERSION) .textValue() : ""); writeAttributeValue(xmlsw, SedaConstants.TAG_MESSAGE_DIGEST_ALGORITHM_CODE_LIST_VERSION, (infoATR.get(SedaConstants.TAG_CODE_LIST_VERSIONS) .get(SedaConstants.TAG_MESSAGE_DIGEST_ALGORITHM_CODE_LIST_VERSION) != null) ? infoATR.get(SedaConstants.TAG_CODE_LIST_VERSIONS) .get(SedaConstants.TAG_MESSAGE_DIGEST_ALGORITHM_CODE_LIST_VERSION).textValue() : ""); writeAttributeValue(xmlsw, SedaConstants.TAG_FILE_FORMAT_CODE_LIST_VERSION, (infoATR.get(SedaConstants.TAG_CODE_LIST_VERSIONS) .get(SedaConstants.TAG_FILE_FORMAT_CODE_LIST_VERSION) != null) ? infoATR.get(SedaConstants.TAG_CODE_LIST_VERSIONS) .get(SedaConstants.TAG_FILE_FORMAT_CODE_LIST_VERSION) .textValue() : ""); } xmlsw.writeEndElement(); // END SedaConstants.TAG_CODE_LIST_VERSIONS } xmlsw.writeStartElement(SedaConstants.TAG_DATA_OBJECT_PACKAGE); writeAttributeValue(xmlsw, SedaConstants.TAG_DESCRIPTIVE_METADATA, null); xmlsw.writeStartElement(SedaConstants.TAG_MANAGEMENT_METADATA); xmlsw.writeStartElement(SedaConstants.TAG_REPLY_OUTCOME); addKOReplyOutcomeIterator(xmlsw, params.getContainerName()); xmlsw.writeEndElement(); // END REPLY_OUTCOME xmlsw.writeEndElement(); // END MANAGEMENT_METADATA writeAttributeValue(xmlsw, SedaConstants.TAG_REPLY_CODE, statusPrefix + workflowStatus.name()); writeAttributeValue(xmlsw, SedaConstants.TAG_MESSAGE_REQUEST_IDENTIFIER, messageIdentifier); if (!isBlankTestWorkflow) { writeAttributeValue(xmlsw, SedaConstants.TAG_GRANT_DATE, sdfDate.format(new Date())); } xmlsw.writeStartElement(SedaConstants.TAG_ARCHIVAL_AGENCY); if (infoATR != null && infoATR.get(SedaConstants.TAG_ARCHIVAL_AGENCY) != null) { writeAttributeValue(xmlsw, SedaConstants.TAG_IDENTIFIER, (infoATR.get(SedaConstants.TAG_ARCHIVAL_AGENCY).get(SedaConstants.TAG_IDENTIFIER) != null) ? infoATR.get(SedaConstants.TAG_ARCHIVAL_AGENCY).get(SedaConstants.TAG_IDENTIFIER).textValue() : ""); } xmlsw.writeEndElement(); // END SedaConstants.TAG_ARCHIVAL_AGENCY xmlsw.writeStartElement(SedaConstants.TAG_TRANSFERRING_AGENCY); if (infoATR != null && infoATR.get(SedaConstants.TAG_TRANSFERRING_AGENCY) != null) { writeAttributeValue(xmlsw, SedaConstants.TAG_IDENTIFIER, (infoATR.get(SedaConstants.TAG_TRANSFERRING_AGENCY).get(SedaConstants.TAG_IDENTIFIER) != null) ? infoATR.get(SedaConstants.TAG_TRANSFERRING_AGENCY).get(SedaConstants.TAG_IDENTIFIER) .textValue() : ""); } xmlsw.writeEndElement(); // END SedaConstants.TAG_TRANSFERRING_AGENCY xmlsw.writeEndElement(); xmlsw.writeEndDocument(); xmlsw.flush(); xmlsw.close(); } catch (XMLStreamException | IOException | InvalidCreateOperationException e) { LOGGER.error("Error of response generation"); throw new ProcessingException(e); } return atrTmpFile; } /** * Add the KO (which could be KO or FATAL) replyOutcome to the ATR xml * * @param xmlsw xml writer * @param containerName the operation identifier * @throws ProcessingException thrown if a logbook could not be retrieved * @throws XMLStreamException * @throws FileNotFoundException * @throws InvalidParseOperationException * @throws InvalidCreateOperationException */ private void addKOReplyOutcomeIterator(XMLStreamWriter xmlsw, String containerName) throws ProcessingException, XMLStreamException, FileNotFoundException, InvalidParseOperationException, InvalidCreateOperationException { final LogbookOperation logbookOperation; try (LogbookOperationsClient client = LogbookOperationsClientFactory.getInstance().getClient()) { Select select = new Select(); select.setQuery(QueryHelper.eq(EVENT_ID_PROCESS, containerName)); final JsonNode node = client.selectOperationById(containerName, select.getFinalSelect()); // FIXME P1 hack since Jackson cannot parse it correctly // RequestResponseOK response = JsonHandler.getFromJsonNode(node, RequestResponseOK.class); // logbookOperation = JsonHandler.getFromJsonNode(response.getResult(), LogbookOperation.class); final JsonNode elmt = node.get("$results").get(0); if (elmt == null) { LOGGER.error("Error while loading logbook operation: no result"); throw new ProcessingException("Error while loading logbook operation: no result"); } logbookOperation = new LogbookOperation(elmt); } catch (final LogbookClientException e) { LOGGER.error("Error while loading logbook operation", e); throw new ProcessingException(e); } catch (InvalidCreateOperationException e) { LOGGER.error("Error while creating DSL query", e); throw new ProcessingException(e); } final List<Document> logbookOperationEvents = (List<Document>) logbookOperation.get(LogbookDocument.EVENTS.toString()); xmlsw.writeStartElement(SedaConstants.TAG_OPERATION); for (final Document event : logbookOperationEvents) { writeEvent(xmlsw, event, SedaConstants.TAG_OPERATION, null); } xmlsw.writeEndElement(); // END SedaConstants.TAG_OPERATION try (LogbookLifeCyclesClient client = LogbookLifeCyclesClientFactory.getInstance().getClient()) { try (VitamRequestIterator<JsonNode> iterator = client.unitLifeCyclesByOperationIterator(containerName, LifeCycleStatusCode.LIFE_CYCLE_IN_PROCESS)) { Map<String, Object> archiveUnitSystemGuid = null; InputStream archiveUnitMapTmpFile = null; final File file = (File) handlerIO.getInput(ARCHIVE_UNIT_MAP_RANK); if (file != null) { archiveUnitMapTmpFile = new FileInputStream(file); } Map<String, String> systemGuidArchiveUnitId = null; if (archiveUnitMapTmpFile != null) { archiveUnitSystemGuid = JsonHandler.getMapFromInputStream(archiveUnitMapTmpFile); if (archiveUnitSystemGuid != null) { systemGuidArchiveUnitId = new HashMap<>(); for (final Map.Entry<String, Object> entry : archiveUnitSystemGuid.entrySet()) { systemGuidArchiveUnitId.put(entry.getValue().toString(), entry.getKey()); } } } xmlsw.writeStartElement(SedaConstants.TAG_ARCHIVE_UNIT_LIST); while (iterator.hasNext()) { JsonNode next = iterator.next(); final LogbookLifeCycleUnitInProcess logbookLifeCycleUnit = new LogbookLifeCycleUnitInProcess(next); final List<Document> logbookLifeCycleUnitEvents = (List<Document>) logbookLifeCycleUnit.get(LogbookDocument.EVENTS.toString()); xmlsw.writeStartElement(SedaConstants.TAG_ARCHIVE_UNIT); if (systemGuidArchiveUnitId != null && logbookLifeCycleUnit.get(SedaConstants.PREFIX_ID) != null && systemGuidArchiveUnitId .get(logbookLifeCycleUnit.get(SedaConstants.PREFIX_ID).toString()) != null) { xmlsw.writeAttribute(SedaConstants.ATTRIBUTE_ID, systemGuidArchiveUnitId .get(logbookLifeCycleUnit.get(SedaConstants.PREFIX_ID).toString())); writeAttributeValue(xmlsw, SedaConstants.TAG_ARCHIVE_SYSTEM_ID, logbookLifeCycleUnit.get(SedaConstants.PREFIX_ID).toString()); } for (final Document event : logbookLifeCycleUnitEvents) { writeEvent(xmlsw, event, SedaConstants.TAG_ARCHIVE_UNIT, null); } xmlsw.writeEndElement(); // END SedaConstants.TAG_ARCHIVE_UNIT } xmlsw.writeEndElement(); // END SedaConstants.TAG_ARCHIVE_UNIT_LIST } catch (final LogbookClientException e) { LOGGER.error("Error while loading logbook lifecycle units", e); throw new ProcessingException(e); } try (VitamRequestIterator<JsonNode> iterator = client.objectGroupLifeCyclesByOperationIterator(containerName, LifeCycleStatusCode.LIFE_CYCLE_IN_PROCESS)) { Map<String, Object> binaryDataObjectSystemGuid = new HashMap<>(); Map<String, Object> bdoObjectGroupSystemGuid = new HashMap<>(); final Map<String, String> objectGroupGuid = new HashMap<>(); final Map<String, List<String>> dataObjectsForOG = new HashMap<>(); final File file1 = (File) handlerIO.getInput(BINARY_DATAOBJECT_MAP_RANK); final File file2 = (File) handlerIO.getInput(BDO_OG_STORED_MAP_RANK); final File file3 = (File) handlerIO.getInput(OBJECT_GROUP_ID_TO_GUID_MAP_RANK); if (file1 != null && file2 != null) { final InputStream binaryDataObjectMapTmpFile = new FileInputStream(file1); final InputStream bdoObjectGroupStoredMapTmpFile = new FileInputStream(file2); binaryDataObjectSystemGuid = JsonHandler.getMapFromInputStream(binaryDataObjectMapTmpFile); bdoObjectGroupSystemGuid = JsonHandler.getMapFromInputStream(bdoObjectGroupStoredMapTmpFile); } for (final Map.Entry<String, Object> entry : bdoObjectGroupSystemGuid.entrySet()) { final String idOG = entry.getValue().toString(); final String idObj = entry.getKey(); if (!dataObjectsForOG.containsKey(idOG)) { final List<String> listObj = new ArrayList<>(); listObj.add(idObj); dataObjectsForOG.put(idOG, listObj); } else { dataObjectsForOG.get(idOG).add(idObj); } } if (file3 != null) { final InputStream objectGroupGuidMapTmpFile = new FileInputStream(file3); final Map<String, Object> objectGroupGuidBefore = JsonHandler.getMapFromInputStream(objectGroupGuidMapTmpFile); if (objectGroupGuidBefore != null) { for (final Map.Entry<String, Object> entry : objectGroupGuidBefore.entrySet()) { final String guid = entry.getValue().toString(); objectGroupGuid.put(guid, entry.getKey()); } } } xmlsw.writeStartElement(SedaConstants.TAG_DATA_OBJECT_LIST); while (iterator.hasNext()) { final LogbookLifeCycleObjectGroupInProcess logbookLifeCycleObjectGroup = new LogbookLifeCycleObjectGroupInProcess(iterator.next()); final String eventIdentifier = null; xmlsw.writeStartElement(SedaConstants.TAG_DATA_OBJECT_GROUP); final String ogGUID = logbookLifeCycleObjectGroup.get(LogbookMongoDbName.objectIdentifier.getDbname()) != null ? logbookLifeCycleObjectGroup.get(LogbookMongoDbName.objectIdentifier.getDbname()) .toString() : ""; String igId = ""; if (objectGroupGuid.containsKey(ogGUID)) { igId = objectGroupGuid.get(ogGUID); xmlsw.writeAttribute(SedaConstants.ATTRIBUTE_ID, objectGroupGuid.get(ogGUID)); } if (dataObjectsForOG.get(igId) != null) { for (final String idObj : dataObjectsForOG.get(igId)) { xmlsw.writeStartElement(SedaConstants.TAG_BINARY_DATA_OBJECT); xmlsw.writeAttribute(SedaConstants.ATTRIBUTE_ID, idObj); if (binaryDataObjectSystemGuid.get(idObj) != null) { writeAttributeValue(xmlsw, SedaConstants.TAG_BINARY_DATA_OBJECT_SYSTEM_ID, binaryDataObjectSystemGuid.get(idObj).toString()); } xmlsw.writeEndElement(); // END SedaConstants.TAG_BINARY_DATA_OBJECT } } final List<Document> logbookLifeCycleObjectGroupEvents = (List<Document>) logbookLifeCycleObjectGroup.get(LogbookDocument.EVENTS.toString()); for (final Document event : logbookLifeCycleObjectGroupEvents) { writeEvent(xmlsw, event, SedaConstants.TAG_DATA_OBJECT_GROUP, eventIdentifier); } xmlsw.writeEndElement(); // END SedaConstants.TAG_DATA_OBJECT_GROUP } xmlsw.writeEndElement(); // END SedaConstants.TAG_DATA_OBJECT_LIST } catch (final LogbookClientException e) { LOGGER.error("Error while loading logbook lifecycle ObjectGroups", e); throw new ProcessingException(e); } } } @Override public void checkMandatoryIOParameter(HandlerIO handler) throws ProcessingException { if (!handler.checkHandlerIO(1, handlerInitialIOList)) { throw new ProcessingException(HandlerIOImpl.NOT_CONFORM_PARAM); } } /** * Write an attribute with only one value * * @param writer : The XMLStreamWriter on which the attribute is written * @param attribute * @param value * @throws XMLStreamException */ private void writeAttributeValue(XMLStreamWriter writer, String attribute, String value) throws XMLStreamException { writer.writeStartElement(attribute); writer.writeCharacters(value); writer.writeEndElement(); } /** * Write the event part of the xml in the KO ATR case * * @param xmlsw * @param event * @throws XMLStreamException */ private void writeEvent(XMLStreamWriter xmlsw, Document event, String eventType, String eventIdentifierManifest) throws XMLStreamException { if (event.get(LogbookMongoDbName.outcome.getDbname()) != null && (StatusCode.FATAL.toString().equals(event.get(LogbookMongoDbName.outcome.getDbname()).toString()) || StatusCode.KO.toString() .equals(event.get(LogbookMongoDbName.outcome.getDbname()).toString()))) { xmlsw.writeStartElement(SedaConstants.TAG_EVENT); if (event.get(LogbookMongoDbName.eventType.getDbname()) != null) { writeAttributeValue(xmlsw, SedaConstants.TAG_EVENT_TYPE_CODE, event.get(LogbookMongoDbName.eventType.getDbname()).toString()); if (SedaConstants.TAG_OPERATION.equals(eventType)) { writeAttributeValue(xmlsw, SedaConstants.TAG_EVENT_TYPE, VitamLogbookMessages .getLabelOp(event.get(LogbookMongoDbName.eventType.getDbname()).toString())); } else if (SedaConstants.TAG_ARCHIVE_UNIT.equals(eventType) || SedaConstants.TAG_DATA_OBJECT_GROUP .equals(eventType)) { writeAttributeValue(xmlsw, SedaConstants.TAG_EVENT_TYPE, VitamLogbookMessages .getFromFullCodeKey(event.get(LogbookMongoDbName.eventType.getDbname()).toString())); } } if (event.get(LogbookMongoDbName.eventDateTime.getDbname()) != null) { writeAttributeValue(xmlsw, SedaConstants.TAG_EVENT_DATE_TIME, event.get(LogbookMongoDbName.eventDateTime.getDbname()).toString()); } if (event.get(LogbookMongoDbName.outcome.getDbname()) != null) { writeAttributeValue(xmlsw, SedaConstants.TAG_EVENT_OUTCOME, event.get(LogbookMongoDbName.outcome.getDbname()).toString()); } if (event.get(LogbookMongoDbName.outcomeDetail.getDbname()) != null) { writeAttributeValue(xmlsw, SedaConstants.TAG_EVENT_OUTCOME_DETAIL, event.get(LogbookMongoDbName.outcomeDetail.getDbname()).toString()); } if (event.get(LogbookMongoDbName.outcomeDetailMessage.getDbname()) != null) { writeAttributeValue(xmlsw, SedaConstants.TAG_EVENT_OUTCOME_DETAIL_MESSAGE, event.get(LogbookMongoDbName.outcomeDetailMessage.getDbname()).toString()); } xmlsw.writeEndElement(); // END SedaConstants.TAG_EVENT } } }