All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.helger.peppol.xhe.read.DBNAllianceXHEDocumentReader Maven / Gradle / Ivy

/*
 * Copyright (C) 2024 Philip Helger
 * philip[at]helger[dot]com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.helger.peppol.xhe.read;

import java.io.InputStream;
import java.util.List;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.WillClose;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

import com.helger.commons.ValueEnforcer;
import com.helger.commons.annotation.OverrideOnDemand;
import com.helger.commons.datetime.XMLOffsetDateTime;
import com.helger.commons.error.IError;
import com.helger.commons.error.SingleError;
import com.helger.commons.error.level.IHasErrorLevel;
import com.helger.commons.error.list.ErrorList;
import com.helger.commons.io.resource.IReadableResource;
import com.helger.commons.io.stream.StreamHelper;
import com.helger.commons.string.StringHelper;
import com.helger.peppol.xhe.CDBNAllianceXHE;
import com.helger.peppol.xhe.DBNAlliancePayload;
import com.helger.peppol.xhe.DBNAllianceXHEData;
import com.helger.peppolid.CIdentifier;
import com.helger.peppolid.IParticipantIdentifier;
import com.helger.peppolid.factory.IIdentifierFactory;
import com.helger.xhe.v10.XHE10Marshaller;
import com.helger.xhe.v10.XHE10XHEType;
import com.helger.xhe.v10.cac.XHE10HeaderType;
import com.helger.xhe.v10.cac.XHE10PartyType;
import com.helger.xhe.v10.cac.XHE10PayloadContentType;
import com.helger.xhe.v10.cac.XHE10PayloadType;
import com.helger.xhe.v10.cac.XHE10PayloadsType;
import com.helger.xhe.v10.cbc.XHE10ContentTypeCodeType;
import com.helger.xhe.v10.cbc.XHE10CustomizationIDType;
import com.helger.xhe.v10.cbc.XHE10IDType;
import com.helger.xhe.v10.cbc.XHE10InstanceEncryptionIndicatorType;
import com.helger.xhe.v10.cbc.XHE10InstanceEncryptionMethodType;
import com.helger.xhe.v10.cbc.XHE10ProfileIDType;

/**
 * Main class to read exchange header envelope and extract the DBNAlliance
 * required data out of it.
 *
 * @author Robinson Garcia
 * @author Philip Helger
 */
public class DBNAllianceXHEDocumentReader
{
  public static final boolean DEFAULT_PERFORM_VALUE_CHECKS = true;

  private static final Logger LOGGER = LoggerFactory.getLogger (DBNAllianceXHEDocumentReader.class);

  private final IIdentifierFactory m_aIdentifierFactory;
  private boolean m_bPerformValueChecks = DEFAULT_PERFORM_VALUE_CHECKS;

  public DBNAllianceXHEDocumentReader (@Nonnull final IIdentifierFactory aIdentifierFactory)
  {
    ValueEnforcer.notNull (aIdentifierFactory, "IdentifierFactory");

    m_aIdentifierFactory = aIdentifierFactory;
  }

  /**
   * @return The identifier provided in the constructor. Never
   *         null.
   */
  @Nonnull
  public final IIdentifierFactory getIdentifierFactory ()
  {
    return m_aIdentifierFactory;
  }

  /**
   * @return true if value checks on data extraction are enabled,
   *         false if not. By default checks are enabled - see
   *         {@link #DEFAULT_PERFORM_VALUE_CHECKS}.
   */
  public final boolean isPerformValueChecks ()
  {
    return m_bPerformValueChecks;
  }

  /**
   * Enable or disable the performing of value checks on data extraction.
   *
   * @param b
   *        true to enable checks, false to disable
   *        them.
   * @return this for chaining
   */
  @Nonnull
  public final DBNAllianceXHEDocumentReader setPerformValueChecks (final boolean b)
  {
    m_bPerformValueChecks = b;
    return this;
  }

  /**
   * Check if the passed XHE version is valid or not. By default is must match
   * {@link CDBNAllianceXHE#XHE_VERSION_ID}. Override this method to allow for
   * other schemes as well.
   *
   * @param sXHEVersionID
   *        The value to be checked. This is the content of the XML element
   *        /XHE/XHEVersionID. May be null.
   * @return true if the value is valid, false
   *         otherwise.
   */
  @OverrideOnDemand
  protected boolean isValidXHEVersionID (@Nullable final String sXHEVersionID)
  {
    return CDBNAllianceXHE.XHE_VERSION_ID.equals (sXHEVersionID);
  }

