Example #1
0
  public static List<ErrorLogger.ErrorObject> conformVirtualTracksInCPL(
      PayloadRecord cplPayloadRecord,
      List<PayloadRecord> essencesHeaderPartitionPayloads,
      boolean conformAllVirtualTracks)
      throws IOException {

    IMFErrorLogger imfErrorLogger = new IMFErrorLoggerImpl();
    List<PayloadRecord> essencesHeaderPartition =
        Collections.unmodifiableList(essencesHeaderPartitionPayloads);

    try {
      imfErrorLogger.addAllErrors(validateCPL(cplPayloadRecord));
      if (imfErrorLogger.hasFatalErrors())
        return Collections.unmodifiableList(imfErrorLogger.getErrors());

      Composition composition =
          new Composition(new ByteArrayByteRangeProvider(cplPayloadRecord.getPayload()));

      imfErrorLogger.addAllErrors(validateIMFTrackFileHeaderMetadata(essencesHeaderPartition));

      List<HeaderPartitionTuple> headerPartitionTuples = new ArrayList<>();
      for (PayloadRecord payloadRecord : essencesHeaderPartition) {
        if (payloadRecord.getPayloadAssetType()
            != PayloadRecord.PayloadAssetType.EssencePartition) {
          imfErrorLogger.addError(
              IMFErrorLogger.IMFErrors.ErrorCodes.IMF_MASTER_PACKAGE_ERROR,
              IMFErrorLogger.IMFErrors.ErrorLevels.FATAL,
              String.format(
                  "Payload asset type is %s, expected asset type %s",
                  payloadRecord.getPayloadAssetType(),
                  PayloadRecord.PayloadAssetType.EssencePartition.toString()));
          continue;
        }
        headerPartitionTuples.add(
            new HeaderPartitionTuple(
                new HeaderPartition(
                    new ByteArrayDataProvider(payloadRecord.getPayload()),
                    0L,
                    (long) payloadRecord.getPayload().length,
                    imfErrorLogger),
                new ByteArrayByteRangeProvider(payloadRecord.getPayload())));
      }

      if (imfErrorLogger.hasFatalErrors()) {
        return imfErrorLogger.getErrors();
      }

      imfErrorLogger.addAllErrors(
          composition.conformVirtualTracksInComposition(
              Collections.unmodifiableList(headerPartitionTuples), conformAllVirtualTracks));

      imfErrorLogger.addAllErrors(composition.getErrors());
    } catch (IMFException e) {
      imfErrorLogger.addAllErrors(e.getErrors());
    }

    return imfErrorLogger.getErrors();
  }
