code: public Data processPipeline(Data data) throws ProcessingStageException {
      for (ProcessingStage<Data, Data> stage : pipeline) {
        data = stage.process(data);
      }
      return data;
    }
docs: Process the {@link Data} before sending it; this runs the packet through
  each registered {@link ProcessingStage} in order.
  
  @param data the {@link Data} to process
  @return a processed {@link Data} packet; no guarantee as to whether it is
  the same instance as passed in as a parameter (and likely not).
  @throws ProcessingStageException if a pipeline stage fails