  /**
   * Check if the passed customization id schema is valid or not. By default is
   * must match {@link CDBNAllianceXHE#CUSTOMIZATION_SCHEMA_ID}. Override this
   * method to allow for other schemes as well.
   *
   * @param sSchemaID
   *        The value to be checked. This is the content of the XML attribute
   *        XHE/CustomizationID/@schemeID. May be
   *        null.
   * @return true if the value is valid, false
   *         otherwise.
   */
  @OverrideOnDemand
  protected boolean isValidCustomizationIDSchemaID (@Nullable final String sSchemaID)
  {
    return CDBNAllianceXHE.CUSTOMIZATION_SCHEMA_ID.equals (sSchemaID);
  }

  /**
   * Check if the passed customization id is valid or not. By default is must
   * match {@link CDBNAllianceXHE#CUSTOMIZATION_ID}. Override this method to
   * allow for other schemes as well.
   *
   * @param sCustomizationID
   *        The value to be checked. This is the content of the XML attribute
   *        XHE/CustomizationID/. May be null.
   * @return true if the value is valid, false
   *         otherwise.
   */
  @OverrideOnDemand
  protected boolean isValidCustomizationID (@Nullable final String sCustomizationID)
  {
    return CDBNAllianceXHE.CUSTOMIZATION_ID.equals (sCustomizationID);
  }

  /**
   * Check if the passed profile id is valid or not. By default is must match
   * {@link CDBNAllianceXHE#PROFILE_ID}. Override this method to allow for other
   * schemes as well.
   *
   * @param sProfileID
   *        The value to be checked. This is the content of the XML attribute
   *        XHE/ProfileID/. May be null.
   * @return true if the value is valid, false
   *         otherwise.
   */
  @OverrideOnDemand
  protected boolean isValidProfileID (@Nullable final String sProfileID)
  {
    return CDBNAllianceXHE.PROFILE_ID.equals (sProfileID);
  }

  /**
   * Check if the passed header id is valid or not. By default is must not be
   * empty. Override this method to perform further checks.
   *
   * @param sHeaderID
   *        The value to be checked. This conforms to the XML element value of
   *        XHE/Header/ID. May be null.
   * @return true if the value is valid, false
   *         otherwise.
   */
  @OverrideOnDemand
  protected boolean isValidHeaderID (@Nullable final String sHeaderID)
  {
    return StringHelper.hasText (sHeaderID);
  }

  /**
   * Check if the passed document identification creation date time is valid or
   * not. By default all values are valid as they cannot be null.
   * Override this method to perform further or other checks.
   *
   * @param aCreationDateTime
   *        The value to be checked. This corresponds to the field
   *        "XHE/Header/CreationDateTime". Is never null .
   * @return true if the value is valid, false
   *         otherwise.
   */
  @OverrideOnDemand
  protected boolean isValidCreationDateTime (@Nonnull final XMLOffsetDateTime aCreationDateTime)
  {
    return true;
  }

  /**
   * Check if the passed from party schema is is valid or not. By default is
   * must not be empty.
   *
   * @param sFromPartySchemaID
   *        The value to be checked. This is the content of the XML attribute
   *        XHE/Header/FromParty/PartyIdentification/ID/@schemaID.
   *        May be null.
   * @return true if the value is valid, false
   *         otherwise.
   */
  @OverrideOnDemand
  protected boolean isValidFromPartySchemaID (@Nullable final String sFromPartySchemaID)
  {
    return StringHelper.hasText (sFromPartySchemaID);
  }

  /**
   * Check if the passed from party value is valid or not. By default is must
   * not be empty. Override this method to perform further checks.
   *
   * @param sFromPartySchemaID
   *        The value to be checked. This is the content of the XML attribute
   *        XHE/Header/FromParty/PartyIdentification/ID/@schemaID.
   *        May be null.
   * @param sFromPartyValue
   *        The value to be checked. This conforms to the XML element value of
   *        XHE/Header/FromParty/PartyIdentification/ID/. May be
   *        null.
   * @return true if the value is valid, false
   *         otherwise.
   */
  @OverrideOnDemand
  protected boolean isValidFromPartyValue (@Nullable final String sFromPartySchemaID,
                                           @Nullable final String sFromPartyValue)
  {
    return StringHelper.hasText (sFromPartyValue);
  }

