/** {@link IDataUpgrader} implementations to delegate upgrade operations to. */
  @Autowired(required = false)
  public void setDataUpgraders(Collection<IDataUpgrader> dataUpgraders) {
    final Map<PortalDataKey, IDataUpgrader> dataUpgraderMap =
        new LinkedHashMap<PortalDataKey, IDataUpgrader>();

    for (final IDataUpgrader dataUpgrader : dataUpgraders) {

      try {

        final Set<PortalDataKey> upgradeDataKeys = dataUpgrader.getSourceDataTypes();
        for (final PortalDataKey upgradeDataKey : upgradeDataKeys) {
          this.logger.debug(
              "Registering IDataUpgrader for '{}' - {}", upgradeDataKey, dataUpgrader);
          final IDataUpgrader existing = dataUpgraderMap.put(upgradeDataKey, dataUpgrader);
          if (existing != null) {
            this.logger.warn(
                "Duplicate IDataUpgrader PortalDataKey for {} Replacing {} with {}",
                new Object[] {upgradeDataKey, existing, dataUpgrader});
          }
        }

      } catch (Exception exception) {
        logger.error("Failed to register data upgrader {}.", dataUpgrader, exception);
      }
    }

    this.portalDataUpgraders = Collections.unmodifiableMap(dataUpgraderMap);
  }
  /** Run the import/update process on the data */
  protected final void importOrUpgradeData(
      String systemId, PortalDataKey portalDataKey, XMLEventReader xmlEventReader) {
    // See if there is a registered importer for the data, if so import
    final IDataImporter<Object> dataImporterExporter = this.portalDataImporters.get(portalDataKey);
    if (dataImporterExporter != null) {
      this.logger.debug("Importing: {}", getPartialSystemId(systemId));
      final Object data = unmarshallData(xmlEventReader, dataImporterExporter);
      dataImporterExporter.importData(data);
      this.logger.info("Imported : {}", getPartialSystemId(systemId));
      return;
    }

    // No importer, see if there is an upgrader, if so upgrade
    final IDataUpgrader dataUpgrader = this.portalDataUpgraders.get(portalDataKey);
    if (dataUpgrader != null) {
      this.logger.debug("Upgrading: {}", getPartialSystemId(systemId));

      // Convert the StAX stream to a DOM node, due to poor JDK support for StAX with XSLT
      final Node sourceNode;
      try {
        sourceNode = xmlUtilities.convertToDom(xmlEventReader);
      } catch (XMLStreamException e) {
        throw new RuntimeException("Failed to create StAXSource from original XML reader", e);
      }
      final DOMSource source = new DOMSource(sourceNode);

      final DOMResult result = new DOMResult();
      final boolean doImport = dataUpgrader.upgradeData(source, result);
      if (doImport) {
        // If the upgrader didn't handle the import as well wrap the result DOM in a new Source and
        // start the import process over again
        final org.w3c.dom.Node node = result.getNode();
        final PortalDataKey upgradedPortalDataKey = new PortalDataKey(node);
        if (this.logger.isTraceEnabled()) {
          this.logger.trace(
              "Upgraded: "
                  + getPartialSystemId(systemId)
                  + " to "
                  + upgradedPortalDataKey
                  + "\n\nSource XML: \n"
                  + XmlUtilitiesImpl.toString(source.getNode())
                  + "\n\nResult XML: \n"
                  + XmlUtilitiesImpl.toString(node));
        } else {
          this.logger.info(
              "Upgraded: {} to {}", getPartialSystemId(systemId), upgradedPortalDataKey);
        }
        final DOMSource upgradedSource = new DOMSource(node, systemId);
        this.importData(upgradedSource, upgradedPortalDataKey);
      } else {
        this.logger.info("Upgraded and Imported: {}", getPartialSystemId(systemId));
      }
      return;
    }

    // No importer or upgrader found, fail
    throw new IllegalArgumentException(
        "Provided data "
            + portalDataKey
            + " has no registered importer or upgrader support: "
            + systemId);
  }