Example #2
0
  /**
   * A stateless method that validates an IMFEssenceComponent's header partition and verifies MXF
   * OP1A and IMF compliance. This could be utilized to perform preliminary validation of IMF
   * essences
   *
   * @param essencesHeaderPartitionPayloads - a list of IMF Essence Component header partition
   *     payloads
   * @return a list of errors encountered while performing compliance checks on the IMF Essence
   *     Component Header partition
   * @throws IOException - any I/O related error is exposed through an IOException
   */
  public static List<ErrorLogger.ErrorObject> validateIMFTrackFileHeaderMetadata(
      List<PayloadRecord> essencesHeaderPartitionPayloads) throws IOException {
    IMFErrorLogger imfErrorLogger = new IMFErrorLoggerImpl();
    List<PayloadRecord> essencesHeaderPartition =
        Collections.unmodifiableList(essencesHeaderPartitionPayloads);
    for (PayloadRecord payloadRecord : essencesHeaderPartition) {
      if (payloadRecord.getPayloadAssetType() != PayloadRecord.PayloadAssetType.EssencePartition) {
        imfErrorLogger.addError(
            IMFErrorLogger.IMFErrors.ErrorCodes.IMP_VALIDATOR_PAYLOAD_ERROR,
            IMFErrorLogger.IMFErrors.ErrorLevels.FATAL,
            String.format(
                "Payload asset type is %s, expected asset type %s",
                payloadRecord.getPayloadAssetType(),
                PayloadRecord.PayloadAssetType.EssencePartition.toString()));
        continue;
      }
      HeaderPartition headerPartition = null;
      try {
        headerPartition =
            new HeaderPartition(
                new ByteArrayDataProvider(payloadRecord.getPayload()),
                0L,
                (long) payloadRecord.getPayload().length,
                imfErrorLogger);

        MXFOperationalPattern1A.HeaderPartitionOP1A headerPartitionOP1A =
            MXFOperationalPattern1A.checkOperationalPattern1ACompliance(
                headerPartition, imfErrorLogger);
        IMFConstraints.checkIMFCompliance(headerPartitionOP1A, imfErrorLogger);
      } catch (IMFException | MXFException e) {
        if (headerPartition != null) {
          Preface preface = headerPartition.getPreface();
          GenericPackage genericPackage =
              preface.getContentStorage().getEssenceContainerDataList().get(0).getLinkedPackage();
          SourcePackage filePackage = (SourcePackage) genericPackage;
          UUID packageUUID = filePackage.getPackageMaterialNumberasUUID();
          imfErrorLogger.addError(
              new ErrorLogger.ErrorObject(
                  IMFErrorLogger.IMFErrors.ErrorCodes.IMF_ESSENCE_COMPONENT_ERROR,
                  IMFErrorLogger.IMFErrors.ErrorLevels.FATAL,
                  String.format(
                      "IMFTrackFile with ID %s has fatal errors", packageUUID.toString())));
        }
        if (e instanceof IMFException) {
          IMFException imfException = (IMFException) e;
          imfErrorLogger.addAllErrors(imfException.getErrors());
        } else if (e instanceof MXFException) {
          MXFException mxfException = (MXFException) e;
          imfErrorLogger.addAllErrors(mxfException.getErrors());
        }
      }
    }
    return imfErrorLogger.getErrors();
  }
Example #3
0
 /**
  * A stateless method that will validate an IMF AssetMap document
  *
  * @param assetMapPayload - a payload record for an AssetMap document
  * @return list of error messages encountered while validating an AssetMap document
  * @throws IOException - any I/O related error is exposed through an IOException
  */
 public static List<ErrorLogger.ErrorObject> validateAssetMap(PayloadRecord assetMapPayload)
     throws IOException {
   if (assetMapPayload.getPayloadAssetType() != PayloadRecord.PayloadAssetType.AssetMap) {
     throw new IMFException(
         String.format(
             "Payload asset type is %s, expected asset type %s",
             assetMapPayload.getPayloadAssetType(),
             PayloadRecord.PayloadAssetType.AssetMap.toString()));
   }
   try {
     AssetMap assetMap =
         new AssetMap(new ByteArrayByteRangeProvider(assetMapPayload.getPayload()));
     return assetMap.getErrors();
   } catch (IMFException e) {
     return e.getErrors();
   }
 }
Example #4
0
  /**
   * A stateless method that will validate an IMF PackingList document
   *
   * @param pkl - a payload record for a Packing List document
   * @return list of error messages encountered while validating a Packing List document
   * @throws IOException - any I/O related error is exposed through an IOException
   */
  public static List<ErrorLogger.ErrorObject> validatePKL(PayloadRecord pkl) throws IOException {
    IMFErrorLogger imfErrorLogger = new IMFErrorLoggerImpl();

    if (pkl.getPayloadAssetType() != PayloadRecord.PayloadAssetType.PackingList) {
      throw new IMFException(
          String.format(
              "Payload asset type is %s, expected asset type %s",
              pkl.getPayloadAssetType(), PayloadRecord.PayloadAssetType.PackingList.toString()),
          imfErrorLogger);
    }
    try {
      PackingList packingList = new PackingList(new ByteArrayByteRangeProvider(pkl.getPayload()));
      imfErrorLogger.addAllErrors(packingList.getErrors());
    } catch (IMFException e) {
      imfErrorLogger.addAllErrors(e.getErrors());
    }
    return imfErrorLogger.getErrors();
  }