  /**
   * Check if the passed to party schema is valid or not. By default is must not
   * be empty.
   *
   * @param sToPartySchemaID
   *        The value to be checked. This is the content of the XML attribute
   *        XHE/Header/ToParty/PartyIdentification/ID/@schemaID.
   *        May be null.
   * @return true if the value is valid, false
   *         otherwise.
   */
  @OverrideOnDemand
  protected boolean isValidToPartySchemaID (@Nullable final String sToPartySchemaID)
  {
    return StringHelper.hasText (sToPartySchemaID);
  }

  /**
   * Check if the passed to party value is valid or not. By default is must not
   * be empty. Override this method to perform further checks.
   *
   * @param sToPartySchemaID
   *        The value to be checked. This is the content of the XML attribute
   *        XHE/Header/ToParty/PartyIdentification/ID/@schemaID.
   *        May be null.
   * @param sToPartyValue
   *        The value to be checked. This conforms to the XML element value of
   *        XHE/Header/ToParty/PartyIdentification/ID/. May be
   *        null.
   * @return true if the value is valid, false
   *         otherwise.
   */
  @OverrideOnDemand
  protected boolean isValidToPartyValue (@Nullable final String sToPartySchemaID, @Nullable final String sToPartyValue)
  {
    return StringHelper.hasText (sToPartyValue);
  }

  // Payloads validations

  /**
   * Check if the passed payload id is valid or not. By default is must not be
   * empty.
   *
   * @param sPayloadID
   *        The value to be checked. This corresponds to the field
   *        XHE/Payloads/Payload/ID. May be null.
   * @return true if the value is valid, false
   *         otherwise.
   */
  @OverrideOnDemand
  protected boolean isValidPayloadIDValue (@Nullable final String sPayloadID)
  {
    return StringHelper.hasText (sPayloadID);
  }

  /**
   * Check if the passed list id is valid or not.
   *
   * @param sListID
   *        The value to be checked. This is the content of the XML attribute
   *        XHE/Payloads/Payload/ContentTypeCode/@listID. May be
   *        null.
   * @return true if the value is valid, false
   *         otherwise.
   */
  @OverrideOnDemand
  protected boolean isValidContentTypeCodeListID (@Nullable final String sListID)
  {
    return "MIME".equals (sListID);
  }

  /**
   * Check if the passed content type code value is valid or not. By default is
   * must not be empty.
   *
   * @param sListID
   *        The value to be checked. This is the content of the XML attribute
   *        XHE/Payloads/Payload/ContentTypeCode/@listID. May be
   *        null.
   * @param sValue
   *        The value to be checked. This corresponds to the field
   *        XHE/Payloads/Payload/ContentTypeCode. May be
   *        null.
   * @return true if the value is valid, false
   *         otherwise.
   */
  @OverrideOnDemand
  protected boolean isValidContentTypeCodeValue (@Nullable final String sListID, @Nullable final String sValue)
  {
    return "application/xml".equals (sValue);
  }

  /**
   * Check if the passed instance encryption indicator value is valid or not. By
   * default all values are valid as they cannot be null. Override
   * this method to perform further or other checks.
   *
   * @param bInstanceEncryptionIndicator
   *        The value to be checked. This corresponds to the field
   *        "XHE/Payloads/Payload/InstanceEncryptionIndicator". Is never
   *        null .
   * @return true if the value is valid, false
   *         otherwise.
   */
  @OverrideOnDemand
  protected boolean isValidInstanceEncryptionIndicatorValue (@Nullable final boolean bInstanceEncryptionIndicator)
  {
    return true;
  }

  /**
   * The Instance Hash Value MUST NOT be included in the envelope. By default
   * all values are invalid as they cannot be present. Override this method to
   * perform further or other checks.
   *
   * @param sInstanceHashValue
   *        The value to be checked. This corresponds to the field
   *        "XHE/Payloads/Payload/InstanceHashValue". Is always
   *        null .
   * @return true if the field does not exist, false
   *         otherwise.
   */
  @OverrideOnDemand
  protected boolean isInstanceHashValueExist (@Nullable final String sInstanceHashValue)
  {
    return sInstanceHashValue == null;
  }

  /**
   * Check if the passed business message is valid or not. By default this
   * method always returns true since the element is never
   * null and no UBL specific checks are performed. Override this
   * method to perform further or other checks.
   *
   * @param aBusinessMessage
   *        The business message element to check against. Never
   *        null.
   * @return true if the value is valid, false
   *         otherwise.
   */
  @OverrideOnDemand
  protected boolean isValidBusinessMessage (@Nonnull final Element aBusinessMessage)
  {
    return true;
  }

