diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3e23475a..d6333515 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -21,6 +21,7 @@ jobs: - name: Build and Run Tests run: mvn --settings .ci/github-actions-settings.xml verify env: + JAVA_TOOL_OPTIONS: "-Duser.timezone=Europe/Paris" SERVICE_NEXUS_URL: ${{ secrets.SERVICE_NEXUS_URL }} CI_USR: ${{ secrets.CI_USR }} CI_PSW: ${{ secrets.CI_PSW }} diff --git a/Jenkinsfile b/Jenkinsfile index 4b8b16af..a432b2be 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -10,7 +10,7 @@ pipeline { environment { MVN_BASE = "/usr/local/maven/bin/mvn" - MVN_COMMAND = "${MVN_BASE} --settings ${pwd()}/.ci/settings.xml --show-version --batch-mode --errors --fail-at-end -DinstallAtEnd=true -DdeployAtEnd=true " + MVN_COMMAND = "${MVN_BASE} --settings ${pwd()}/.ci/settings.xml --show-version --batch-mode --errors --fail-at-end -DinstallAtEnd=true -DdeployAtEnd=true -Duser.timezone=Europe/Paris" DEPLOY_GOAL = " " // Deploy goal used by maven ; typically "deploy" for master* branches & "" (nothing) for everything else (we don't deploy) ; keep a space so can work in other branches than develop CI = credentials("app-jenkins") SERVICE_SONAR_URL = credentials("service-sonar-url") diff --git a/mailextractlib/src/main/java/fr/gouv/vitam/tools/mailextractlib/core/StoreExtractor.java b/mailextractlib/src/main/java/fr/gouv/vitam/tools/mailextractlib/core/StoreExtractor.java index c928600e..35099309 100644 --- a/mailextractlib/src/main/java/fr/gouv/vitam/tools/mailextractlib/core/StoreExtractor.java +++ b/mailextractlib/src/main/java/fr/gouv/vitam/tools/mailextractlib/core/StoreExtractor.java @@ -298,14 +298,6 @@ public static void initDefaultExtractors(boolean allowsExternalToolsForTextExtra * errors, it could lead to silent data loss or misinterpretation if the encoded data is critical. */ System.setProperty("mail.mime.base64.ignoreerrors", "true"); - - /* - * Set the default time zone of the application to UTC. - * This ensures that MIME message generation will use normalized - * UTC dates everywhere. This is important for consistency across - * different systems and timezones. - */ - TimeZone.setDefault(TimeZone.getTimeZone("UTC")); } private static void preventExternalToolsForTextExtractionInTika() { diff --git a/mailextractlib/src/test/resources/msg/results/embeddedMail.eml b/mailextractlib/src/test/resources/msg/results/embeddedMail.eml index d5db3d79..062a798d 100644 --- a/mailextractlib/src/test/resources/msg/results/embeddedMail.eml +++ b/mailextractlib/src/test/resources/msg/results/embeddedMail.eml @@ -1,4 +1,4 @@ -Date: Mon, 19 Aug 2019 21:18:50 +0000 (UTC) +Date: Mon, 19 Aug 2019 23:18:50 +0200 (CEST) From: "Test" To: Message-ID: <003e01d556d3$b3116ed0$19344c70$@programmevitam.fr> diff --git a/mailextractlib/src/test/resources/msg/results/mail.eml b/mailextractlib/src/test/resources/msg/results/mail.eml index 184709b4..2d5fda75 100644 --- a/mailextractlib/src/test/resources/msg/results/mail.eml +++ b/mailextractlib/src/test/resources/msg/results/mail.eml @@ -1,4 +1,4 @@ -Date: Mon, 19 Aug 2019 21:30:50 +0000 (UTC) +Date: Mon, 19 Aug 2019 23:30:50 +0200 (CEST) From: "Test" To: , Message-ID: <000c01d556d5$611cfc50$2356f4f0$@programmevitam.fr> @@ -72,7 +72,7 @@ div.WordSection1 Content-Type: message/rfc822; name="Test message 1.eml" Content-Disposition: attachment; filename="Test message 1.eml" -Date: Mon, 19 Aug 2019 21:18:50 +0000 (UTC) +Date: Mon, 19 Aug 2019 23:18:50 +0200 (CEST) From: "Test" To: Message-ID: <003e01d556d3$b3116ed0$19344c70$@programmevitam.fr> diff --git a/mailextractlib/src/test/resources/pst/results/mail.eml b/mailextractlib/src/test/resources/pst/results/mail.eml index 0db70841..f6813769 100644 --- a/mailextractlib/src/test/resources/pst/results/mail.eml +++ b/mailextractlib/src/test/resources/pst/results/mail.eml @@ -1,4 +1,4 @@ -Date: Mon, 19 Aug 2019 21:30:50 +0000 (UTC) +Date: Mon, 19 Aug 2019 23:30:50 +0200 (CEST) From: "Test" To: , Message-ID: <000c01d556d5$611cfc50$2356f4f0$@programmevitam.fr> @@ -71,7 +71,7 @@ div.WordSection1 Content-Type: message/rfc822; name="Test message 1.eml" Content-Disposition: attachment; filename="Test message 1.eml" -Date: Mon, 19 Aug 2019 21:18:50 +0000 (UTC) +Date: Mon, 19 Aug 2019 23:18:50 +0200 (CEST) From: "Test" To: Message-ID: <003e01d556d3$b3116ed0$19344c70$@programmevitam.fr> diff --git a/resip/src/main/java/fr/gouv/vitam/tools/resip/sedaobjecteditor/DateTimeTypeEditor.java b/resip/src/main/java/fr/gouv/vitam/tools/resip/sedaobjecteditor/DateTimeTypeEditor.java index 75e2b073..8d0d3b39 100644 --- a/resip/src/main/java/fr/gouv/vitam/tools/resip/sedaobjecteditor/DateTimeTypeEditor.java +++ b/resip/src/main/java/fr/gouv/vitam/tools/resip/sedaobjecteditor/DateTimeTypeEditor.java @@ -34,9 +34,17 @@ import fr.gouv.vitam.tools.sedalib.metadata.namedtype.DateTimeType; import fr.gouv.vitam.tools.sedalib.utils.SEDALibException; -import javax.swing.*; -import java.awt.*; +import javax.swing.JLabel; +import javax.swing.JPanel; +import java.awt.Color; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.time.temporal.TemporalAccessor; + +import fr.gouv.vitam.tools.sedalib.metadata.namedtype.DateTimeType.DateTimeFormatType; /** * The DateTimeType object editor class. @@ -46,22 +54,73 @@ public class DateTimeTypeEditor extends SEDAObjectEditor { /** * The editedObject edition graphic component */ - private DateTimePicker valueDateTimePicker; + private final DateTimePicker valueDateTimePicker = new DateTimePicker(); + private final JLabel warningLabel = new JLabel(); + private DateTimeType lastDateTimeType; /** * Instantiates a new DateTimeType editor. * * @param metadata the DateTimeType editedObject - * @param father the father + * @param parent the parent editor * @throws SEDALibException if not a DateTimeType editedObject */ - public DateTimeTypeEditor(SEDAMetadata metadata, SEDAObjectEditor father) throws SEDALibException { - super(metadata, father); + public DateTimeTypeEditor(SEDAMetadata metadata, SEDAObjectEditor parent) throws SEDALibException { + super(metadata, parent); + if (!(metadata instanceof DateTimeType)) throw new SEDALibException("La métadonnée à éditer n'est pas du bon type"); + + this.update(getInitialValue()); + + valueDateTimePicker.setDateTimePermissive(getInitialValue().toLocalDateTime()); + valueDateTimePicker.addDateTimeChangeListener((event) -> { + LocalDateTime old = event.getOldDateTimePermissive(); + LocalDateTime next = event.getNewDateTimePermissive(); + + if (next != null && !next.equals(old)) { + update(new DateTimeType(getInitialValue().getXmlElementName(), next)); + } + }); + + JPanel labelPanel = new JPanel(); + GridBagLayout gbl = new GridBagLayout(); + gbl.columnWeights = new double[] { 1.0 }; + labelPanel.setLayout(gbl); + + JLabel label = new JLabel(getName() + " :"); + label.setToolTipText(getTag()); + label.setFont(SEDAObjectEditor.LABEL_FONT); + GridBagConstraints gbc = new GridBagConstraints(); + gbc.anchor = GridBagConstraints.LINE_END; + gbc.insets = new Insets(0, 5, 0, 0); + gbc.gridx = 0; + gbc.gridy = 0; + labelPanel.add(label, gbc); + + JPanel editPanel = new JPanel(); + gbl = new GridBagLayout(); + gbl.columnWeights = new double[] { 1.0 }; + editPanel.setLayout(gbl); + + gbc = new GridBagConstraints(); + gbc.insets = new Insets(0, 0, 0, 0); + gbc.anchor = GridBagConstraints.LINE_START; + gbc.gridx = 0; + gbc.gridy = 0; + editPanel.add(valueDateTimePicker, gbc); + + gbc = new GridBagConstraints(); + gbc.insets = new Insets(0, 0, 0, 0); + gbc.anchor = GridBagConstraints.LINE_START; + gbc.gridx = 0; + gbc.gridy = 1; + editPanel.add(warningLabel, gbc); + + this.sedaObjectEditorPanel = new SEDAObjectEditorSimplePanel(this, labelPanel, editPanel); } - private DateTimeType getDateTimeTypeMetadata() { + private DateTimeType getInitialValue() { return (DateTimeType) editedObject; } @@ -69,11 +128,13 @@ private DateTimeType getDateTimeTypeMetadata() { * Gets DateTimeType sample. * * @param elementName the element name, corresponding to the XML tag in SEDA - * @param minimal the minimal flag, if true subfields are selected and values are empty, if false all subfields are added and values are default values + * @param minimal the minimal flag, if true subfields are selected and + * values are empty, if false all subfields are added and + * values are default values * @return the seda editedObject sample * @throws SEDALibException the seda lib exception */ - static public SEDAMetadata getSEDAMetadataSample(String elementName, boolean minimal) throws SEDALibException { + public static SEDAMetadata getSEDAMetadataSample(String elementName, boolean minimal) throws SEDALibException { if (minimal) return new DateTimeType(elementName); else @@ -82,8 +143,7 @@ static public SEDAMetadata getSEDAMetadataSample(String elementName, boolean min @Override public SEDAMetadata extractEditedObject() throws SEDALibException { - getDateTimeTypeMetadata().setValue(valueDateTimePicker.getDateTimePermissive()); - return getDateTimeTypeMetadata(); + return lastDateTimeType; } @Override @@ -96,35 +156,44 @@ public String getSummary() throws SEDALibException { @Override public void createSEDAObjectEditorPanel() throws SEDALibException { - JPanel labelPanel = new JPanel(); - GridBagLayout gbl = new GridBagLayout(); - gbl.columnWeights = new double[]{1.0}; - labelPanel.setLayout(gbl); - JLabel label = new JLabel(getName() + " :"); - label.setToolTipText(getTag()); - label.setFont(SEDAObjectEditor.LABEL_FONT); - GridBagConstraints gbc = new GridBagConstraints(); - gbc.anchor = GridBagConstraints.LINE_END; - gbc.insets = new Insets(0, 5, 0, 0); - gbc.gridx = 0; - gbc.gridy = 0; - labelPanel.add(label, gbc); + } - JPanel editPanel = new JPanel(); - gbl = new GridBagLayout(); - gbl.columnWeights = new double[]{1.0}; - editPanel.setLayout(gbl); + private String computeWarningMessage(DateTimeType dateTimeType) { + String warning = ""; + if (dateTimeType.getFormatTypeEnum() == DateTimeFormatType.OFFSET_DATE_TIME) + warning += " (Timezone)"; + TemporalAccessor ta = dateTimeType.getTemporalValue(); + if (ta instanceof LocalDateTime) { + LocalDateTime ldt = (LocalDateTime) ta; + if (ldt.getSecond() != 0 || ldt.getNano() != 0) + warning += " (Secondes/Millisecondes)"; + } else if (ta instanceof OffsetDateTime) { + OffsetDateTime odt = (OffsetDateTime) ta; + if (odt.getSecond() != 0 || odt.getNano() != 0) + warning += " (Secondes/Millisecondes)"; + } - valueDateTimePicker = new DateTimePicker(); - valueDateTimePicker.setDateTimePermissive(getDateTimeTypeMetadata().getValue()); - gbc = new GridBagConstraints(); - gbc.insets = new Insets(0, 0, 0, 0); - gbc.anchor = GridBagConstraints.LINE_START; - gbc.gridx = 0; - gbc.gridy = 0; - editPanel.add(valueDateTimePicker, gbc); + if (!warning.isEmpty()) { + return "Perte si édition en mode structuré: " + warning; + } - this.sedaObjectEditorPanel = new SEDAObjectEditorSimplePanel(this, labelPanel, editPanel); + return ""; + } + + private String computeWarningTooltip() { + return "Afin de ne pas perdre d'information, \n" + + "il est nécessaire de modifier les dates en mode non structuré."; + } + + private void updateWarning(DateTimeType dateTimeType) { + warningLabel.setText(computeWarningMessage(dateTimeType)); + warningLabel.setForeground(Color.RED); + warningLabel.setToolTipText(computeWarningTooltip()); + } + + private void update(DateTimeType next) { + this.lastDateTimeType = next; + this.updateWarning(this.lastDateTimeType); } } diff --git a/sedalib/src/main/java/fr/gouv/vitam/tools/sedalib/metadata/namedtype/ComplexListInterface.java b/sedalib/src/main/java/fr/gouv/vitam/tools/sedalib/metadata/namedtype/ComplexListInterface.java index 84909207..432e01fd 100644 --- a/sedalib/src/main/java/fr/gouv/vitam/tools/sedalib/metadata/namedtype/ComplexListInterface.java +++ b/sedalib/src/main/java/fr/gouv/vitam/tools/sedalib/metadata/namedtype/ComplexListInterface.java @@ -732,10 +732,7 @@ else if ((sm instanceof TextType) && (((TextType) sm).getLang().equals("fr"))) else if ((sm instanceof EnumType)) return ((EnumType) sm).getValue(); else if (sm instanceof DateTimeType) { - if (((DateTimeType) sm).getValue() == null) - return ""; - else - return SEDAXMLStreamWriter.getStringFromDateTime(((DateTimeType) sm).getValue()); + return (((DateTimeType) sm).getDateTimeString()); } } } diff --git a/sedalib/src/main/java/fr/gouv/vitam/tools/sedalib/metadata/namedtype/DateTimeType.java b/sedalib/src/main/java/fr/gouv/vitam/tools/sedalib/metadata/namedtype/DateTimeType.java index c1ec0076..a8364c4a 100644 --- a/sedalib/src/main/java/fr/gouv/vitam/tools/sedalib/metadata/namedtype/DateTimeType.java +++ b/sedalib/src/main/java/fr/gouv/vitam/tools/sedalib/metadata/namedtype/DateTimeType.java @@ -36,195 +36,400 @@ import javax.xml.stream.XMLStreamException; import javax.xml.stream.events.XMLEvent; -import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.MonthDay; +import java.time.OffsetDateTime; +import java.time.Year; +import java.time.YearMonth; +import java.time.ZoneId; import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; +import java.time.temporal.TemporalAccessor; import java.util.LinkedHashMap; +import java.util.regex.Pattern; /** - * The Class DateTimeType. + * The {@code DateTimeType} class represents a SEDA metadata element containing a temporal value. *

- * For abstract DateTime formatted SEDA metadata + * It supports all XML Schema Definition (XSD) temporal types: + *

    + *
  • date
  • + *
  • dateTime
  • + *
  • dateTime with timezone (OffsetDateTime)
  • + *
  • gYear
  • + *
  • gYearMonth
  • + *
  • gMonth
  • + *
  • gMonthDay
  • + *
  • gDay
  • + *
*/ public class DateTimeType extends NamedTypeMetadata { /** - * The value. + * Enumeration of supported temporal format types. */ + public enum DateTimeFormatType { + OFFSET_DATE_TIME, DATE_TIME, DATE, + G_YEAR, G_YEAR_MONTH, G_MONTH, G_MONTH_DAY, G_DAY + } + @JsonIgnore - private LocalDateTime value; + private TemporalAccessor temporalValue; + + private DateTimeFormatType formatType; + + // --- Regex patterns for format detection --- + private static final Pattern OFFSET_DATE_TIME_PATTERN = + Pattern.compile("^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}(:\\d{2}(\\.\\d{1,9})?)?([+-]\\d{2}:\\d{2}|Z)$"); + private static final Pattern DATE_TIME_PATTERN = + Pattern.compile("^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}(:\\d{2}(\\.\\d{1,9})?)?$"); + private static final Pattern DATE_PATTERN = + Pattern.compile("^\\d{4}-\\d{2}-\\d{2}$"); + private static final Pattern G_YEAR_PATTERN = + Pattern.compile("^\\d{4}$"); + private static final Pattern G_YEAR_MONTH_PATTERN = + Pattern.compile("^\\d{4}-\\d{2}$"); + private static final Pattern G_MONTH_PATTERN = + Pattern.compile("^--\\d{2}$"); + private static final Pattern G_MONTH_DAY_PATTERN = + Pattern.compile("^--\\d{2}-\\d{2}$"); + private static final Pattern G_DAY_PATTERN = + Pattern.compile("^---\\d{2}$"); + + // ===================================================================================== + // Constructors + // ===================================================================================== /** - * Instantiates a new string. + * Default constructor. + *

+ * Creates an empty {@code DateTimeType} without element name or value. */ public DateTimeType() { - this(null, (LocalDateTime) null); + this(null, (String) null); } /** - * Instantiates a new string. + * Constructor with an element name only. * - * @param elementName the XML element name + * @param elementName the XML/SEDALib element name */ public DateTimeType(String elementName) { - this(elementName, (LocalDateTime) null); + this(elementName, (String) null); + } + + /** + * Constructor for {@link OffsetDateTime} values (date and time with timezone). + * + * @param elementName the XML/SEDALib element name + * @param value the OffsetDateTime value + */ + public DateTimeType(String elementName, OffsetDateTime value) { + super(elementName); + this.temporalValue = value; + this.formatType = DateTimeFormatType.OFFSET_DATE_TIME; } /** - * Instantiates a new date time from LocalDateTime. + * Constructor for {@link LocalDateTime} values (date and time without timezone). * - * @param elementName the XML element name - * @param value the value + * @param elementName the XML/SEDALib element name + * @param value the LocalDateTime value */ public DateTimeType(String elementName, LocalDateTime value) { super(elementName); - this.value = value; + this.temporalValue = value; + this.formatType = DateTimeFormatType.DATE_TIME; } /** - * Instantiates a new date time from LocalDate. + * Constructor for {@link LocalDate} values (date only). * - * @param elementName the XML element name - * @param dateValue the date (no time) value + * @param elementName the XML/SEDALib element name + * @param dateValue the LocalDate value */ public DateTimeType(String elementName, LocalDate dateValue) { super(elementName); - this.value = dateValue.atStartOfDay(); + this.temporalValue = dateValue; + this.formatType = DateTimeFormatType.DATE; } /** - * Instantiates a new date time from String. + * Constructor for string date values. + *

+ * The string is automatically parsed into the appropriate temporal type. * - * @param elementName the XML element name - * @param dateString the date string value - * @throws SEDALibException if wrong date time format + * @param elementName the XML/SEDALib element name + * @param dateString the date/time string to parse */ - public DateTimeType(String elementName, String dateString) throws SEDALibException { + public DateTimeType(String elementName, String dateString) { super(elementName); + if (dateString == null || dateString.isEmpty()) { + this.temporalValue = null; + this.formatType = null; + } else { + parseDateString(dateString); + } + } + + // ===================================================================================== + // Parsing and Conversion + // ===================================================================================== + + /** + * Parses a string into a temporal object and determines its format type. + * + * @param dateString the date string to parse + * @throws RuntimeException if the string format is invalid or unrecognized + */ + private void parseDateString(String dateString) { try { - if (dateString.isEmpty()) - this.value = null; - else - this.value = SEDAXMLEventReader.getDateTimeFromString(dateString); - } catch (DateTimeParseException e) { - throw new SEDALibException("Problème de formatage de date/temps à la création d'un élément [" + elementName + "]"); + if (OFFSET_DATE_TIME_PATTERN.matcher(dateString).matches()) { + this.temporalValue = OffsetDateTime.parse(dateString); + this.formatType = DateTimeFormatType.OFFSET_DATE_TIME; + } else if (DATE_TIME_PATTERN.matcher(dateString).matches()) { + this.temporalValue = LocalDateTime.parse(dateString); + this.formatType = DateTimeFormatType.DATE_TIME; + } else if (DATE_PATTERN.matcher(dateString).matches()) { + this.temporalValue = LocalDate.parse(dateString); + this.formatType = DateTimeFormatType.DATE; + } else if (G_YEAR_PATTERN.matcher(dateString).matches()) { + this.temporalValue = Year.parse(dateString); + this.formatType = DateTimeFormatType.G_YEAR; + } else if (G_YEAR_MONTH_PATTERN.matcher(dateString).matches()) { + this.temporalValue = YearMonth.parse(dateString); + this.formatType = DateTimeFormatType.G_YEAR_MONTH; + } else if (G_MONTH_DAY_PATTERN.matcher(dateString).matches()) { + this.temporalValue = MonthDay.parse(dateString); + this.formatType = DateTimeFormatType.G_MONTH_DAY; + } else if (G_MONTH_PATTERN.matcher(dateString).matches()) { + this.temporalValue = MonthDay.parse(dateString + "-01"); + this.formatType = DateTimeFormatType.G_MONTH; + } else if (G_DAY_PATTERN.matcher(dateString).matches()) { + int day = Integer.parseInt(dateString.substring(3)); + this.temporalValue = LocalDate.of(2000, 1, day); + this.formatType = DateTimeFormatType.G_DAY; + } else { + throw new SEDALibException("Unrecognized date format: " + dateString); + } + } catch (DateTimeParseException | SEDALibException e) { + throw new RuntimeException("Error parsing date: " + dateString, e); } } - /* - * (non-Javadoc) + // ===================================================================================== + // XML Serialization + // ===================================================================================== + + /** + * Writes the value as XML in SEDA format. * - * @see - * fr.gouv.vitam.tools.sedalib.metadata.SEDAMetadata#toSedaXml(fr.gouv.vitam. - * tools.sedalib.xml.SEDAXMLStreamWriter) + * @param xmlWriter the XML writer to use + * @throws SEDALibException if an XML writing error occurs */ @Override public void toSedaXml(SEDAXMLStreamWriter xmlWriter) throws SEDALibException { try { - if (value == null) + if (temporalValue == null) { xmlWriter.writeElementValue(elementName, null); - else - xmlWriter.writeElementValue(elementName, SEDAXMLStreamWriter.getStringFromDateTime(value)); + return; + } + DateTimeFormatter formatter = getFormatter(); + xmlWriter.writeElementValue(elementName, formatter.format(temporalValue)); } catch (XMLStreamException e) { - throw new SEDALibException("Erreur d'écriture XML dans un élément de type DateTimeType [" + getXmlElementName() + "]", e); + throw new SEDALibException("XML writing error in DateTimeType [" + elementName + "]", e); } } - /* - * (non-Javadoc) + /** + * Returns the formatter corresponding to the current {@link DateTimeFormatType}. * - * @see - * fr.gouv.vitam.tools.sedalib.metadata.SEDAMetadata#toCsvList() + * @return a {@link DateTimeFormatter} adapted to the format type + * @throws SEDALibException if the format type is unknown + */ + private DateTimeFormatter getFormatter() throws SEDALibException { + switch (formatType) { + case OFFSET_DATE_TIME: return DateTimeFormatter.ISO_OFFSET_DATE_TIME; + case DATE_TIME: return DateTimeFormatter.ISO_LOCAL_DATE_TIME; + case DATE: return DateTimeFormatter.ISO_LOCAL_DATE; + case G_YEAR: return DateTimeFormatter.ofPattern("uuuu"); + case G_YEAR_MONTH: return DateTimeFormatter.ofPattern("uuuu-MM"); + case G_MONTH: return DateTimeFormatter.ofPattern("'--'MM"); + case G_MONTH_DAY: return DateTimeFormatter.ofPattern("'--'MM-dd"); + case G_DAY: return DateTimeFormatter.ofPattern("'---'dd"); + default: throw new SEDALibException("Date type not handled: " + formatType); + } + } + + // ===================================================================================== + // CSV Export + // ===================================================================================== + + /** + * Converts this date/time value into a CSV-compatible representation. + * + * @return a {@link LinkedHashMap} containing one entry: the string representation of the value + * @throws SEDALibException if the date format cannot be determined */ public LinkedHashMap toCsvList() throws SEDALibException { LinkedHashMap result = new LinkedHashMap<>(); - if (value != null) - result.put("", SEDAXMLStreamWriter.getStringFromDateTime(value)); - else - result.put("", ""); + String valueStr = (temporalValue != null) ? getFormatter().format(temporalValue) : ""; + result.put("", valueStr); return result; } + // ===================================================================================== + // XML Import + // ===================================================================================== + /** - * Import the metadata content in XML expected form from the SEDA Manifest. + * Reads a DateTimeType element from an XML stream in SEDA format. * - * @param xmlReader the SEDAXMLEventReader reading the SEDA manifest - * @return true, if it finds something convenient, false if not - * @throws SEDALibException if the XML can't be read or the SEDA scheme is not respected, for example + * @param xmlReader the XML reader + * @return {@code true} if the element was successfully read, {@code false} otherwise + * @throws SEDALibException if XML parsing fails or the element is malformed */ public boolean fillFromSedaXml(SEDAXMLEventReader xmlReader) throws SEDALibException { - String tmpDate; try { - if (xmlReader.peekBlockIfNamed(elementName)) { - XMLEvent event = xmlReader.nextUsefullEvent(); - elementName = event.asStartElement().getName().getLocalPart(); + if (!xmlReader.peekBlockIfNamed(elementName)) + return false; + XMLEvent event = xmlReader.nextUsefullEvent(); + elementName = event.asStartElement().getName().getLocalPart(); + event = xmlReader.nextUsefullEvent(); + if (event.isCharacters()) { + parseDateString(event.asCharacters().getData()); event = xmlReader.nextUsefullEvent(); - if (event.isCharacters()) { - tmpDate = event.asCharacters().getData(); - try { - value = SEDAXMLEventReader.getDateTimeFromString(tmpDate); - } catch (DateTimeParseException e) { - throw new SEDALibException("La date est mal formatée", e); - } - event = xmlReader.nextUsefullEvent(); - } else - value = null; - if ((!event.isEndElement()) || (!elementName.equals(event.asEndElement().getName().getLocalPart()))) - throw new SEDALibException("Elément " + elementName + " mal terminé"); - } else return false; - } catch (XMLStreamException | IllegalArgumentException | SEDALibException e) { - throw new SEDALibException("Erreur de lecture XML dans un élément de type DateTimeType", e); + } else { + temporalValue = null; + formatType = null; + } + if (!event.isEndElement() || !elementName.equals(event.asEndElement().getName().getLocalPart())) + throw new SEDALibException("Element " + elementName + " not properly terminated"); + return true; + } catch (Exception e) { + throw new SEDALibException("XML reading error in DateTimeType", e); } - return true; } - // Getters and setters + // ===================================================================================== + // Getters and Utility Methods + // ===================================================================================== - /** - * Get the value - * - * @return the value - */ + /** @return the underlying temporal value */ + @JsonIgnore + public TemporalAccessor getTemporalValue() { + return temporalValue; + } + + /** @return the {@link DateTimeFormatType} enum value */ @JsonIgnore - public LocalDateTime getValue() { - return value; + public DateTimeFormatType getFormatTypeEnum() { + return formatType; + } + + /** @return the format type as a string */ + @JsonIgnore + @JsonGetter("dateTimeFormat") + public String getFormatType() { + return (formatType == null) ? "" : formatType.name(); + } + + /** @return the date/time as a formatted string */ + @JsonGetter("dateTimeString") + public String getDateTimeString() { + if (temporalValue == null) + return ""; + try { + return getFormatter().format(temporalValue); + } catch (SEDALibException e) { + return ""; + } } /** - * Sets value. + * Sets the temporal value from a string representation. * - * @param value the value + * @param dateTimeString the date/time string to parse */ - @JsonIgnore - public void setValue(LocalDateTime value) { - this.value = value; + @JsonSetter("dateTimeString") + public void setDateTimeString(String dateTimeString) { + if (dateTimeString == null || dateTimeString.trim().isEmpty()) { + this.temporalValue = null; + this.formatType = null; + } else { + parseDateString(dateTimeString); + } } /** - * Get the value as an ISO8601 String + * Returns the UTC ISO 8601 representation of the temporal value (if applicable). * - * @return the datetime string + * @return the UTC date-time string, or an empty string if not relevant */ - @JsonGetter("dateTimeString") - public String getDateTimeString() { - if (value == null) + @JsonIgnore + public String getUtcDateTimeString() { + if (temporalValue == null) return ""; - else - return value.toInstant(ZoneOffset.UTC).toString(); + if (formatType == DateTimeFormatType.G_YEAR + || formatType == DateTimeFormatType.G_YEAR_MONTH + || formatType == DateTimeFormatType.G_MONTH + || formatType == DateTimeFormatType.G_MONTH_DAY + || formatType == DateTimeFormatType.G_DAY) + return ""; + try { + OffsetDateTime utcDateTime; + if (temporalValue instanceof OffsetDateTime) { + utcDateTime = ((OffsetDateTime) temporalValue).withOffsetSameInstant(ZoneOffset.UTC); + } else if (temporalValue instanceof LocalDateTime) { + utcDateTime = ((LocalDateTime) temporalValue) + .atZone(ZoneId.systemDefault()) + .withZoneSameInstant(ZoneOffset.UTC) + .toOffsetDateTime(); + } else if (temporalValue instanceof LocalDate) { + utcDateTime = ((LocalDate) temporalValue) + .atStartOfDay(ZoneOffset.UTC) + .toOffsetDateTime(); + } else { + return ""; + } + return DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(utcDateTime); + } catch (Exception e) { + return ""; + } } /** - * Sets value from an ISO8601 String. + * Converts the value to a {@link LocalDateTime} (only for precise date/time formats). * - * @param dateTimeString the datetime string + * @return the {@link LocalDateTime} equivalent, or {@code null} if the type is partial (gYear, gMonth, etc.) */ - @JsonSetter("dateTimeString") - public void setDateTimeString(String dateTimeString) { - if ((dateTimeString==null) || dateTimeString.trim().isEmpty()) - this.value=null; - else - this.value = LocalDateTime.ofInstant(Instant.parse(dateTimeString), ZoneOffset.UTC); + @JsonIgnore + public LocalDateTime toLocalDateTime() { + if (temporalValue == null) + return null; + if (formatType == DateTimeFormatType.G_YEAR + || formatType == DateTimeFormatType.G_YEAR_MONTH + || formatType == DateTimeFormatType.G_MONTH + || formatType == DateTimeFormatType.G_MONTH_DAY + || formatType == DateTimeFormatType.G_DAY) + return null; + try { + switch (formatType) { + case OFFSET_DATE_TIME: + return ((OffsetDateTime) temporalValue) + .atZoneSameInstant(ZoneId.systemDefault()) + .toLocalDateTime(); + case DATE_TIME: + return (LocalDateTime) temporalValue; + case DATE: + return ((LocalDate) temporalValue).atStartOfDay(); + default: + return null; + } + } catch (Exception e) { + return null; + } } } diff --git a/sedalib/src/test/java/fr/gouv/vitam/tools/sedalib/core/SEDA2VersionTest.java b/sedalib/src/test/java/fr/gouv/vitam/tools/sedalib/core/SEDA2VersionTest.java index 7536e462..a244f46a 100644 --- a/sedalib/src/test/java/fr/gouv/vitam/tools/sedalib/core/SEDA2VersionTest.java +++ b/sedalib/src/test/java/fr/gouv/vitam/tools/sedalib/core/SEDA2VersionTest.java @@ -33,7 +33,7 @@ void testSeda2VersionComplianceTest() throws SEDALibException { String xmlFragments=" \n" + " AUT-234452\n" + " Autorisation\n" + - " 2104-05-31T01:00:00.000\n" + + " 2104-05-31T01:00:00\n" + " OK\n" + " OK\n" + " \n" + diff --git a/sedalib/src/test/java/fr/gouv/vitam/tools/sedalib/inout/SIPBuilderTest.java b/sedalib/src/test/java/fr/gouv/vitam/tools/sedalib/inout/SIPBuilderTest.java index e0d66667..25717d14 100644 --- a/sedalib/src/test/java/fr/gouv/vitam/tools/sedalib/inout/SIPBuilderTest.java +++ b/sedalib/src/test/java/fr/gouv/vitam/tools/sedalib/inout/SIPBuilderTest.java @@ -2,6 +2,7 @@ import fr.gouv.vitam.tools.sedalib.TestUtilities; import fr.gouv.vitam.tools.sedalib.core.ArchiveUnit; +import fr.gouv.vitam.tools.sedalib.core.SEDA2Version; import fr.gouv.vitam.tools.sedalib.metadata.content.Content; import fr.gouv.vitam.tools.sedalib.metadata.content.Event; import fr.gouv.vitam.tools.sedalib.metadata.management.AppraisalRule; @@ -10,6 +11,7 @@ import fr.gouv.vitam.tools.sedalib.utils.SEDALibException; import fr.gouv.vitam.tools.sedalib.utils.SEDALibProgressLogger; import fr.gouv.vitam.tools.sedalib.xml.SEDAXMLEventReader; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.slf4j.LoggerFactory; @@ -36,6 +38,11 @@ private static String stripFileName(String fileName) { return tmp; } + @BeforeEach + void setUp() throws SEDALibException { + SEDA2Version.setSeda2Version(1); + } + @Test void generateSimpleSIP() throws Exception { diff --git a/sedalib/src/test/java/fr/gouv/vitam/tools/sedalib/inout/SIPImportTest.java b/sedalib/src/test/java/fr/gouv/vitam/tools/sedalib/inout/SIPImportTest.java index a0e98f3e..7d234c12 100644 --- a/sedalib/src/test/java/fr/gouv/vitam/tools/sedalib/inout/SIPImportTest.java +++ b/sedalib/src/test/java/fr/gouv/vitam/tools/sedalib/inout/SIPImportTest.java @@ -114,7 +114,7 @@ void TestSIPOKImport() throws Exception { " \"value\" : \"CreatingApplicationVersion0\"\n" + " }, {\n" + " \"type\" : \"DateTimeType\",\n" + - " \"dateTimeString\" : \"2006-05-04T18:13:51Z\",\n" + + " \"dateTimeString\" : \"2006-05-04T18:13:51\",\n" + " \"elementName\" : \"DateCreatedByApplication\"\n" + " }, {\n" + " \"type\" : \"StringType\",\n" + @@ -126,7 +126,7 @@ void TestSIPOKImport() throws Exception { " \"value\" : \"CreatingOsVersion0\"\n" + " }, {\n" + " \"type\" : \"DateTimeType\",\n" + - " \"dateTimeString\" : \"2017-04-04T08:07:06.487Z\",\n" + + " \"dateTimeString\" : \"2017-04-04T08:07:06.487+02:00\",\n" + " \"elementName\" : \"LastModified\"\n" + " } ]\n" + " } ],\n" + diff --git a/sedalib/src/test/java/fr/gouv/vitam/tools/sedalib/metadata/namedtype/DateTimeTypeTest.java b/sedalib/src/test/java/fr/gouv/vitam/tools/sedalib/metadata/namedtype/DateTimeTypeTest.java new file mode 100644 index 00000000..e051ba57 --- /dev/null +++ b/sedalib/src/test/java/fr/gouv/vitam/tools/sedalib/metadata/namedtype/DateTimeTypeTest.java @@ -0,0 +1,181 @@ +package fr.gouv.vitam.tools.sedalib.metadata.namedtype; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.time.*; + +import static org.junit.jupiter.api.Assertions.*; + +@DisplayName("Unit tests of DateTimeType for all XSD temporal formats") +public class DateTimeTypeTest { + + // --- Precise formats --- + @Test + @DisplayName("Should recognise an OFFSET_DATE_TIME with explicit timezone offset (+02:00) and produce the correct UTC date") + void testOffsetDateTime() { + String input = "2025-10-28T14:30:15+02:00"; + DateTimeType dtt = new DateTimeType("Test", input); + assertEquals(DateTimeType.DateTimeFormatType.OFFSET_DATE_TIME, dtt.getFormatTypeEnum()); + assertEquals(input, dtt.getDateTimeString()); + assertEquals("2025-10-28T12:30:15Z", dtt.getUtcDateTimeString()); + } + + @Test + @DisplayName("Should recognise an OFFSET_DATE_TIME in Zulu format (Z) and keep the UTC time unchanged") + void testOffsetDateTimeZulu() { + String input = "2025-10-28T14:30:15Z"; + DateTimeType dtt = new DateTimeType("Test", input); + assertEquals(DateTimeType.DateTimeFormatType.OFFSET_DATE_TIME, dtt.getFormatTypeEnum()); + assertEquals(input, dtt.getDateTimeString()); + assertEquals("2025-10-28T14:30:15Z", dtt.getUtcDateTimeString()); + } + + @Test + @DisplayName("Should recognise a DATE_TIME without timezone and generate a valid UTC") + void testLocalDateTime() { + String input = "2025-10-28T14:30:15.529"; + DateTimeType dtt = new DateTimeType("Test", input); + assertEquals(DateTimeType.DateTimeFormatType.DATE_TIME, dtt.getFormatTypeEnum()); + assertEquals(input, dtt.getDateTimeString()); + assertTrue(dtt.getUtcDateTimeString().matches("\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z")); + } + + @Test + @DisplayName("Should recognise a simple DATE format and produce the corresponding UTC instant at midnight") + void testDate() { + String input = "2025-10-28"; + DateTimeType dtt = new DateTimeType("Test", input); + assertEquals(DateTimeType.DateTimeFormatType.DATE, dtt.getFormatTypeEnum()); + assertEquals(input, dtt.getDateTimeString()); + assertEquals("2025-10-28T00:00:00Z", dtt.getUtcDateTimeString()); + } + + // --- Imprecise formats --- + @Test + @DisplayName("Should recognise a G_YEAR format (year only) and not produce a UTC date") + void testGYear() { + String input = "2025"; + DateTimeType dtt = new DateTimeType("Test", input); + assertEquals(DateTimeType.DateTimeFormatType.G_YEAR, dtt.getFormatTypeEnum()); + assertEquals(input, dtt.getDateTimeString()); + assertEquals("", dtt.getUtcDateTimeString()); + } + + @Test + @DisplayName("Should recognise a G_YEAR_MONTH format (year + month) and not produce a UTC date") + void testGYearMonth() { + String input = "2025-10"; + DateTimeType dtt = new DateTimeType("Test", input); + assertEquals(DateTimeType.DateTimeFormatType.G_YEAR_MONTH, dtt.getFormatTypeEnum()); + assertEquals(input, dtt.getDateTimeString()); + assertEquals("", dtt.getUtcDateTimeString()); + } + + @Test + @DisplayName("Should recognise a G_MONTH format (month only) and not produce a UTC date") + void testGMonth() { + String input = "--10"; + DateTimeType dtt = new DateTimeType("Test", input); + assertEquals(DateTimeType.DateTimeFormatType.G_MONTH, dtt.getFormatTypeEnum()); + assertEquals(input, dtt.getDateTimeString()); + assertEquals("", dtt.getUtcDateTimeString()); + } + + @Test + @DisplayName("Should recognise a G_MONTH_DAY format (month + day without year) and not produce a UTC date") + void testGMonthDay() { + String input = "--10-28"; + DateTimeType dtt = new DateTimeType("Test", input); + assertEquals(DateTimeType.DateTimeFormatType.G_MONTH_DAY, dtt.getFormatTypeEnum()); + assertEquals(input, dtt.getDateTimeString()); + assertEquals("", dtt.getUtcDateTimeString()); + } + + @Test + @DisplayName("Should recognise a G_DAY format (day only) and not produce a UTC date") + void testGDay() { + String input = "---28"; + DateTimeType dtt = new DateTimeType("Test", input); + assertEquals(DateTimeType.DateTimeFormatType.G_DAY, dtt.getFormatTypeEnum()); + assertEquals(input, dtt.getDateTimeString()); + assertEquals("", dtt.getUtcDateTimeString()); + } + + // --- Errors and utilities --- + @Test + @DisplayName("Should throw an exception when an invalid date is provided") + void testInvalidDate() { + assertThrows(RuntimeException.class, () -> new DateTimeType("Test", "invalid-date")); + } + + @Test + @DisplayName("Should export a valid date in the expected CSV format") + void testCsvExport() throws Exception { + DateTimeType dtt = new DateTimeType("DateElement", "2025-10-28T14:30:00Z"); + var csv = dtt.toCsvList(); + assertTrue(csv.containsKey("")); + assertEquals("2025-10-28T14:30:00Z", csv.get("")); + } + + @Test + @DisplayName("Should correctly handle JSON setters for the value and format") + void testJsonSetters() { + DateTimeType dtt = new DateTimeType(); + dtt.setDateTimeString("2025-10-28T14:30:00Z"); + assertEquals(DateTimeType.DateTimeFormatType.OFFSET_DATE_TIME, dtt.getFormatTypeEnum()); + assertEquals("2025-10-28T14:30:00Z", dtt.getDateTimeString()); + dtt.setDateTimeString(""); + assertNull(dtt.getTemporalValue()); + assertNull(dtt.getFormatTypeEnum()); + } + + // --- toLocalDateTime() tests robust against system timezone --- + @Test + @DisplayName("toLocalDateTime() should return the local date-time corresponding to an OffsetDateTime UTC") + void toLocalDateTime_givenOffsetDateTime_shouldReturnLocalDateTimeWithSystemOffset() { + DateTimeType dt = new DateTimeType("LastModified", "2025-10-29T18:30:00Z"); + LocalDateTime result = dt.toLocalDateTime(); + assertNotNull(result, "Expected non-null LocalDateTime for OFFSET_DATE_TIME"); + // Conversion UTC -> system LocalDateTime + LocalDateTime expectedLocal = ((OffsetDateTime) dt.getTemporalValue()) + .atZoneSameInstant(ZoneId.systemDefault()) + .toLocalDateTime(); + assertEquals(expectedLocal, result, "LocalDateTime must match system local time"); + } + + @Test + @DisplayName("toLocalDateTime() should extract the local date/time part of a LocalDateTime with no timezone") + void toLocalDateTime_givenLocalDateTime_shouldReturnSameLocalDateTime() { + DateTimeType dt = new DateTimeType("EventTime", "2025-10-29T18:30:00"); + LocalDateTime result = dt.toLocalDateTime(); + assertNotNull(result, "Expected non-null LocalDateTime for DATE_TIME"); + assertEquals(LocalDateTime.of(2025, 10, 29, 18, 30, 0), result); + } + + @Test + @DisplayName("toLocalDateTime() should convert a LocalDate to a LocalDateTime at local midnight") + void toLocalDateTime_givenLocalDate_shouldReturnLocalDateAtMidnight() { + DateTimeType dt = new DateTimeType("CreationDate", "2025-10-29"); + LocalDateTime result = dt.toLocalDateTime(); + assertNotNull(result, "Expected non-null LocalDateTime for DATE"); + assertEquals(LocalDateTime.of(2025, 10, 29, 0, 0, 0), result); + } + + @Test + @DisplayName("toLocalDateTime() should return null for all imprecise formats (gYear, gMonth, etc.)") + void toLocalDateTime_givenImpreciseFormats_shouldReturnNull() { + assertNull(new DateTimeType("YearOnly", "2025").toLocalDateTime(), "Expected null for gYear format"); + assertNull(new DateTimeType("YearMonth", "2025-10").toLocalDateTime(), "Expected null for gYearMonth format"); + assertNull(new DateTimeType("MonthOnly", "--10").toLocalDateTime(), "Expected null for gMonth format"); + assertNull(new DateTimeType("MonthDay", "--10-29").toLocalDateTime(), "Expected null for gMonthDay format"); + assertNull(new DateTimeType("DayOnly", "---29").toLocalDateTime(), "Expected null for gDay format"); + } + + @Test + @DisplayName("toLocalDateTime() should return null if no value is defined") + void toLocalDateTime_givenNullValue_shouldReturnNull() { + DateTimeType dt = new DateTimeType("Empty", (String) null); + assertNull(dt.toLocalDateTime(), "Expected null when temporalValue is null"); + } +} diff --git a/sedalib/src/test/resources/ExpectedResults/ExportedMetadata.csv b/sedalib/src/test/resources/ExpectedResults/ExportedMetadata.csv index 5ac7f703..4e7a922d 100644 --- a/sedalib/src/test/resources/ExpectedResults/ExportedMetadata.csv +++ b/sedalib/src/test/resources/ExpectedResults/ExportedMetadata.csv @@ -1,7 +1,7 @@ File;Content.DescriptionLevel;Content.Title;Content.OriginatingSystemId;Content.Description;Content.Writer.FirstName;Content.Writer.BirthName;Content.Writer.Identifier;Content.Addressee.0.FirstName;Content.Addressee.0.BirthName;Content.Addressee.0.Identifier;Content.Addressee.1.BirthName;Content.Addressee.1.FirstName;Content.Addressee.1.Identifier;Content.Recipient.FirstName;Content.Recipient.BirthName;Content.Recipient.Identifier;Content.CreatedDate;Content.SentDate;Content.ReceivedDate;Content.TextContent;Content.ExtensionSEDA0.0;Content.ExtensionSEDA0.1;Content.ExtensionSEDA1;Management.AccessRule.Rule.0;Management.AccessRule.StartDate;Management.AccessRule.Rule.1;Management.AccessRule.PreventInheritance;Management.AccessRule.RefNonRuleId.0;Management.AccessRule.RefNonRuleId.1;Management.ClassificationRule.Rule;Management.ClassificationRule.StartDate;Management.ClassificationRule.ClassificationOwner;Management.ClassificationRule.NeedReassessingAuthorization -"../../../src/test/resources/PacketSamples/SampleWithTitleDirectoryNameModelV2/Root/Node 1/Node 1.1";"Item";"Node 1.1";;"Document ""201609_TdB_suivi_des_activites_VITAM.ods"" joint au message <79980C36BA239C449A9575FE17591F3D0C237AD1@prd-exch-b01.solano.alize>";;;;;;;;;;;;;"2016-08-30T10:13:03.000";;;;;;;;;;;;;;;; +"../../../src/test/resources/PacketSamples/SampleWithTitleDirectoryNameModelV2/Root/Node 1/Node 1.1";"Item";"Node 1.1";;"Document ""201609_TdB_suivi_des_activites_VITAM.ods"" joint au message <79980C36BA239C449A9575FE17591F3D0C237AD1@prd-exch-b01.solano.alize>";;;;;;;;;;;;;"2016-08-30T10:13:03Z";;;;;;;;;;;;;;;; "../../../src/test/resources/PacketSamples/SampleWithTitleDirectoryNameModelV2/Root/Node 1/image001.jpg";"Item";"image001.jpg";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -"../../../src/test/resources/PacketSamples/SampleWithTitleDirectoryNameModelV2/Root/Node 1";"Item";"Node 1";"<79980C36BA239C449A9575FE17591F3D0C237AD1@prd-exch-b01.solano.alize>";;"PLANCHOT Benjamin";"PLANCHOT Benjamin";"benjamin.planchot@modernisation.gouv.fr";"frederic.deguilhen@culture.gouv.fr";"frederic.deguilhen@culture.gouv.fr";"frederic.deguilhen@culture.gouv.fr";"jean-severin.lair@culture.gouv.fr";"jean-severin.lair@culture.gouv.fr";"jean-severin.lair@culture.gouv.fr";"PLANCHOT Benjamin";"PLANCHOT Benjamin";"benjamin.planchot@modernisation.gouv.fr";;"2016-08-30T10:14:17.000";"2016-08-30T10:14:18.000";"Bonjour, +"../../../src/test/resources/PacketSamples/SampleWithTitleDirectoryNameModelV2/Root/Node 1";"Item";"Node 1";"<79980C36BA239C449A9575FE17591F3D0C237AD1@prd-exch-b01.solano.alize>";;"PLANCHOT Benjamin";"PLANCHOT Benjamin";"benjamin.planchot@modernisation.gouv.fr";"frederic.deguilhen@culture.gouv.fr";"frederic.deguilhen@culture.gouv.fr";"frederic.deguilhen@culture.gouv.fr";"jean-severin.lair@culture.gouv.fr";"jean-severin.lair@culture.gouv.fr";"jean-severin.lair@culture.gouv.fr";"PLANCHOT Benjamin";"PLANCHOT Benjamin";"benjamin.planchot@modernisation.gouv.fr";;"2016-08-30T10:14:17Z";"2016-08-30T10:14:18Z";"Bonjour, Vous trouverez ci-joint les éléments collectés au mois de juillet sous forme de tableur correspondant à l'avancement de vos activités. Afin de publier une mise à jour en CSIC Tech, merci de mettre à jour les éléments pour le jeudi 08 septembre au plus tard. Sans retour de votre part, je tiendrai compte de la dernière mise à jour. diff --git a/sedalib/src/test/resources/ExpectedResults/ExportedMetadataWithExtendedFormat.csv b/sedalib/src/test/resources/ExpectedResults/ExportedMetadataWithExtendedFormat.csv index 0e3da1f9..51890345 100644 --- a/sedalib/src/test/resources/ExpectedResults/ExportedMetadataWithExtendedFormat.csv +++ b/sedalib/src/test/resources/ExpectedResults/ExportedMetadataWithExtendedFormat.csv @@ -1,7 +1,7 @@ Id;ParentId;File;ObjectFiles;Content.DescriptionLevel;Content.Title;Content.OriginatingSystemId;Content.Description;Content.Writer.FirstName;Content.Writer.BirthName;Content.Writer.Identifier;Content.Addressee.0.FirstName;Content.Addressee.0.BirthName;Content.Addressee.0.Identifier;Content.Addressee.1.BirthName;Content.Addressee.1.FirstName;Content.Addressee.1.Identifier;Content.Recipient.FirstName;Content.Recipient.BirthName;Content.Recipient.Identifier;Content.CreatedDate;Content.SentDate;Content.ReceivedDate;Content.TextContent;Content.ExtensionSEDA0.0;Content.ExtensionSEDA0.1;Content.ExtensionSEDA1;Management.AccessRule.Rule.0;Management.AccessRule.StartDate;Management.AccessRule.Rule.1;Management.AccessRule.PreventInheritance;Management.AccessRule.RefNonRuleId.0;Management.AccessRule.RefNonRuleId.1;Management.ClassificationRule.Rule;Management.ClassificationRule.StartDate;Management.ClassificationRule.ClassificationOwner;Management.ClassificationRule.NeedReassessingAuthorization -"ID12";"ID11";"../../../src/test/resources/PacketSamples/SampleWithTitleDirectoryNameModelV2/Root/Node 1/Node 1.1";"../../../src/test/resources/PacketSamples/SampleWithTitleDirectoryNameModelV2/Root/Node 1/Node 1.1/__BinaryMaster_1__201609-TdB-suivi-des-a.ods|../../../src/test/resources/PacketSamples/SampleWithTitleDirectoryNameModelV2/Root/Node 1/Node 1.1/__TextContent_1__201609-TdB-suivi-des-a.txt";"Item";"Node 1.1";;"Document ""201609_TdB_suivi_des_activites_VITAM.ods"" joint au message <79980C36BA239C449A9575FE17591F3D0C237AD1@prd-exch-b01.solano.alize>";;;;;;;;;;;;;"2016-08-30T10:13:03.000";;;;;;;;;;;;;;;; +"ID12";"ID11";"../../../src/test/resources/PacketSamples/SampleWithTitleDirectoryNameModelV2/Root/Node 1/Node 1.1";"../../../src/test/resources/PacketSamples/SampleWithTitleDirectoryNameModelV2/Root/Node 1/Node 1.1/__BinaryMaster_1__201609-TdB-suivi-des-a.ods|../../../src/test/resources/PacketSamples/SampleWithTitleDirectoryNameModelV2/Root/Node 1/Node 1.1/__TextContent_1__201609-TdB-suivi-des-a.txt";"Item";"Node 1.1";;"Document ""201609_TdB_suivi_des_activites_VITAM.ods"" joint au message <79980C36BA239C449A9575FE17591F3D0C237AD1@prd-exch-b01.solano.alize>";;;;;;;;;;;;;"2016-08-30T10:13:03Z";;;;;;;;;;;;;;;; "ID19";"ID11";"../../../src/test/resources/PacketSamples/SampleWithTitleDirectoryNameModelV2/Root/Node 1/image001.jpg";"../../../src/test/resources/PacketSamples/SampleWithTitleDirectoryNameModelV2/Root/Node 1/image001.jpg";"Item";"image001.jpg";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -"ID11";"ID10";"../../../src/test/resources/PacketSamples/SampleWithTitleDirectoryNameModelV2/Root/Node 1";"";"Item";"Node 1";"<79980C36BA239C449A9575FE17591F3D0C237AD1@prd-exch-b01.solano.alize>";;"PLANCHOT Benjamin";"PLANCHOT Benjamin";"benjamin.planchot@modernisation.gouv.fr";"frederic.deguilhen@culture.gouv.fr";"frederic.deguilhen@culture.gouv.fr";"frederic.deguilhen@culture.gouv.fr";"jean-severin.lair@culture.gouv.fr";"jean-severin.lair@culture.gouv.fr";"jean-severin.lair@culture.gouv.fr";"PLANCHOT Benjamin";"PLANCHOT Benjamin";"benjamin.planchot@modernisation.gouv.fr";;"2016-08-30T10:14:17.000";"2016-08-30T10:14:18.000";"Bonjour, +"ID11";"ID10";"../../../src/test/resources/PacketSamples/SampleWithTitleDirectoryNameModelV2/Root/Node 1";"";"Item";"Node 1";"<79980C36BA239C449A9575FE17591F3D0C237AD1@prd-exch-b01.solano.alize>";;"PLANCHOT Benjamin";"PLANCHOT Benjamin";"benjamin.planchot@modernisation.gouv.fr";"frederic.deguilhen@culture.gouv.fr";"frederic.deguilhen@culture.gouv.fr";"frederic.deguilhen@culture.gouv.fr";"jean-severin.lair@culture.gouv.fr";"jean-severin.lair@culture.gouv.fr";"jean-severin.lair@culture.gouv.fr";"PLANCHOT Benjamin";"PLANCHOT Benjamin";"benjamin.planchot@modernisation.gouv.fr";;"2016-08-30T10:14:17Z";"2016-08-30T10:14:18Z";"Bonjour, Vous trouverez ci-joint les éléments collectés au mois de juillet sous forme de tableur correspondant à l'avancement de vos activités. Afin de publier une mise à jour en CSIC Tech, merci de mettre à jour les éléments pour le jeudi 08 septembre au plus tard. Sans retour de votre part, je tiendrai compte de la dernière mise à jour. diff --git a/sedalib/src/test/resources/import/AU_ID2.xml b/sedalib/src/test/resources/import/AU_ID2.xml index e1be241d..1a9b9f66 100644 --- a/sedalib/src/test/resources/import/AU_ID2.xml +++ b/sedalib/src/test/resources/import/AU_ID2.xml @@ -107,8 +107,8 @@ PLANCHOT Benjamin benjamin.planchot@modernisation.gouv.fr - 2016-08-30T10:14:17.000 - 2016-08-30T10:14:18.000 + 2016-08-30T10:14:17Z + 2016-08-30T10:14:18Z Bonjour, Vous trouverez ci-joint les éléments collectés au mois de juillet sous forme de tableur correspondant à l'avancement de vos activités. Afin de publier une mise à jour en CSIC Tech, merci de mettre à jour les éléments pour le jeudi 08 septembre au plus tard. Sans retour de votre part, je tiendrai compte de la dernière mise à jour. @@ -150,7 +150,7 @@ modernisation.gouv.fr< http://www.modernisation.gouv.fr/> Item 201609_TdB_suivi_des_activites_VITAM.ods Document "201609_TdB_suivi_des_activites_VITAM.ods" joint au message <79980C36BA239C449A9575FE17591F3D0C237AD1@prd-exch-b01.solano.alize> - 2016-08-30T10:13:03.000 + 2016-08-30T10:13:03Z BinaryMaster_1 @@ -188,7 +188,7 @@ modernisation.gouv.fr< http://www.modernisation.gouv.fr/> Item image001.jpg Document "image001.jpg" joint au message <79980C36BA239C449A9575FE17591F3D0C237AD1@prd-exch-b01.solano.alize> - 2016-08-30T10:14:17.000 + 2016-08-30T10:14:17Z BinaryMaster_1 diff --git a/sedalib/src/test/resources/import/AU_ID2V3.xml b/sedalib/src/test/resources/import/AU_ID2V3.xml index a8114816..698f7925 100644 --- a/sedalib/src/test/resources/import/AU_ID2V3.xml +++ b/sedalib/src/test/resources/import/AU_ID2V3.xml @@ -107,8 +107,8 @@ PLANCHOT Benjamin benjamin.planchot@modernisation.gouv.fr - 2016-08-30T10:14:17.000 - 2016-08-30T10:14:18.000 + 2016-08-30T10:14:17Z + 2016-08-30T10:14:18Z Bonjour, Vous trouverez ci-joint les éléments collectés au mois de juillet sous forme de tableur correspondant à l'avancement de vos activités. Afin de publier une mise à jour en CSIC Tech, merci de mettre à jour les éléments pour le jeudi 08 septembre au plus tard. Sans retour de votre part, je tiendrai compte de la dernière mise à jour. @@ -150,7 +150,7 @@ modernisation.gouv.fr< http://www.modernisation.gouv.fr/> Item 201609_TdB_suivi_des_activites_VITAM.ods Document "201609_TdB_suivi_des_activites_VITAM.ods" joint au message <79980C36BA239C449A9575FE17591F3D0C237AD1@prd-exch-b01.solano.alize> - 2016-08-30T10:13:03.000 + 2016-08-30T10:13:03Z BinaryMaster_1 @@ -188,7 +188,7 @@ modernisation.gouv.fr< http://www.modernisation.gouv.fr/> Item image001.jpg Document "image001.jpg" joint au message <79980C36BA239C449A9575FE17591F3D0C237AD1@prd-exch-b01.solano.alize> - 2016-08-30T10:14:17.000 + 2016-08-30T10:14:17Z BinaryMaster_1 diff --git a/sedalib/src/test/resources/import/AU_ID4.xml b/sedalib/src/test/resources/import/AU_ID4.xml index 3a6a3604..8e14dc20 100644 --- a/sedalib/src/test/resources/import/AU_ID4.xml +++ b/sedalib/src/test/resources/import/AU_ID4.xml @@ -266,19 +266,19 @@ 4-LK18-3389 - 2017-01-01T00:00:00.000 - 2017-01-01T00:00:00.000 - 2017-01-01T00:00:00.000 - 2017-01-01T00:00:00.000 - 2017-01-01T00:00:00.000 - 2017-01-01T00:00:00.000 - 2017-04-04T08:07:06.000 - 2017-04-04T08:07:06.000 + 2017-01-01 + 2017-01-01 + 2017-01-01 + 2017-01-01 + 2017-01-01 + 2017-01-01 + 2017-04-04T08:07:06 + 2017-04-04T08:07:06 123456 Ligne_ouverture Ouverture - 1998-05-25T08:07:06.000 + 1998-05-25T08:07:06 Ouverture de la station à l'exploitation OK Ligne_Ouverture_OK @@ -312,7 +312,7 @@ Française 0000 0000 5488 9547 - 1998-04-04T08:07:06.000 + 1998-04-04T08:07:06 Ingénierie Conception de lignes de métro Chef de l'inspection des Ponts et Chaussées @@ -345,7 +345,7 @@ Française 0000 0000 5488 9547 - 1998-04-04T08:07:06.000 + 1998-04-04T08:07:06 Ingénierie Conception de lignes de métro Chef de l'inspection des Ponts et Chaussées diff --git a/sedalib/src/test/resources/import/AU_Import_01.json b/sedalib/src/test/resources/import/AU_Import_01.json index 702b6750..9c5607b2 100644 --- a/sedalib/src/test/resources/import/AU_Import_01.json +++ b/sedalib/src/test/resources/import/AU_Import_01.json @@ -1,7 +1,7 @@ { "archiveUnitProfileXmlData" : null, "managementXmlData" : "\n \n ACC-00001\n 2015-11-19\n ACC-00002\n true\n ACC-00003\n ACC-00004\n \n \n CLAS-00001\n 2015-11-19\n Autorité\n true\n \n", - "contentXmlData" : "\n Item\n image001.jpg\n Document \"image001.jpg\" joint au message <79980C36BA239C449A9575FE17591F3D0C237AD1@prd-exch-b01.solano.alize>\n 2016-08-30T10:14:17.000\n", + "contentXmlData" : "\n Item\n image001.jpg\n Document \"image001.jpg\" joint au message <79980C36BA239C449A9575FE17591F3D0C237AD1@prd-exch-b01.solano.alize>\n 2016-08-30T10:14:17Z\n", "childrenAuList" : { "inDataObjectPackageIdList" : [ ] }, diff --git a/sedalib/src/test/resources/import/AU_Import_02.json b/sedalib/src/test/resources/import/AU_Import_02.json index a5259a17..5f3a91e4 100644 --- a/sedalib/src/test/resources/import/AU_Import_02.json +++ b/sedalib/src/test/resources/import/AU_Import_02.json @@ -1,7 +1,7 @@ { "archiveUnitProfileXmlData" : null, "managementXmlData" : null, - "contentXmlData" : "\n Item\n image001.jpg\n Document \"image001.jpg\" joint au message <79980C36BA239C449A9575FE17591F3D0C237AD1@prd-exch-b01.solano.alize>\n 2016-08-30T10:14:17.000\n", + "contentXmlData" : "\n Item\n image001.jpg\n Document \"image001.jpg\" joint au message <79980C36BA239C449A9575FE17591F3D0C237AD1@prd-exch-b01.solano.alize>\n 2016-08-30T10:14:17Z\n", "childrenAuList" : { "inDataObjectPackageIdList" : [ ] }, diff --git a/sedalib/src/test/resources/import/binary_data_object_ID7.xml b/sedalib/src/test/resources/import/binary_data_object_ID7.xml index cdeef4f6..dec684aa 100644 --- a/sedalib/src/test/resources/import/binary_data_object_ID7.xml +++ b/sedalib/src/test/resources/import/binary_data_object_ID7.xml @@ -9,7 +9,7 @@ image001.jpg - 2018-08-28T19:22:19.000 + 2018-08-28T19:22:19Z diff --git a/sedalib/src/test/resources/import/binary_data_object_ID7_seda2.2.xml b/sedalib/src/test/resources/import/binary_data_object_ID7_seda2.2.xml index 4beae03c..072a05da 100644 --- a/sedalib/src/test/resources/import/binary_data_object_ID7_seda2.2.xml +++ b/sedalib/src/test/resources/import/binary_data_object_ID7_seda2.2.xml @@ -10,7 +10,7 @@ image001.jpg - 2018-08-28T19:22:19.000 + 2018-08-28T19:22:19Z diff --git a/sedalib/src/test/resources/import/binary_data_object_ID7_seda2.3.xml b/sedalib/src/test/resources/import/binary_data_object_ID7_seda2.3.xml index fa6e68f7..7256436d 100644 --- a/sedalib/src/test/resources/import/binary_data_object_ID7_seda2.3.xml +++ b/sedalib/src/test/resources/import/binary_data_object_ID7_seda2.3.xml @@ -18,7 +18,7 @@ image001.jpg - 2018-08-28T19:22:19.000 + 2018-08-28T19:22:19Z diff --git a/sedalib/src/test/resources/metadata/content_01_csv_list.txt b/sedalib/src/test/resources/metadata/content_01_csv_list.txt index 0fbbce67..3d522f11 100644 --- a/sedalib/src/test/resources/metadata/content_01_csv_list.txt +++ b/sedalib/src/test/resources/metadata/content_01_csv_list.txt @@ -27,28 +27,28 @@ RelatedObjectReference.Replaces.0.DataObjectReference.DataObjectReferenceId: DoR RelatedObjectReference.Requires.0.RepositoryArchiveUnitPID: AuPid RelatedObjectReference.IsPartOf.0.RepositoryObjectPID: DoPid RelatedObjectReference.References.0.ExternalReference: ExtrenalRef -RegisteredDate: 2104-05-13T00:00:00.000 -Event.0.EventDateTime: 1970-01-01T01:00:00.000 +RegisteredDate: 2104-05-13T00:00:00 +Event.0.EventDateTime: 1970-01-01T01:00:00 Event.0.Outcome: OK Event.0.Information.0: OK Event.1.EventIdentifier: AUT-234452 Event.1.EventTypeCode: Autorisation -Event.1.EventDateTime: 2104-05-31T01:00:00.000 +Event.1.EventDateTime: 2104-05-31T01:00:00 Event.1.Outcome: OK Signature.0.Signer.0.FirstName: Paul Signature.0.Signer.0.BirthName: Dupont -Signature.0.Signer.0.SigningTime: 1970-01-01T01:00:00.000 +Signature.0.Signer.0.SigningTime: 1970-01-01T01:00:00 Signature.0.Signer.1.FullName: Martin Durant -Signature.0.Signer.1.SigningTime: 1970-01-02T01:00:00.000 +Signature.0.Signer.1.SigningTime: 1970-01-02T01:00:00 Signature.0.Signer.2.FirstName: Emilie Signature.0.Signer.2.BirthName: Martin Signature.0.Signer.2.Identifier: emilie.martin@corp.fr -Signature.0.Signer.2.SigningTime: 1970-01-02T01:00:00.000 +Signature.0.Signer.2.SigningTime: 1970-01-02T01:00:00 Signature.0.Signer.3.FullName: Laura Tremoulet Signature.0.Signer.3.BirthPlace.Geogname: TestLocation1 -Signature.0.Signer.3.SigningTime: 1970-01-01T02:00:00.000 +Signature.0.Signer.3.SigningTime: 1970-01-01T02:00:00 Signature.0.Validator.Corpname: The corporation -Signature.0.Validator.ValidationTime: 1970-01-03T01:00:00.000 +Signature.0.Validator.ValidationTime: 1970-01-03T01:00:00 Signature.0.ReferencedObject.SignedObjectId: TestID1 Signature.0.ReferencedObject.SignedObjectDigest: TestDigest1 Signature.0.ReferencedObject.SignedObjectDigest.attr: algorithm="TestSHA" diff --git a/sedalib/src/test/resources/metadata/content_02.xml b/sedalib/src/test/resources/metadata/content_02.xml index 3d4eca39..123ee354 100644 --- a/sedalib/src/test/resources/metadata/content_02.xml +++ b/sedalib/src/test/resources/metadata/content_02.xml @@ -1,14 +1,14 @@ TestDescription EN - 1970-01-01T01:00:00.000 + 1970-01-01T01:00:00 OK OK AUT-234452 Autorisation - 2104-05-31T01:00:00.000 + 2104-05-31T01:00:00 OK diff --git a/sedalib/src/test/resources/metadata/content_03.xml b/sedalib/src/test/resources/metadata/content_03.xml index ac8d5b58..2844648a 100644 --- a/sedalib/src/test/resources/metadata/content_03.xml +++ b/sedalib/src/test/resources/metadata/content_03.xml @@ -47,42 +47,42 @@ TestGeogname - 2019-01-01T01:00:00.000 - 2104-05-13T00:00:00.000 + 2019-01-01T01:00:00 + 2104-05-13T00:00:00 TestEventIdentifier2 TestEventIdentifier TestEventType - 1970-01-01T01:00:00.000 + 1970-01-01T01:00:00 TestOutcome AUT-234452 Autorisation - 2104-05-31T01:00:00.000 + 2104-05-31T01:00:00 OK TestFullName - 1970-01-01T01:00:00.000 + 1970-01-01T01:00:00 TestFirstName TestBirthName - 1970-01-01T01:00:00.000 + 1970-01-01T01:00:00 TestFirstName TestBirthName TestIdentifier - 1970-01-01T01:00:00.000 + 1970-01-01T01:00:00 TestFullName - 1970-01-01T01:00:00.000 + 1970-01-01T01:00:00 TestSystemID diff --git a/sedalib/src/test/resources/metadata/content_04_csv_list.txt b/sedalib/src/test/resources/metadata/content_04_csv_list.txt index 349e124b..1ab0f03f 100644 --- a/sedalib/src/test/resources/metadata/content_04_csv_list.txt +++ b/sedalib/src/test/resources/metadata/content_04_csv_list.txt @@ -1,11 +1,11 @@ Content.Description.0: TestDescription EN Content.Description.0.attr: xml:lang="en" -Content.Event.0.EventDateTime: 1970-01-01T01:00:00.000 +Content.Event.0.EventDateTime: 1970-01-01T01:00:00 Content.Event.0.Outcome: OK Content.Event.0.Information.0: OK Content.Event.1.EventIdentifier: AUT-234452 Content.Event.1.EventTypeCode: Autorisation -Content.Event.1.EventDateTime: 2104-05-31T01:00:00.000 +Content.Event.1.EventDateTime: 2104-05-31T01:00:00 Content.Event.1.Outcome: OK Content.Frog.0: Rouge à laser diff --git a/sedalib/src/test/resources/metadata/file_info_01.xml b/sedalib/src/test/resources/metadata/file_info_01.xml index dcdfc0bd..c7d9ae34 100644 --- a/sedalib/src/test/resources/metadata/file_info_01.xml +++ b/sedalib/src/test/resources/metadata/file_info_01.xml @@ -2,8 +2,8 @@ TestFileName TestCreatingApplicationName TestCreatingApplicationVersion - 2006-05-04T18:13:51.000 + 2006-05-04T18:13:51 TestCreatingOs TestCreatingOsVersion - 1970-01-01T00:00:00.000 + 1970-01-01T00:00:00Z \ No newline at end of file diff --git a/sedalib/src/test/resources/metadata/metadate_out.xml b/sedalib/src/test/resources/metadata/metadate_out.xml index 5b5b5205..ab83f35e 100644 --- a/sedalib/src/test/resources/metadata/metadate_out.xml +++ b/sedalib/src/test/resources/metadata/metadate_out.xml @@ -61,7 +61,7 @@ ID-00001 Request - 2000-01-01T13:10:00.000 + 2000-01-01T13:10:00 OK