Example #5
0
  /**
   * A stateless method that will validate an IMF Composition document
   *
   * @param cpl - a payload record for a Composition document
   * @return list of error messages encountered while validating an AssetMap document
   * @throws IOException - any I/O related error is exposed through an IOException
   */
  public static List<ErrorLogger.ErrorObject> validateCPL(PayloadRecord cpl) throws IOException {
    IMFErrorLogger imfErrorLogger = new IMFErrorLoggerImpl();
    if (cpl.getPayloadAssetType() != PayloadRecord.PayloadAssetType.CompositionPlaylist) {
      throw new IMFException(
          String.format(
              "Payload asset type is %s, expected asset type %s",
              cpl.getPayloadAssetType(),
              PayloadRecord.PayloadAssetType.CompositionPlaylist.toString()));
    }

    try {
      Composition composition = new Composition(new ByteArrayByteRangeProvider(cpl.getPayload()));
      imfErrorLogger.addAllErrors(composition.getErrors());
    } catch (IMFException e) {
      imfErrorLogger.addAllErrors(e.getErrors());
    }
    return imfErrorLogger.getErrors();
  }
Example #6
0
  private static List<ErrorLogger.ErrorObject>
      checkVirtualTrackAndEssencesHeaderPartitionPayloadRecords(
          List<VirtualTrack> virtualTracks, List<PayloadRecord> essencesHeaderPartition)
          throws IOException {
    IMFErrorLogger imfErrorLogger = new IMFErrorLoggerImpl();
    Set<UUID> trackFileIDsSet = new HashSet<>();

    for (PayloadRecord payloadRecord : essencesHeaderPartition) {
      if (payloadRecord.getPayloadAssetType() != PayloadRecord.PayloadAssetType.EssencePartition) {
        throw new IMFException(
            String.format(
                "Payload asset type is %s, expected asset type %s",
                payloadRecord.getPayloadAssetType(),
                PayloadRecord.PayloadAssetType.EssencePartition.toString()),
            imfErrorLogger);
      }
      HeaderPartition headerPartition =
          new HeaderPartition(
              new ByteArrayDataProvider(payloadRecord.getPayload()),
              0L,
              (long) payloadRecord.getPayload().length,
              imfErrorLogger);
      try {
        /**
         * Add the Top Level Package UUID to the set of TrackFileIDs, this is required to validate
         * that the essences header partition that were passed in are in fact from the constituent
         * resources of the VirtualTack
         */
        MXFOperationalPattern1A.HeaderPartitionOP1A headerPartitionOP1A =
            MXFOperationalPattern1A.checkOperationalPattern1ACompliance(
                headerPartition, imfErrorLogger);
        IMFConstraints.HeaderPartitionIMF headerPartitionIMF =
            IMFConstraints.checkIMFCompliance(headerPartitionOP1A, imfErrorLogger);
        Preface preface =
            headerPartitionIMF.getHeaderPartitionOP1A().getHeaderPartition().getPreface();
        GenericPackage genericPackage =
            preface.getContentStorage().getEssenceContainerDataList().get(0).getLinkedPackage();
        SourcePackage filePackage = (SourcePackage) genericPackage;
        UUID packageUUID = filePackage.getPackageMaterialNumberasUUID();
        trackFileIDsSet.add(packageUUID);
      } catch (IMFException | MXFException e) {
        Preface preface = headerPartition.getPreface();
        GenericPackage genericPackage =
            preface.getContentStorage().getEssenceContainerDataList().get(0).getLinkedPackage();
        SourcePackage filePackage = (SourcePackage) genericPackage;
        UUID packageUUID = filePackage.getPackageMaterialNumberasUUID();
        imfErrorLogger.addError(
            new ErrorLogger.ErrorObject(
                IMFErrorLogger.IMFErrors.ErrorCodes.IMF_ESSENCE_COMPONENT_ERROR,
                IMFErrorLogger.IMFErrors.ErrorLevels.FATAL,
                String.format("IMFTrackFile with ID %s has fatal errors", packageUUID.toString())));
        if (e instanceof IMFException) {
          IMFException imfException = (IMFException) e;
          imfErrorLogger.addAllErrors(imfException.getErrors());
        } else if (e instanceof MXFException) {
          MXFException mxfException = (MXFException) e;
          imfErrorLogger.addAllErrors(mxfException.getErrors());
        }
      }
    }

    Set<UUID> virtualTrackResourceIDsSet = new HashSet<>();
    for (Composition.VirtualTrack virtualTrack : virtualTracks) {
      if (virtualTrack instanceof IMFEssenceComponentVirtualTrack) {
        virtualTrackResourceIDsSet.addAll(
            IMFEssenceComponentVirtualTrack.class.cast(virtualTrack).getTrackResourceIds());
      } else {
        imfErrorLogger.addError(
            IMFErrorLogger.IMFErrors.ErrorCodes.IMF_ESSENCE_COMPONENT_ERROR,
            IMFErrorLogger.IMFErrors.ErrorLevels.FATAL,
            String.format(
                "VirtualTrack with TrackId %s is not an Essence Component Virtual Track",
                virtualTrack.getTrackID().toString()));
      }
    }
    /**
     * Following check ensures that the Header Partitions corresponding to all the Resources of the
     * VirtualTracks were passed in.
     */
    Set<UUID> unreferencedResourceIDsSet = new HashSet<>();
    for (UUID uuid : virtualTrackResourceIDsSet) {
      if (!trackFileIDsSet.contains(uuid)) {
        unreferencedResourceIDsSet.add(uuid);
      }
    }
    if (unreferencedResourceIDsSet.size() > 0) {
      imfErrorLogger.addError(
          new ErrorLogger.ErrorObject(
              IMFErrorLogger.IMFErrors.ErrorCodes.IMP_VALIDATOR_PAYLOAD_ERROR,
              IMFErrorLogger.IMFErrors.ErrorLevels.FATAL,
              String.format(
                  "It seems that no EssenceHeaderPartition data was passed in for "
                      + "VirtualTrack Resource Ids %s, please verify that the correct Header Partition payloads for the "
                      + "Virtual Track were passed in",
                  Utilities.serializeObjectCollectionToString(unreferencedResourceIDsSet))));
    }

    /**
     * Following check ensures that the Header Partitions corresponding to only the Resource that
     * are a part of the VirtualTracks were passed in.
     */
    Set<UUID> unreferencedTrackFileIDsSet = new HashSet<>();
    for (UUID uuid : trackFileIDsSet) {
      if (!virtualTrackResourceIDsSet.contains(uuid)) {
        unreferencedTrackFileIDsSet.add(uuid);
      }
    }
    if (unreferencedTrackFileIDsSet.size() > 0) {
      imfErrorLogger.addError(
          new ErrorLogger.ErrorObject(
              IMFErrorLogger.IMFErrors.ErrorCodes.IMP_VALIDATOR_PAYLOAD_ERROR,
              IMFErrorLogger.IMFErrors.ErrorLevels.FATAL,
              String.format(
                  "It seems that EssenceHeaderPartition data was passed in for "
                      + "Resource Ids %s which are not part of this virtual track, please verify that only the Header "
                      + "Partition payloads for the Virtual Track were passed in",
                  Utilities.serializeObjectCollectionToString(unreferencedTrackFileIDsSet))));
    }

    return imfErrorLogger.getErrors();
  }
