Coverage Report - org.kuali.rice.kns.rules.PromptBeforeValidationBase
 
Classes in this File Line Coverage Branch Coverage Complexity
PromptBeforeValidationBase
0%
0/38
0%
0/18
3
PromptBeforeValidationBase$1
N/A
N/A
3
PromptBeforeValidationBase$ContextSession
0%
0/29
0%
0/12
3
PromptBeforeValidationBase$IsAskingException
0%
0/1
N/A
3
 
 1  
 /*
 2  
  * Copyright 2006-2007 The Kuali Foundation
 3  
  * 
 4  
  * Licensed under the Educational Community License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  * 
 8  
  * http://www.opensource.org/licenses/ecl2.php
 9  
  * 
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 package org.kuali.rice.kns.rules;
 17  
 
 18  
 import java.util.Arrays;
 19  
 import java.util.Iterator;
 20  
 import java.util.NoSuchElementException;
 21  
 
 22  
 import javax.servlet.http.HttpServletRequest;
 23  
 
 24  
 import org.apache.commons.lang.StringUtils;
 25  
 import org.apache.struts.action.ActionForm;
 26  
 import org.kuali.rice.core.util.RiceConstants;
 27  
 import org.kuali.rice.kns.document.Document;
 28  
 import org.kuali.rice.kns.question.ConfirmationQuestion;
 29  
 import org.kuali.rice.kns.rule.PromptBeforeValidation;
 30  
 import org.kuali.rice.kns.rule.event.PromptBeforeValidationEvent;
 31  
 import org.kuali.rice.kns.util.KNSConstants;
 32  
 import org.kuali.rice.kns.web.struts.form.KualiForm;
 33  
 
 34  
 /**
 35  
  * 
 36  
  * This class simplifies requesting clarifying user input prior to applying business rules. It mostly shields the classes that
 37  
  * extend it from being aware of the web layer, even though the input is collected via a series of one or more request/response
 38  
  * cycles.
 39  
  * 
 40  
  * Beware: method calls with side-effects will have unusual results. While it looks like the doRules method is executed
 41  
  * sequentially, in fact, it is more of a geometric series: if n questions are asked, then the code up to and including the first
 42  
  * question is executed n times, the second n-1 times, ..., the last question only one time.
 43  
  * 
 44  
  * 
 45  
  */
 46  
 public abstract class PromptBeforeValidationBase implements PromptBeforeValidation {
 47  
 
 48  0
     protected static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(PromptBeforeValidationBase.class);
 49  
 
 50  
     protected String question;
 51  
     protected String buttonClicked;
 52  
     protected PromptBeforeValidationEvent event;
 53  
     protected KualiForm form;
 54  
 
 55  0
     private class IsAskingException extends RuntimeException {
 56  
     }
 57  
 
 58  
     /**
 59  
      * 
 60  
      * This class acts similarly to HTTP session, but working inside a REQUEST parameter
 61  
      * 
 62  
      * 
 63  
      */
 64  
     /**
 65  
      * This is a description of what this class does - wliang don't forget to fill this in. 
 66  
      * 
 67  
      * @author Kuali Rice Team (rice.collab@kuali.org)
 68  
      *
 69  
      */
 70  
     public class ContextSession {
 71  
         private final static String DELIMITER = ".";
 72  
         PromptBeforeValidationEvent event;
 73  
 
 74  0
         public ContextSession(String context, PromptBeforeValidationEvent event) {
 75  0
             this.event = event;
 76  
 
 77  0
             this.event.setQuestionContext(context);
 78  0
             if (this.event.getQuestionContext() == null) {
 79  0
                 this.event.setQuestionContext("");
 80  
             }
 81  
 
 82  0
         }
 83  
 
 84  
         /**
 85  
          * Whether a question with a given ID has already been asked
 86  
          * 
 87  
          * @param id the ID of the question, an arbitrary value, but must be consistent
 88  
          * @return
 89  
          */
 90  
         public boolean hasAsked(String id) {
 91  0
             return StringUtils.contains(event.getQuestionContext(), id);
 92  
         }
 93  
 
 94  
         /**
 95  
          * Invoked to indicate that the user should be prompted a question
 96  
          * 
 97  
          * @param id the ID of the question, an arbitrary value, but must be consistent
 98  
          * @param text the question text, to be displayed to the user
 99  
          */
 100  
         public void askQuestion(String id, String text) {
 101  0
             event.setQuestionId(id);
 102  0
             event.setQuestionType(KNSConstants.CONFIRMATION_QUESTION);
 103  0
             event.setQuestionText(text);
 104  0
             event.setPerformQuestion(true);
 105  0
         }
 106  
 
 107  
         public void setAttribute(String name, String value) {
 108  0
             if (LOG.isDebugEnabled()) {
 109  0
                 LOG.debug("setAttribute(" + name + "," + value + ")");
 110  
             }
 111  0
             event.setQuestionContext(event.getQuestionContext() + DELIMITER + name + DELIMITER + value);
 112  
 
 113  0
         }
 114  
 
 115  
         public String getAttribute(String name) {
 116  0
             if (LOG.isDebugEnabled()) {
 117  0
                 LOG.debug("getAttribute(" + name + ")");
 118  
             }
 119  0
             String result = null;
 120  
 
 121  0
             Iterator values = Arrays.asList(event.getQuestionContext().split("\\" + DELIMITER)).iterator();
 122  
 
 123  0
             while (values.hasNext()) {
 124  0
                 if (values.next().equals(name)) {
 125  
                     try {
 126  0
                         result = (String) values.next();
 127  
                     }
 128  0
                     catch (NoSuchElementException e) {
 129  0
                         result = null;
 130  0
                     }
 131  
                 }
 132  
             }
 133  0
             if (LOG.isDebugEnabled()) {
 134  0
                 LOG.debug("returning " + result);
 135  
             }
 136  0
             return result;
 137  
         }
 138  
 
 139  
     }
 140  
 
 141  
     /**
 142  
      * Implementations will override this method to do perform the actual prompting and/or logic
 143  
      * 
 144  
      * They are able to utilize the following methods:
 145  
      * <li> {@link PromptBeforeValidationBase#abortRulesCheck()}
 146  
      * <li> {@link PromptBeforeValidationBase#askOrAnalyzeYesNoQuestion(String, String)}
 147  
      * <li> {@link #hasAsked(String)}
 148  
      * 
 149  
      * @param document
 150  
      * @return
 151  
      */
 152  
     public abstract boolean doPrompts(Document document);
 153  
 
 154  
     private boolean isAborting;
 155  
 
 156  
     ContextSession session;
 157  
 
 158  0
     public PromptBeforeValidationBase() {
 159  0
     }
 160  
 
 161  
 
 162  
     public boolean processPrompts(ActionForm form, HttpServletRequest request, PromptBeforeValidationEvent event) {
 163  0
         question = request.getParameter(KNSConstants.QUESTION_INST_ATTRIBUTE_NAME);
 164  0
         buttonClicked = request.getParameter(KNSConstants.QUESTION_CLICKED_BUTTON);
 165  0
         this.event = event;
 166  0
         this.form = (KualiForm) form;
 167  
 
 168  0
         if (LOG.isDebugEnabled()) {
 169  0
             LOG.debug("Question is: " + question);
 170  0
             LOG.debug("ButtonClicked: " + buttonClicked);
 171  0
             LOG.debug("QuestionContext() is: " + event.getQuestionContext());
 172  
         }
 173  
 
 174  0
         session = new ContextSession(request.getParameter(KNSConstants.QUESTION_CONTEXT), event);
 175  
 
 176  0
         boolean result = false;
 177  
 
 178  
         try {
 179  0
             result = doPrompts(event.getDocument());
 180  
         }
 181  0
         catch (IsAskingException e) {
 182  0
             return false;
 183  0
         }
 184  
 
 185  0
         if (isAborting) {
 186  0
             return false;
 187  
         }
 188  
 
 189  0
         return result;
 190  
     }
 191  
 
 192  
     /**
 193  
      * This bounces the user back to the document as if they had never tried to routed it. (Business rules are not invoked
 194  
      * and the action is not executed.)
 195  
      * 
 196  
      */
 197  
     public void abortRulesCheck() {
 198  0
         event.setActionForwardName(RiceConstants.MAPPING_BASIC);
 199  0
         isAborting = true;
 200  0
     }
 201  
 
 202  
     /**
 203  
      * This method poses a Y/N question to the user.  If the user has already answered the question, then it returns whether
 204  
      * the answer to the question was yes or no
 205  
      * 
 206  
      * Code that invokes this method will behave a bit strangely, so you should try to keep it as simple as possible.
 207  
      * 
 208  
      * @param id an ID for the question
 209  
      * @param text the text of the question, to be displayed on the screen
 210  
      * @return true if the user answered Yes, false if the user answers no
 211  
      * @throws IsAskingException if the user needs to be prompted the question
 212  
      */
 213  
     public boolean askOrAnalyzeYesNoQuestion(String id, String text) throws IsAskingException {
 214  
 
 215  0
         if (LOG.isDebugEnabled()) {
 216  0
             LOG.debug("Entering askOrAnalyzeYesNoQuestion(" + id + "," + text + ")");
 217  
         }
 218  
 
 219  0
         String cached = (String) session.getAttribute(id);
 220  0
         if (cached != null) {
 221  0
             LOG.debug("returning cached value: " + id + "=" + cached);
 222  0
             return new Boolean(cached).booleanValue();
 223  
         }
 224  
 
 225  0
         if (id.equals(question)) {
 226  0
             session.setAttribute(id, Boolean.toString(!ConfirmationQuestion.NO.equals(buttonClicked)));
 227  0
             return !ConfirmationQuestion.NO.equals(buttonClicked);
 228  
         }
 229  0
         else if (!session.hasAsked(id)) {
 230  0
             if (LOG.isDebugEnabled()) {
 231  0
                 LOG.debug("Forcing question to be asked: " + id);
 232  
             }
 233  0
             session.askQuestion(id, text);
 234  
         }
 235  
 
 236  0
         LOG.debug("Throwing Exception to force return to Action");
 237  0
         throw new IsAskingException();
 238  
     }
 239  
 
 240  
 }