/**
   * Adds a summary message and a list of errors for each processed record that failed.
   *
   * @param context the processing context
   * @param msgBroker the message broker
   * @param resourceKey the resource key associated with the status type
   * @param statusType the sstatus type
   * @param count the count associated with the status type
   */
  private void addErrorMessages(
      ProcessingContext context,
      MessageBroker msgBroker,
      String resourceKey,
      ProcessedRecord.StatusType statusType,
      int count) {

    Object[] parameters = new Integer[] {count};
    String msg = msgBroker.retrieveMessage(resourceKey);
    msg = MessageFormat.format(msg, parameters);
    FacesMessage fm = new FacesMessage(FacesMessage.SEVERITY_ERROR, msg, null);
    msgBroker.addMessage(fm);
    for (ProcessedRecord processedRecord : context.getProcessedRecords()) {
      if (processedRecord.getStatusType().equals(statusType)
          && (processedRecord.getExceptions() != null)) {
        StringBuilder sb = new StringBuilder();
        sb.append(processedRecord.getSourceUri());
        if (processedRecord.getExceptions() != null) {
          for (String error : processedRecord.getExceptions()) {
            sb.append("<br />").append(error);
          }
        }
        fm = new FacesMessage(FacesMessage.SEVERITY_ERROR, sb.toString(), null);
        msgBroker.addMessage(fm);
      }
    }
  }
 /**
  * Adds a summary message and a list processed records for a processd status type.
  *
  * @param context the processing context
  * @param msgBroker the message broker
  * @param resourceKey the resource key associated with the status type
  * @param statusType the sstatus type
  * @param count the count associated with the status type
  */
 private void addSummaryMessage(
     ProcessingContext context,
     MessageBroker msgBroker,
     String resourceKey,
     ProcessedRecord.StatusType statusType,
     int count) {
   Object[] parameters = new Integer[] {count};
   String msg = msgBroker.retrieveMessage(resourceKey);
   msg = MessageFormat.format(msg, parameters);
   StringBuilder sb = new StringBuilder(msg);
   for (ProcessedRecord processedRecord : context.getProcessedRecords()) {
     if (processedRecord.getStatusType().equals(statusType)) {
       sb.append("<br />").append(processedRecord.getSourceUri());
     }
   }
   if (sb.length() > 0) {
     FacesMessage fm = new FacesMessage(FacesMessage.SEVERITY_INFO, sb.toString(), null);
     msgBroker.addMessage(fm);
   }
 }
  /**
   * Handles a metadata file upload action. <br>
   * This is the default entry point for a sub-class of BaseActionListener. <br>
   * This BaseActionListener handles the JSF processAction method and invokes the processSubAction
   * method of the sub-class.
   *
   * @param event the associated JSF action event
   * @param context the context associated with the active request
   * @throws AbortProcessingException if processing should be aborted
   * @throws Exception if an exception occurs
   */
  @Override
  protected void processSubAction(ActionEvent event, RequestContext context)
      throws AbortProcessingException, Exception {

    // initialize
    MessageBroker msgBroker = extractMessageBroker();
    String sFileName = "";
    String sXml = "";
    UIComponent component = event.getComponent();
    String sCommand = Val.chkStr((String) component.getAttributes().get("command"));
    boolean bValidateOnly = sCommand.equalsIgnoreCase("validate");
    boolean bIsBrowse =
        this.getSpecificationMethod().equals(UploadMetadataController.SPECIFICATIONMETHOD_BROWSE);
    String sExplicitPath = this.getExplicitPath();

    try {

      // upload a single file from disk
      if (bIsBrowse) {
        FileItem item = extractFileItem();
        if (item != null) {
          sFileName = Val.chkStr(item.getName());
          if (sFileName.length() > 0) {
            File file = new File(sFileName);
            sFileName = file.getName();
          }
          sXml = extractItemXml(item);
        }
        if (sFileName.length() > 0) {
          FacesMessage fm = new FacesMessage(FacesMessage.SEVERITY_WARN, sFileName, null);
          msgBroker.addMessage(fm);
        }

        if (sFileName.length() == 0) {
          msgBroker.addErrorMessage("publication.uploadMetadata.err.file.required");
        } else if (sXml.length() == 0) {
          msgBroker.addErrorMessage("publication.uploadMetadata.err.file.empty");
        } else if (bValidateOnly) {
          ValidationRequest request = new ValidationRequest(context, sFileName, sXml);
          request.verify();
          msgBroker.addSuccessMessage("catalog.publication.success.validated");
        } else {
          Publisher publisher = getSelectablePublishers().selectedAsPublisher(context, false);
          UploadRequest request = new UploadRequest(context, publisher, sFileName, sXml);
          request.publish();
          if (request.getPublicationRecord().getWasDocumentUnchanged()) {
            msgBroker.addSuccessMessage("publication.success.unchanged");
          } else if (request.getPublicationRecord().getWasDocumentReplaced()) {
            msgBroker.addSuccessMessage("publication.success.replaced");
          } else {
            msgBroker.addSuccessMessage("publication.success.created");
          }
        }

        // handle an empty explicit url or network path
      } else if (sExplicitPath.length() == 0) {
        msgBroker.addErrorMessage("publication.uploadMetadata.err.file.required");

        // process an explicit url or network path
      } else {
        FacesMessage fm = new FacesMessage(FacesMessage.SEVERITY_WARN, sExplicitPath, null);
        msgBroker.addMessage(fm);

        sFileName = sExplicitPath;
        Publisher publisher = getSelectablePublishers().selectedAsPublisher(context, false);
        HttpClientRequest httpClient = HttpClientRequest.newRequest();

        ProcessingContext pContext =
            new ProcessingContext(context, publisher, httpClient, null, bValidateOnly);
        pContext.setMessageBroker(msgBroker);
        ProcessorFactory factory = new ProcessorFactory();
        ResourceProcessor processor = factory.interrogate(pContext, sExplicitPath);

        if (processor == null) {
          throw new IOException("Unable to process resource.");
        }
        processor.process();
        boolean wasSingleSource = pContext.getWasSingleSource();

        // summary messages
        if (bValidateOnly) {

          if (wasSingleSource && (pContext.getNumberValidated() == 1)) {
            msgBroker.addSuccessMessage("catalog.publication.success.validated");
          } else if (pContext.getNumberValidated() > 0) {
            addSummaryMessage(
                pContext,
                msgBroker,
                "catalog.publication.uploadMetadata.summary.valid",
                ProcessedRecord.StatusType.VALIDATED,
                pContext.getNumberValidated());
          }
          if (wasSingleSource && (pContext.getNumberFailed() == 1)) {
            Exception lastException = pContext.getLastException();
            if (pContext.getLastException() != null) {
              throw lastException;
            } else {
              // TODO message here ??
            }
          } else if (pContext.getNumberFailed() > 0) {
            addErrorMessages(
                pContext,
                msgBroker,
                "catalog.publication.uploadMetadata.summary.invalid",
                ProcessedRecord.StatusType.FAILED,
                pContext.getNumberFailed());
          }
          if ((pContext.getNumberValidated() == 0) && (pContext.getNumberFailed() == 0)) {
            msgBroker.addErrorMessage(
                "catalog.publication.uploadMetadata.summary.valid", new Integer[] {0});
          }

          // publication related messages
        } else {

          if (wasSingleSource && (pContext.getNumberCreated() == 1)) {
            msgBroker.addSuccessMessage("publication.success.created");
          } else if (pContext.getNumberCreated() > 0) {
            addSummaryMessage(
                pContext,
                msgBroker,
                "catalog.publication.uploadMetadata.summary.created",
                ProcessedRecord.StatusType.CREATED,
                pContext.getNumberCreated());
          }
          if (wasSingleSource && (pContext.getNumberReplaced() == 1)) {
            msgBroker.addSuccessMessage("publication.success.replaced");
          } else if (pContext.getNumberReplaced() > 0) {
            addSummaryMessage(
                pContext,
                msgBroker,
                "catalog.publication.uploadMetadata.summary.replaced",
                ProcessedRecord.StatusType.REPLACED,
                pContext.getNumberReplaced());
          }
          if (wasSingleSource && (pContext.getNumberUnchanged() == 1)) {
            msgBroker.addSuccessMessage("publication.success.unchanged");
          } else if (pContext.getNumberUnchanged() > 0) {
            addSummaryMessage(
                pContext,
                msgBroker,
                "catalog.publication.uploadMetadata.summary.unchanged",
                ProcessedRecord.StatusType.UNCHNAGED,
                pContext.getNumberUnchanged());
          }
          if (pContext.getNumberDeleted() > 0) {
            addSummaryMessage(
                pContext,
                msgBroker,
                "catalog.publication.uploadMetadata.summary.deleted",
                ProcessedRecord.StatusType.DELETED,
                pContext.getNumberDeleted());
          }

          if (wasSingleSource && (pContext.getNumberFailed() == 1)) {
            Exception lastException = pContext.getLastException();
            if (pContext.getLastException() != null) {
              throw lastException;
            } else {
              // TODO message here ??
            }
          } else if (pContext.getNumberFailed() > 0) {
            addErrorMessages(
                pContext,
                msgBroker,
                "catalog.publication.uploadMetadata.summary.failed",
                ProcessedRecord.StatusType.FAILED,
                pContext.getNumberFailed());
          }
        }
      }

      // handle a validation exception
    } catch (ValidationException e) {

      String sKey = e.getKey();
      if (sKey.length() > 0) {
        String sMsg = sKey;
        Schema schema = context.getCatalogConfiguration().getConfiguredSchemas().get(sKey);
        if (schema != null) {
          if (schema.getLabel() != null) {
            String sResKey = schema.getLabel().getResourceKey();
            if (sResKey.length() > 0) {
              sMsg = extractMessageBroker().retrieveMessage(sResKey) + " (" + sKey + ")";
            }
          }
        }
        FacesMessage fm = new FacesMessage(FacesMessage.SEVERITY_WARN, " - " + sMsg, null);
        extractMessageBroker().addMessage(fm);
      }

      e.getValidationErrors().buildMessages(msgBroker, true);

      // handle remaining exceptions
    } catch (Exception e) {

      // there seems to be no good exception related to a file that is simply
      // not an XML file, a message containing "content is not allowed in prolog"
      // seems to be the best guess at the moment
      String sMsg = e.toString().toLowerCase();
      if (sMsg.indexOf("content is not allowed in prolog") != -1) {
        msgBroker.addErrorMessage("publication.uploadMetadata.err.file.prolog");
      } else {
        throw e;
      }
    }
  }