  /**
   * Create a new XHE10 marshaller used for reading XHE documents. Override this
   * method to customize reading.
   *
   * @return An instance of the {@link XHE10Marshaller} and never
   *         null.
   */
  @Nonnull
  @OverrideOnDemand
  protected XHE10Marshaller createXHEMarshaller ()
  {
    final XHE10Marshaller ret = new XHE10Marshaller ();
    // Simply swallow all error messages where possible
    ret.setValidationEventHandler (null);
    return ret;
  }

  /**
   * Extract the document data from the Exchange Header Envelope represents by
   * the passed parameter.
   *
   * @param aExchangeHeaderEnvelope
   *        The input stream to read from. Will be closed by this method. May
   *        not be null.
   * @return The document data and never null.
   * @throws DBNAllianceXHEDocumentReadException
   *         In case the passed Exchange Header Envelope does not conform to the
   *         DBNAlliance rules.
   */
  @Nonnull
  public DBNAllianceXHEData extractData (@Nonnull @WillClose final InputStream aExchangeHeaderEnvelope) throws DBNAllianceXHEDocumentReadException
  {
    ValueEnforcer.notNull (aExchangeHeaderEnvelope, "ExchangeHeaderEnvelope");

    try
    {
      // Convert to domain object
      final XHE10XHEType aXHE = createXHEMarshaller ().read (aExchangeHeaderEnvelope);
      if (aXHE == null)
        throw new DBNAllianceXHEDocumentReadException (EDBNAllianceXHEDocumentReadError.INVALID_XHE_XML);

      return extractData (aXHE);
    }
    finally
    {
      StreamHelper.close (aExchangeHeaderEnvelope);
    }
  }

  /**
   * Extract the document data from the Exchange Header Envelope represents by
   * the passed parameter.
   *
   * @param aExchangeHeaderEnvelope
   *        The resource to read from. May not be null.
   * @return The document data and never null.
   * @throws DBNAllianceXHEDocumentReadException
   *         In case the passed Exchange Header Envelope does not conform to the
   *         DBNAlliance rules.
   */
  @Nonnull
  public DBNAllianceXHEData extractData (@Nonnull final IReadableResource aExchangeHeaderEnvelope) throws DBNAllianceXHEDocumentReadException
  {
    ValueEnforcer.notNull (aExchangeHeaderEnvelope, "StandardBusinessDocument");

    // Convert to domain object
    final XHE10XHEType aXHE = createXHEMarshaller ().read (aExchangeHeaderEnvelope);
    if (aXHE == null)
      throw new DBNAllianceXHEDocumentReadException (EDBNAllianceXHEDocumentReadError.INVALID_XHE_XML);

    return extractData (aXHE);
  }

  /**
   * Extract the document data from the Exchange Header Envelope represents by
   * the passed parameter.
   *
   * @param aExchangeHeaderEnvelope
   *        The DOM node to read from. May not be null.
   * @return The document data and never null.
   * @throws DBNAllianceXHEDocumentReadException
   *         In case the passed Exchange Header Envelope does not conform to the
   *         DBNAlliance rules.
   */
  @Nonnull
  public DBNAllianceXHEData extractData (@Nonnull final Node aExchangeHeaderEnvelope) throws DBNAllianceXHEDocumentReadException
  {
    ValueEnforcer.notNull (aExchangeHeaderEnvelope, "ExchangeHeaderEnvelope");

    // Convert to domain object
    final XHE10XHEType aXHE = createXHEMarshaller ().read (aExchangeHeaderEnvelope);
    if (aXHE == null)
      throw new DBNAllianceXHEDocumentReadException (EDBNAllianceXHEDocumentReadError.INVALID_XHE_XML);

    return extractData (aXHE);
  }

  /**
   * Extract the document data from the Exchange Header Envelope represents by
   * the passed parameter.
   *
   * @param aExchangeHeaderEnvelope
   *        The domain object to read from. May not be null.
   * @return The document data and never null.
   * @throws DBNAllianceXHEDocumentReadException
   *         In case the passed Exchange Header Envelope does not conform to the
   *         DBNAlliance rules.
   */
  @Nonnull
  public DBNAllianceXHEData extractData (@Nonnull final XHE10XHEType aExchangeHeaderEnvelope) throws DBNAllianceXHEDocumentReadException
  {
    ValueEnforcer.notNull (aExchangeHeaderEnvelope, "ExchangeHeaderEnvelope");

    // Grab the payloads
    final XHE10PayloadsType aPayloads = aExchangeHeaderEnvelope.getPayloads ();
    if (aPayloads == null || aPayloads.getPayload ().isEmpty ())
      throw new DBNAllianceXHEDocumentReadException (EDBNAllianceXHEDocumentReadError.MISSING_PAYLOADS_PAYLOAD);

    return extractData (aExchangeHeaderEnvelope, aPayloads);
  }

