001    package edu.nrao.sss.validation;
002    
003    import java.util.List;
004    
005    /**
006     * An individual test run by a {@link Validator}.
007     * Instances of this class are not generally needed by clients who request
008     * validation, but are instead used by specific implementations of validators.
009     * <p>
010     * <b>Version Info:</b>
011     * <table style="margin-left:2em">
012     *   <tr><td>$Revision: 868 $</td></tr>
013     *   <tr><td>$Date: 2007-09-12 13:15:10 -0600 (Wed, 12 Sep 2007) $</td></tr>
014     *   <tr><td>$Author: dharland $</td></tr>
015     * </table></p>
016     * 
017     * @author David M. Harland
018     * @since 2007-02-05
019     */
020    public abstract class Validation<T>
021    {
022      /** The validator of which this validation is a part. */
023      protected AbstractValidator<T> container;
024      
025      /** A measure of the consequences of failing this validation. */
026      protected FailureSeverity severity;
027      
028      /** The reason for doing this validation. */
029      protected ValidationPurpose purpose;
030    
031      /**
032       * Helps create a new instance.
033       * 
034       * @param validationContainer the validator that holds this validation.
035       * @param reasonForValidation the reason this validation is being performed.
036       */
037      protected Validation(AbstractValidator<T> validationContainer,
038                           ValidationPurpose    reasonForValidation)
039      {
040        container = validationContainer;
041        purpose   = reasonForValidation;
042        severity  = FailureSeverity.CONCERN;
043      }
044      
045      /**
046       * Runs this validation and places any failures in the given list.
047       * 
048       * @param failures the destination for any failures encountered while
049       *                 running this validation.
050       *                 
051       * @return <i>true</i> if this validation was successful, <i>false</i>
052       *         otherwise.
053       */
054      protected boolean run(List<ValidationFailure> failures)
055      {
056        boolean success = true;
057        
058        if (container == null)
059        {
060          failures.add(noContainer());
061          success = false;
062        }
063        else if (!passesTest())
064        {
065          failures.add(failure());
066          success = false;
067        }
068        
069        return success;
070      }
071      
072      /**
073       * Returns the name of this test.
074       * <p>
075       * This default implementation returns the fully qualified class name of
076       * the validation class.  Implementing subclasses may choose to override
077       * this default and use some other name.</p>
078       * 
079       * @return the name of this test.
080       */
081      protected String getName()
082      {
083        return getClass().getName();
084      }
085      
086      /**
087       * Creates and returns a failure to be used if the target object fails
088       * this validation.
089       * 
090       * @return a failure to be used if the target object fails this validation.
091       */
092      private ValidationFailure failure()
093      {
094        return new ValidationFailure
095        (
096          displayMessage(),
097          debugMessage(),
098          severity,
099          container.getTarget(),
100          container.getName(),
101          getName()
102        );
103      }
104      
105      /**
106       * Creates and returns a failure to be used if this validation has no
107       * container.
108       * 
109       * @return a failure to be used if this validation has no container.
110       */
111      private ValidationFailure noContainer()
112      {
113        return new ValidationFailure
114        (
115          "",
116          "PROGRAMMER ERROR: Validation '" +
117            getClass().getName() + "' has no container.",
118          FailureSeverity.ERROR,
119          null,
120          "",
121          "no container"
122        );
123      }
124      
125      //============================================================================
126      // OBLIGATIONS OF SUBCLASSES
127      //============================================================================
128      
129      /**
130       * Returns <i>true</i> if the target object passes this validation.
131       * @return <i>true</i> if the target object passes this validation.
132       */
133      abstract protected boolean passesTest();
134      
135      /**
136       * Returns a user-friendly message to be used if this validation fails.
137       * @return a user-friendly message to be used if this validation fails.
138       */
139      abstract protected String displayMessage();
140      
141      /**
142       * Returns a technical message to be used if this validation fails.
143       * @return a technical message to be used if this validation fails.
144       */
145      abstract protected String debugMessage();
146    }