Example #7
0
  /**
   * A stateless method that determines if 2 or more Composition documents corresponding to the same
   * title can be inferred to represent the same presentation timeline. This method is present to
   * work around current limitations in the IMF eco system wherein CPL's might not be built
   * incrementally to include all the IMF essences that are a part of the same timeline
   *
   * @param referenceCPLPayloadRecord - a payload record corresponding to a Reference Composition
   *     document, perhaps the first composition playlist document that was delivered for a
   *     particular composition.
   * @param cplPayloads - a list of payload records corresponding to each of the Composition
   *     documents that need to be verified for mergeability
   * @return a boolean indicating if the CPLs can be merged or not
   * @throws IOException - any I/O related error is exposed through an IOException
   */
  public static List<ErrorLogger.ErrorObject> isCPLMergeable(
      PayloadRecord referenceCPLPayloadRecord, List<PayloadRecord> cplPayloads) throws IOException {

    IMFErrorLogger imfErrorLogger = new IMFErrorLoggerImpl();
    List<PayloadRecord> cplPayloadRecords = Collections.unmodifiableList(cplPayloads);
    List<Composition> compositions = new ArrayList<>();
    try {
      compositions.add(
          new Composition(new ByteArrayByteRangeProvider(referenceCPLPayloadRecord.getPayload())));
    } catch (IMFException e) {
      imfErrorLogger.addAllErrors(e.getErrors());
    }

    for (PayloadRecord cpl : cplPayloadRecords) {
      try {
        compositions.add(new Composition(new ByteArrayByteRangeProvider(cpl.getPayload())));
      } catch (IMFException e) {
        imfErrorLogger.addAllErrors(e.getErrors());
      }
    }

    if (imfErrorLogger.hasFatalErrors()) {
      return imfErrorLogger.getErrors();
    }

    VirtualTrack referenceVideoVirtualTrack = compositions.get(0).getVideoVirtualTrack();
    UUID referenceCPLUUID = compositions.get(0).getUUID();
    for (int i = 1; i < compositions.size(); i++) {
      if (!referenceVideoVirtualTrack.equivalent(compositions.get(i).getVideoVirtualTrack())) {
        imfErrorLogger.addError(
            IMFErrorLogger.IMFErrors.ErrorCodes.IMF_CPL_ERROR,
            IMFErrorLogger.IMFErrors.ErrorLevels.WARNING,
            String.format(
                "CPL Id %s can't be merged with Reference CPL Id %s, since the video virtual tracks do not seem to represent the same timeline.",
                compositions.get(i).getUUID(), referenceCPLUUID));
      }
    }

    /**
     * Perform AudioTrack mergeability checks 1) Identify AudioTracks that are the same language 2)
     * Compare language tracks to see if they represent the same timeline
     */
    Boolean bAudioVirtualTrackMapFail = false;
    List<Map<Set<DOMNodeObjectModel>, ? extends VirtualTrack>> audioVirtualTracksMapList =
        new ArrayList<>();
    for (Composition composition : compositions) {
      try {
        audioVirtualTracksMapList.add(composition.getAudioVirtualTracksMap());
      } catch (IMFException e) {
        bAudioVirtualTrackMapFail = false;
        imfErrorLogger.addAllErrors(e.getErrors());
      }
    }

    if (!bAudioVirtualTrackMapFail) {
      Map<Set<DOMNodeObjectModel>, ? extends VirtualTrack> referenceAudioVirtualTracksMap =
          audioVirtualTracksMapList.get(0);
      for (int i = 1; i < audioVirtualTracksMapList.size(); i++) {
        if (!compareAudioVirtualTrackMaps(
            Collections.unmodifiableMap(referenceAudioVirtualTracksMap),
            Collections.unmodifiableMap(audioVirtualTracksMapList.get(i)),
            imfErrorLogger)) {
          imfErrorLogger.addError(
              IMFErrorLogger.IMFErrors.ErrorCodes.IMF_CPL_ERROR,
              IMFErrorLogger.IMFErrors.ErrorLevels.WARNING,
              String.format(
                  "CPL Id %s can't be merged with Reference CPL Id %s, since 2 same language audio tracks do not seem to represent the same timeline.",
                  compositions.get(i).getUUID(), referenceCPLUUID));
        }
      }
    }

    /** Perform MarkerTrack mergeability checks */
    Composition.VirtualTrack referenceMarkerVirtualTrack =
        compositions.get(0).getMarkerVirtualTrack();
    if (referenceMarkerVirtualTrack != null) {
      UUID referenceMarkerCPLUUID = compositions.get(0).getUUID();
      for (int i = 1; i < compositions.size(); i++) {
        if (!referenceVideoVirtualTrack.equivalent(compositions.get(i).getMarkerVirtualTrack())) {
          imfErrorLogger.addError(
              IMFErrorLogger.IMFErrors.ErrorCodes.IMF_CPL_ERROR,
              IMFErrorLogger.IMFErrors.ErrorLevels.WARNING,
              String.format(
                  "CPL Id %s can't be merged with Reference CPL Id %s, since the marker virtual tracks do not seem to represent the same timeline.",
                  compositions.get(i).getUUID(), referenceMarkerCPLUUID));
        }
      }
    }

    return imfErrorLogger.getErrors();
  }
