ChainedListener implements InstrumentedContext.Listener { @Override public void close() throws IOException { final List<IOException> exceptions = Stream.of(first, second) .map(this::close) .filter(Optional::isPresent) .map(Optional::get) .collect(Collectors.toList()); if (!exceptions.isEmpty()) { throw exceptions.get(0); } } ChainedListener(InstrumentedContext.Listener first,
                  InstrumentedContext.Listener second,
                  Logger logger); @Override void task(Task<?> task); @Override void status(TaskId taskId, Phase phase); @Override void meta(TaskId taskId, Map<String, String> data); @Override void close();  }
@Test(expected = IOException.class) public void shouldThrowExceptionOnClose() throws IOException { doThrow(ioException).when(first).close(); verifyListenerClose(); }
@Test(expected = IOException.class) public void shouldThrowExceptionOnClose2() throws IOException { doThrow(ioException).when(second).close(); verifyListenerClose(); }
@Test(expected = IOException.class) public void shouldThrowExceptionOnClose3() throws IOException { doThrow(ioException).when(first).close(); doThrow(ioException).when(second).close(); verifyListenerClose(); }