class TransformTask extends StreamBasedTask implements Context {

    @TaskAction
    void transform(final IncrementalTaskInputs incrementalTaskInputs)
            throws IOException, TransformException, InterruptedException {

        final ReferenceHolder<List<TransformInput>> consumedInputs = ReferenceHolder.empty();
        final ReferenceHolder<List<TransformInput>> referencedInputs = ReferenceHolder.empty();
        final ReferenceHolder<Boolean> isIncremental = ReferenceHolder.empty();
        final ReferenceHolder<Collection<SecondaryInput>> changedSecondaryInputs =
                ReferenceHolder.empty();

        isIncremental.setValue(transform.isIncremental() && incrementalTaskInputs.isIncremental());

        GradleTransformExecution preExecutionInfo =
                GradleTransformExecution.newBuilder()
                        .setType(AnalyticsUtil.getTransformType(transform.getClass()).getNumber())
                        .setIsIncremental(isIncremental.getValue())
                        .build();

        recorder.record(
                ExecutionType.TASK_TRANSFORM_PREPARATION,
                preExecutionInfo,
                getProject().getPath(),
                getVariantName(),
                new Recorder.Block<Void>() {
                    @Override
                    public Void call() throws Exception {

                        Map<File, Status> changedMap = Maps.newHashMap();
                        Set<File> removedFiles = Sets.newHashSet();
                        if (isIncremental.getValue()) {
                            // gather the changed files first.
                            gatherChangedFiles(
                                    getLogger(), incrementalTaskInputs, changedMap, removedFiles);

                            // and check against secondary files, which disables
                            // incremental mode.
                            isIncremental.setValue(checkSecondaryFiles(changedMap, removedFiles));
                        }

                        if (isIncremental.getValue()) {
                            // ok create temporary incremental data
                            List<IncrementalTransformInput> incInputs =
                                    createIncrementalInputs(consumedInputStreams);
                            List<IncrementalTransformInput> incReferencedInputs =
                                    createIncrementalInputs(referencedInputStreams);

                            // then compare to changed list and create final Inputs
                            if (isIncremental.setValue(
                                    updateIncrementalInputsWithChangedFiles(
                                            incInputs,
                                            incReferencedInputs,
                                            changedMap,
                                            removedFiles))) {
                                consumedInputs.setValue(convertToImmutable(incInputs));
                                referencedInputs.setValue(convertToImmutable(incReferencedInputs));
                            }
                        }

                        // at this point if we do not have incremental mode, got with
                        // default TransformInput with no inc data.
                        if (!isIncremental.getValue()) {
                            consumedInputs.setValue(
                                    computeNonIncTransformInput(consumedInputStreams));
                            referencedInputs.setValue(
                                    computeNonIncTransformInput(referencedInputStreams));
                            changedSecondaryInputs.setValue(ImmutableList.of());
                        } else {
                            // gather all secondary input changes.
                            changedSecondaryInputs.setValue(
                                    gatherSecondaryInputChanges(changedMap, removedFiles));
                        }

                        return null;
                    }
                });

        GradleTransformExecution executionInfo =
                preExecutionInfo.toBuilder().setIsIncremental(isIncremental.getValue()).build();

        recorder.record(
                ExecutionType.TASK_TRANSFORM,
                executionInfo,
                getProject().getPath(),
                getVariantName(),
                new Recorder.Block<Void>() {
                    @Override
                    public Void call() throws Exception {

                        transform.transform(
                                new TransformInvocationBuilder(TransformTask.this)
                                        .addInputs(consumedInputs.getValue())
                                        .addReferencedInputs(referencedInputs.getValue())
                                        .addSecondaryInputs(changedSecondaryInputs.getValue())
                                        .addOutputProvider(
                                                outputStream != null
                                                        ? outputStream.asOutput(
                                                                isIncremental.getValue())
                                                        : null)
                                        .setIncrementalMode(isIncremental.getValue())
                                        .build());

                        if (outputStream != null) {
                            outputStream.save();
                        }
                        return null;
                    }
                });
    }

    @Inject public  TransformTask(@NonNull WorkerExecutor workerExecutor);

}