View Javadoc

1   package com.explosion.expfmodules.wizard.standard;
2   
3   /* =============================================================================
4    *       
5    *     Copyright 2004 Stephen Cowx
6    *
7    *     Licensed under the Apache License, Version 2.0 (the "License");
8    *     you may not use this file except in compliance with the License.
9    *     You may obtain a copy of the License at
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
13   *     Unless required by applicable law or agreed to in writing, software
14   *     distributed under the License is distributed on an "AS IS" BASIS,
15   *     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   *     See the License for the specific language governing permissions and
17   *     limitations under the License.
18   * 
19   * =============================================================================
20   */
21  
22  import java.util.ArrayList;
23  import java.util.HashMap;
24  import java.util.Iterator;
25  import java.util.List;
26  import java.util.Map;
27  
28  import com.explosion.expfmodules.wizard.Step;
29  import com.explosion.expfmodules.wizard.Wizard;
30  import com.explosion.utilities.exception.ExceptionManagerFactory;
31  
32  /***
33   * @author Stephen Cowx
34   * This is a standard and basic implementation of the Wizard interface intended for use with simple wizards
35   * Created on 02-Dec-2004
36   */
37  public class StandardWizard implements Wizard
38  {
39      private static org.apache.log4j.Logger log = org.apache.log4j.LogManager.getLogger(StandardWizard.class);
40      private String name;
41      private String version;
42      
43      private Map stepDefinitions;
44      private Step firstStep;
45      
46      private Step currentStep;
47      private List previousSteps = new ArrayList();
48      private List previousDataValues = new ArrayList();
49      private Map currentDataValues = new HashMap(); 
50       
51      /***
52       * Advances to the next step by checking all of the conditions of the outbound routes
53       * the first outbound step with no condition or with a condition thatmatches will be chosen
54       * 
55       * It also copies all of the data items from this step into the data items set for the wizard.
56       * If the step is reversed (using back) the dataitems are also reversed.  The step dataitems are remembered
57       * usign shallow copies so any changes to the actual data items may not be rolled back
58       * @see com.explosion.expfmodules.wizard.Wizard#next()
59       *
60       */
61      public void next()
62      {
63          try
64          {
65              log.debug("Called next");
66              boolean found = false;
67              if (currentStep != null)
68              {
69                /* Make the decision about what the next step should be */  
70                List outboundRoutes = currentStep.getOutboundSteps();
71                for (Iterator it = outboundRoutes.iterator(); it.hasNext();)
72                {
73                    Step step = (Step) it.next();
74                    if (step.getCondition() == null || step.getCondition().conditionMet(this))
75                    {
76                        /* Add the old step to the history */
77                        previousSteps.add(currentStep);
78                        
79                        /* Move the datavalues from the last step into the wizard data values map */
80                        promoteDataValues();
81                        
82                        /* Execute the action for the last step*/
83                        if (currentStep.getStepDefinition().getAction() != null)
84  	          		  {
85  	          			 boolean advance = currentStep.getStepDefinition().getAction().execute(this);
86  	          			 if (!advance)
87  	          			 {
88  	          			 	//reverse any progress we have made and go back to the current step
89  	          			 	undoPromote();
90  	          	            break;
91  	          			 }
92  	          		  }
93                        
94                        /* Set the current step to the new value */
95                        currentStep = step;
96                        found = true;
97                        
98                        break;
99                    }
100               }
101               if (!found)
102                   log.error("No suitable outbound routes found for step " + currentStep.getStepDefinition().getName() + " (ID: )" + currentStep.getStepDefinition().getId());
103             }
104         }
105         catch (Exception e)
106         {
107             ExceptionManagerFactory.getExceptionManager().manageException(e,"Exception caught while advancing wizard to the next step.");
108         }
109     }
110     
111     /***
112 	 * This method moves the data values from the current step into the data values for the wizard.
113 	 * It also saves the previous data values hash map and makes a new one
114 	 */
115 	private void promoteDataValues() {
116 		/* Advance the data values in the wizard */
117 		  previousDataValues.add(currentDataValues);
118 		  Map newDataValues = new HashMap();
119 		  for (Iterator valKeys = currentDataValues.keySet().iterator(); valKeys.hasNext();)
120 		  {
121 		  	 Object key = valKeys.next();
122 		  	 newDataValues.put(key, currentDataValues.get(key));
123 		  }
124 		  
125 		  if (currentStep.getStepDefinition().getDataItems() != null)
126 		  {
127 			  /* Add the data values from this step */
128 			  for (Iterator newKeys = currentStep.getStepDefinition().getDataItems().keySet().iterator(); newKeys.hasNext();)
129 			  {
130 			  	 Object key = newKeys.next();
131 			  	 newDataValues.put(key, currentStep.getStepDefinition().getDataItems().get(key));
132 			  }
133 		  }
134 		  /* Set the currentDataValues to the newDataValues so that the current Data values 
135 		   * has all of the data values collected so far*/
136 		  currentDataValues = newDataValues;
137 	}
138 
139 	/***
140      * This method must be called for the wizard to be initialised and ready for processing.
141      * It initialises the currentStep with the step set as the firstStep and clears the previousSteps array.
142      * @see com.explosion.expfmodules.wizard.Wizard#start()
143      *
144      */
145     public void start()
146     {
147         log.debug("Called start");
148         if (firstStep != null)
149         {
150             previousSteps = new ArrayList();
151             currentStep = firstStep;
152             
153             previousDataValues = new ArrayList();
154             currentDataValues = (Map) new HashMap();
155         }
156     }
157     
158     /***
159      * This method moves the currentStep to the previous step,
160      * essentially just moving the wizard back one step.
161      * @see com.explosion.expfmodules.wizard.Wizard#back()
162      */
163     public void back()
164     {
165         log.debug("Called back");
166         if (previousSteps.size() > 0)
167         {
168             currentStep = (Step) previousSteps.get(previousSteps.size()-1);
169             undoPromote();
170         }
171          
172     }
173     
174     /***
175      * This is a helper method for code shared in several places in this class.It rolls back changes made 
176      * to the data items and steps
177      */
178     private void undoPromote()
179     {
180         previousSteps.remove(previousSteps.size()-1);
181         currentDataValues = (Map) previousDataValues.get(previousDataValues.size()-1);
182         previousDataValues.remove(previousDataValues.size()-1);
183     }
184     
185     /***
186      * This method cancels the wizard.
187      * It may perform some logic here perhaps instantiate a class of type Cencel and invoke the Cancel method.
188      * Currently it is not implemented.
189      * @see com.explosion.expfmodules.wizard.Wizard#cancel()
190      *
191      */
192     public void cancel()
193     {
194         log.debug("Called cancel");
195     }
196     
197     /***
198      * This method completes the wizard.
199      * It may perform some logic here perhaps instantiate a class of type Completion and invoke the complete method.
200      * Currently it is not implemented.
201      * @see com.explosion.expfmodules.wizard.Wizard#finish()
202      *
203      */
204     public void finish()
205     {
206         try {
207 			log.debug("Called finish");
208 			
209 			/* Add the old step to the history */
210             previousSteps.add(currentStep);
211             
212 			/* Move the datavalues from the last step into the wizard data values map */
213             promoteDataValues();
214 			
215             /* Execute the action for the last step*/
216             if (currentStep.getStepDefinition().getAction() != null)
217 			{
218             	boolean advance = currentStep.getStepDefinition().getAction().execute(this);
219      			 if (!advance)
220      			 {
221      			 	//reverse any progress we have made and go back to the current step
222      			 	undoPromote();
223      			 	return;
224      			 }
225 			}
226             
227             currentStep = null;
228             
229 		} catch (Exception e) {
230 			ExceptionManagerFactory.getExceptionManager().manageException(e,"Exception caught while finshing wizard");
231 		}
232     }
233     
234     /***
235      * 
236      * @see com.explosion.expfmodules.wizard.Wizard#getName()
237      * @return
238      */
239     public String getName()
240     {
241         log.debug("Called getName");
242         return name;
243     }
244     
245     /***
246      * Sets the name for this wizard
247      * @param name
248      */
249     public void setName(String name)
250     {
251         this.name = name;
252     }
253      
254     
255     /***
256      * 
257      * @see com.explosion.expfmodules.wizard.Wizard#getFirstStep()
258      * @return
259      */
260     public Step getFirstStep()
261     {
262         log.debug("Called getStepsDefinitions");
263         return firstStep;
264     }
265     
266     /***
267      * Sets the first step for this wizard
268      * @param steps
269      */
270     public void setFirstStep(Step firstStep)
271     {
272         this.firstStep = firstStep;
273         this.currentStep = firstStep;
274     }  
275       
276     
277     /***
278      * @return Returns the stepDefinitions.
279      */
280     public Map getStepDefinitions()
281     {
282         return stepDefinitions;
283     }
284     
285     /***
286      * @param stepDefinitions The stepDefinitions to set.
287      */
288     public void setStepDefinitions(Map stepDefinitions)
289     {
290         this.stepDefinitions = stepDefinitions;
291     }
292     
293     /***
294      * This method returns the current step which the wizard is on.
295      * @return
296      */
297     public Step getCurrentStep()
298     {
299         return currentStep;
300     }
301     
302     /***
303      * REeturns the version of this Wizard
304      * @return
305      */
306     public String getVersion()
307     {
308         return version;
309     }
310     
311     /***
312      * Sets the version of this wizard
313      * @param version
314      */
315     public void setVersion(String version)
316     {
317         this.version = version;
318     }
319     
320     /***
321      * These values will be populated by each step in the wizard as it progresses so that at the end of the wizard
322      * the values collected can be used by the action performed
323      * @return
324      */
325     public Map getWizardDataValues()
326     {
327     	return this.currentDataValues;
328     }
329     
330     /***
331      * Returns true if this wizard is finshed
332      * @return
333      */
334     public boolean isFinished()
335     {
336     	if (this.currentStep == null)
337     		return true;
338     	else
339     		return false;
340     }
341 }