001/*-------------------------------------------------------------------------+
002|                                                                          |
003| Copyright 2005-2011 The ConQAT Project                                   |
004|                                                                          |
005| Licensed under the Apache License, Version 2.0 (the "License");          |
006| you may not use this file except in compliance with the License.         |
007| You may obtain a copy of the License at                                  |
008|                                                                          |
009|    http://www.apache.org/licenses/LICENSE-2.0                            |
010|                                                                          |
011| Unless required by applicable law or agreed to in writing, software      |
012| distributed under the License is distributed on an "AS IS" BASIS,        |
013| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
014| See the License for the specific language governing permissions and      |
015| limitations under the License.                                           |
016+-------------------------------------------------------------------------*/
017package org.conqat.lib.commons.constraint;
018
019import org.conqat.lib.commons.collections.PairList;
020import org.conqat.lib.commons.error.IExceptionHandler;
021import org.conqat.lib.commons.error.RethrowingExceptionHandler;
022import org.conqat.lib.commons.visitor.IMeshWalker;
023import org.conqat.lib.commons.visitor.ITreeWalker;
024import org.conqat.lib.commons.visitor.IVisitor;
025import org.conqat.lib.commons.visitor.VisitorUtils;
026
027/**
028 * A class for storing constraints in the context of classes for which the
029 * constraint applies. Additionally it provides methods for checking all
030 * matching constraints for a given class.
031 * 
032 * @author hummelb
033 */
034public class ConstraintValidator {
035
036        /** Storage for constraints in conjunction with the class they apply to. */
037        private final PairList<Class<?>, ILocalConstraint<?>> localConstraints = new PairList<Class<?>, ILocalConstraint<?>>();
038
039        /** Adds a constraint for a class. */
040        public <T> void addConstraint(Class<? extends T> clazz, ILocalConstraint<T> constraint) {
041                localConstraints.add(clazz, constraint);
042        }
043
044        /**
045         * Checks all constraints to the given object which are applicable to it.
046         * 
047         * @throws ConstraintViolationException
048         *             if any constraint is violated
049         */
050        public void checkConstaints(Object o) throws ConstraintViolationException {
051                checkConstaints(o, RethrowingExceptionHandler.<ConstraintViolationException> getInstance());
052        }
053
054        /**
055         * Checks all constraints to the given object which are applicable to it. If
056         * a constraint is violated, the thrown exception is handled by the given
057         * provider.
058         */
059        @SuppressWarnings({ "unchecked", "rawtypes" })
060        public <X extends Exception> void checkConstaints(Object o,
061                        IExceptionHandler<ConstraintViolationException, X> handler) throws X {
062                Class<?> clazz = o.getClass();
063                for (int i = 0; i < localConstraints.size(); ++i) {
064                        if (localConstraints.getFirst(i).isAssignableFrom(clazz)) {
065                                ILocalConstraint<?> constraint = localConstraints.getSecond(i);
066                                try {
067                                        ((ILocalConstraint) constraint).checkLocalConstraint(o);
068                                } catch (ConstraintViolationException e) {
069                                        handler.handleException(e);
070                                }
071                        }
072                }
073        }
074
075        /**
076         * Validates all nodes of a tree. The first violation found is propagated to
077         * the top using a {@link ConstraintViolationException}.
078         * 
079         * @param root
080         *            the root of the tree.
081         * @param walker
082         *            the walker used to navigate the tree.
083         * @throws ConstraintViolationException
084         *             if a constraint violation was found.
085         * @throws X_WALKER
086         *             if the walker throws an exception.
087         */
088        public <T, X_WALKER extends Exception> void validateTree(T root, ITreeWalker<T, X_WALKER> walker)
089                        throws ConstraintViolationException, X_WALKER {
090
091                validateTree(root, walker, RethrowingExceptionHandler.<ConstraintViolationException> getInstance());
092        }
093
094        /**
095         * Validates all nodes of a tree.
096         * 
097         * @param root
098         *            the root of the tree.
099         * @param walker
100         *            the walker used to navigate the tree.
101         * @param handler
102         *            the exception handler used for dealing with constraint
103         *            violations.
104         * @throws X
105         *             if the constraint violation handler throws it.
106         * @throws X_WALKER
107         *             if the walker throws an exception.
108         */
109        public <T, X extends Exception, X_WALKER extends Exception> void validateTree(T root,
110                        ITreeWalker<T, X_WALKER> walker, IExceptionHandler<ConstraintViolationException, X> handler)
111                        throws X, X_WALKER {
112
113                VisitorUtils.visitAllPreOrder(root, walker, new CheckVisitor<T, X>(handler));
114        }
115
116        /**
117         * Validates all reachable elements of a mesh. The first violation found is
118         * propagated to the top using a {@link ConstraintViolationException}.
119         * 
120         * @param start
121         *            the start element of the mesh.
122         * @param walker
123         *            the walker used to navigate the mesh.
124         * @throws ConstraintViolationException
125         *             if a constraint violation was found.
126         * @throws X_WALKER
127         *             if the walker throws an exception.
128         */
129        public <T, X_WALKER extends Exception> void validateMesh(T start, IMeshWalker<T, X_WALKER> walker)
130                        throws ConstraintViolationException, X_WALKER {
131
132                validateMesh(start, walker, RethrowingExceptionHandler.<ConstraintViolationException> getInstance());
133        }
134
135        /**
136         * Validates all reachable elements of a mesh.
137         * 
138         * @param start
139         *            the start element of the mesh.
140         * @param walker
141         *            the walker used to navigate the mesh.
142         * @param handler
143         *            the exception handler used for dealing with constraint
144         *            violations.
145         * @throws X
146         *             if the constraint violation handler throws it.
147         * @throws X_WALKER
148         *             if the walker throws an exception.
149         */
150        public <T, X extends Exception, X_WALKER extends Exception> void validateMesh(T start,
151                        IMeshWalker<T, X_WALKER> walker, IExceptionHandler<ConstraintViolationException, X> handler)
152                        throws X, X_WALKER {
153
154                VisitorUtils.visitAllDepthFirst(start, walker, new CheckVisitor<T, X>(handler));
155        }
156
157        /**
158         * A simple visitor checking each element with the
159         * {@link ConstraintValidator#checkConstaints(Object, IExceptionHandler)}
160         * method.
161         */
162        private class CheckVisitor<T, X extends Exception> implements IVisitor<T, X> {
163
164                /** The handler used. */
165                private final IExceptionHandler<ConstraintViolationException, X> handler;
166
167                /** Constructor. */
168                public CheckVisitor(IExceptionHandler<ConstraintViolationException, X> handler) {
169                        this.handler = handler;
170                }
171
172                /** {@inheritDoc} */
173                @Override
174                public void visit(T element) throws X {
175                        checkConstaints(element, handler);
176                }
177
178        }
179}