001 package edu.nrao.sss.validation; 002 003 import java.util.ArrayList; 004 import java.util.HashMap; 005 import java.util.List; 006 import java.util.Map; 007 008 /** 009 * Partial implementation of a {@link Validator}. 010 * <p> 011 * <b>Version Info:</b> 012 * <table style="margin-left:2em"> 013 * <tr><td>$Revision: 1511 $</td></tr> 014 * <tr><td>$Date: 2008-08-19 11:43:17 -0600 (Tue, 19 Aug 2008) $</td></tr> 015 * <tr><td>$Author: dharland $</td></tr> 016 * </table></p> 017 * 018 * @author David M. Harland 019 * @since 2007-02-05 020 */ 021 public abstract class AbstractValidator<T> 022 implements Validator 023 { 024 private String name; 025 private Class<? extends T> expectedClass; 026 027 private Map<ValidationPurpose, List<Validation<T>>> validationMap; 028 029 /** 030 * The object most recently subject to validation by this validator. 031 * This variable is initially null. 032 */ 033 protected T target; 034 035 /** 036 * The purpose for which this validator was most recently run. 037 * This variable is initially ValidationPurpose.CERTIFY_READY_TO_USE. 038 */ 039 protected ValidationPurpose purpose; 040 041 /** 042 * List of all validation failures. 043 * This list is never null, but may be empty. 044 */ 045 protected List<ValidationFailure> failures; 046 047 /** 048 * The manager for which this validator is performing its duties. 049 * This variable is initially null. 050 */ 051 protected ValidationManager manager; 052 053 /** 054 * When true, validate() stops running tests after first failure. 055 * This variable is initially false. 056 */ 057 protected boolean failFast; 058 059 /** Helps create a new instance. */ 060 protected AbstractValidator(String validatorName, Class<? extends T> targetClass) 061 { 062 //TODO null handling? 063 064 name = validatorName; 065 expectedClass = targetClass; 066 067 target = null; 068 purpose = ValidationPurpose.CERTIFY_READY_TO_USE; 069 failFast = false; 070 failures = new ArrayList<ValidationFailure>(); 071 manager = null; 072 073 validationMap = new HashMap<ValidationPurpose, List<Validation<T>>>(); 074 } 075 076 //============================================================================ 077 // IMPLEMENTATION OF INTERFACE Validator 078 //============================================================================ 079 080 /* (non-Javadoc) 081 * @see edu.nrao.sss.validation.Validator#getName() 082 */ 083 public String getName() { return name; } 084 085 /* (non-Javadoc) 086 * @see edu.nrao.sss.validation.Validator#getTarget() 087 */ 088 public T getTarget() { return target; } 089 090 /* (non-Javadoc) 091 * @see edu.nrao.sss.validation.Validator#getPurpose() 092 */ 093 public ValidationPurpose getPurpose() { return purpose; } 094 095 /* (non-Javadoc) 096 * @see edu.nrao.sss.validation.Validator#setManager(ValidationManager) 097 */ 098 public void setManager(ValidationManager newManager) 099 { 100 manager = newManager; 101 } 102 103 /** 104 * Tells this validator whether it should run all validations or stop 105 * after the first validation that fails. The concrete implementations 106 * of this abstract are free to override this default implementation, 107 * whic is to run all validations. 108 * 109 * @param stop if <i>true</i> this validator will stop running its 110 * validations after the first one fails. 111 */ 112 public void stopTestingAfterFirstFailure(boolean stop) 113 { 114 failFast = stop; 115 } 116 117 118 /* (non-Javadoc) 119 * @see Validator#validate(Object, ValidationPurpose) 120 */ 121 @SuppressWarnings("unchecked") 122 public List<ValidationFailure> validate(Object target, 123 ValidationPurpose purpose) 124 { 125 failures.clear(); 126 127 if (expectedClass.isInstance(target)) 128 { 129 this.target = (T)target; 130 this.purpose = purpose; 131 132 validate(); 133 } 134 else //target is wrong class 135 { 136 failures.add(ValidationFailure.wrongObjectType(name, target, 137 expectedClass.getName())); 138 } 139 140 return failures; 141 } 142 143 //============================================================================ 144 // 145 //============================================================================ 146 147 /** 148 * Runs each of the individual validations. 149 * <p> 150 * Subclasses may use this default implementation or override it. 151 * Subclasses that contain collections of component objects will typically 152 * override this method, call {@code super.validate()}, and then invoke 153 * other validators on the elements of the collections.</p> 154 */ 155 protected void validate() 156 { 157 if (failFast) 158 validateUntilFailure(); 159 else 160 validateAll(); 161 } 162 163 /** Runs all validations. */ 164 private void validateAll() 165 { 166 for (Validation<T> test : getValidations()) 167 test.run(failures); 168 } 169 170 /** Runs validations until one fails. */ 171 private void validateUntilFailure() 172 { 173 for (Validation<T> test : getValidations()) 174 if (!test.run(failures)) 175 break; 176 } 177 178 /** 179 * Returns the list of validations to be used for this validator's 180 * current purpose. 181 * 182 * @return the list of validations for the current purpose. 183 */ 184 private List<Validation<T>> getValidations() 185 { 186 List<Validation<T>> validations = validationMap.get(purpose); 187 188 //Just-in-time creation 189 if (validations == null) 190 { 191 validations = makeValidationList(purpose); 192 validationMap.put(purpose, validations); 193 } 194 195 return validations; 196 } 197 198 //============================================================================ 199 // OBLIGATIONS OF SUBCLASSES 200 //============================================================================ 201 202 /** 203 * Creates and returns a list of validations to be performed for the given 204 * {@code purpose}. 205 * 206 * @param purpose the reason for which a validation is performed. 207 * 208 * @return a list of validations to be used for {@code purpose}. 209 */ 210 abstract 211 protected List<Validation<T>> makeValidationList(ValidationPurpose purpose); 212 }