/** Accumulates fragments and passes the "big" message to the processing route. */
  @Override
  public void process(Exchange exchange) throws Exception {
    String requestString = exchange.getIn().getBody(String.class);
    Parser parser = getEndpoint().getHl7v2TransactionConfiguration().getParser();
    Message requestMessage = parser.parse(requestString);
    Terser requestTerser = new Terser(requestMessage);
    String msh14 = requestTerser.get("MSH-14");
    String dsc1 = null;
    try {
      if (!"I".equals(requestTerser.get("DSC-2"))) {
        dsc1 = requestTerser.get("DSC-1");
      }
    } catch (HL7Exception e) {
      // segment DSC does not exist in cancel requests
    }

    // pass when the message is not fragmented
    if (isEmpty(msh14) && isEmpty(dsc1)) {
      getWrappedProcessor().process(exchange);
      return;
    }

    // get pieces of the accumulator's key
    String msh31 = requestTerser.get("MSH-3-1");
    String msh32 = requestTerser.get("MSH-3-2");
    String msh33 = requestTerser.get("MSH-3-3");

    // create an accumulator (on the arrival of the first fragment)
    // or get an existing one (on the arrival of fragments 2..n)
    StringBuilder accumulator;
    if (isEmpty(msh14)) {
      accumulator = new StringBuilder();
    } else {
      accumulator = storage.getAndRemove(keyString(msh14, msh31, msh32, msh33));
      if (accumulator == null) {
        LOG.warn("Pass unknown fragment with MSH-14=={} to the route", msh14);
        getWrappedProcessor().process(exchange);
        return;
      }
    }

    // append current fragment to the accumulator
    int beginIndex = isEmpty(msh14) ? 0 : requestString.indexOf('\r');
    int endIndex = isEmpty(dsc1) ? requestString.length() : (requestString.indexOf("\rDSC") + 1);
    accumulator.append(requestString, beginIndex, endIndex);

    // DSC-1 is empty -- finish accumulation, pass message to the marshaller
    if (isEmpty(dsc1)) {
      LOG.debug("Finished fragment chain {}", msh14);
      exchange.getIn().setBody(accumulator.toString());
      getWrappedProcessor().process(exchange);
      return;
    }

    // DSC-1 is not empty -- update accumulators map, request the next fragment
    LOG.debug("Processed fragment {} requesting {}", msh14, dsc1);

    storage.put(keyString(dsc1, msh31, msh32, msh33), accumulator);
    Message ack = MessageUtils.response(requestMessage, "ACK", requestTerser.get("MSH-9-2"));
    Terser ackTerser = new Terser(ack);
    ackTerser.set("MSA-1", "CA");
    ackTerser.set("MSA-2", requestTerser.get("MSH-10"));
    Exchanges.resultMessage(exchange).setBody(parser.encode(ack));
  }