  @Nonnull
  private static IError _toError (@Nullable final String sErrorField,
                                  @Nonnull final EDBNAllianceXHEDocumentReadError e,
                                  @Nullable final Object... aArgs)
  {
    return SingleError.builderError ()
                      .errorFieldName (sErrorField)
                      .errorID (e.getID ())
                      .errorText (aArgs == null ? e.getErrorMessage () : e.getErrorMessage (aArgs))
                      .build ();
  }

  /**
   * Validate the provided XHE and the Payloads according to the DBNAlliance
   * rules and store the results in an Error List.
   *
   * @param aXHE
   *        The SBDH to be validated. Must not be null.
   * @param aPayloads
   *        The Payloads list to be validated (this does NOT mean Schematron
   *        validation). Must not be null.
   * @param aErrorList
   *        The error list to be filled. Must not be null.
   */
  public void validateData (@Nonnull final XHE10XHEType aXHE,
                            @Nonnull final XHE10PayloadsType aPayloads,
                            @Nonnull final ErrorList aErrorList)
  {
    ValueEnforcer.notNull (aXHE, "ExchangeHeaderEnvelope");
    ValueEnforcer.notNull (aPayloads, "Payloads");
    ValueEnforcer.notNull (aErrorList, "ErrorList");

    // Check that the xhe version id is correct
    if (!isValidXHEVersionID (aXHE.getXHEVersionIDValue ()))
      aErrorList.add (_toError ("XHE/XHEVersionID",
                                EDBNAllianceXHEDocumentReadError.INVALID_XHE_VERSION_ID,
                                aXHE.getXHEVersionIDValue ()));

    // Check CustomizationID
    {
      final XHE10CustomizationIDType aCustomizationID = aXHE.getCustomizationID ();
      if (aCustomizationID == null)
      {
        aErrorList.add (_toError ("XHE/CustomizationID", EDBNAllianceXHEDocumentReadError.CUSTOMIZATION_ID_MISSING));
      }
      else
      {
        // schemaID is mandatory
        final String sCustomizationIDSchemaID = aCustomizationID.getSchemeID ();
        if (!isValidCustomizationIDSchemaID (sCustomizationIDSchemaID))
          aErrorList.add (_toError ("XHE/CustomizationID/SchemaID",
                                    EDBNAllianceXHEDocumentReadError.INVALID_CUSTOMIZATION_ID_SCHEMA_ID,
                                    sCustomizationIDSchemaID));

        final String sCustomizationIDValue = aCustomizationID.getValue ();
        if (!isValidCustomizationID (sCustomizationIDValue))
          aErrorList.add (_toError ("XHE/CustomizationID/Value",
                                    EDBNAllianceXHEDocumentReadError.INVALID_CUSTOMIZATION_ID_VALUE,
                                    sCustomizationIDValue));
      }
    }

    // Check ProfileID
    {
      final XHE10ProfileIDType aProfileID = aXHE.getProfileID ();
      if (aProfileID == null)
      {
        aErrorList.add (_toError ("XHE/ProfileID", EDBNAllianceXHEDocumentReadError.PROFILE_ID_MISSING));
      }
      else
      {
        final String sProfileIDValue = aProfileID.getValue ();
        if (!isValidProfileID (sProfileIDValue))
          aErrorList.add (_toError ("XHE/ProfileID/Value",
                                    EDBNAllianceXHEDocumentReadError.INVALID_PROFILE_ID_VALUE,
                                    sProfileIDValue));
      }
    }

    // Check Header
    {
      final XHE10HeaderType aHeader = aXHE.getHeader ();
      if (aHeader == null)
      {
        aErrorList.add (_toError ("XHE/Header", EDBNAllianceXHEDocumentReadError.HEADER_MISSING));
      }
      else
      {
        // Header id is mandatory
        final String sHeaderID = aHeader.getIDValue ();
        if (!isValidHeaderID (sHeaderID))
        {
          aErrorList.add (_toError ("XHE/Header/ID", EDBNAllianceXHEDocumentReadError.INVALID_HEADER_ID, sHeaderID));
        }
        // Header creation date time is mandatory
        final XMLOffsetDateTime aCreationDateTime = aHeader.getCreationDateTimeValue ();
        if (!isValidCreationDateTime (aCreationDateTime))
        {
          aErrorList.add (_toError ("XHE/Header/CreationDateTime",
                                    EDBNAllianceXHEDocumentReadError.INVALID_CREATION_DATE_TIME,
                                    sHeaderID));
        }

        // Check from party
        final XHE10PartyType aFromParty = aHeader.getFromParty ();
        if (aFromParty != null)
        {
          final int nFromPartyCount = aFromParty.getPartyIdentificationCount ();
          if (nFromPartyCount != 1)
            aErrorList.add (_toError ("XHE/Header/FromParty/PartyIdentification",
                                      EDBNAllianceXHEDocumentReadError.INVALID_FROM_PARTY_COUNT,
                                      Integer.toString (nFromPartyCount)));

          if (nFromPartyCount > 0)
          {
            final XHE10IDType aFromPartyID = aFromParty.getPartyIdentificationAtIndex (0).getID ();
            final String sScheme = aFromPartyID.getSchemeID ();
            if (!isValidFromPartySchemaID (sScheme))
            {
              aErrorList.add (_toError ("XHE/Header/FromParty/PartyIdentification/ID/schemaID",
                                        EDBNAllianceXHEDocumentReadError.INVALID_FROM_PARTY_SCHEMA_ID,
                                        sScheme));
            }

            // Check from party id value
            final String sValue = aFromPartyID.getValue ();
            if (!isValidFromPartyValue (sScheme, sValue))
            {
              aErrorList.add (_toError ("XHE/Header/FromParty/PartyIdentification/ID",
                                        EDBNAllianceXHEDocumentReadError.INVALID_FROM_PARTY_VALUE,
                                        sValue));
            }
            else
            {
              final IParticipantIdentifier aPID = m_aIdentifierFactory.createParticipantIdentifier (sScheme, sValue);
              if (aPID == null)
                aErrorList.add (_toError ("XHE/Header/FromParty/PartyIdentification/ID",
                                          EDBNAllianceXHEDocumentReadError.INVALID_FROM_PARTY_VALUE,
                                          CIdentifier.getURIEncoded (sScheme, sValue)));
            }
          }
        }

        // Check to party
        final int nToPartyCount = aHeader.getToPartyCount ();
        if (nToPartyCount != 1)
          aErrorList.add (_toError ("XHE/Header/ToParty",
                                    EDBNAllianceXHEDocumentReadError.INVALID_TO_PARTY_COUNT,
                                    Integer.toString (nToPartyCount)));

        if (nToPartyCount > 0)
        {
          final XHE10PartyType nToParty = aHeader.getToPartyAtIndex (0);
          final int nFromPartyIdentificationCount = nToParty.getPartyIdentificationCount ();
          if (nFromPartyIdentificationCount != 1)
            aErrorList.add (_toError ("XHE/Header/ToParty/PartyIdentification",
                                      EDBNAllianceXHEDocumentReadError.INVALID_TO_PARTY_IDENTIFICATION_COUNT,
                                      Integer.toString (nFromPartyIdentificationCount)));

          if (nFromPartyIdentificationCount > 0)
          {
            final XHE10IDType aToPartyID = nToParty.getPartyIdentificationAtIndex (0).getID ();
            final String sScheme = aToPartyID.getSchemeID ();
            if (!isValidToPartySchemaID (sScheme))
            {
              aErrorList.add (_toError ("XHE/Header/ToParty/PartyIdentification/ID/schemaID",
                                        EDBNAllianceXHEDocumentReadError.INVALID_TO_PARTY_SCHEMA_ID,
                                        sScheme));
            }

            // Check to party id value
            final String sValue = aToPartyID.getValue ();
            if (!isValidToPartyValue (sScheme, sValue))
            {
              aErrorList.add (_toError ("XHE/Header/ToParty/PartyIdentification/ID",
                                        EDBNAllianceXHEDocumentReadError.INVALID_TO_PARTY_VALUE,
                                        sValue));
            }
            else
            {
              final IParticipantIdentifier aPID = m_aIdentifierFactory.createParticipantIdentifier (sScheme, sValue);
              if (aPID == null)
                aErrorList.add (_toError ("XHE/Header/ToParty/PartyIdentification/ID",
                                          EDBNAllianceXHEDocumentReadError.INVALID_TO_PARTY_VALUE,
                                          CIdentifier.getURIEncoded (sScheme, sValue)));
            }
          }
        }
      }
    }

    // Check Payloads
    final List  aPayloadList = aPayloads.getPayload ();
    int nPayload = 1;
    for (final XHE10PayloadType aPayload : aPayloadList)
    {

      // ID is mandatory
      final String sPayloadID = aPayload.getIDValue ();
      if (!isValidPayloadIDValue (sPayloadID))
        aErrorList.add (_toError ("XHE/Payloads/Payload[" + nPayload + "]/ID",
                                  EDBNAllianceXHEDocumentReadError.INVALID_PAYLOAD_ID_VALUE,
                                  sPayloadID));

      // Check content type code
      {
        final XHE10ContentTypeCodeType aContentTypeCode = aPayload.getContentTypeCode ();

        final String sContentTypeCodeListID = aContentTypeCode.getListID ();
        if (sContentTypeCodeListID != null && !isValidContentTypeCodeListID (sContentTypeCodeListID))
          aErrorList.add (_toError ("XHE/Payloads/Payload[" + nPayload + "]/ContentTypeCode/listID",
                                    EDBNAllianceXHEDocumentReadError.INVALID_CONTENT_TYPE_CODE_LIST_ID,
                                    sContentTypeCodeListID));

        // Content type code values is mandatory
        final String sContentTypeCodeValue = aContentTypeCode.getValue ();
        if (!isValidContentTypeCodeValue (sContentTypeCodeListID, sContentTypeCodeValue))
          aErrorList.add (_toError ("XHE/Payloads/Payload[" + nPayload + "]/ContentTypeCode",
                                    EDBNAllianceXHEDocumentReadError.INVALID_CONTENT_TYPE_CODE_VALUE,
                                    sContentTypeCodeValue));
      }

      // Check instance encription indicator
      final XHE10InstanceEncryptionIndicatorType aInstanceEncryptionIndicator = aPayload.getInstanceEncryptionIndicator ();
      if (aInstanceEncryptionIndicator == null)
        aErrorList.add (_toError ("XHE/Payloads/Payload[" + nPayload + "]/InstanceEncryptionIndicator",
                                  EDBNAllianceXHEDocumentReadError.INSTANCE_ENCRYPTION_INDICATOR_MISSING));

      // Extract the payload content (business message) - cannot be null and
      // must be an
      // Element!
      final Element aPayloadContent = (Element) aPayload.getPayloadContent ();
      if (!isValidBusinessMessage (aPayloadContent))
        aErrorList.add (_toError (null, EDBNAllianceXHEDocumentReadError.INVALID_BUSINESS_MESSAGE));

      nPayload++;
    }
  }

