ExecutionDecoratorStack { public Runnable createWrappedRunnable(Runnable r) { if (decorators.isEmpty()) { return r; } synchronized (decorators) { Runnable outerRunnable = r; for (ExecutionDecorator decorator : decorators) { final Runnable innerRunnable = outerRunnable; outerRunnable = () -> { decorator.wrapExecution(innerRunnable); }; } return outerRunnable; } }  void addOuterDecorator(ExecutionDecorator decorator); void addInnerDecorator(ExecutionDecorator decorator); void removeDecorator(ExecutionDecorator decorator); Runnable createWrappedRunnable(Runnable r);  }
@Test public void createWrappedRunnable() { ExecutionDecoratorStack stack = new ExecutionDecoratorStack(); final List<String> invocationTraces = new ArrayList<>(); ExecutionDecorator decorator1 = createDecorator(invocationTraces, "before 1", "after 1"); ExecutionDecorator decorator2 = createDecorator(invocationTraces, "before 2", "after 2"); ExecutionDecorator decorator3 = createDecorator(invocationTraces, "before 3", "after 3"); stack.addOuterDecorator(decorator1); stack.addOuterDecorator(decorator2); stack.addOuterDecorator(decorator3); stack.createWrappedRunnable(() -> invocationTraces.add("actual execution")) .run(); Assertions.assertThat(invocationTraces).containsExactly( "before 3", "before 2", "before 1", "actual execution", "after 1", "after 2", "after 3" ); }