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.Stack;
019
020 import org.apache.commons.logging.Log;
021 import org.apache.commons.logging.LogFactory;
022 import org.springframework.rules.constraint.Constraint;
023 import org.springframework.core.style.ToStringCreator;
024 import org.springframework.rules.constraint.*;
025
026 /**
027 * @author Keith Donald
028 */
029 public abstract class ValidationResultsBuilder {
030 protected static final Log logger = LogFactory
031 .getLog(ValidationResultsBuilder.class);
032 private Constraint top;
033 private Stack levels = new Stack();
034
035 public void pushAnd() {
036 And and = new And();
037 add(and);
038 }
039
040 public void pushOr() {
041 Or or = new Or();
042 add(or);
043 }
044
045 public void pushNot() {
046 Not not = new Not();
047 add(not);
048 }
049
050 private void add(Constraint predicate) {
051 if (top != null) {
052 if (top instanceof Not) {
053 if (logger.isDebugEnabled()) {
054 logger.debug("Negating predicate [" + predicate + "]");
055 }
056 ((Not)this.top).setConstraint(predicate);
057 } else {
058 if (logger.isDebugEnabled()) {
059 logger.debug("Aggregating nested predicate [" + predicate
060 + "]");
061 }
062 ((CompoundConstraint)this.top).add(predicate);
063 }
064 }
065 levels.push(predicate);
066 this.top = predicate;
067 if (logger.isDebugEnabled()) {
068 logger.debug("Predicate [" + predicate + "] is at the top.");
069 }
070 }
071
072 public void push(Constraint constraint) {
073 if (this.top instanceof CompoundConstraint) {
074 if (logger.isDebugEnabled()) {
075 logger.debug("Adding constraint [" + constraint + "]");
076 }
077 ((CompoundConstraint)this.top).add(constraint);
078 } else if (this.top instanceof Not) {
079 if (logger.isDebugEnabled()) {
080 logger.debug("Negating constraint [" + constraint + "]");
081 }
082 ((Not)this.top).setConstraint(constraint);
083 } else if (this.top == null) {
084 constraintViolated(constraint);
085 } else {
086 throw new IllegalArgumentException(constraint.toString());
087 }
088 }
089
090 public void pop(boolean result) {
091 Constraint p = (Constraint)levels.pop();
092 if (logger.isDebugEnabled()) {
093 logger.debug("Top [" + p + "] popped; result was " + result
094 + "; stack now has " + levels.size() + " elements");
095 }
096 if (levels.isEmpty()) {
097 if (!result) {
098 constraintViolated(top);
099 } else {
100 constraintSatisfied();
101 }
102 top = null;
103 } else {
104 this.top = (Constraint)levels.peek();
105 if (result) {
106 if (logger.isDebugEnabled()) {
107 logger.debug("Removing compound predicate [" + p
108 + "]; tested true.");
109 }
110 ((CompoundConstraint)this.top).remove(p);
111 }
112 }
113 }
114
115 protected void clear() {
116 levels.clear();
117 top = null;
118 }
119
120 public boolean negated() {
121 if (levels.size() == 0) {
122 return false;
123 }
124 return peek() instanceof Not;
125 }
126
127 private Constraint peek() {
128 return (Constraint)levels.peek();
129 }
130
131 protected abstract void constraintViolated(Constraint constraint);
132 protected abstract void constraintSatisfied();
133
134 public String toString() {
135 return new ToStringCreator(this).append("topOfStack", top).append(
136 "levelsStack", levels).toString();
137 }
138
139 }