  /**
   * Extract the document data from the Standard Business Document represents by
   * the passed parameter. Eventually value checks are performed if
   * {@link #isPerformValueChecks()} is true.
   *
   * @param aXHE
   *        The xhe object to read from. May not be null.
   * @param aPayloads
   *        The list of DBNAlliance payload to extract data from. May not be
   *        null.
   * @return The document data and never null.
   * @throws DBNAllianceXHEDocumentReadException
   *         In case the passed Exchange Header Envelope does not conform to the
   *         DBNAlliance rules.
   */
  @Nonnull
  public DBNAllianceXHEData extractData (@Nonnull final XHE10XHEType aXHE,
                                         @Nonnull final XHE10PayloadsType aPayloads) throws DBNAllianceXHEDocumentReadException
  {
    ValueEnforcer.notNull (aXHE, "ExchangeHeaderEnvelope");
    ValueEnforcer.notNull (aPayloads, "Payloads");

    if (isPerformValueChecks ())
    {
      // Validate data
      final ErrorList aErrorList = new ErrorList ();
      validateData (aXHE, aPayloads, aErrorList);
      final int nErrors = aErrorList.getErrorCount ();
      if (nErrors > 0)
      {
        // Collect all errors
        final StringBuilder aErrorMsgSB = new StringBuilder ();

        aErrorList.forEach (x -> {
          if (x.isError ())
          {
            final String sMsg = x.getAsStringLocaleIndepdent ();
            LOGGER.error ("DBNAlliance XHE validation " + sMsg);
            if (aErrorMsgSB.length () > 0)
              aErrorMsgSB.append ('\n');
            aErrorMsgSB.append (sMsg);
          }
        });

        // Find an error code
        final IError aFirst = aErrorList.findFirst (IHasErrorLevel::isError);
        final EDBNAllianceXHEDocumentReadError eError = EDBNAllianceXHEDocumentReadError.getFromIDOrDefault (aFirst.getErrorID (),
                                                                                                             EDBNAllianceXHEDocumentReadError.GENERIC_XHE_ERROR);
        throw new DBNAllianceXHEDocumentReadException (aErrorMsgSB.toString (), eError);
      }
    }

    return extractDataUnchecked (aXHE, aPayloads);
  }

