001package org.andromda.metafacades.uml14;
002
003import java.util.ArrayList;
004import java.util.Collection;
005import java.util.Collections;
006import java.util.LinkedHashSet;
007import java.util.List;
008import java.util.Set;
009import org.andromda.metafacades.uml.EventFacade;
010import org.andromda.metafacades.uml.FrontEndAction;
011import org.andromda.metafacades.uml.FrontEndActionState;
012import org.andromda.metafacades.uml.FrontEndActivityGraph;
013import org.andromda.metafacades.uml.FrontEndControllerOperation;
014import org.andromda.metafacades.uml.FrontEndEvent;
015import org.andromda.metafacades.uml.FrontEndForward;
016import org.andromda.metafacades.uml.FrontEndUseCase;
017import org.andromda.metafacades.uml.FrontEndView;
018import org.andromda.metafacades.uml.ParameterFacade;
019import org.andromda.metafacades.uml.PseudostateFacade;
020import org.andromda.metafacades.uml.StateVertexFacade;
021import org.andromda.metafacades.uml.TransitionFacade;
022import org.andromda.metafacades.uml.UseCaseFacade;
023import org.andromda.utils.StringUtilsHelper;
024
025/**
026 * MetafacadeLogic implementation for org.andromda.metafacades.uml.FrontEndForward.
027 *
028 * @see org.andromda.metafacades.uml.FrontEndForward
029 * @author Bob Fields
030 */
031public class FrontEndForwardLogicImpl
032    extends FrontEndForwardLogic
033{
034    private static final long serialVersionUID = 34L;
035    /**
036     * @param metaObject
037     * @param context
038     */
039    public FrontEndForwardLogicImpl(
040        Object metaObject,
041        String context)
042    {
043        super(metaObject, context);
044    }
045
046    /**
047     * @see org.andromda.metafacades.uml.FrontEndForward#isContainedInFrontEndUseCase()
048     */
049    @Override
050    protected boolean handleIsContainedInFrontEndUseCase()
051    {
052        return this.getFrontEndActivityGraph() != null;
053    }
054
055    /**
056     * @see org.andromda.metafacades.uml.FrontEndForward#getFrontEndActivityGraph()
057     */
058    @Override
059    protected FrontEndActivityGraph handleGetFrontEndActivityGraph()
060    {
061        final Object graph = this.getSource().getStateMachine();
062        return (FrontEndActivityGraph)(graph instanceof FrontEndActivityGraph ? graph : null);
063    }
064
065    /**
066     * If this forward has a trigger this method returns that trigger's name, otherwise if this forward
067     * has a name this method returns that name, otherwise if this forward's target has a name this
068     * method returns that name, otherwise simply returns <code>"unknown"</code>
069     *
070     * @see org.andromda.metafacades.uml14.ModelElementFacadeLogic#handleGetName()
071     */
072    protected final String handleGetName()
073    {
074        String forwardName = null;
075
076        // - trigger
077        final EventFacade trigger = getTrigger();
078        if (trigger != null)
079        {
080            forwardName = trigger.getName();
081        }
082
083        // - name
084        if (forwardName == null)
085        {
086            forwardName = super.handleGetName();
087        }
088
089        // - target
090        if (forwardName == null)
091        {
092            forwardName = this.getTarget().getName();
093        }
094
095        // - else
096        if (forwardName == null)
097        {
098            forwardName = "unknown";
099        }
100        return forwardName;
101    }
102
103    /**
104     * @see org.andromda.metafacades.uml.FrontEndForward#getActionMethodName()
105     */
106    @Override
107    protected String handleGetActionMethodName()
108    {
109        return StringUtilsHelper.lowerCamelCaseName(this.getName());
110    }
111
112    /**
113     * @see org.andromda.metafacades.uml.FrontEndForward#isEnteringView()
114     */
115    @Override
116    protected boolean handleIsEnteringView()
117    {
118        return this.getTarget() instanceof FrontEndView;
119    }
120
121    /**
122     * @see org.andromda.metafacades.uml.FrontEndForward#isExitingView()
123     */
124    @Override
125    protected boolean handleIsExitingView()
126    {
127        return this.getSource() instanceof FrontEndView;
128    }
129
130    /**
131     * @see org.andromda.metafacades.uml.FrontEndForward#getUseCase()
132     */
133    @Override
134    protected FrontEndUseCase handleGetUseCase()
135    {
136        FrontEndUseCase useCase = null;
137        final FrontEndActivityGraph graph = this.getFrontEndActivityGraph();
138        if (graph != null)
139        {
140            final UseCaseFacade graphUseCase = graph.getUseCase();
141            if (graphUseCase instanceof FrontEndUseCase)
142            {
143                useCase = (FrontEndUseCase)graphUseCase;
144            }
145        }
146        return useCase;
147    }
148
149    /**
150     * All action states that make up this action, this includes all possible action states traversed
151     * after a decision point too.
152     */
153    private Collection<FrontEndActionState> actionStates = null;
154
155    /**
156     * @return new ArrayList(actionStates)
157     * @see org.andromda.metafacades.uml.FrontEndAction#getActionStates()
158     */
159    //@Override
160    protected List<FrontEndActionState> handleGetActionStates()
161    {
162        if (actionStates == null)
163        {
164            this.initializeCollections();
165        }
166        return new ArrayList<FrontEndActionState>(actionStates);
167    }
168
169    /**
170     * Initializes all action states, action forwards, decision transitions and transitions in one shot, so that they
171     * can be queried more efficiently later on.
172     */
173    private void initializeCollections()
174    {
175        this.actionStates = new LinkedHashSet<FrontEndActionState>();
176        this.collectTransitions(
177            this,
178            new LinkedHashSet<TransitionFacade>());
179    }
180
181    /**
182     * Recursively collects all action states, action forwards, decision transitions and transitions.
183     *
184     * @param transition the current transition that is being processed
185     * @param processedTransitions the set of transitions already processed
186     */
187    private void collectTransitions(
188        final TransitionFacade transition,
189        final Collection<TransitionFacade> processedTransitions)
190    {
191        if (processedTransitions.contains(transition))
192        {
193            return;
194        }
195        processedTransitions.add(transition);
196
197        final StateVertexFacade target = transition.getTarget();
198        if (target instanceof FrontEndActionState)
199        {
200            this.actionStates.add((FrontEndActionState)target);
201            final FrontEndForward forward = ((FrontEndActionState)target).getForward();
202            if (forward != null)
203            {
204                collectTransitions(
205                    forward,
206                    processedTransitions);
207            }
208        }
209    }
210
211    /**
212     * @see org.andromda.metafacades.uml.FrontEndAction#getDecisionTrigger()
213     */
214    @Override
215    protected EventFacade handleGetDecisionTrigger()
216    {
217        return (this.isEnteringDecisionPoint() ? getTrigger() : null);
218    }
219
220    /**
221     * @see org.andromda.metafacades.uml.FrontEndAction#getActions()
222     */
223    @Override
224    protected List<FrontEndAction> handleGetActions()
225    {
226        final Set<FrontEndAction> actions = new LinkedHashSet<FrontEndAction>();
227        this.findActions(
228            actions,
229            new LinkedHashSet<FrontEndForward>());
230        return new ArrayList<FrontEndAction>(actions);
231    }
232
233    /**
234     * Recursively finds all actions for this forward, what this means depends on the context in which
235     * this forward is used: if the source is a page action state it will collect all actions going out
236     * of this page, if the source is a regular action state it will collect all actions that might traverse
237     * this action state, if the source is the initial state it will collect all actions forwarding to this
238     * forward's use-case (please not that those actions most likely are defined in other use-cases).
239     *
240     * @param actions the default set of actions, duplicates will not be recorded
241     * @param handledForwards the forwards already processed
242     */
243    private void findActions(
244        final Set<FrontEndAction> actions,
245        final Set<FrontEndForward> handledForwards)
246    {
247        if (!handledForwards.contains(this.THIS()))
248        {
249            handledForwards.add(this);
250
251            if (this instanceof FrontEndAction) // TODO this is not so nice because FrontEndAction extends FrontEndForward, solution would be to override in FrontEndAction
252            {
253                actions.add((FrontEndAction)this.THIS());
254            }
255            else
256            {
257                final StateVertexFacade vertex = getSource();
258                if (vertex instanceof FrontEndView)
259                {
260                    final FrontEndView view = (FrontEndView)vertex;
261                    actions.addAll(view.getActions());
262                }
263                else if (vertex instanceof FrontEndActionState)
264                {
265                    final FrontEndActionState actionState = (FrontEndActionState)vertex;
266                    actions.addAll(actionState.getContainerActions());
267                }
268                else if (vertex instanceof PseudostateFacade)
269                {
270                    final PseudostateFacade pseudostate = (PseudostateFacade)vertex;
271                    if (!pseudostate.isInitialState())
272                    {
273                        final Collection<TransitionFacade> incomingForwards = pseudostate.getIncomings();
274                        for (TransitionFacade incomingForward : incomingForwards)
275                        {
276                            final FrontEndForward forward = (FrontEndForward) incomingForward;
277                            actions.addAll(forward.getActions());
278                        }
279                    }
280                }
281            }
282        }
283    }
284
285    /**
286     * Overridden since a transition doesn't exist in a package.
287     *
288     * @see org.andromda.metafacades.uml14.ModelElementFacadeLogic#handleGetPackageName()
289     */
290    protected String handleGetPackageName()
291    {
292        String packageName = null;
293
294        final UseCaseFacade useCase = this.getUseCase();
295        if (useCase != null)
296        {
297            packageName = useCase.getPackageName();
298        }
299        return packageName;
300    }
301
302    /**
303     * @see org.andromda.metafacades.uml.FrontEndAction#getForwardParameters()
304     */
305    @Override
306    protected List<ParameterFacade> handleGetForwardParameters()
307    {
308        final EventFacade trigger = this.getTrigger();
309        return trigger == null ? Collections.EMPTY_LIST : new ArrayList<ParameterFacade>(trigger.getParameters());
310    }
311
312    /**
313     * @see org.andromda.metafacades.uml.FrontEndAction#getOperationCall()
314     */
315    @Override
316   protected Object handleGetOperationCall()
317    {
318        FrontEndControllerOperation operation = null;
319        final EventFacade triggerEvent = this.getTrigger();
320        if (triggerEvent instanceof FrontEndEvent)
321        {
322            final FrontEndEvent trigger = (FrontEndEvent)triggerEvent;
323            operation = trigger.getControllerCall();
324        }
325        return operation;
326    }
327}