001    package org.nakedobjects.applib.spec;
002    
003    import org.nakedobjects.applib.util.ReasonBuffer;
004    
005    
006    /**
007     * Adapter to make it easy to perform boolean algebra on {@link Specification}s.
008     * 
009     * <p>
010     * Subclasses represent the conjunction of multiple {@link Specification}s.  An 
011     * implementation should instantiate the {@link Specification}s to be satisfied 
012     * in its constructor.
013     * 
014     * <p>
015     * For example:
016     * <pre>
017     * public class TeaOrCoffeeSpec extends SpecificationOr {
018     *     public TeaOrCoffeeSpec() {
019     *         super(
020     *             new MustBeTeaSpec(), 
021     *             new MustBeCoffeeSpec()
022     *         );
023     *     }
024     * }
025     * </pre>
026     * 
027     * @see SpecificationAnd
028     * @see SpecificationNot
029     */
030    public abstract class SpecificationOr implements Specification {
031    
032        private final Specification[] specifications;
033    
034        public SpecificationOr(Specification... specifications) {
035            this.specifications = specifications;
036        }
037     
038        public String satisfies(Object obj) {
039            ReasonBuffer buf = new ReasonBuffer();
040            for(Specification specification: specifications) {
041                String reasonNotSatisfiedIfAny = specification.satisfies(obj);
042                if (reasonNotSatisfiedIfAny == null) {
043                    // at least one is ok, so all is ok.
044                    return null;
045                }
046                buf.append(reasonNotSatisfiedIfAny);
047            }
048            return buf.getReason(); // may be null if all were satisfied.
049        }
050    
051    
052    }