001 /******************************************************************************* 002 * Portions created by Sebastian Thomschke are copyright (c) 2005-2011 Sebastian 003 * Thomschke. 004 * 005 * All Rights Reserved. This program and the accompanying materials 006 * are made available under the terms of the Eclipse Public License v1.0 007 * which accompanies this distribution, and is available at 008 * http://www.eclipse.org/legal/epl-v10.html 009 * 010 * Contributors: 011 * Sebastian Thomschke - initial implementation. 012 *******************************************************************************/ 013 package net.sf.oval; 014 015 import java.io.IOException; 016 import java.io.Serializable; 017 import java.util.List; 018 import java.util.Map; 019 020 import net.sf.oval.context.OValContext; 021 import net.sf.oval.internal.Log; 022 023 /** 024 * An instance of this class provides detailed information about a single constraint 025 * violation that occurred during validation. 026 * 027 * @author Sebastian Thomschke 028 */ 029 public class ConstraintViolation implements Serializable 030 { 031 private static final Log LOG = Log.getLog(ConstraintViolation.class); 032 033 private static final long serialVersionUID = 1L; 034 035 private final ConstraintViolation[] causes; 036 private final OValContext checkDeclaringContext; 037 private final String checkName; 038 private final OValContext context; 039 private final String errorCode; 040 private transient Object invalidValue; 041 private final String message; 042 private final String messageTemplate; 043 private final Map<String, ? extends Serializable> messageVariables; 044 045 private final int severity; 046 private transient Object validatedObject; 047 048 public ConstraintViolation(final Check check, final String message, final Object validatedObject, 049 final Object invalidValue, final OValContext context) 050 { 051 this(check, message, validatedObject, invalidValue, context, (ConstraintViolation[]) null); 052 } 053 054 public ConstraintViolation(final Check check, final String message, final Object validatedObject, 055 final Object invalidValue, final OValContext context, final ConstraintViolation... causes) 056 { 057 checkName = check.getClass().getName(); 058 checkDeclaringContext = check.getContext(); 059 errorCode = check.getErrorCode(); 060 this.message = message; 061 messageTemplate = check.getMessage(); 062 messageVariables = check.getMessageVariables(); 063 severity = check.getSeverity(); 064 this.validatedObject = validatedObject; 065 this.invalidValue = invalidValue; 066 this.context = context; 067 this.causes = causes != null && causes.length == 0 ? null : causes; 068 } 069 070 public ConstraintViolation(final Check check, final String message, final Object validatedObject, 071 final Object invalidValue, final OValContext context, final List<ConstraintViolation> causes) 072 { 073 checkName = check.getClass().getName(); 074 checkDeclaringContext = check.getContext(); 075 errorCode = check.getErrorCode(); 076 this.message = message; 077 messageTemplate = check.getMessage(); 078 messageVariables = check.getMessageVariables(); 079 severity = check.getSeverity(); 080 this.validatedObject = validatedObject; 081 this.invalidValue = invalidValue; 082 this.context = context; 083 this.causes = causes == null || causes.size() == 0 ? null : causes.toArray(new ConstraintViolation[causes 084 .size()]); 085 } 086 087 /** 088 * @return the causes or null of no causes exists 089 */ 090 public ConstraintViolation[] getCauses() 091 { 092 return causes == null ? null : causes.clone(); 093 } 094 095 /** 096 * @return Returns the context where the constraint was declared. 097 * 098 * @see net.sf.oval.context.ClassContext 099 * @see net.sf.oval.context.ConstraintSetContext 100 * @see net.sf.oval.context.FieldContext 101 * @see net.sf.oval.context.MethodEntryContext 102 * @see net.sf.oval.context.MethodExitContext 103 * @see net.sf.oval.context.MethodParameterContext 104 * @see net.sf.oval.context.MethodReturnValueContext 105 */ 106 public OValContext getCheckDeclaringContext() 107 { 108 return checkDeclaringContext; 109 } 110 111 /** 112 * @return the fully qualified class name of the corresponding check 113 */ 114 public String getCheckName() 115 { 116 return checkName; 117 } 118 119 /** 120 * @return Returns the context where the constraint violation occurred. 121 * 122 * @see net.sf.oval.context.ClassContext 123 * @see net.sf.oval.context.FieldContext 124 * @see net.sf.oval.context.MethodEntryContext 125 * @see net.sf.oval.context.MethodExitContext 126 * @see net.sf.oval.context.MethodParameterContext 127 * @see net.sf.oval.context.MethodReturnValueContext 128 */ 129 public OValContext getContext() 130 { 131 return context; 132 } 133 134 /** 135 * @return the error code 136 */ 137 public String getErrorCode() 138 { 139 return errorCode; 140 } 141 142 /** 143 * @return Returns the value that was validated. 144 */ 145 public Object getInvalidValue() 146 { 147 return invalidValue; 148 } 149 150 /** 151 * @return the localized and rendered message 152 */ 153 public String getMessage() 154 { 155 return message; 156 } 157 158 /** 159 * @return the raw message specified for the constraint without variable resolution and localization 160 */ 161 public String getMessageTemplate() 162 { 163 return messageTemplate; 164 } 165 166 /** 167 * Returns the message variables provided by the corresponding check. 168 * @return an unmodifiable map holding the message variables provided by the corresponding check. 169 */ 170 public Map<String, ? extends Serializable> getMessageVariables() 171 { 172 return messageVariables; 173 } 174 175 /** 176 * @return the severity 177 */ 178 public int getSeverity() 179 { 180 return severity; 181 } 182 183 /** 184 * @return the validatedObject 185 */ 186 public Object getValidatedObject() 187 { 188 return validatedObject; 189 } 190 191 /** 192 * see http://java.sun.com/developer/technicalArticles/ALT/serialization/ 193 * 194 * @param in 195 * @throws IOException 196 * @throws ClassNotFoundException 197 */ 198 private void readObject(final java.io.ObjectInputStream in) throws IOException, ClassNotFoundException 199 { 200 in.defaultReadObject(); 201 if (in.readBoolean()) validatedObject = in.readObject(); 202 if (in.readBoolean()) invalidValue = in.readObject(); 203 } 204 205 /** 206 * {@inheritDoc} 207 */ 208 @Override 209 public String toString() 210 { 211 return getClass().getName() + ": " + message; 212 } 213 214 /** 215 * see http://java.sun.com/developer/technicalArticles/ALT/serialization/ 216 * 217 * @param out 218 * @throws IOException 219 */ 220 private void writeObject(final java.io.ObjectOutputStream out) throws IOException 221 { 222 out.defaultWriteObject(); 223 if (validatedObject instanceof Serializable) 224 { 225 // indicate validatedObject implements Serializable 226 out.writeBoolean(true); 227 out.writeObject(validatedObject); 228 } 229 else 230 { 231 LOG.warn("Field 'validatedObject' not serialized because the field value object " + validatedObject 232 + " of type " + invalidValue.getClass() + " does not implement " + Serializable.class.getName()); 233 234 // indicate validatedObject does not implement Serializable 235 out.writeBoolean(false); 236 } 237 238 if (invalidValue instanceof Serializable) 239 { 240 // indicate value implements Serializable 241 out.writeBoolean(true); 242 out.writeObject(invalidValue); 243 } 244 else 245 { 246 final String warning = // 247 "Field 'invalidValue' could not be serialized because the field value object {1} does not implement java.io.Serializable."; 248 LOG.warn(warning, invalidValue); 249 // indicate value does not implement Serializable 250 out.writeBoolean(false); 251 } 252 } 253 }