  /**
   * Extract the document data from the Standard Business Document represents by
   * the passed parameter without any value checks. This might be handy, if
   * value checks were executed separately.
   *
   * @param aXHE
   *        The header object to read from. May not be null.
   * @param aPayloads
   *        The list of DBNAlliance payload to extract data from. May not be
   *        null.
   * @return The document data and never null.
   */
  @Nonnull
  public DBNAllianceXHEData extractDataUnchecked (@Nonnull final XHE10XHEType aXHE,
                                                  @Nonnull final XHE10PayloadsType aPayloads)
  {
    ValueEnforcer.notNull (aXHE, "ExchangeHeaderEnvelope");
    ValueEnforcer.notNull (aPayloads, "Payloads");
    final DBNAllianceXHEData ret = new DBNAllianceXHEData (m_aIdentifierFactory);

    // Check Header
    {
      final XHE10HeaderType aHeader = aXHE.getHeader ();
      if (aHeader != null)
      {
        ret.setID (aHeader.getIDValue ());
        ret.setCreationDateAndTime (aHeader.getCreationDateTimeValue ());

        // From Party
        {
          final XHE10PartyType aFromParty = aHeader.getFromParty ();
          if (aFromParty != null && aFromParty.hasPartyIdentificationEntries ())
          {
            final XHE10IDType aFromPartyID = aFromParty.getPartyIdentificationAtIndex (0).getID ();
            ret.setFromParty (aFromPartyID.getSchemeID (), aFromPartyID.getValue ());
          }
        }

        // To Party
        {
          if (aHeader.hasToPartyEntries ())
          {
            final XHE10PartyType aToParty = aHeader.getToPartyAtIndex (0);
            if (aToParty.hasPartyIdentificationEntries ())
            {
              final XHE10IDType aToPartyID = aToParty.getPartyIdentificationAtIndex (0).getID ();
              ret.setFromParty (aToPartyID.getSchemeID (), aToPartyID.getValue ());
            }
          }
        }
      }
    }

    // Check Payloads
    {
      final List  aXHEPayloads = aPayloads.getPayload ();
      for (final XHE10PayloadType aXHEPayload : aXHEPayloads)
      {
        final DBNAlliancePayload aPayload = new DBNAlliancePayload (m_aIdentifierFactory);
        if (aXHEPayload.hasDescriptionEntries ())
          aPayload.setDescription (aXHEPayload.getDescriptionAtIndex (0).getValue ());

        // Check content type code
        final XHE10ContentTypeCodeType aContentTypeCode = aXHEPayload.getContentTypeCode ();
        if (aContentTypeCode != null)
          aPayload.setContentTypeCode (aContentTypeCode.getListID (), aContentTypeCode.getValue ());

        // Check customization id
        final XHE10CustomizationIDType aCustomizationID = aXHEPayload.getCustomizationID ();
        if (aCustomizationID != null)
          aPayload.setCustomizationID (aCustomizationID.getSchemeID (), aCustomizationID.getValue ());

        // Check profile id
        final XHE10ProfileIDType aProfileID = aXHEPayload.getProfileID ();
        if (aProfileID != null)
          aPayload.setProfileID (aProfileID.getSchemeID (), aProfileID.getValue ());

        final XHE10InstanceEncryptionIndicatorType aInstanceEncryptionIndicator = aXHEPayload.getInstanceEncryptionIndicator ();
        if (aInstanceEncryptionIndicator != null)
          aPayload.setInstanceEncryptionIndicator (aInstanceEncryptionIndicator.isValue ());

        final XHE10InstanceEncryptionMethodType aInstanceEncryptionMethod = aXHEPayload.getInstanceEncryptionMethod ();
        if (aInstanceEncryptionMethod != null)
          aPayload.setInstanceEncryptionMethod (aInstanceEncryptionMethod.getValue ());

        final XHE10PayloadContentType aPayloadContent = aXHEPayload.getPayloadContent ();
        if (aPayloadContent != null)
          aPayload.setPayloadContent ((Element) aPayloadContent);

        ret.addPayload (aPayload);

      }
    }

    return ret;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy