View Javadoc
1   package org.andromda.metafacades.uml14;
2   
3   import java.util.ArrayList;
4   import java.util.Collection;
5   import java.util.Collections;
6   import java.util.Iterator;
7   import java.util.LinkedHashMap;
8   import java.util.LinkedHashSet;
9   import java.util.List;
10  import java.util.Map;
11  import org.andromda.metafacades.uml.EventFacade;
12  import org.andromda.metafacades.uml.FrontEndActionState;
13  import org.andromda.metafacades.uml.FrontEndActivityGraph;
14  import org.andromda.metafacades.uml.FrontEndController;
15  import org.andromda.metafacades.uml.FrontEndControllerOperation;
16  import org.andromda.metafacades.uml.FrontEndEvent;
17  import org.andromda.metafacades.uml.FrontEndFinalState;
18  import org.andromda.metafacades.uml.FrontEndForward;
19  import org.andromda.metafacades.uml.FrontEndParameter;
20  import org.andromda.metafacades.uml.FrontEndUseCase;
21  import org.andromda.metafacades.uml.FrontEndView;
22  import org.andromda.metafacades.uml.ModelElementFacade;
23  import org.andromda.metafacades.uml.OperationFacade;
24  import org.andromda.metafacades.uml.ParameterFacade;
25  import org.andromda.metafacades.uml.PseudostateFacade;
26  import org.andromda.metafacades.uml.StateVertexFacade;
27  import org.andromda.metafacades.uml.TransitionFacade;
28  import org.andromda.metafacades.uml.UseCaseFacade;
29  import org.apache.commons.collections.CollectionUtils;
30  import org.apache.commons.collections.Predicate;
31  import org.apache.commons.lang.StringUtils;
32  
33  
34  /**
35   * MetafacadeLogic implementation for org.andromda.metafacades.uml.FrontEndAction.
36   *
37   * @see org.andromda.metafacades.uml.FrontEndAction
38   * @author Bob Fields
39   */
40  public class FrontEndActionLogicImpl
41      extends FrontEndActionLogic
42  {
43      private static final long serialVersionUID = -5553731254658712583L;
44  
45      /**
46       * @param metaObject
47       * @param context
48       */
49      public FrontEndActionLogicImpl(
50          Object metaObject,
51          String context)
52      {
53          super(metaObject, context);
54      }
55  
56      /**
57       * Returns either a PseudostateFacade or FrontEndView
58       * @return input source
59       * @see org.andromda.metafacades.uml.FrontEndAction#getInput()
60       */
61      protected Object handleGetInput()
62      {
63          Object input = null;
64          final ModelElementFacade source = this.getSource();
65          if (source instanceof PseudostateFacade)
66          {
67              final PseudostateFacade pseudostate = (PseudostateFacade)source;
68              if (pseudostate.isInitialState())
69              {
70                  input = source;
71              }
72          }
73          else
74          {
75              if (source instanceof FrontEndView)
76              {
77                  input = source;
78              }
79          }
80          return input;
81      }
82  
83      /**
84       * @see org.andromda.metafacades.uml.FrontEndAction#getParameters()
85       */
86      @Override
87      protected List handleGetParameters()
88      {
89          final EventFacade trigger = this.getTrigger();
90          return trigger == null ? Collections.emptyList() : new ArrayList(trigger.getParameters());
91      }
92  
93      /**
94       * @see  org.andromda.metafacades.uml.FrontEndAction#findParameter(String)
95       */
96      @Override
97      protected ParameterFacade handleFindParameter(final String name)
98      {
99          return (ParameterFacade)CollectionUtils.find(
100             this.getParameters(),
101             new Predicate()
102             {
103                 public boolean evaluate(Object object)
104                 {
105                     final ParameterFacade parameter = (ParameterFacade)object;
106                     return StringUtils.trimToEmpty(parameter.getName()).equals(name);
107                 }
108             });
109     }
110 
111     /**
112      * @see org.andromda.metafacades.uml.FrontEndAction#getDeferredOperations()
113      */
114     @Override
115     protected List handleGetDeferredOperations()
116     {
117         final Collection deferredOperations = new LinkedHashSet();
118         final FrontEndController controller = this.getController();
119         if (controller != null)
120         {
121             final List actionStates = this.getActionStates();
122             for (int ctr = 0; ctr < actionStates.size(); ctr++)
123             {
124                 final FrontEndActionState actionState = (FrontEndActionState)actionStates.get(ctr);
125                 deferredOperations.addAll(actionState.getControllerCalls());
126             }
127 
128             final List transitions = this.getDecisionTransitions();
129             for (int ctr = 0; ctr < transitions.size(); ctr++)
130             {
131                 final FrontEndForward forward = (FrontEndForward)transitions.get(ctr);
132                 final FrontEndEvent trigger = forward.getDecisionTrigger();
133                 if (trigger != null)
134                 {
135                     deferredOperations.add(trigger.getControllerCall());
136                 }
137             }
138         }
139         return new ArrayList(deferredOperations);
140     }
141 
142     /**
143      * @see org.andromda.metafacades.uml.FrontEndAction#getDecisionTransitions()
144      */
145     @Override
146     protected List handleGetDecisionTransitions()
147     {
148         if (decisionTransitions == null)
149         {
150             initializeCollections();
151         }
152         return new ArrayList(decisionTransitions);
153     }
154 
155     /**
156      * @see org.andromda.metafacades.uml.FrontEndAction#getTargetViews()
157      */
158     @Override
159     protected List<StateVertexFacade> handleGetTargetViews()
160     {
161         final Collection<StateVertexFacade> targetViews = new LinkedHashSet<StateVertexFacade>();
162         final Collection<FrontEndForward> forwards = this.getActionForwards();
163         for (final Iterator<FrontEndForward> iterator = forwards.iterator(); iterator.hasNext();)
164         {
165             final FrontEndForward forward = iterator.next();
166             if (forward.isEnteringView())
167             {
168                 targetViews.add(forward.getTarget());
169             }
170         }
171         return new ArrayList(targetViews);
172     }
173 
174     /**
175      * All action states that make up this action, this includes all possible action states traversed
176      * after a decision point too.
177      */
178     private Collection actionStates = null;
179 
180     /**
181      * All transitions leading into either a page or final state that originated from a call to this action.
182      */
183     private Map actionForwards = null;
184 
185     /**
186      * All transitions leading into a decision point that originated from a call to this action.
187      */
188     private Collection decisionTransitions = null;
189 
190     /**
191      * All transitions that can be traversed when calling this action.
192      */
193     private Collection transitions = null;
194 
195     /**
196      * Initializes all action states, action forwards, decision transitions and transitions in one shot, so that they
197      * can be queried more effiencently later on.
198      */
199     private void initializeCollections()
200     {
201         this.actionStates = new LinkedHashSet();
202         this.actionForwards = new LinkedHashMap();
203         this.decisionTransitions = new LinkedHashSet();
204         this.transitions = new LinkedHashSet();
205         this.collectTransitions(
206             (TransitionFacade)this.THIS(),
207             transitions);
208     }
209 
210     /**
211      * Recursively collects all action states, action forwards, decision transitions and transitions.
212      *
213      * @param transition the current transition that is being processed
214      * @param processedTransitions the set of transitions already processed
215      */
216     private void collectTransitions(
217         TransitionFacade transition,
218         Collection processedTransitions)
219     {
220         if (processedTransitions.contains(transition))
221         {
222             return;
223         }
224         processedTransitions.add(transition);
225         final StateVertexFacade target = transition.getTarget();
226         if (target instanceof FrontEndView || target instanceof FrontEndFinalState)
227         {
228             if (!this.actionForwards.containsKey(transition.getTarget()))
229             {
230                 this.actionForwards.put(
231                     transition.getTarget(),
232                     transition);
233             }
234         }
235         else if (target instanceof PseudostateFacade && ((PseudostateFacade)target).isDecisionPoint())
236         {
237             this.decisionTransitions.add(transition);
238             final Collection<TransitionFacade> outcomes = target.getOutgoings();
239             for (final Iterator<TransitionFacade> iterator = outcomes.iterator(); iterator.hasNext();)
240             {
241                 final TransitionFacade outcome = iterator.next();
242                 collectTransitions(
243                     outcome,
244                     processedTransitions);
245             }
246         }
247         else if (target instanceof FrontEndActionState)
248         {
249             this.actionStates.add(target);
250             final FrontEndForward forward = ((FrontEndActionState)target).getForward();
251             if (forward != null)
252             {
253                 collectTransitions(
254                     forward,
255                     processedTransitions);
256             }
257         }
258         else // all the rest is ignored but outgoing transitions are further processed
259         {
260             final Collection<TransitionFacade> outcomes = target.getOutgoings();
261             for (final Iterator<TransitionFacade> iterator = outcomes.iterator(); iterator.hasNext();)
262             {
263                 final TransitionFacade outcome = iterator.next();
264                 collectTransitions(
265                     outcome,
266                     processedTransitions);
267             }
268         }
269     }
270 
271     /**
272      * @see org.andromda.metafacades.uml.FrontEndAction#getActionStates()
273      */
274     @Override
275     protected List handleGetActionStates()
276     {
277         if (this.actionStates == null)
278         {
279             this.initializeCollections();
280         }
281         return new ArrayList(this.actionStates);
282     }
283 
284     /**
285      * @see org.andromda.metafacades.uml.FrontEndAction#getTransitions()
286      */
287     @Override
288     protected List handleGetTransitions()
289     {
290         if (this.transitions == null)
291         {
292             this.initializeCollections();
293         }
294         return new ArrayList(this.transitions);
295     }
296 
297     /**
298      * @see org.andromda.metafacades.uml.FrontEndAction#getActionForwards()
299      */
300     @Override
301     protected List handleGetActionForwards()
302     {
303         if (this.actionForwards == null)
304         {
305             this.initializeCollections();
306         }
307         return new ArrayList(this.actionForwards.values());
308     }
309 
310     /**
311      * @see org.andromda.metafacades.uml.FrontEndAction#getController()
312      */
313     @Override
314     protected FrontEndController handleGetController()
315     {
316         final FrontEndActivityGraph graph = this.getFrontEndActivityGraph();
317         return graph == null ? null : graph.getController();
318     }
319 
320     /**
321      * Overridden because actions (transitions) are not directly contained in a UML namespace.
322      *
323      * @see org.andromda.metafacades.uml.ModelElementFacade#getPackageName()
324      */
325     @Override
326     public String handleGetPackageName()
327     {
328         String packageName = null;
329 
330         final UseCaseFacade useCase = this.getUseCase();
331         if (useCase != null)
332         {
333             packageName = useCase.getPackageName();
334         }
335         return packageName;
336     }
337 
338     /**
339      * @see org.andromda.metafacades.uml.FrontEndAction#isUseCaseStart()
340      */
341     @Override
342     protected boolean handleIsUseCaseStart()
343     {
344         final StateVertexFacade source = getSource();
345         return source instanceof PseudostateFacade && ((PseudostateFacade)source).isInitialState();
346     }
347 
348     /**
349      * @see org.andromda.metafacades.uml.FrontEndAction#getFormFields()
350      */
351     @Override
352     protected List<ParameterFacade> handleGetFormFields()
353     {
354         final Map<String, ParameterFacade> formFieldMap = new LinkedHashMap<String, ParameterFacade>();
355 
356         // - For an action that starts the use case, we need to detect all usecases forwarding to the one
357         //   belonging to this action if there are any parameters in those transitions we need to have
358         //   them included in this action's form
359         if (this.isUseCaseStart())
360         {
361             final FrontEndUseCase useCase = this.getUseCase();
362             if (useCase != null)
363             {
364                 final Collection<FrontEndFinalState> finalStates = useCase.getReferencingFinalStates();
365                 for (final Iterator<FrontEndFinalState> finalStateIterator = finalStates.iterator(); finalStateIterator.hasNext();)
366                 {
367                     final Object finalStateObject = finalStateIterator.next();
368 
369                     // we need to test for the type because a non struts-use-case final state might accidently
370                     // link to this use-case (for example: the user temporarily wants to disable code generation
371                     // for a specific use-case and is not removing the final-state to use-case link(s))
372                     if (finalStateObject instanceof FrontEndFinalState)
373                     {
374                         final FrontEndFinalState finalState = (FrontEndFinalState)finalStateObject;
375                         final Collection<FrontEndParameter> parameters = finalState.getInterUseCaseParameters();
376                         for (final Iterator<FrontEndParameter> parameterIterator = parameters.iterator(); parameterIterator.hasNext();)
377                         {
378                             final ParameterFacade parameter = (ParameterFacade)parameterIterator.next();
379                             formFieldMap.put(
380                                 parameter.getName(),
381                                 parameter);
382                         }
383                     }
384                 }
385             }
386         }
387 
388         // if any action encountered by the execution of the complete action-graph path emits a forward
389         // containing one or more parameters they need to be included as a form field too
390         final Collection actionStates = this.getActionStates();
391         for (final Iterator iterator = actionStates.iterator(); iterator.hasNext();)
392         {
393             final FrontEndActionState actionState = (FrontEndActionState)iterator.next();
394             final FrontEndForward forward = actionState.getForward();
395             if (forward != null)
396             {
397                 final Collection<FrontEndParameter> forwardParameters = forward.getForwardParameters();
398                 for (final Iterator<FrontEndParameter> parameterIterator = forwardParameters.iterator(); parameterIterator.hasNext();)
399                 {
400                     final ParameterFacade forwardParameter = (ParameterFacade)parameterIterator.next();
401                     formFieldMap.put(
402                         forwardParameter.getName(),
403                         forwardParameter);
404                 }
405             }
406         }
407 
408         // add page variables for all pages/final-states targetted
409         // also add the fields of the target page's actions (for preloading)
410         final Collection forwards = this.getActionForwards();
411         for (final Iterator iterator = forwards.iterator(); iterator.hasNext();)
412         {
413             final FrontEndForward forward = (FrontEndForward)iterator.next();
414             final StateVertexFacade target = forward.getTarget();
415             if (target instanceof FrontEndView)
416             {
417                 final FrontEndView view = (FrontEndView)target;
418                 final Collection<FrontEndParameter> viewVariables = view.getVariables();
419                 for (final Iterator<FrontEndParameter> pageVariableIterator = viewVariables.iterator(); pageVariableIterator.hasNext();)
420                 {
421                     final ParameterFacade facade = (ParameterFacade)pageVariableIterator.next();
422                     formFieldMap.put(
423                         facade.getName(),
424                         facade);
425                 }
426                 final Collection<FrontEndParameter> allActionParameters = view.getAllFormFields();
427                 for (final Iterator<FrontEndParameter> actionParameterIterator = allActionParameters.iterator();
428                     actionParameterIterator.hasNext();)
429                 {
430                     // - don't allow existing parameters that are tables be overwritten (since they take
431                     //   precedence
432                     final Object parameter = actionParameterIterator.next();
433                     if (parameter instanceof FrontEndParameter)
434                     {
435                         FrontEndParameter variable = (FrontEndParameter)parameter;
436                         final String name = variable.getName();
437                         final Object existingParameter = formFieldMap.get(name);
438                         if (existingParameter instanceof FrontEndParameter)
439                         {
440                             final FrontEndParameter existingVariable = (FrontEndParameter)existingParameter;
441                             if (existingVariable.isTable())
442                             {
443                                 variable = existingVariable;
444                             }
445                         }
446                         formFieldMap.put(
447                             name,
448                             variable);
449                     }
450                 }
451             }
452             else if (target instanceof FrontEndFinalState)
453             {
454                 // only add these if there is no parameter recorded yet with the same name
455                 final Collection<FrontEndParameter> forwardParameters = forward.getForwardParameters();
456                 for (final Iterator<FrontEndParameter> parameterIterator = forwardParameters.iterator(); parameterIterator.hasNext();)
457                 {
458                     final FrontEndParameter facade = parameterIterator.next();
459                     if (!formFieldMap.containsKey(facade.getName()))
460                     {
461                         formFieldMap.put(
462                             facade.getName(),
463                             facade);
464                     }
465                 }
466             }
467         }
468 
469         // we do the action parameters in the end because they are allowed to overwrite existing properties
470         final Collection<FrontEndParameter> actionParameters = this.getParameters();
471         for (final Iterator<FrontEndParameter> parameterIterator = actionParameters.iterator(); parameterIterator.hasNext();)
472         {
473             final Object parameter = parameterIterator.next();
474             if (parameter instanceof FrontEndParameter)
475             {
476                 final FrontEndParameter variable = (FrontEndParameter)parameter;
477                 formFieldMap.put(
478                     variable.getName(),
479                     variable);
480             }
481         }
482 
483         // - if we don't have any fields defined on this action and there are no action forwards,
484         //   take the parameters from the deferred operations (since we would want to stay on the same view)
485         if (formFieldMap.isEmpty() && this.getActionForwards().isEmpty())
486         {
487             for (final Iterator<FrontEndControllerOperation> iterator = this.getDeferredOperations().iterator(); iterator.hasNext();)
488             {
489                 final OperationFacade operation = (OperationFacade)iterator.next();
490                 for (final Iterator<ParameterFacade> parameterIterator = operation.getArguments().iterator(); parameterIterator.hasNext();)
491                 {
492                     final ParameterFacade parameter = parameterIterator.next();
493                     formFieldMap.put(parameter.getName(), parameter);
494                 }
495             }
496         }
497         return new ArrayList<ParameterFacade>(formFieldMap.values());
498     }
499 }