001    package org.junit.rules;
002    
003    import java.util.ArrayList;
004    import java.util.Collections;
005    import java.util.List;
006    
007    import org.junit.runner.Description;
008    import org.junit.runners.model.Statement;
009    
010    /**
011     * The RuleChain rule allows ordering of TestRules. You create a
012     * {@code RuleChain} with {@link #outerRule(TestRule)} and subsequent calls of
013     * {@link #around(TestRule)}:
014     *
015     * <pre>
016     * public class UseRuleChain {
017     *      &#064;Rule
018     *      public RuleChain chain= RuleChain
019     *                             .outerRule(new LoggingRule("outer rule"))
020     *                             .around(new LoggingRule("middle rule"))
021     *                             .around(new LoggingRule("inner rule"));
022     *
023     *      &#064;Test
024     *      public void example() {
025     *              assertTrue(true);
026     *     }
027     * }
028     * </pre>
029     *
030     * writes the log
031     *
032     * <pre>
033     * starting outer rule
034     * starting middle rule
035     * starting inner rule
036     * finished inner rule
037     * finished middle rule
038     * finished outer rule
039     * </pre>
040     * 
041     * {@code RuleChain} cannot be used to define the order of existing rules.
042     * For example in the below snippet the LoggingRule {@code middle} would be
043     * executed outside as well as inside the {@code RuleChain}:
044     *
045     * <pre>
046     * &#064;Rule
047     * public LoggingRule middle = new LoggingRule("middle rule");
048     * 
049     * &#064;Rule
050     * public RuleChain chain = RuleChain
051     *                          .outerRule(new LoggingRule("outer rule"))
052     *                          .around(middle)
053     *                          .around(new LoggingRule("inner rule"));
054     * </pre>
055     *
056     * @deprecated Since 4.13 ordering of rules can be naturally specified with an annotation attribute.
057     * @see org.junit.Rule#order()
058     * @see org.junit.ClassRule#order()
059     * @since 4.10
060     */
061    @Deprecated
062    public class RuleChain implements TestRule {
063        private static final RuleChain EMPTY_CHAIN = new RuleChain(
064                Collections.<TestRule>emptyList());
065    
066        private List<TestRule> rulesStartingWithInnerMost;
067    
068        /**
069         * Returns a {@code RuleChain} without a {@link TestRule}. This method may
070         * be the starting point of a {@code RuleChain}.
071         *
072         * @return a {@code RuleChain} without a {@link TestRule}.
073         */
074        public static RuleChain emptyRuleChain() {
075            return EMPTY_CHAIN;
076        }
077    
078        /**
079         * Returns a {@code RuleChain} with a single {@link TestRule}. This method
080         * is the usual starting point of a {@code RuleChain}.
081         *
082         * @param outerRule the outer rule of the {@code RuleChain}.
083         * @return a {@code RuleChain} with a single {@link TestRule}.
084         */
085        public static RuleChain outerRule(TestRule outerRule) {
086            return emptyRuleChain().around(outerRule);
087        }
088    
089        private RuleChain(List<TestRule> rules) {
090            this.rulesStartingWithInnerMost = rules;
091        }
092    
093        /**
094         * Create a new {@code RuleChain}, which encloses the given {@link TestRule} with
095         * the rules of the current {@code RuleChain}.
096         *
097         * @param enclosedRule the rule to enclose; must not be {@code null}.
098         * @return a new {@code RuleChain}.
099         * @throws NullPointerException if the argument {@code enclosedRule} is {@code null}
100         */
101        public RuleChain around(TestRule enclosedRule) {
102            if (enclosedRule == null) {
103                throw new NullPointerException("The enclosed rule must not be null");
104            }
105            List<TestRule> rulesOfNewChain = new ArrayList<TestRule>();
106            rulesOfNewChain.add(enclosedRule);
107            rulesOfNewChain.addAll(rulesStartingWithInnerMost);
108            return new RuleChain(rulesOfNewChain);
109        }
110    
111        /**
112         * {@inheritDoc}
113         */
114        public Statement apply(Statement base, Description description) {
115            return new RunRules(base, rulesStartingWithInnerMost, description);
116        }
117    }