/** 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);
  }
  protected void testXsltUpgrade(
      final Resource xslResource,
      final PortalDataKey dataKey,
      final Resource inputResource,
      final Resource expectedResultResource,
      final Resource xsdResource)
      throws Exception {

    final XmlUtilities xmlUtilities =
        new XmlUtilitiesImpl() {
          @Override
          public Templates getTemplates(Resource stylesheet)
              throws TransformerConfigurationException, IOException {
            final TransformerFactory transformerFactory = TransformerFactory.newInstance();
            return transformerFactory.newTemplates(new StreamSource(stylesheet.getInputStream()));
          }
        };

    final XsltDataUpgrader xsltDataUpgrader = new XsltDataUpgrader();
    xsltDataUpgrader.setPortalDataKey(dataKey);
    xsltDataUpgrader.setXslResource(xslResource);
    xsltDataUpgrader.setXmlUtilities(xmlUtilities);
    xsltDataUpgrader.afterPropertiesSet();

    // Create XmlEventReader (what the JaxbPortalDataHandlerService has)
    final XMLInputFactory xmlInputFactory = xmlUtilities.getXmlInputFactory();
    final XMLEventReader xmlEventReader =
        xmlInputFactory.createXMLEventReader(inputResource.getInputStream());
    final Node sourceNode = xmlUtilities.convertToDom(xmlEventReader);
    final DOMSource source = new DOMSource(sourceNode);

    final DOMResult result = new DOMResult();
    xsltDataUpgrader.upgradeData(source, result);

    // XSD Validation
    final String resultString = XmlUtilitiesImpl.toString(result.getNode());
    if (xsdResource != null) {
      final Schema schema =
          this.loadSchema(new Resource[] {xsdResource}, XMLConstants.W3C_XML_SCHEMA_NS_URI);
      final Validator validator = schema.newValidator();
      try {
        validator.validate(new StreamSource(new StringReader(resultString)));
      } catch (Exception e) {
        throw new XmlTestException(
            "Failed to validate XSLT output against provided XSD", resultString, e);
      }
    }

    XMLUnit.setIgnoreWhitespace(true);
    try {
      Diff d =
          new Diff(
              new InputStreamReader(expectedResultResource.getInputStream()),
              new StringReader(resultString));
      assertTrue("Upgraded data doesn't match expected data: " + d, d.similar());
    } catch (Exception e) {
      throw new XmlTestException(
          "Failed to assert similar between XSLT output and expected XML", resultString, e);
    } catch (Error e) {
      throw new XmlTestException(
          "Failed to assert similar between XSLT output and expected XML", resultString, e);
    }
  }