001 /*
002 * Copyright 2002-2004 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005 * use this file except in compliance with the License. You may obtain a copy of
006 * the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013 * License for the specific language governing permissions and limitations under
014 * the License.
015 */
016 package org.springframework.rules.constraint;
017
018 import java.util.ArrayList;
019 import java.util.Arrays;
020 import java.util.Iterator;
021 import java.util.List;
022
023 import org.springframework.rules.constraint.Constraint;
024 import org.springframework.rules.closure.support.Algorithms;
025 import org.springframework.rules.closure.support.Block;
026 import org.springframework.core.style.ToStringCreator;
027 import org.springframework.util.Assert;
028
029 /**
030 * Abstract base class for unary constraints which compose other constraints.
031 *
032 * @author Keith Donald
033 */
034 public abstract class CompoundConstraint extends AbstractConstraint {
035
036 private List constraints = new ArrayList();
037
038 /**
039 * Constructs a compound constraint with no initial members. It is expected
040 * the client will call "add" to add individual constraints.
041 */
042 public CompoundConstraint() {
043
044 }
045
046 /**
047 * Creates a CompoundUnaryPredicate composed of two constraints.
048 *
049 * @param constraint1
050 * the first constraint
051 * @param constraint2
052 * the second constraint
053 */
054 public CompoundConstraint(Constraint constraint1, Constraint constraint2) {
055 Assert.isTrue(constraint1 != null && constraint2 != null, "Both constraints are required");
056 constraints.add(constraint1);
057 constraints.add(constraint2);
058 }
059
060 /**
061 * Creates a CompoundUnaryPredicate composed of the specified constraints.
062 *
063 * @param constraints
064 * the aggregated constraints
065 */
066 public CompoundConstraint(Constraint[] constraints) {
067 this.constraints.addAll(Arrays.asList(constraints));
068 }
069
070 /**
071 * Add the specified constraint to the set of constraints aggregated by this
072 * compound constraint.
073 *
074 * @param constraint
075 * the constraint to add
076 * @return A reference to this, to support chaining.
077 */
078 public CompoundConstraint add(Constraint constraint) {
079 this.constraints.add(constraint);
080 return this;
081 }
082
083 /**
084 * Add the list of constraints to the set of constraints aggregated by this
085 * compound constraint.
086 *
087 * @param constraints
088 * the list of constraints to add
089 * @return A reference to this, to support chaining.
090 */
091 public CompoundConstraint addAll(List constraints) {
092 Algorithms.instance().forEach(constraints, new Block() {
093 protected void handle(Object o) {
094 add((Constraint)o);
095 }
096 });
097 return this;
098 }
099
100 public void remove(Constraint constraint) {
101 constraints.remove(constraint);
102 }
103
104 public int indexOf(Constraint child) {
105 return constraints.indexOf(child);
106 }
107
108 public Constraint get(int index) {
109 return (Constraint)constraints.get(index);
110 }
111
112 public void copyInto(CompoundConstraint p) {
113 p.constraints.clear();
114 p.constraints.addAll(constraints);
115 }
116
117 public void set(int index, Constraint constraint) {
118 constraints.set(index, constraint);
119 }
120
121 /**
122 * Return an iterator over the aggregated constraints.
123 *
124 * @return An iterator
125 */
126 public Iterator iterator() {
127 return constraints.iterator();
128 }
129
130 /**
131 * Returns the number of constraints aggregated by this compound constraint.
132 *
133 * @return The size.
134 */
135 public int size() {
136 return constraints.size();
137 }
138
139 public abstract boolean test(Object argument);
140
141 public void validateTypeSafety(final Class constraintType) {
142 Assert.notNull(constraintType, "Constraint type is required");
143 Assert.isTrue(Constraint.class.isAssignableFrom(constraintType),
144 "Argument must be a specialization of the Constraint interface");
145 boolean result = new AbstractConstraint() {
146 public boolean test(Object o) {
147 return constraintType.isAssignableFrom(o.getClass());
148 }
149 }.allTrue(iterator());
150 Assert.isTrue(result, "One or more of the aggregated constraints is not assignable to " + constraintType);
151 }
152
153 public String toString() {
154 return new ToStringCreator(this).append("constraints", constraints).toString();
155 }
156
157 }