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