001    package edu.nrao.sss.model.project.scan;
002    
003    import java.util.ArrayList;
004    import java.util.List;
005    
006    import edu.nrao.sss.validation.AbstractValidator;
007    import edu.nrao.sss.validation.FailureSeverity;
008    import edu.nrao.sss.validation.Validation;
009    import edu.nrao.sss.validation.ValidationFailure;
010    import edu.nrao.sss.validation.ValidationPurpose;
011    import edu.nrao.sss.validation.Validator;
012    
013    /**
014     * A validator of {@link ScanLoop scan loops}.
015     * <p>
016     * <u>Validations Performed for All Purposes</u>
017     * <ol>
018     *   <li>Loop is not empty.</li>
019     *   <li>Iteration count is positive.</li>
020     *   <li>Maximum duration is positive.</li>
021     *   <li>TODO: Start/stop times and durations of contained scans makes sense.</li>
022     *   <li>Contained scans and scan loops are valid.<sup>1</sup></li>
023     * </ol>
024     * <sup>1</sup><i>The particular validations performed depend on the
025     * validator used by this one to operate on those contained scans</i>.</p>
026     * <p>
027     * <b>Version Info:</b>
028     * <table style="margin-left:2em">
029     *   <tr><td>$Revision: 1709 $</td></tr>
030     *   <tr><td>$Date: 2008-11-14 11:22:37 -0700 (Fri, 14 Nov 2008) $</td></tr>
031     *   <tr><td>$Author: dharland $</td></tr>
032     * </table></p>
033     * 
034     * @author David M. Harland
035     * @since 2007-02-13
036     */
037    public class ScanLoopValidator
038      extends AbstractValidator<ScanLoop>
039    {
040      private ScanValidator<? extends Scan> scanValidator;
041      
042      private boolean skipLoop;
043      private int     depth;
044    
045      /** Creates a new instance. */
046      public ScanLoopValidator()
047      {
048        super(ScanLoopValidator.class.getName(), ScanLoop.class);
049        skipLoop = false;
050        depth    = 0;
051      }
052    
053      public void setScanValidator(ScanValidator<? extends Scan> scanValidator)
054      {
055        this.scanValidator = scanValidator;
056      }
057    
058      /**
059       * Tells this validator whether or not it should skip the validation
060       * of the target loop.  Even if <tt>skip</tt> is set to <i>true</i>,
061       * the scans and inner loops of this loop will be validated.
062       * <p>
063       * This validator is originally configured so that it will
064       * not skip any validation.</p>
065       * <p>
066       * It is expected that validators of scheduling blocks will
067       * use this method with a parameter of <i>true</i>.</p>
068       * 
069       * @param skip
070       *   <i>true</i> if this validator should validate the contents
071       *   of the target loop, but not the target loop itself.
072       */
073      public void setSkipOutermostLoop(boolean skip)
074      {
075        skipLoop = skip;
076      }
077      
078      /* (non-Javadoc)
079       * @see AbstractValidator#makeValidationList(ValidationPurpose)
080       */
081      @Override
082      protected List<Validation<ScanLoop>>
083        makeValidationList(ValidationPurpose purpose)
084      {
085        List<Validation<ScanLoop>> validations =
086          new ArrayList<Validation<ScanLoop>>();
087        
088        validations.add(new HasElements  (this, purpose));
089        validations.add(new HasIterations(this, purpose));
090        validations.add(new HasTime      (this, purpose));
091        
092        return validations; 
093      }
094    
095      /* (non-Javadoc)
096       * @see edu.nrao.sss.model.validation.AbstractValidator#validate()
097       */
098      @Override
099      protected void validate()
100      {
101        depth++;
102        
103        if (!skipLoop || depth > 1)
104          super.validate();
105        
106        //Validate elements of the loop.
107        //Need to fetch validator within the loop because each element
108        //could be of a different type, requiring a diff validator.
109        for (ScanLoopElement element : target.getElements())
110        {
111          Validator elemVal = getScanLoopElementValidator(element);
112          
113          List<ValidationFailure> elemFailures = elemVal.validate(element, purpose);
114          
115          if (elemVal != this)
116            failures.addAll(elemFailures);
117        }
118        
119        depth--;
120      }
121    
122      //============================================================================
123      // COMPONENT VALIDATORS
124      //============================================================================
125    
126      /** Returns a validator for scan loop elements. */
127      public Validator getScanLoopElementValidator(ScanLoopElement element)
128      {
129        Validator validator = scanValidator;
130        
131        if (validator == null)
132        {
133          if (manager != null)
134            validator = manager.getValidator(element.getClass());
135        
136          if (validator == null)
137            validator = (element instanceof ScanLoop) ? this : new SimpleScanValidator();
138        }
139        
140        return validator;
141      }
142    
143      //============================================================================
144      // ENSURE LOOP HAS ELEMENTS
145      //============================================================================
146      
147      /** Make sure scan loop contains at least one scan or scan loop. */
148      class HasElements extends Validation<ScanLoop>
149      {
150        protected HasElements(AbstractValidator<ScanLoop> validationContainer,
151                              ValidationPurpose           reasonForValidation)
152        {
153          super(validationContainer, reasonForValidation);
154          
155          severity = 
156            (reasonForValidation == ValidationPurpose.CERTIFY_READY_TO_USE) ?
157              FailureSeverity.ERROR : FailureSeverity.WARNING;
158        }
159        
160        /** This test is passed if loop is not empty. */
161        @Override
162        protected boolean passesTest()
163        {
164          return target.size() > 0;
165        }
166        
167        /* (non-Javadoc)
168         * @see edu.nrao.sss.validation.Validation#displayMessage()
169         */
170        @Override
171        protected String displayMessage()
172        {
173          StringBuilder buff = new StringBuilder("Scan loop '");
174          buff.append(target.getName()).append("' is empty.  ");
175          
176          if (purpose == ValidationPurpose.CERTIFY_READY_TO_USE)
177          {
178            buff.append("A scan loop must have at least one scan or scan loop")
179                .append(" in order to be executed.  Please add a scan or scan loop")
180                .append(" to this loop, or remove it altogether.");
181          }
182          else
183          {
184            buff.append("This is fine for now, but you will need to add at least")
185                .append(" one scan or scan loop to this loop before the")
186                .append(" containing project is ready for execution.");
187          }
188    
189          return buff.toString();
190        }
191        
192        /* (non-Javadoc)
193         * @see edu.nrao.sss.validation.Validation#debugMessage()
194         */
195        @Override
196        protected String debugMessage()
197        {
198          StringBuilder buff = new StringBuilder("ScanLoop '");
199          
200          buff.append(target.getId()).append("' has no elements.");
201          
202          return buff.toString();
203        }
204      }
205    
206      //============================================================================
207      // ENSURE LOOP HAS POSITIVE ITERATION COUNT
208      //============================================================================
209      
210      /** Make sure scan loop has iteration count > 0. */
211      class HasIterations extends Validation<ScanLoop>
212      {
213        protected HasIterations(AbstractValidator<ScanLoop> validationContainer,
214                                ValidationPurpose           reasonForValidation)
215        {
216          super(validationContainer, reasonForValidation);
217          
218          severity = 
219            (reasonForValidation == ValidationPurpose.CERTIFY_READY_TO_USE) ?
220              FailureSeverity.ERROR : FailureSeverity.WARNING;
221        }
222        
223        /** This test is passed if loop is not empty. */
224        @Override
225        protected boolean passesTest()
226        {
227          return target.getIterationCount() > 0;
228        }
229        
230        /* (non-Javadoc)
231         * @see edu.nrao.sss.validation.Validation#displayMessage()
232         */
233        @Override
234        protected String displayMessage()
235        {
236          StringBuilder buff = new StringBuilder("Scan loop '");
237          buff.append(target.getName());
238          buff.append("' has an iteration count of zero.  ");
239          
240          if (purpose == ValidationPurpose.CERTIFY_READY_TO_USE)
241          {
242            buff.append("A scan loop must have at least one iteration")
243                .append(" in order to be executed.  Please set the iteration")
244                .append(" count to a value greater than zero.");
245          }
246          else
247          {
248            buff.append("This is fine for now, but you will need to set the")
249                .append(" iteration count to a value greater than zero before the")
250                .append(" containing project is ready for execution.");
251          }
252    
253          return buff.toString();
254        }
255        
256        /* (non-Javadoc)
257         * @see edu.nrao.sss.validation.Validation#debugMessage()
258         */
259        @Override
260        protected String debugMessage()
261        {
262          StringBuilder buff = new StringBuilder("ScanLoop '");
263          
264          buff.append(target.getId()).append("' has no iterations.");
265          
266          return buff.toString();
267        }
268      }
269    
270      //============================================================================
271      // ENSURE LOOP HAS POSITIVE MAXIMUM DURATION
272      //============================================================================
273      
274      /** Make sure scan loop has max duration > 0. */
275      class HasTime extends Validation<ScanLoop>
276      {
277        protected HasTime(AbstractValidator<ScanLoop> validationContainer,
278                          ValidationPurpose           reasonForValidation)
279        {
280          super(validationContainer, reasonForValidation);
281          
282          severity = 
283            (reasonForValidation == ValidationPurpose.CERTIFY_READY_TO_USE) ?
284              FailureSeverity.ERROR : FailureSeverity.WARNING;
285        }
286        
287        /** This test is passed if loop has positive maximum duration. */
288        @Override
289        protected boolean passesTest()
290        {
291          return target.getMaximumDuration().getValue().signum() > 0;
292        }
293        
294        /* (non-Javadoc)
295         * @see edu.nrao.sss.validation.Validation#displayMessage()
296         */
297        @Override
298        protected String displayMessage()
299        {
300          StringBuilder buff = new StringBuilder("Scan loop '");
301          buff.append(target.getName());
302          buff.append("' has a maximum duration of zero.  ");
303          
304          if (purpose == ValidationPurpose.CERTIFY_READY_TO_USE)
305          {
306            buff.append("A scan loop must have at a positive maximum duration")
307                .append(" in order to be executed.  Please set the maximum")
308                .append(" duration to a value greater than zero.");
309          }
310          else
311          {
312            buff.append("This is fine for now, but you will need to set the")
313                .append(" maximum duration to a value greater than zero before the")
314                .append(" containing project is ready for execution.");
315          }
316    
317          return buff.toString();
318        }
319        
320        /* (non-Javadoc)
321         * @see edu.nrao.sss.validation.Validation#debugMessage()
322         */
323        @Override
324        protected String debugMessage()
325        {
326          StringBuilder buff = new StringBuilder("ScanLoop '");
327          
328          buff.append(target.getId()).append("' has max duration of zero.");
329          
330          return buff.toString();
331        }
332      }
333    }