@Override
  public String invokeIncidentSearchRequest(
      IncidentSearchRequest incidentSearchRequest, String federatedQueryID, Element samlToken)
      throws Exception {

    if (allowQueriesWithoutSAMLToken) {
      if (samlToken == null) {
        // Add SAML token to request call
        samlToken =
            SAMLTokenUtils.createStaticAssertionAsElement(
                "https://idp.ojbc-local.org:9443/idp/shibboleth",
                SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS,
                SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA1,
                true,
                true,
                null);
      }
    }

    if (samlToken == null) {
      throw new Exception("No SAML token provided. Unable to perform query.");
    }

    // POJO to XML Request
    // When multiple operations are supported, we will call the appropriate POJO to XML Method
    Document incidentRequestPayload =
        RequestMessageBuilderUtilities.createIncidentSearchRequest(
            incidentSearchRequest, cityTownCodelistNamespace, cityTownCodelistElementName);

    incidentRequestPayload.normalizeDocument();

    log.debug(OJBUtils.getStringFromDocument(incidentRequestPayload));

    // Create exchange
    Exchange senderExchange = new DefaultExchange(camelContext, ExchangePattern.InOnly);

    // Set exchange body to XML Request message
    senderExchange.getIn().setBody(incidentRequestPayload);

    // Set reply to and WS-Addressing message ID
    senderExchange.getIn().setHeader("federatedQueryRequestGUID", federatedQueryID);
    senderExchange.getIn().setHeader("WSAddressingReplyTo", this.getReplyToAddress());

    // Set the token header so that CXF can retrieve this on the outbound call
    String tokenID = senderExchange.getExchangeId();
    senderExchange.getIn().setHeader("tokenID", tokenID);
    OJBSamlMap.putToken(tokenID, samlToken);

    incidentSearchMessageProcessor.sendResponseMessage(camelContext, senderExchange);

    // Put message ID and "noResponse" place holder.
    putRequestInMap(federatedQueryID);

    String response = pollMap(federatedQueryID);

    if (response.length() > 500) {
      log.debug("Here is the response (truncated): " + response.substring(0, 500));
    } else {
      log.debug("Here is the response: " + response);
    }

    // This is a defensive check in case the polling completes and the service has not yet returned
    // a response
    // In this case we send back an empty search result
    if (response.equals(NO_RESPONSE)) {
      log.debug("Endpoints timed out and no response recieved at web app, create error response");
      response = MergeNotificationErrorProcessor.returnMergeNotificationErrorMessage();
    }

    // return response here
    return response;
  }
  @SuppressWarnings({"unchecked", "rawtypes"})
  public void aggregateMergedMessageWithErrorResponses(Exchange groupedExchange) throws Exception {
    // Get the grouped exchanged consisting of the aggregated search results and merged results
    List<Exchange> grouped = groupedExchange.getProperty(Exchange.GROUPED_EXCHANGE, List.class);

    boolean responseHasErrors = false;
    Document erResponseBodyDocument = null;
    Document psResultsBeforeER = null;

    for (Exchange exchange : grouped) {
      // This is the original exchange, it contains the aggregated response message before the
      // Person Search to ER XSLT
      if (grouped.indexOf(exchange) == 0) {
        String messageID = (String) exchange.getIn().getHeader("federatedQueryRequestGUID");

        // The new grouped exchange does not get the message headers from the original exchange so
        // we manually copy the message ID
        groupedExchange.getIn().setHeader("federatedQueryRequestGUID", messageID);

        // Get header to see if we have error nodes.  This is the exchange before calling ER so it
        // has these headers, subsequent exchanges do not.
        String errorResponseNodeCountString =
            (String) exchange.getIn().getHeader("errorResponseNodeCount");

        Integer errorResponseNodeCount = null;

        if (errorResponseNodeCountString != null) {
          errorResponseNodeCount = Integer.valueOf(errorResponseNodeCountString);
        } else {
          errorResponseNodeCount = 0;
        }

        if (errorResponseNodeCount > 0) {
          responseHasErrors = true;
          String aggregatedResponse = (String) exchange.getIn().getBody();

          // Load up the aggregated results into a document
          psResultsBeforeER = OJBUtils.loadXMLFromString(aggregatedResponse);
        }

      }

      // This is the actual response from the ER service, it will always be exchange indexed at
      // position 1
      else {
        // Uncomment the line below to see the individual aggregated message
        // log.debug("This is the body of the exchange in the exchange group: " +
        // exchange.getIn().getBody());

        CxfPayload cxfPayload = (CxfPayload) exchange.getIn().getBody();
        List<Element> elementList = cxfPayload.getBody();

        erResponseBodyDocument = elementList.get(0).getOwnerDocument();
      }
    }

    // The ER service did not return with an actual response, it is down or has timed out.  Set a
    // static error response and return.
    if (erResponseBodyDocument == null) {
      String returnMessage =
          MergeNotificationErrorProcessor.returnMergeNotificationErrorMessageEntityResolution();
      groupedExchange.getIn().setBody(returnMessage);
      return;
    }

    // If we have errors, splice them into the response
    if (responseHasErrors) {
      log.debug("Response has errors, splice them in here");

      NodeList list =
          psResultsBeforeER.getElementsByTagNameNS(
              "http://ojbc.org/IEPD/Extensions/SearchResultsMetadata/1.0", "SearchResultsMetadata");
      Element searchResultsMetadataElement =
          (Element) erResponseBodyDocument.importNode(list.item(0), true);

      Element searchResultsMetadataCollectionElement =
          erResponseBodyDocument.createElementNS(
              "http://nij.gov/IEPD/Exchange/EntityMergeResultMessage/1.0",
              "SearchResultsMetadataCollection");
      searchResultsMetadataCollectionElement.appendChild(searchResultsMetadataElement);

      erResponseBodyDocument.getFirstChild().appendChild(searchResultsMetadataCollectionElement);
    }

    // Set the response
    groupedExchange.getIn().setBody(erResponseBodyDocument);
  }