Example #8
0
  /**
   * A stateless method that will validate IMF AssetMap and PackingList documents for all the data
   * that should be cross referenced by both
   *
   * @param assetMapPayload - a payload record for an AssetMap document
   * @param pklPayloads - a list of payload records for Packing List documents referenced by the
   *     AssetMap
   * @return list of error messages encountered while validating an AssetMap document
   * @throws IOException - any I/O related error is exposed through an IOException
   */
  public static List<ErrorLogger.ErrorObject> validatePKLAndAssetMap(
      PayloadRecord assetMapPayload, List<PayloadRecord> pklPayloads) throws IOException {
    IMFErrorLogger imfErrorLogger = new IMFErrorLoggerImpl();
    List<PayloadRecord> packingListPayloadRecords = Collections.unmodifiableList(pklPayloads);

    if (assetMapPayload.getPayloadAssetType() != PayloadRecord.PayloadAssetType.AssetMap) {
      imfErrorLogger.addError(
          IMFErrorLogger.IMFErrors.ErrorCodes.IMF_AM_ERROR,
          IMFErrorLogger.IMFErrors.ErrorLevels.FATAL,
          String.format(
              "Payload asset type is %s, expected asset type %s",
              assetMapPayload.getPayloadAssetType(),
              PayloadRecord.PayloadAssetType.AssetMap.toString()));
    }

    ResourceByteRangeProvider assetMapByteRangeProvider =
        new ByteArrayByteRangeProvider(assetMapPayload.getPayload());
    AssetMap assetMapObjectModel = null;
    try {
      assetMapObjectModel = new AssetMap(assetMapByteRangeProvider);
      imfErrorLogger.addAllErrors(assetMapObjectModel.getErrors());

      if (assetMapObjectModel.getPackingListAssets().size() == 0) {
        imfErrorLogger.addError(
            IMFErrorLogger.IMFErrors.ErrorCodes.IMF_AM_ERROR,
            IMFErrorLogger.IMFErrors.ErrorLevels.FATAL,
            String.format(
                "Asset map should reference atleast one PackingList, %d " + "references found",
                assetMapObjectModel.getPackingListAssets().size()));
      }
    } catch (IMFException e) {
      imfErrorLogger.addAllErrors(e.getErrors());
    }

    List<ResourceByteRangeProvider> packingLists = new ArrayList<>();
    for (PayloadRecord payloadRecord : packingListPayloadRecords) {
      if (payloadRecord.getPayloadAssetType() != PayloadRecord.PayloadAssetType.PackingList) {
        imfErrorLogger.addError(
            IMFErrorLogger.IMFErrors.ErrorCodes.IMF_MASTER_PACKAGE_ERROR,
            IMFErrorLogger.IMFErrors.ErrorLevels.FATAL,
            String.format(
                "Payload asset type is %s, expected asset type %s",
                assetMapPayload.getPayloadAssetType(),
                PayloadRecord.PayloadAssetType.PackingList.toString()));
      } else {
        packingLists.add(new ByteArrayByteRangeProvider(payloadRecord.getPayload()));
      }
    }

    if (packingLists.size() == 0) {
      imfErrorLogger.addError(
          IMFErrorLogger.IMFErrors.ErrorCodes.IMF_MASTER_PACKAGE_ERROR,
          IMFErrorLogger.IMFErrors.ErrorLevels.FATAL,
          String.format(
              "Atleast one PackingList is expected, %d were detected", packingLists.size()));
    }

    if (imfErrorLogger.hasFatalErrors()) {
      return imfErrorLogger.getErrors();
    }

    List<PackingList> packingListObjectModels = new ArrayList<>();
    for (ResourceByteRangeProvider resourceByteRangeProvider : packingLists) {
      try {
        PackingList packingList = new PackingList(resourceByteRangeProvider);
        packingListObjectModels.add(packingList);
        imfErrorLogger.addAllErrors(packingList.getErrors());
      } catch (IMFException e) {
        imfErrorLogger.addAllErrors(e.getErrors());
        return imfErrorLogger.getErrors();
      }
    }
    List<UUID> assetUUIDsAssetMapList = new ArrayList<>();
    for (AssetMap.Asset asset : assetMapObjectModel.getAssetList()) {
      assetUUIDsAssetMapList.add(asset.getUUID());
    }

    /*
            //Sort the UUIDs in the AssetMap
            assetUUIDsAssetMapList.sort(new Comparator<UUID>() {
                                        @Override
                                        public int compare(UUID o1, UUID o2) {
                                            return o1.compareTo(o2);
                                        }
                                    });
    */

    /* Collect all the assets in all of the PKLs that are a part of this IMP delivery */
    List<UUID> assetUUIDsPackingList = new ArrayList<>();
    for (PackingList packingList : packingListObjectModels) {
      assetUUIDsPackingList.add(
          packingList
              .getUUID()); // PKL's UUID is also added to this list since that should be present in
                           // the AssetMap
      for (PackingList.Asset asset : packingList.getAssets()) {
        assetUUIDsPackingList.add(asset.getUUID());
      }
    }

    /*
            //Sort the UUIDs in the PackingList
            assetUUIDsPackingList.sort(new Comparator<UUID>() {
                @Override
                public int compare(UUID o1, UUID o2) {
                    return o1.compareTo(o2);
                }
            });
    */

    /* Check to see if all the Assets referenced in the PKL are also referenced by the Asset Map */
    Set<UUID> assetUUIDsAssetMapSet = new HashSet<>(assetUUIDsAssetMapList);
    Set<UUID> assetUUIDsPKLSet = new HashSet<>(assetUUIDsPackingList);

    StringBuilder unreferencedPKLAssetsUUIDs = new StringBuilder();
    for (UUID uuid : assetUUIDsPKLSet) {
      if (!assetUUIDsAssetMapSet.contains(uuid)) {
        unreferencedPKLAssetsUUIDs.append(uuid.toString());
        unreferencedPKLAssetsUUIDs.append(", ");
      }
    }

    if (!unreferencedPKLAssetsUUIDs.toString().isEmpty()) {
      imfErrorLogger.addError(
          IMFErrorLogger.IMFErrors.ErrorCodes.IMF_AM_ERROR,
          IMFErrorLogger.IMFErrors.ErrorLevels.FATAL,
          String.format(
              "The following UUID/s %s in the Packing list are not referenced by the AssetMap.",
              unreferencedPKLAssetsUUIDs.toString()));
      return imfErrorLogger.getErrors();
    }

    /* Check if all the assets in the AssetMap that are supposed to be PKLs have the same UUIDs as the PKLs themselves */
    Set<UUID> packingListAssetsUUIDsSet = new HashSet<>();
    for (AssetMap.Asset asset : assetMapObjectModel.getPackingListAssets()) {
      packingListAssetsUUIDsSet.add(asset.getUUID());
    }
    StringBuilder unreferencedPKLUUIDs = new StringBuilder();
    for (PackingList packingList : packingListObjectModels) {
      if (!packingListAssetsUUIDsSet.contains(packingList.getUUID())) {
        unreferencedPKLUUIDs.append(packingList.getUUID());
      }
    }
    if (!unreferencedPKLUUIDs.toString().isEmpty()) {
      imfErrorLogger.addError(
          IMFErrorLogger.IMFErrors.ErrorCodes.IMF_AM_ERROR,
          IMFErrorLogger.IMFErrors.ErrorLevels.FATAL,
          String.format(
              "The following Packing lists %s are not referenced in the AssetMap",
              unreferencedPKLUUIDs.toString()));
      return imfErrorLogger.getErrors();
    }
    return imfErrorLogger.getErrors();
  }