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 }