private Fragment insertRecorder(final String elementId,
                                    final PipelineElementType elementType,
                                    final Fragment fragment,
                                    final boolean input,
                                    final SteppingController controller,
                                    final int controllerSplitDepth) {
        Fragment result = fragment;

        // Get any filter settings that might be applied to XML output.
        SteppingFilterSettings steppingFilterSettings = null;
        if (!input) {
            steppingFilterSettings = controller.getRequest().getStepFilterSettings(elementId);
        }

        if (input) {
            final Element in = fragment.getIn();

            if (in instanceof DestinationProvider) {
                // Replace all destination providers.
                final OutputRecorder outputRecorder = elementFactory.getElementInstance(OutputRecorder.class);
                outputRecorder.setElementId(elementId);
                result = new Fragment(outputRecorder);

            } else if (in instanceof final AbstractInputElement filter) {
                final ReaderRecorder recorder = new ReaderRecorder(errorReceiverProxy);
                recorder.setElementId(elementId);
                recorder.setTarget(filter);
                result = new Fragment(recorder, fragment.getOut());

            } else if (in instanceof final AbstractReaderElement filter) {
                final ReaderRecorder recorder = new ReaderRecorder(errorReceiverProxy);
                recorder.setElementId(elementId);
                recorder.setTarget(filter);
                result = new Fragment(recorder, fragment.getOut());

            } else if (in instanceof final AbstractParser parser) {
                final ReaderRecorder recorder = new ReaderRecorder(errorReceiverProxy);
                recorder.setElementId(elementId);
                recorder.setTarget(parser);
                result = new Fragment(recorder, fragment.getOut());

            } else if (in instanceof final XMLFilter filter && elementType.hasRole(PipelineElementType.ROLE_MUTATOR)) {

                // Create stepping filter.
                final SAXEventRecorder recorder = elementFactory.getElementInstance(SAXEventRecorder.class);
                recorder.setElementId(elementId);
                recorder.setTarget(filter);

                // Initialise stepping filter settings.
                recorder.setSettings(steppingFilterSettings);

                result = new Fragment(recorder, fragment.getOut());
            }

        } else {
            final Element out = fragment.getOut();

            if (out instanceof DestinationProvider) {
                // Replace all destination providers.
                final OutputRecorder outputRecorder = elementFactory.getElementInstance(OutputRecorder.class);
                outputRecorder.setElementId(elementId);
                result = new Fragment(outputRecorder);

            } else if (out instanceof final AbstractInputElement filter) {
                final ReaderRecorder recorder = new ReaderRecorder(errorReceiverProxy);
                recorder.setElementId(elementId);
                filter.setTarget(recorder);
                result = new Fragment(fragment.getIn(), recorder);

            } else if (out instanceof final AbstractReaderElement filter) {
                final ReaderRecorder recorder = new ReaderRecorder(errorReceiverProxy);
                recorder.setElementId(elementId);
                filter.setTarget(recorder);
                result = new Fragment(fragment.getIn(), recorder);

            } else if (out instanceof final AbstractParser parser) {

                // Insert a split filter after the parser to split all XML into
                // single records.
                final SplitFilter splitFilter = elementFactory.getElementInstance(SplitFilter.class);
                splitFilter.setSplitDepth(controllerSplitDepth);
                splitFilter.setSplitCount(controller.getRequest().getStepSize());
                parser.setTarget(splitFilter);

                // Create SAX event recorder.
                final SAXEventRecorder recorder = elementFactory.getElementInstance(SAXEventRecorder.class);
                recorder.setElementId(elementId);

                splitFilter.setTarget(recorder);

                // Initialise stepping filter settings.
                recorder.setSettings(steppingFilterSettings);

                result = new Fragment(fragment.getIn(), recorder);

            } else if (out instanceof final XMLFilter filter && elementType.hasRole(PipelineElementType.ROLE_WRITER)) {

                final OutputRecorder outputRecorder = elementFactory.getElementInstance(OutputRecorder.class);
                outputRecorder.setElementId(elementId);
                ((HasTargets) filter).setTarget(outputRecorder);

                result = new Fragment(fragment.getIn(), outputRecorder);

            } else if (out instanceof final XMLFilter filter &&
                       (elementType.hasRole(PipelineElementType.ROLE_MUTATOR) ||
                        elementType.hasRole(PipelineElementType.ROLE_VALIDATOR))) {

                // Create stepping filter.
                final SAXEventRecorder recorder = elementFactory.getElementInstance(SAXEventRecorder.class);
                recorder.setElementId(elementId);
                ((HasTargets) filter).setTarget(recorder);

                // Initialise stepping filter settings.
                recorder.setSettings(steppingFilterSettings);

                result = new Fragment(fragment.getIn(), recorder);
            }
        }

        return result;
    }
Creates an appropriate input or output recorder for the supplied pipeline
fragment and modifies the fragment. If it is an input recorder then the
supplied fragment input is attached as a target of the recorder. If it is
an output recorder it is attached as the target of the supplied fragment
output.

@param elementId   The id of the element that we might be inserting a recorder
                   before or after.
@param elementType The type of the element that we might be inserting a recorder
                   before or after.
@param fragment    The current pipeline fragment we are modifying.
@param input       True if we are modifying the input element of the fragment,
                   false if we are modifying the output.
@param controller  The stepping controller.
@return A modified pipeline fragment if a recorder was added or the
original if it remains unchanged.
stroom-pipeline/src/main/java/stroom/pipeline/factory/PipelineFactory.java