001    package org.junit.rules;
002    
003    import java.util.ArrayList;
004    import java.util.List;
005    
006    import org.junit.runner.Description;
007    import org.junit.runners.model.MultipleFailureException;
008    import org.junit.runners.model.Statement;
009    
010    /**
011     * A base class for Rules (like TemporaryFolder) that set up an external
012     * resource before a test (a file, socket, server, database connection, etc.),
013     * and guarantee to tear it down afterward:
014     *
015     * <pre>
016     * public static class UsesExternalResource {
017     *  Server myServer= new Server();
018     *
019     *  &#064;Rule
020     *  public ExternalResource resource= new ExternalResource() {
021     *      &#064;Override
022     *      protected void before() throws Throwable {
023     *          myServer.connect();
024     *         };
025     *
026     *      &#064;Override
027     *      protected void after() {
028     *          myServer.disconnect();
029     *         };
030     *     };
031     *
032     *  &#064;Test
033     *  public void testFoo() {
034     *      new Client().run(myServer);
035     *     }
036     * }
037     * </pre>
038     *
039     * @since 4.7
040     */
041    public abstract class ExternalResource implements TestRule {
042        public Statement apply(Statement base, Description description) {
043            return statement(base);
044        }
045    
046        private Statement statement(final Statement base) {
047            return new Statement() {
048                @Override
049                public void evaluate() throws Throwable {
050                    before();
051    
052                    List<Throwable> errors = new ArrayList<Throwable>();
053                    try {
054                        base.evaluate();
055                    } catch (Throwable t) {
056                        errors.add(t);
057                    } finally {
058                        try {
059                            after();
060                        } catch (Throwable t) {
061                            errors.add(t);
062                        }
063                    }
064                    MultipleFailureException.assertEmpty(errors);
065                }
066            };
067        }
068    
069        /**
070         * Override to set up your specific external resource.
071         *
072         * @throws Throwable if setup fails (which will disable {@code after}
073         */
074        protected void before() throws Throwable {
075            // do nothing
076        }
077    
078        /**
079         * Override to tear down your specific external resource.
080         */
081        protected void after() {
082            // do nothing
083        }
084    }