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    }