001package org.andromda.metafacades.uml14;
002
003import java.util.ArrayList;
004import java.util.Collection;
005import java.util.Iterator;
006import java.util.LinkedHashMap;
007import java.util.LinkedHashSet;
008import java.util.List;
009import java.util.Map;
010import java.util.Set;
011import org.andromda.metafacades.uml.ActionStateFacade;
012import org.andromda.metafacades.uml.ClassifierFacade;
013import org.andromda.metafacades.uml.EventFacade;
014import org.andromda.metafacades.uml.FrontEndAction;
015import org.andromda.metafacades.uml.FrontEndActionState;
016import org.andromda.metafacades.uml.FrontEndActivityGraph;
017import org.andromda.metafacades.uml.FrontEndController;
018import org.andromda.metafacades.uml.FrontEndControllerOperation;
019import org.andromda.metafacades.uml.FrontEndEvent;
020import org.andromda.metafacades.uml.FrontEndForward;
021import org.andromda.metafacades.uml.FrontEndParameter;
022import org.andromda.metafacades.uml.FrontEndPseudostate;
023import org.andromda.metafacades.uml.FrontEndUseCase;
024import org.andromda.metafacades.uml.ModelElementFacade;
025import org.andromda.metafacades.uml.OperationFacade;
026import org.andromda.metafacades.uml.ParameterFacade;
027import org.andromda.metafacades.uml.StateVertexFacade;
028import org.andromda.metafacades.uml.TransitionFacade;
029import org.apache.log4j.Logger;
030
031/**
032 * MetafacadeLogic implementation for org.andromda.metafacades.uml.FrontEndControllerOperation.
033 *
034 * @see org.andromda.metafacades.uml.FrontEndControllerOperation
035 * @author Bob Fields
036 */
037public class FrontEndControllerOperationLogicImpl
038    extends FrontEndControllerOperationLogic
039{
040    private static final long serialVersionUID = 6536778815148740646L;
041
042    /**
043     * @param metaObject
044     * @param context
045     */
046    public FrontEndControllerOperationLogicImpl(
047        Object metaObject,
048        String context)
049    {
050        super(metaObject, context);
051    }
052
053    /**
054     * The logger instance.
055     */
056    private static final Logger logger = Logger.getLogger(FrontEndControllerOperationLogicImpl.class);
057
058    /**
059     * Override to return the owner's package as the package name.
060     *
061     * @see org.andromda.metafacades.uml14.ModelElementFacadeLogic#handleGetPackageName()
062     */
063    public String handleGetPackageName()
064    {
065        final ClassifierFacade owner = this.getOwner();
066        return owner != null ? owner.getPackageName() : "";
067    }
068
069    /**
070     * @see org.andromda.metafacades.uml.FrontEndControllerOperation#isOwnerIsController()
071     */
072    @Override
073    protected boolean handleIsOwnerIsController()
074    {
075        return this.getOwner() instanceof FrontEndController;
076    }
077
078    /**
079     * @see org.andromda.metafacades.uml.FrontEndControllerOperation#getFormFields()
080     */
081    @Override
082    protected List<FrontEndParameter> handleGetFormFields()
083    {
084        final Map<String, FrontEndParameter> formFieldsMap = new LinkedHashMap<String, FrontEndParameter>();
085
086        // for quick lookup we use a hashset for the argument names, we only consider parameters with a name
087        // which is also present in this set
088        final Set argumentNames = new LinkedHashSet();
089        final Collection<ParameterFacade> arguments = this.getArguments();
090        for (final Iterator argumentIterator = arguments.iterator(); argumentIterator.hasNext();)
091        {
092            final ModelElementFacade element = (ModelElementFacade)argumentIterator.next();
093            argumentNames.add(element.getName());
094        }
095
096        // - get all actions deferring to this operation
097        final List<FrontEndAction> deferringActions = this.getDeferringActions();
098        for (final Iterator<FrontEndAction> iterator = deferringActions.iterator(); iterator.hasNext();)
099        {
100            final FrontEndAction action = iterator.next();
101            // store the action parameters
102            final List<FrontEndParameter> actionFormFields = action.getFormFields();
103            for (final Iterator<FrontEndParameter> fieldIterator = actionFormFields.iterator(); fieldIterator.hasNext();)
104            {
105                final FrontEndParameter parameter = fieldIterator.next();
106                final String name = parameter.getName();
107                // - only add if the parameter is an action parameter and its an argument of this operation
108                if (parameter.getAction() != null && argumentNames.contains(name))
109                {
110                    formFieldsMap.put(name, parameter);
111                }
112            }
113            // get all forwards and overwrite when we find a table (or add when not yet present)
114            final List<FrontEndForward> forwards = action.getActionForwards();
115            for (final Iterator<FrontEndForward> forwardIterator = forwards.iterator(); forwardIterator.hasNext();)
116            {
117                final FrontEndForward forward = forwardIterator.next();
118                // - only consider forwards directly entering a view
119                if (forward.isEnteringView())
120                {
121                    final List<FrontEndParameter> viewVariables = forward.getForwardParameters();
122                    for (final Iterator<FrontEndParameter> variableIterator = viewVariables.iterator(); variableIterator.hasNext();)
123                    {
124                        final FrontEndParameter viewVariable = variableIterator.next();
125                        final String name = viewVariable.getName();
126                        if (argumentNames.contains(name))
127                        {
128                            if (!formFieldsMap.containsKey(name) || viewVariable.isTable())
129                            {
130                                formFieldsMap.put(name, viewVariable);
131                            }
132                        }
133                    }
134                }
135            }
136        }
137
138        // since all arguments need to be present we add those that haven't yet been stored in the map
139        for (final Iterator argumentIterator = arguments.iterator(); argumentIterator.hasNext();)
140        {
141            final FrontEndParameter argument = (FrontEndParameter)argumentIterator.next();
142            final String name = argument.getName();
143            if (!formFieldsMap.containsKey(name))
144            {
145                formFieldsMap.put(name, argument);
146            }
147        }
148        return new ArrayList<FrontEndParameter>(formFieldsMap.values());
149    }
150
151    /**
152     * @see org.andromda.metafacades.uml.FrontEndControllerOperation#getActivityGraph()
153     */
154    @Override
155    protected FrontEndActivityGraph handleGetActivityGraph()
156    {
157        FrontEndActivityGraph graph = null;
158
159        final ClassifierFacade owner = getOwner();
160        if (owner instanceof FrontEndController)
161        {
162            final FrontEndController controller = (FrontEndController)owner;
163            final FrontEndUseCase useCase = controller.getUseCase();
164            if (useCase != null)
165            {
166                graph = useCase.getActivityGraph();
167            }
168        }
169        return graph;
170    }
171
172    /**
173     * @see org.andromda.metafacades.uml.FrontEndControllerOperation#getDeferringActions()
174     */
175    @Override
176    protected List<FrontEndAction> handleGetDeferringActions()
177    {
178        final Collection<FrontEndAction> deferringActions = new LinkedHashSet<FrontEndAction>();
179
180        final FrontEndActivityGraph graph = this.getActivityGraph();
181        if (graph != null)
182        {
183            final Collection<ActionStateFacade> actionStates = graph.getActionStates();
184            for (final Iterator<ActionStateFacade> actionStateIterator = actionStates.iterator(); actionStateIterator.hasNext();)
185            {
186                final ActionStateFacade actionStateObject = actionStateIterator.next();
187                if (actionStateObject instanceof FrontEndActionState)
188                {
189                    final FrontEndActionState actionState = (FrontEndActionState)actionStateObject;
190                    final Collection<OperationFacade> controllerCalls = actionState.getControllerCalls();
191                    for (final Iterator<OperationFacade> controllerCallIterator = controllerCalls.iterator();
192                        controllerCallIterator.hasNext();)
193                    {
194                        final OperationFacade operation = controllerCallIterator.next();
195                        if (this.equals(operation))
196                        {
197                            deferringActions.addAll(actionState.getContainerActions());
198                        }
199                    }
200                }
201            }
202
203            final Collection<TransitionFacade> transitions = graph.getTransitions();
204            for (final Iterator<TransitionFacade> transitionIterator = transitions.iterator(); transitionIterator.hasNext();)
205            {
206                final FrontEndForward transition = (FrontEndForward)transitionIterator.next();
207                final EventFacade event = transition.getTrigger();
208                if (event instanceof FrontEndEvent)
209                {
210                    final FrontEndEvent trigger = (FrontEndEvent)event;
211                    final FrontEndControllerOperation operation = trigger.getControllerCall();
212                    if (this.equals(operation))
213                    {
214                        // we have two types of controller calls: the ones in action states and the ones for decisions
215                        final StateVertexFacade source = transition.getSource();
216                        if (source instanceof FrontEndActionState)
217                        {
218                            final FrontEndActionState sourceActionState = (FrontEndActionState)source;
219                            deferringActions.addAll(sourceActionState.getContainerActions());
220                        }
221
222                        // test for decision
223                        final StateVertexFacade target = transition.getTarget();
224                        if (target instanceof FrontEndPseudostate)
225                        {
226                            final FrontEndPseudostate targetPseudoState = (FrontEndPseudostate)target;
227                            if (targetPseudoState.isDecisionPoint())
228                            {
229                                deferringActions.addAll(targetPseudoState.getContainerActions());
230                            }
231                        }
232                    }
233                }
234            }
235        }
236        return new ArrayList(deferringActions);
237    }
238
239    /**
240     * @see org.andromda.metafacades.uml.FrontEndControllerOperation#isAllArgumentsHaveFormFields()
241     */
242    @Override
243    protected boolean handleIsAllArgumentsHaveFormFields()
244    {
245        final Collection<ParameterFacade> arguments = this.getArguments();
246        final Collection<FrontEndAction> deferringActions = this.getDeferringActions();
247
248        boolean allArgumentsHaveFormFields = true;
249        for (final Iterator<ParameterFacade> iterator = arguments.iterator(); iterator.hasNext() && allArgumentsHaveFormFields;)
250        {
251            final ParameterFacade parameter = iterator.next();
252            final String parameterName = parameter.getName();
253            final ClassifierFacade parameterType = parameter.getType();
254            final String parameterTypeName = parameterType != null ? parameterType.getFullyQualifiedName() : "";
255
256            boolean actionMissingField = false;
257            for (final Iterator<FrontEndAction> actionIterator = deferringActions.iterator();
258                actionIterator.hasNext() && !actionMissingField;)
259            {
260                final Object obj = actionIterator.next();
261                // BPM4Struts throws a ClassCastException when validating model unless we add try/catch
262                try
263                {
264                    final FrontEndAction action = (FrontEndAction)obj;
265                    final Collection<FrontEndParameter> actionFormFields = action.getFormFields();
266
267                    boolean fieldPresent = false;
268                    for (final Iterator<FrontEndParameter> fieldIterator = actionFormFields.iterator();
269                        fieldIterator.hasNext() && !fieldPresent;)
270                    {
271                        final ParameterFacade field = (ParameterFacade)fieldIterator.next();
272                        final ClassifierFacade fieldType = field.getType();
273                        final String fieldTypeName = fieldType != null ? fieldType.getFullyQualifiedName() : "";
274                        if (parameterName.equals(field.getName()) && parameterTypeName.equals(fieldTypeName))
275                        {
276                            fieldPresent = true;
277                        }
278                    }
279                    actionMissingField = !fieldPresent;
280                }
281                catch (ClassCastException e)
282                {
283                    logger.error("ClassCastException on handleIsAllArgumentsHaveFormFields for " + obj + ' ' + e.getMessage());
284                }
285            }
286            allArgumentsHaveFormFields = !actionMissingField;
287        }
288        return allArgumentsHaveFormFields;
289    }
290}