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.reporting;
017
018 import java.util.Iterator;
019
020 import org.apache.commons.logging.Log;
021 import org.apache.commons.logging.LogFactory;
022 import org.springframework.core.ReflectiveVisitorHelper;
023 import org.springframework.rules.closure.Closure;
024 import org.springframework.rules.constraint.Constraint;
025 import org.springframework.core.style.ToStringCreator;
026 import org.springframework.rules.constraint.And;
027 import org.springframework.rules.constraint.ClosureResultConstraint;
028 import org.springframework.rules.constraint.Not;
029 import org.springframework.rules.constraint.Or;
030
031 /**
032 * @author Keith Donald
033 */
034 public class ValidationResultsCollector {
035 protected static final Log logger = LogFactory
036 .getLog(ValidationResultsCollector.class);
037
038 protected ReflectiveVisitorHelper visitorSupport = new ReflectiveVisitorHelper();
039
040 private ValidationResultsBuilder resultsBuilder;
041
042 private ValidationResults results;
043
044 private boolean collectAllErrors;
045
046 private Object argument;
047
048 public ValidationResultsCollector() {
049 }
050
051 public ValidationResults collect(final Object argument,
052 final Constraint constraint) {
053 this.resultsBuilder = new ValidationResultsBuilder() {
054 public void constraintSatisfied() {
055 }
056
057 public void constraintViolated(Constraint constraint) {
058 results = new ValueValidationResults(argument, constraint);
059 }
060 };
061 if (results == null) {
062 results = new ValueValidationResults(argument);
063 }
064 this.argument = argument;
065 visitorSupport.invokeVisit(this, constraint);
066 return results;
067 }
068
069 public void setCollectAllErrors(boolean collectAllErrors) {
070 this.collectAllErrors = collectAllErrors;
071 }
072
073 protected ValidationResultsBuilder getResultsBuilder() {
074 return resultsBuilder;
075 }
076
077 protected void setResultsBuilder(ValidationResultsBuilder resultsBuilder) {
078 this.resultsBuilder = resultsBuilder;
079 }
080
081 protected void setArgument(Object argument) {
082 this.argument = argument;
083 }
084
085 boolean visit(And and) {
086 resultsBuilder.pushAnd();
087 if (logger.isDebugEnabled()) {
088 logger.debug("Starting [and]...");
089 }
090 boolean result = true;
091 Iterator it = and.iterator();
092 while (it.hasNext()) {
093 boolean test = ((Boolean)visitorSupport.invokeVisit(
094 ValidationResultsCollector.this, it.next())).booleanValue();
095 if (!test) {
096 if (!collectAllErrors) {
097 resultsBuilder.pop(false);
098 return false;
099 }
100
101 if (result) {
102 result = false;
103 }
104 }
105 }
106 if (logger.isDebugEnabled()) {
107 logger.debug("Finished [and]...");
108 }
109 resultsBuilder.pop(result);
110 return result;
111 }
112
113 boolean visit(Or or) {
114 resultsBuilder.pushOr();
115 if (logger.isDebugEnabled()) {
116 logger.debug("Starting [or]...");
117 }
118 Iterator it = or.iterator();
119 while (it.hasNext()) {
120 boolean result = ((Boolean)visitorSupport.invokeVisit(
121 ValidationResultsCollector.this, it.next())).booleanValue();
122 if (result) {
123 resultsBuilder.pop(result);
124 return true;
125 }
126 }
127 if (logger.isDebugEnabled()) {
128 logger.debug("Finished [or]...");
129 }
130 resultsBuilder.pop(false);
131 return false;
132 }
133
134 Boolean visit(Not not) {
135 resultsBuilder.pushNot();
136 if (logger.isDebugEnabled()) {
137 logger.debug("Starting [not]...");
138 }
139 Boolean result = (Boolean)visitorSupport.invokeVisit(this, not
140 .getConstraint());
141 if (logger.isDebugEnabled()) {
142 logger.debug("Finished [not]...");
143 }
144 resultsBuilder.pop(result.booleanValue());
145 return result;
146 }
147
148 Boolean visit(ClosureResultConstraint ofConstraint) {
149 Closure f = ofConstraint.getFunction();
150 if (logger.isDebugEnabled()) {
151 logger.debug("Invoking function with argument " + argument);
152 }
153 setArgument(f.call(argument));
154 return (Boolean)visitorSupport.invokeVisit(this, ofConstraint
155 .getPredicate());
156 }
157
158 boolean visit(Constraint constraint) {
159 if (logger.isDebugEnabled()) {
160 logger.debug("Testing constraint [" + constraint + "] with argument '"
161 + argument + "']");
162 }
163 boolean result = constraint.test(argument);
164 result = applyAnyNegation(result);
165 if (!result) {
166 resultsBuilder.push(constraint);
167 }
168 if (logger.isDebugEnabled()) {
169 logger.debug("Constraint [" + constraint + "] "
170 + (result ? "passed" : "failed"));
171 }
172 return result;
173 }
174
175 protected boolean applyAnyNegation(boolean result) {
176 boolean negated = resultsBuilder.negated();
177 if (logger.isDebugEnabled()) {
178 if (negated) {
179 logger.debug("[negate result]");
180 }
181 else {
182 logger.debug("[no negation]");
183 }
184 }
185 return negated ? !result : result;
186 }
187
188 public String toString() {
189 return new ToStringCreator(this).append("collectAllErrors",
190 collectAllErrors).append("validationResultsBuilder",
191 resultsBuilder).toString();
192 }
193
194 }