001/**
002 * Copyright 2005-2016 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
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,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.rice.krms.api.engine;
017
018import org.kuali.rice.core.api.exception.RiceRuntimeException;
019
020/**
021 * An exception which indicates that the type of data being evaluated in the
022 * engine does not match the expected type.
023 * 
024 * @author Kuali Rice Team (rice.collab@kuali.org)
025 *
026 */
027public class IncompatibleTypeException extends RiceRuntimeException {
028
029        private static final long serialVersionUID = -8359509154258982033L;
030        
031        private final Object value;
032        private final Class<?>[] validTypes;
033        
034        /**
035         * Constructs an IncompatibleTypeException with a reference to the object
036         * being checked and an array of valid Class objects which the type failed
037         * to match.
038         * 
039         * <p>A message describing the nature of the incompatible types will
040         * automatically be generated and can be retrieved through {@link #getMessage()}
041         * 
042         * @param value the object which was being evaluated against a set of valid types
043         * @param validTypes the valid types against which the value was being evaluated
044         * but failed to be compatible with
045         */
046        public IncompatibleTypeException(Object value, Class<?>... validTypes) {
047                this(null, value, validTypes);
048        }
049        
050        /**
051         * Constructs an IncompatibleTypeException with a message, a reference to the object
052         * being checked, and an array of valid Class objects which the type failed
053         * to match.
054         * 
055         * <p>The additional message will be prepended to the front of an automatically
056         * generated message describing the nature of the incompatible types and can be
057         * retrieved through {@link #getMessage()}.
058         * 
059         * @param additionalMessage the additional message to prepend to the generated exception detail message
060         * @param value the object which was being evaluated against a set of valid types
061         * @param validTypes the valid types against which the value was being evaluated
062         * but failed to be compatible with
063         */
064        public IncompatibleTypeException(String additionalMessage, Object value, Class<?>... validTypes) {
065                super(constructMessage(additionalMessage, value, validTypes));
066                this.value = value;
067                this.validTypes = validTypes;
068        }
069
070    /**
071     * construct a message using the given values
072     * @param additionalMessage the start of the constructed message
073     * @param value the Object that wasn't validly typed
074     * @param validTypes valid types the Type should have been one of.
075     * @return the additionMessaage, valid types, and the class that did not have a valid type.
076     */
077        private static String constructMessage(String additionalMessage, Object value, Class<?>... validTypes) {
078                StringBuilder message = new StringBuilder();
079                if (additionalMessage != null) {
080                        message.append(additionalMessage);
081                }
082                if (message.length() > 0) {
083                        message.append(" -> ");
084                }
085                if (validTypes != null && validTypes.length > 0) {      
086                        message.append("Type should have been one of [");
087                        for (Class<?> validType : validTypes) {
088                                message.append(validType.getName()).append(", ");
089                        }
090                        // trim off the last two character to get rid of the last ", "
091                        message.delete(message.length() - 2, message.length());
092                        message.append("] but was ").append(value == null ? "null" : value.getClass().getName());
093                } else {
094                        message.append("Type was ").append(value == null ? "null" : value.getClass().getName());        
095                }
096                return message.toString();
097        }
098        
099        /**
100         * Returns the object which triggered the incompatible type exception.
101         * 
102         * @return the value passed to this exception upon construction
103         */
104        public Object getValue() {
105                return value;
106        }
107        
108        /**
109         * Returns the array of Class objects which include the types against
110         * which the object value was deemed incompatible.
111         * 
112         * @return the valid types passed to this exception upon construction
113         */
114        public Class<?>[] getValidTypes() {
115                return validTypes;
116        }
117        
118}