View Javadoc

1   /**
2    * 2009, Digitalis Informatica. All rights reserved. Distribuicao e Gestao de Informatica, Lda. Estrada de Paco de Arcos
3    * num.9 - Piso -1 2780-666 Paco de Arcos Telefone: (351) 21 4408990 Fax: (351) 21 4408999 http://www.digitalis.pt
4    */
5   
6   package pt.digitalis.dif.presentation.views.jsp.entities;
7   
8   import java.util.ArrayList;
9   import java.util.HashSet;
10  import java.util.List;
11  import java.util.Set;
12  
13  import pt.digitalis.dif.controller.http.HTTPConstants;
14  import pt.digitalis.dif.controller.http.HTTPControllerConfiguration;
15  import pt.digitalis.dif.controller.interfaces.IDIFContext;
16  import pt.digitalis.dif.controller.interfaces.INavigationHistory;
17  import pt.digitalis.dif.controller.objects.Breadcrumb;
18  import pt.digitalis.dif.dem.annotations.parameter.InjectParameterErrors;
19  import pt.digitalis.dif.dem.annotations.stage.Context;
20  import pt.digitalis.dif.dem.annotations.stage.Execute;
21  import pt.digitalis.dif.dem.objects.ViewObject;
22  import pt.digitalis.dif.dem.objects.parameters.errors.ParameterErrors;
23  import pt.digitalis.dif.presentation.views.jsp.taglibs.AbstractDIFTag;
24  import pt.digitalis.dif.presentation.views.jsp.taglibs.layout.Wizard;
25  import pt.digitalis.dif.presentation.views.jsp.taglibs.objects.WizardDefinition;
26  import pt.digitalis.dif.presentation.views.jsp.taglibs.objects.beans.WizardStepItem;
27  import pt.digitalis.utils.common.CollectionUtils;
28  import pt.digitalis.utils.config.IConfigurations;
29  
30  import com.google.inject.Inject;
31  
32  /**
33   * A wizard stage base class. Implements all the necessary wizard logic, to help create the wizard base stages.
34   *
35   * @author Pedro Viegas <a href="mailto:pviegas@digitalis.pt">pviegas@digitalis.pt</a><br/>
36   * @created Jan 26, 2009
37   */
38  public abstract class AbstractWizardStage {
39  
40      /** The configurations resource */
41      @Inject
42      protected IConfigurations config;
43  
44      /** The current stage context */
45      @Context
46      protected IDIFContext context;
47  
48      /** the wizard definition object */
49      private WizardDefinition wizardDefinition = null;
50  
51      /**
52       * Cancel operation execution method.
53       *
54       * @param context
55       *            the current stage context
56       * @param currentStep
57       *            the wizards current execution step
58       * @return the resulting view or null for default
59       */
60      protected ViewObject cancel(IDIFContext context, int currentStep)
61      {
62          INavigationHistory navHistory = context.getSession().getNavigationHistory();
63  
64          if (navHistory.isEmpty() || navHistory.getHistory().size() < 2)
65          {
66  
67              HTTPControllerConfiguration httpConfig = config.readConfiguration(HTTPControllerConfiguration.class);
68              context.redirectTo(httpConfig.getHomeStageID());
69  
70          }
71          else
72          {
73              Set<String> wizardStageIDs = new HashSet<String>();
74  
75              for (WizardStepItem item: getWizardDefinition().getItems())
76                  if (item.getStageId() != null)
77                      wizardStageIDs.add(item.getStageId());
78  
79              for (int i = navHistory.getHistory().size() - 1; i >= 0; i--)
80                  if (!wizardStageIDs.contains(navHistory.getHistory().get(i).getStageID()))
81                  {
82                      Breadcrumb crumb = navHistory.getHistory().get(i);
83  
84                      context.redirectTo(crumb.getStageID(), CollectionUtils.keyValueStringToMapObject(crumb
85                              .getParameterPassed()));
86  
87                      // Break cycle execution so the redirect will be picked-up.
88                      return null;
89                  }
90          }
91  
92          return null;
93      }
94  
95      /**
96       * Validates custom rules for enabling the finish option. By default it is enabled with the current step is the last
97       * one.
98       *
99       * @return T if is accessible, F otherwise
100      */
101     protected boolean canFinish()
102     {
103         return (getWizardDefinition().getActiveStep() == getWizardDefinition().getItems().size());
104     }
105 
106     /**
107      * @return T if the current stage execution represents a current stage step data submit, F is it is a normal
108      *         redirect from another step.
109      */
110     protected final boolean isCurrentStepSubmit()
111     {
112         Object stepParameter = context.getRequest().getParameter(WizardDefinition.HTML_STEP_PARAMETER);
113         Object formParameter = context.getRequest().getParameter(HTTPConstants.FORM_SUBMIT_NAME);
114         Object stageParameter = context.getRequest().getParameter(HTTPConstants.FORM_SUBMIT_STAGE);
115 
116         return (stepParameter != null && formParameter != null && stageParameter != null
117                 && getWizardDefinition().getName().equalsIgnoreCase(formParameter.toString())
118                 && context.getStage().equalsIgnoreCase(stageParameter.toString()) && context.getStage()
119                 .equalsIgnoreCase(getStep(Integer.parseInt(stepParameter.toString())).getStageId()));
120     }
121 
122     /** Injects the parameter error report */
123     @InjectParameterErrors
124     protected ParameterErrors errors;
125 
126     /**
127      * The stage execution logic method.
128      *
129      * @return the resulting view or null for default
130      */
131     @Execute
132     public final ViewObject execute()
133     {
134         int currentStep = WizardDefinition.getWizardActiveStepNumber(context.getRequest(), getWizardDefinition()
135                 .getName(), getWizardDefinition().getHasIndexPage(), !errors.hasErrors());
136 
137         if (isCurrentStepSubmit() && !errors.hasErrors())
138         {
139 
140             Object stepParameter = context.getRequest().getParameter(WizardDefinition.HTML_STEP_PARAMETER);
141 
142             // Process the redirection after the execution
143             // If the current step is not enabled, calculate the first forward enabled step
144             while (currentStep < getTotalSteps() && !isStepEnabled(currentStep))
145                 currentStep++;
146 
147             // If the current step is not accessible, calculate the first backward accessible step
148             while (currentStep > 1 && (!isStepEnabled(currentStep) || !isStepAccessible(currentStep)))
149                 currentStep--;
150 
151             getWizardDefinition().setActiveStep(currentStep);
152             getWizardDefinition().setCanFinish(canFinish());
153 
154             Object actionParameter = context.getRequest().getParameter(WizardDefinition.HTML_ACTION_PARAMETER);
155 
156             if (actionParameter != null)
157             {
158                 if (canFinish()
159                         && AbstractDIFTag.getTagMessages(Wizard.class, context.getLanguage()).get("finish")
160                                 .equalsIgnoreCase(actionParameter.toString()))
161                 {
162 
163                     // Call the current step stage submit method handler
164                     wizardStepSubmit(context, Integer.parseInt(stepParameter.toString()));
165 
166                     // Execute the finish method
167                     return finish(context, currentStep);
168 
169                 }
170                 else if (AbstractDIFTag.getTagMessages(Wizard.class, context.getLanguage()).get("cancel")
171                         .equalsIgnoreCase(actionParameter.toString()))
172                 {
173                     // Execute the cancel method
174                     return cancel(context, currentStep);
175                 }
176                 else
177                 {
178                     WizardStepItem item = getActiveStep();
179 
180                     if (item.getStageId() != null)
181                         context.redirectTo(getActiveStep().getStageId());
182 
183                     // Call the current step stage submit method handler
184                     return wizardStepSubmit(context, Integer.parseInt(stepParameter.toString()));
185                 }
186             }
187             else
188                 // Call the current step stage submit method handler
189                 return wizardStepSubmit(context, Integer.parseInt(stepParameter.toString()));
190 
191         }
192         else
193         {
194             // If the current step is not enabled, calculate the first forward enabled step
195             while (currentStep < getTotalSteps() && !isStepEnabled(currentStep))
196                 currentStep++;
197 
198             // If the current step is not accessible, calculate the first backward accessible step
199 
200             while (currentStep > 1 && (!isStepEnabled(currentStep) || !isStepAccessible(currentStep)))
201                 currentStep--;
202 
203             getWizardDefinition().setActiveStep(currentStep);
204             getWizardDefinition().setCanFinish(canFinish());
205 
206             Object actionParameter = context.getRequest().getParameter(WizardDefinition.HTML_ACTION_PARAMETER);
207 
208             if (actionParameter != null)
209             {
210                 if (canFinish()
211                         && AbstractDIFTag.getTagMessages(Wizard.class, context.getLanguage()).get("finish")
212                                 .equalsIgnoreCase(actionParameter.toString()))
213                     return finish(context, currentStep);
214 
215                 else if (AbstractDIFTag.getTagMessages(Wizard.class, context.getLanguage()).get("cancel")
216                         .equalsIgnoreCase(actionParameter.toString()))
217                     return cancel(context, currentStep);
218             }
219 
220             return wizardStepEnter(context, currentStep);
221         }
222 
223     }
224 
225     /**
226      * Finish wizard execution method.
227      *
228      * @param context
229      *            the current stage context
230      * @param currentStep
231      *            the wizards current execution step
232      * @return the resulting view or null for default
233      */
234     protected abstract ViewObject finish(IDIFContext context, int currentStep);
235 
236     /**
237      * @return the currently active wizard step definition
238      */
239     protected final WizardStepItem getActiveStep()
240     {
241         return getStep(getWizardDefinition().getActiveStep());
242     }
243 
244     /**
245      * @param step
246      *            the desired step
247      * @return the currently active wizard step definition, or null if inexistent
248      */
249     protected final WizardStepItem getStep(int step)
250     {
251         if (step < 1 || step > getTotalSteps())
252             return null;
253         else
254             return getWizardDefinition().getItems().get(step - 1);
255     }
256 
257     /**
258      * @return the number of registered wizard steps
259      */
260     protected final int getTotalSteps()
261     {
262         return getWizardDefinition().getItems().size();
263     }
264 
265     /**
266      * @return the wizard definition object
267      */
268     public final WizardDefinition getWizardDefinition()
269     {
270         if (wizardDefinition == null)
271         {
272             String wizardFormName = context.getStage();
273 
274             // First initialization. Form name is supposed to be overridden in the initialize method, and step will be
275             // calculated later with the correct form to question for parameters
276             WizardDefinition def = new WizardDefinition(wizardFormName, new ArrayList<WizardStepItem>(), 1);
277 
278             // Call specialized initialization
279             wizardDefinition = initializeWizardDefinition(def);
280 
281             // If an automated index page should be added, add it before all wizard stages
282             if (wizardDefinition.getHasIndexPage())
283             {
284                 List<WizardStepItem> items = new ArrayList<WizardStepItem>();
285 
286                 items.add(new WizardStepItem(AbstractDIFTag.getTagMessages(Wizard.class, context.getLanguage()).get(
287                         "index"), null, null, true, true, false));
288                 items.addAll(wizardDefinition.getItems());
289 
290                 wizardDefinition.setItems(items);
291             }
292 
293             wizardDefinition.setActiveStep(WizardDefinition.getWizardActiveStepNumber(context.getRequest(),
294                     wizardDefinition.getName(), getWizardDefinition().getHasIndexPage(), !errors.hasErrors()));
295 
296             for (int i = 0; i < getTotalSteps(); i++)
297             {
298                 WizardStepItem item = getStep(i + 1);
299 
300                 item.setEnabled(isStepEnabled(i + 1));
301                 item.setAccessible(isStepAccessible(i + 1));
302             }
303 
304             wizardDefinition.setCanFinish(canFinish());
305         }
306 
307         return wizardDefinition;
308     }
309 
310     /**
311      * @return T if the current wizard has an index page
312      */
313     protected final boolean hasIndexStep()
314     {
315         return getWizardDefinition().getHasIndexPage();
316     }
317 
318     /**
319      * @param def
320      *            the {@link WizardDefinition} object to initialize
321      * @return the wizard definition with all specific steps information
322      */
323     protected abstract WizardDefinition initializeWizardDefinition(WizardDefinition def);
324 
325     /**
326      * Validates custom rules for displaying a given step as accessible.
327      *
328      * @param stepNumber
329      *            the step to validate access to
330      * @return T if is accessible, F otherwise
331      */
332     protected boolean isStepAccessible(int stepNumber)
333     {
334         return getStep(stepNumber).isAccessible();
335     }
336 
337     /**
338      * Validates custom rules enabling a specific step.
339      *
340      * @param stepNumber
341      *            the step to validate access to
342      * @return T if is accessible, F otherwise
343      */
344     protected boolean isStepEnabled(int stepNumber)
345     {
346         return getStep(stepNumber).isEnabled();
347     }
348 
349     /**
350      * Should be implemented with the current wizard step execution logic. This is called when the user enters this
351      * step, not when it submit's it. All validation should have already occurred and execution is validated
352      *
353      * @param context
354      *            the current stage context
355      * @param currentStep
356      *            the wizards current execution step
357      * @return the resulting view or null for default
358      */
359     protected ViewObject wizardStepEnter(IDIFContext context, int currentStep)
360     {
361         return null;
362     }
363 
364     /**
365      * Should be implemented with the current wizard step execution logic. This is called when the user submit's this
366      * step, not when he enters it. All validation should have already occurred and execution is validated
367      *
368      * @param context
369      *            the current stage context
370      * @param currentStep
371      *            the wizards current execution step
372      * @return the resulting view or null for default
373      */
374     protected abstract ViewObject wizardStepSubmit(IDIFContext context, int currentStep);
375 }