001package org.andromda.cartridges.bpm4struts.metafacades;
002
003import java.util.ArrayList;
004import java.util.Collection;
005import java.util.Collections;
006import java.util.HashMap;
007import java.util.Iterator;
008import java.util.LinkedHashMap;
009import java.util.LinkedHashSet;
010import java.util.List;
011import java.util.Map;
012import org.andromda.cartridges.bpm4struts.Bpm4StrutsGlobals;
013import org.andromda.cartridges.bpm4struts.Bpm4StrutsProfile;
014import org.andromda.cartridges.bpm4struts.Bpm4StrutsUtils;
015import org.andromda.metafacades.uml.EventFacade;
016import org.andromda.metafacades.uml.FilteredCollection;
017import org.andromda.metafacades.uml.FrontEndEvent;
018import org.andromda.metafacades.uml.FrontEndExceptionHandler;
019import org.andromda.metafacades.uml.FrontEndFinalState;
020import org.andromda.metafacades.uml.FrontEndForward;
021import org.andromda.metafacades.uml.FrontEndParameter;
022import org.andromda.metafacades.uml.FrontEndUseCase;
023import org.andromda.metafacades.uml.ModelElementFacade;
024import org.andromda.metafacades.uml.ParameterFacade;
025import org.andromda.metafacades.uml.PseudostateFacade;
026import org.andromda.metafacades.uml.Role;
027import org.andromda.metafacades.uml.StateVertexFacade;
028import org.andromda.metafacades.uml.TransitionFacade;
029import org.andromda.metafacades.uml.UMLProfile;
030import org.andromda.metafacades.uml.UseCaseFacade;
031import org.andromda.utils.StringUtilsHelper;
032import org.apache.commons.collections.CollectionUtils;
033import org.apache.commons.collections.Predicate;
034import org.apache.commons.lang.ObjectUtils;
035import org.apache.commons.lang.StringUtils;
036
037/**
038 * MetafacadeLogic implementation.
039 *
040 * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsAction
041 */
042public class StrutsActionLogicImpl
043    extends StrutsActionLogic
044{
045    private static final long serialVersionUID = 34L;
046    /**
047     * All action states that make up this action, this includes all possible action states traversed
048     * after a decision point too.
049     */
050    private Collection<StrutsActionState> actionStates = null;
051
052    /**
053     * All transitions leading into either a page or final state that originated from a call to this action.
054     */
055    private Map<StateVertexFacade, TransitionFacade> actionForwards = null;
056
057    /**
058     * All transitions leading into a decision point that originated from a call to this action.
059     */
060    private Collection<TransitionFacade> decisionTransitions = null;
061
062    /**
063     * All transitions that can be traversed when calling this action.
064     */
065    private Collection<TransitionFacade> transitions = null;
066
067    /**
068     * @param metaObject
069     * @param context
070     */
071    public StrutsActionLogicImpl(Object metaObject,
072                                 String context)
073    {
074        super(metaObject, context);
075    }
076
077    /**
078     * Initializes all action states, action forwards, decision transitions and transitions in one shot, so that they
079     * can be queried more efficiently later on.
080     */
081    private void initializeCollections()
082    {
083        actionStates = new LinkedHashSet<StrutsActionState>();
084        actionForwards = new HashMap<StateVertexFacade, TransitionFacade>();
085        decisionTransitions = new LinkedHashSet<TransitionFacade>();
086        transitions = new LinkedHashSet<TransitionFacade>();
087        collectTransitions(this, transitions);
088    }
089
090    /**
091     * Recursively collects all action states, action forwards, decision transitions and transitions.
092     *
093     * @param transition           the current transition that is being processed
094     * @param processedTransitions the set of transitions already processed
095     */
096    private void collectTransitions(TransitionFacade transition,
097                                    Collection<TransitionFacade> processedTransitions)
098    {
099        if (processedTransitions.contains(transition))
100        {
101            return;
102        }
103        processedTransitions.add(transition);
104
105        final StateVertexFacade target = transition.getTarget();
106        if ((target instanceof StrutsJsp) || (target instanceof StrutsFinalState))
107        {
108            if (!actionForwards.containsKey(transition.getTarget()))
109            {
110                actionForwards.put(transition.getTarget(), transition);
111            }
112        }
113        else if ((target instanceof PseudostateFacade) && ((PseudostateFacade) target).isDecisionPoint())
114        {
115            decisionTransitions.add(transition);
116            for (final TransitionFacade outcome : target.getOutgoings())
117            {
118                collectTransitions(outcome, processedTransitions);
119            }
120        }
121        else if (target instanceof StrutsActionState)
122        {
123            actionStates.add((StrutsActionState)target);
124            final FrontEndForward forward = ((StrutsActionState) target).getForward();
125            if (forward != null)
126            {
127                collectTransitions(forward, processedTransitions);
128            }
129        }
130        else // all the rest is ignored but outgoing transitions are further processed
131        {
132            for (final TransitionFacade outcome : target.getOutgoings())
133            {
134                collectTransitions(outcome, processedTransitions);
135            }
136        }
137    }
138
139    /**
140     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleGetActionName()
141     */
142    protected String handleGetActionName()
143    {
144        return getFormBeanName();
145    }
146
147    /**
148     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleGetActionInput()
149     */
150    protected String handleGetActionInput()
151    {
152        final StateVertexFacade source = getSource();
153        return (source instanceof StrutsJsp) ? ((StrutsJsp) source).getFullPath() : "";
154    }
155
156    /**
157     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleIsMultipartFormData()
158     */
159    protected boolean handleIsMultipartFormData()
160    {
161        boolean multipartFormPost = false;
162
163        for (StrutsParameter field : this.getActionFormFields())
164        {
165            if (field.isFile())
166            {
167                multipartFormPost = true;
168                break;
169            }
170        }
171
172        return multipartFormPost;
173    }
174
175    /**
176     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleIsFormPost()
177     */
178    protected boolean handleIsFormPost()
179    {
180        final Object value = this.findTaggedValue(Bpm4StrutsProfile.TAGGEDVALUE_ACTION_TYPE);
181        return value == null || Bpm4StrutsProfile.TAGGEDVALUE_ACTION_TYPE_FORM.equals(value);
182    }
183
184    /**
185     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleIsHyperlink()
186     */
187    protected boolean handleIsHyperlink()
188    {
189        final Object value = findTaggedValue(Bpm4StrutsProfile.TAGGEDVALUE_ACTION_TYPE);
190        return Bpm4StrutsProfile.TAGGEDVALUE_ACTION_TYPE_HYPERLINK
191            .equalsIgnoreCase(value == null ? null : value.toString());
192    }
193
194    /**
195     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleIsImageLink()
196     */
197    protected boolean handleIsImageLink()
198    {
199        final Object value = findTaggedValue(Bpm4StrutsProfile.TAGGEDVALUE_ACTION_TYPE);
200        return Bpm4StrutsProfile.TAGGEDVALUE_ACTION_TYPE_IMAGE
201            .equalsIgnoreCase(value == null ? null : value.toString());
202    }
203
204    /**
205     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleIsTableAction()
206     */
207    protected boolean handleIsTableAction()
208    {
209        return Bpm4StrutsProfile.TAGGEDVALUE_ACTION_TYPE_TABLE
210            .equals(this.findTaggedValue(Bpm4StrutsProfile.TAGGEDVALUE_ACTION_TYPE));
211    }
212
213    /**
214     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleIsTableRowAction()
215     */
216    protected boolean handleIsTableRowAction()
217    {
218        return this.isTableLink() && !this.isTableAction();
219    }
220
221    /**
222     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleIsTableLink()
223     */
224    protected boolean handleIsTableLink()
225    {
226        return this.getTableLinkParameter() != null;
227    }
228
229    /**
230     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleGetTableLinkParameter()
231     */
232    protected Object handleGetTableLinkParameter()
233    {
234        StrutsParameter tableLinkParameter = null;
235
236        final String tableLinkName = getTableLinkName();
237        if (tableLinkName != null)
238        {
239            final StrutsJsp page = this.getInput();
240            if (page != null)
241            {
242                for (FrontEndParameter table : page.getTables())
243                {
244                    if (tableLinkName.equals(table.getName()))
245                    {
246                        tableLinkParameter = (StrutsParameter)table;
247                    }
248                }
249            }
250        }
251
252        return tableLinkParameter;
253    }
254
255    /**
256     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleGetTableNonColumnFormParameters()
257     */
258    protected List<StrutsParameter> handleGetTableNonColumnFormParameters()
259    {
260        List<StrutsParameter> tableNonColumnActionParameters = null;
261
262        final StrutsParameter table = getTableLinkParameter();
263        if (table != null)
264        {
265            final Map<String, StrutsParameter> tableNonColumnActionParametersMap = new LinkedHashMap<String, StrutsParameter>(4);
266            final Collection<String> columnNames = table.getTableColumnNames();
267            final List<StrutsAction> formActions = table.getTableFormActions();
268            int formSize = formActions.size();
269            for (int i = 0; i < formSize; i++)
270            {
271                final StrutsAction action = formActions.get(i);
272                int size = action.getActionParameters().size();
273                for (int j = 0; j < size; j++)
274                {
275                    final StrutsParameter parameter = action.getActionParameters().get(j);
276                    if (!columnNames.contains(parameter.getName()))
277                    {
278                        tableNonColumnActionParametersMap.put(parameter.getName(), parameter);
279                    }
280                }
281            }
282
283            tableNonColumnActionParameters = new ArrayList<StrutsParameter>(tableNonColumnActionParametersMap.values());
284        }
285
286        return tableNonColumnActionParameters;
287    }
288
289    /**
290     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleGetTableLinkName()
291     */
292    protected String handleGetTableLinkName()
293    {
294        String tableLink = null;
295
296        final Object value = findTaggedValue(Bpm4StrutsProfile.TAGGEDVALUE_ACTION_TABLELINK);
297        if (value != null)
298        {
299            tableLink = StringUtils.trimToNull(value.toString());
300
301            if (tableLink != null)
302            {
303                final int columnOffset = tableLink.indexOf('.');
304                tableLink = (columnOffset == -1) ? tableLink : tableLink.substring(0, columnOffset);
305            }
306        }
307
308        return tableLink;
309    }
310
311    /**
312     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleGetTableLinkColumnName()
313     */
314    protected String handleGetTableLinkColumnName()
315    {
316        String tableLink = null;
317
318        final Object value = findTaggedValue(Bpm4StrutsProfile.TAGGEDVALUE_ACTION_TABLELINK);
319        if (value != null)
320        {
321            tableLink = StringUtils.trimToNull(value.toString());
322
323            if (tableLink != null)
324            {
325                final int columnOffset = tableLink.indexOf('.');
326                tableLink = (columnOffset == -1 || columnOffset == tableLink.length() - 1)
327                    ? null
328                    : tableLink.substring(columnOffset + 1);
329            }
330        }
331
332        return tableLink;
333    }
334
335    /**
336     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleGetImagePath()
337     */
338    protected String handleGetImagePath()
339    {
340        return getPackagePath() + '/' + Bpm4StrutsUtils.toWebFileName(getActionClassName()) + ".gif";
341    }
342
343    /**
344     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleGetActionPath()
345     */
346    protected String handleGetActionPath()
347    {
348        return getActionPathRoot() + '/' + getActionClassName();
349    }
350
351    /**
352     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleGetActionPathRoot()
353     */
354    protected String handleGetActionPathRoot()
355    {
356        String actionPathRoot = null;
357
358        final FrontEndUseCase useCase = this.getUseCase();
359        if (useCase != null)
360        {
361            final StringBuilder buffer = new StringBuilder();
362
363            final String actionPathPrefix = Bpm4StrutsGlobals.PROPERTY_ACTION_PATH_PREFIX;
364            String prefix = this.isConfiguredProperty(actionPathPrefix) ? ObjectUtils
365                .toString(this.getConfiguredProperty(actionPathPrefix)) : "";
366
367            final ModelElementFacade useCasePackage = useCase.getPackage();
368            if (useCasePackage != null)
369            {
370                prefix = prefix.replaceAll("\\{0\\}", useCasePackage.getPackagePath());
371            }
372
373            buffer.append(prefix);
374            buffer.append('/');
375            buffer.append(StringUtilsHelper.upperCamelCaseName(useCase.getName()));
376
377            actionPathRoot = buffer.toString();
378        }
379        return actionPathRoot;
380    }
381
382    /**
383     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleGetActionScope()
384     */
385    protected String handleGetActionScope()
386    {
387        return "request";
388    }
389
390    /**
391     * @return getRoleUsers()
392     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsAction#getActionRoles()
393     */
394    protected String handleGetActionRoles()
395    {
396        final Collection users = getRoleUsers();
397        final StringBuilder roles = new StringBuilder();
398        for (final Iterator userIterator = users.iterator(); userIterator.hasNext();)
399        {
400            roles.append(((ModelElementFacade) userIterator.next()).getName());
401            if (userIterator.hasNext())
402            {
403                roles.append(',');
404            }
405        }
406        return roles.toString();
407    }
408
409    /**
410     * Returns a collection containing StrutsUser instances representing the roles
411     * authorized to call this action. If this action starts the use-case that use-case's users
412     * are returned, otherwise it will return the users associated to the use-cases targeted by this
413     * action (which may be none at all)
414     */
415    private Collection<Role> getRoleUsers()
416    {
417        final Collection<Role> roleUsers = new ArrayList<Role>();
418
419        if (this.isUseCaseStart())
420        {
421            final FrontEndUseCase useCase = getUseCase();
422            if (useCase != null)
423            {
424                roleUsers.addAll(useCase.getRoles());
425            }
426        }
427        else
428        {
429            for (final StrutsForward forward : getActionForwards())
430            {
431                if (forward.getTarget() instanceof StrutsFinalState)
432                {
433                    final FrontEndUseCase useCase = ((StrutsFinalState) forward.getTarget()).getTargetUseCase();
434                    if (useCase != null)
435                    {
436                        roleUsers.addAll(useCase.getRoles());
437                    }
438                }
439            }
440        }
441
442        return roleUsers;
443    }
444
445    /**
446     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleGetActionClassName()
447     */
448    protected String handleGetActionClassName()
449    {
450        String name = null;
451
452        if (this.isExitingInitialState())
453        {
454            final UseCaseFacade useCase = this.getUseCase();
455            if (useCase != null)
456            {
457                name = useCase.getName();
458            }
459        }
460        else
461        {
462            final EventFacade trigger = getTrigger();
463            final String suffix = (trigger == null) ? getTarget().getName() : trigger.getName();
464            name = getSource().getName() + ' ' + suffix;
465        }
466        return StringUtilsHelper.upperCamelCaseName(name);
467    }
468
469    /**
470     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleGetActionType()
471     */
472    protected String handleGetActionType()
473    {
474        return getPackageName() + '.' + getActionClassName();
475    }
476
477    /**
478     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleGetFormBeanClassName()
479     */
480    protected String handleGetFormBeanClassName()
481    {
482        return getActionClassName() + Bpm4StrutsGlobals.FORM_IMPLEMENTATION_SUFFIX;
483    }
484
485    /**
486     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleGetFormBeanName()
487     */
488    protected String handleGetFormBeanName()
489    {
490        String formBeanName = null;
491
492        final UseCaseFacade useCase = this.getUseCase();
493        if (useCase != null)
494        {
495            final String useCaseName = useCase.getName();
496            formBeanName = StringUtilsHelper.lowerCamelCaseName(useCaseName) + getActionClassName() + Bpm4StrutsGlobals
497                .FORM_SUFFIX;
498        }
499        return formBeanName;
500    }
501
502    /**
503     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleGetFormValidationMethodName()
504     */
505    protected String handleGetFormValidationMethodName()
506    {
507        return "validate" + this.getActionClassName() + Bpm4StrutsGlobals.FORM_SUFFIX;
508    }
509
510    /**
511     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleGetMessageKey()
512     */
513    protected String handleGetMessageKey()
514    {
515        String messageKey = null;
516
517        final StrutsTrigger actionTrigger = getActionTrigger();
518        if (actionTrigger != null)
519        {
520            messageKey = actionTrigger.getTriggerKey();
521        }
522
523        return messageKey;
524    }
525
526    /**
527     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleGetImageMessageKey()
528     */
529    protected String handleGetImageMessageKey()
530    {
531        return getMessageKey() + ".image";
532    }
533
534    /**
535     * Overrides the method defined in the facade parent of StrutsAction, this is done because actions (transitions) are
536     * not directly contained in a UML namespace.
537     * @return useCase.getPackageName()
538     */
539    public String getPackageName()
540    {
541        String packageName = null;
542
543        final UseCaseFacade useCase = this.getUseCase();
544        if (useCase != null)
545        {
546            packageName = useCase.getPackageName();
547        }
548        return packageName;
549    }
550
551    /**
552     * @return Bpm4StrutsProfile.TAGGEDVALUE_ACTION_RESETTABLE
553     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsAction#isResettable()
554     */
555    protected boolean handleIsResettable()
556    {
557        Object value = findTaggedValue(Bpm4StrutsProfile.TAGGEDVALUE_ACTION_RESETTABLE);
558        return isTrue(value == null ? null : value.toString());
559    }
560
561    /**
562     * Convenient method to detect whether or not a String instance represents a boolean <code>true</code> value.
563     */
564    private boolean isTrue(String string)
565    {
566        return "yes".equalsIgnoreCase(string) ||
567            "true".equalsIgnoreCase(string) ||
568            "on".equalsIgnoreCase(string) ||
569            "1".equalsIgnoreCase(string);
570    }
571
572    /**
573     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleIsUseCaseStart()
574     */
575    protected boolean handleIsUseCaseStart()
576    {
577        StateVertexFacade source = getSource();
578        return source instanceof PseudostateFacade && ((PseudostateFacade) source).isInitialState();
579    }
580
581    /**
582     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleGetFullActionPath()
583     */
584    protected String handleGetFullActionPath()
585    {
586        return getPackagePath() + '/' + getActionClassName();
587    }
588
589    /**
590     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleGetFullTilePath()
591     */
592    protected String handleGetFullTilePath()
593    {
594        return isUseCaseStart()
595            ? "empty-file"
596            : getPackagePath() + '/' + Bpm4StrutsUtils.toWebFileName(getActionClassName());
597    }
598
599    /**
600     * We override this method here to make sure the actions end-up in the same package as their use-case. A transition
601     * (this class' parent type) does not have a real package as we need it here.
602     * @return this.getUseCase() / useCase.getPackagePath()
603     */
604    public String getPackagePath()
605    {
606        String packagePath = null;
607
608        final UseCaseFacade useCase = this.getUseCase();
609        if (useCase != null)
610        {
611            packagePath = '/' + useCase.getPackagePath();
612        }
613        return packagePath;
614    }
615
616    /**
617     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleGetFullFormBeanPath()
618     */
619    protected String handleGetFullFormBeanPath()
620    {
621        return '/' + (getPackageName() + '/' + getFormBeanClassName()).replace('.', '/');
622    }
623
624    /**
625     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleIsValidationRequired()
626     */
627    protected boolean handleIsValidationRequired()
628    {
629        for (final StrutsParameter parameter : getActionParameters())
630        {
631            if (parameter.isValidationRequired())
632            {
633                return true;
634            }
635        }
636        return false;
637    }
638
639    /**
640     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleIsDateFieldPresent()
641     */
642    protected boolean handleIsDateFieldPresent()
643    {
644        for (final StrutsParameter parameter : getActionParameters())
645        {
646            if (parameter.isDate())
647            {
648                return true;
649            }
650        }
651        return false;
652    }
653
654    /**
655     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleIsCalendarRequired()
656     */
657    protected boolean handleIsCalendarRequired()
658    {
659        for (final StrutsParameter parameter : getActionParameters())
660        {
661            if (parameter.isCalendarRequired())
662            {
663                return true;
664            }
665        }
666        return false;
667    }
668
669    /**
670     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleGetFormBeanPackageName()
671     */
672    protected String handleGetFormBeanPackageName()
673    {
674        return getPackageName();
675    }
676
677    /**
678     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleGetFormBeanType()
679     */
680    protected String handleGetFormBeanType()
681    {
682        return getFormBeanPackageName() + '.' + getFormBeanClassName();
683    }
684
685    /**
686     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleGetDocumentationKey()
687     */
688    protected String handleGetDocumentationKey()
689    {
690        final StrutsTrigger trigger = getActionTrigger();
691        return ((trigger == null) ? getMessageKey() + ".is.an.action.without.trigger" : trigger.getTriggerKey()) +
692            ".documentation";
693    }
694
695    /**
696     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleGetDocumentationValue()
697     */
698    protected String handleGetDocumentationValue()
699    {
700        final String value = StringUtilsHelper.toResourceMessage(getDocumentation("", 64, false));
701        return (value == null) ? "" : value;
702    }
703
704    /**
705     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleGetOnlineHelpKey()
706     */
707    protected String handleGetOnlineHelpKey()
708    {
709        final StrutsTrigger trigger = getActionTrigger();
710        return ((trigger == null) ? getMessageKey() + ".is.an.action.without.trigger" : trigger.getTriggerKey()) +
711            ".online.help";
712    }
713
714    /**
715     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleGetOnlineHelpValue()
716     */
717    protected String handleGetOnlineHelpValue()
718    {
719        final String crlf = "<br/>";
720        final StringBuilder buffer = new StringBuilder();
721
722        final String value = StringUtilsHelper.toResourceMessage(getDocumentation("", 64, false));
723        buffer.append((value == null) ? "No action documentation has been specified" : value);
724        buffer.append(crlf);
725
726        return StringUtilsHelper.toResourceMessage(buffer.toString());
727    }
728
729    /**
730     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleGetActionForwards()
731     */
732    protected List<TransitionFacade> handleGetActionForwards()
733    {
734        if (actionForwards == null) initializeCollections();
735        return new ArrayList<TransitionFacade>(actionForwards.values());
736    }
737
738    /**
739     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleGetDecisionTransitions()
740     */
741    protected List<TransitionFacade> handleGetDecisionTransitions()
742    {
743        if (decisionTransitions == null) initializeCollections();
744        return new ArrayList<TransitionFacade>(decisionTransitions);
745    }
746
747    /**
748     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleGetActionStates()
749     */
750    protected List<StrutsActionState> handleGetActionStates()
751    {
752        if (actionStates == null) initializeCollections();
753        return new ArrayList<StrutsActionState>(actionStates);
754    }
755
756    /**
757     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleGetActionExceptions()
758     */
759    protected List<FrontEndExceptionHandler> handleGetActionExceptions()
760    {
761        final Collection<FrontEndExceptionHandler> exceptions = new LinkedHashSet<FrontEndExceptionHandler>();
762        final Collection<StrutsActionState> actionStates = getActionStates();
763        for (final Iterator<StrutsActionState> iterator = actionStates.iterator(); iterator.hasNext();)
764        {
765            StrutsActionState actionState = iterator.next();
766            exceptions.addAll(actionState.getExceptions());
767        }
768
769        return new ArrayList<FrontEndExceptionHandler>(exceptions);
770    }
771
772    /**
773     * @return PseudostateFacade or STEREOTYPE_FRONT_END_VIEW
774     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsAction#getInput()
775     */
776    protected Object handleGetInput()
777    {
778        Object input = null;
779        final ModelElementFacade source = getSource();
780        if (source instanceof PseudostateFacade)
781        {
782            final PseudostateFacade pseudostate = (PseudostateFacade) source;
783            if (pseudostate.isInitialState())
784            {
785                input = source;
786            }
787        }
788        else
789        {
790            if (source.hasStereotype(UMLProfile.STEREOTYPE_FRONT_END_VIEW))
791            {
792                input = source;
793            }
794        }
795        return input;
796    }
797
798    /**
799     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleGetController()
800     */
801    protected Object handleGetController()
802    {
803        final StrutsActivityGraph graph = this.getStrutsActivityGraph();
804        return graph == null ? null : graph.getController();
805    }
806
807    /**
808     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleGetActionTrigger()
809     */
810    protected Object handleGetActionTrigger()
811    {
812        return this.getTrigger();
813    }
814
815    /**
816     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleGetActionFormFields()
817     */
818    protected List<FrontEndParameter> handleGetActionFormFields()
819    {
820        final Map<String, FrontEndParameter> formFieldMap = new HashMap<String, FrontEndParameter>();
821
822        /**
823         * for useCaseStart actions we need to detect all usecases forwarding to the one belonging to this action
824         * if there are any parameters in those requests we need to have them included in this action's form
825         */
826        if (this.isUseCaseStart())
827        {
828            final FrontEndUseCase useCase = this.getUseCase();
829            if (useCase != null)
830            {
831                final Collection<FrontEndFinalState> finalStates = useCase.getReferencingFinalStates();
832                for (final Iterator<FrontEndFinalState> finalStateIterator = finalStates.iterator(); finalStateIterator.hasNext();)
833                {
834                    final Object finalStateObject = finalStateIterator.next();
835                    // we need to test for the type because a non struts-use-case final state might accidentally
836                    // be linking to this use-case (for example: the user temporarily wants to disable code generation
837                    // for a specific use-case and is not removing the final-state to use-case link(s))
838                    if (finalStateObject instanceof StrutsFinalState)
839                    {
840                        final StrutsFinalState finalState = (StrutsFinalState) finalStateObject;
841                        for (final FrontEndParameter parameter : finalState.getInterUseCaseParameters())
842                        {
843                            formFieldMap.put(parameter.getName(), parameter);
844                        }
845                    }
846                }
847            }
848        }
849
850        // if any action encountered by the execution of the complete action-graph path emits a forward
851        // containing one or more parameters they need to be included as a form field too
852        for (final StrutsActionState actionState : getActionStates())
853        {
854            final StrutsForward forward = (StrutsForward) actionState.getForward();
855            if (forward != null)
856            {
857                for (final FrontEndParameter forwardParameter : forward.getForwardParameters())
858                {
859                    formFieldMap.put(forwardParameter.getName(), forwardParameter);
860                }
861            }
862        }
863
864        // add page variables for all pages/final-states targeted
865        // also add the fields of the target page's actions (for preloading)
866        for (final StrutsForward forward : getActionForwards())
867        {
868            final StateVertexFacade target = forward.getTarget();
869            if (target instanceof StrutsJsp)
870            {
871                final StrutsJsp jsp = (StrutsJsp) target;
872                for (final StrutsParameter facade : jsp.getPageVariables())
873                {
874                    formFieldMap.put(facade.getName(), facade);
875                }
876                for (final FrontEndParameter facade : jsp.getAllActionParameters())
877                {
878                    formFieldMap.put(facade.getName(), facade);
879                }
880            }
881            else if (target instanceof StrutsFinalState)
882            {
883                // only add these if there is no parameter recorded yet with the same name
884                for (final FrontEndParameter facade : forward.getForwardParameters())
885                {
886                    if (!formFieldMap.containsKey(facade.getName()))
887                    {
888                        formFieldMap.put(facade.getName(), facade);
889                    }
890                }
891            }
892        }
893
894        // we do the action parameters in the end because they are allowed to overwrite existing properties
895        for (final StrutsParameter facade : getActionParameters())
896        {
897            formFieldMap.put(facade.getName(), facade);
898        }
899
900        return new ArrayList<FrontEndParameter>(formFieldMap.values());
901    }
902
903    /**
904     * FrontEndControllerOperation does not extend OperationFacade
905     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleGetDeferredOperations()
906     */
907    protected List handleGetDeferredOperations()
908    {
909        final Collection deferredOperations = new LinkedHashSet();
910
911        final StrutsController controller = getController();
912        if (controller != null)
913        {
914            final List<StrutsActionState> actionStates = getActionStates();
915            int size = actionStates.size();
916            for (int i = 0; i < size; i++)
917            {
918                final StrutsActionState actionState = actionStates.get(i);
919                deferredOperations.addAll(actionState.getControllerCalls());
920            }
921
922            for (StrutsForward forward : this.getDecisionTransitions())
923            {
924                final FrontEndEvent trigger = forward.getDecisionTrigger();
925                if (trigger != null)
926                {
927                    deferredOperations.add(trigger.getControllerCall());
928                }
929            }
930        }
931        return new ArrayList(deferredOperations);
932    }
933
934    /**
935     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleGetActionParameters()
936     */
937    protected List<ParameterFacade> handleGetActionParameters()
938    {
939        final StrutsTrigger trigger = getActionTrigger();
940        return (trigger == null) ? Collections.emptyList() : new ArrayList(trigger.getParameters());
941    }
942
943    /**
944     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleGetInterUseCaseParameters(org.andromda.cartridges.bpm4struts.metafacades.StrutsFinalState)
945     */
946    protected List<FrontEndParameter> handleGetInterUseCaseParameters(StrutsFinalState finalState)
947    {
948        List<FrontEndParameter> parameters;
949
950        if (finalState == null)
951        {
952            parameters = Collections.emptyList();
953        }
954        else
955        {
956            // we don't want to list parameters with the same name to we use a hash map
957            final Map<String, FrontEndParameter> parameterMap = new HashMap<String, FrontEndParameter>();
958
959            for (final StrutsForward forward : this.getActionForwards())
960            {
961                // only return those parameters that belong to both this action and the argument final state
962                if (finalState.equals(forward.getTarget()))
963                {
964                    for (FrontEndParameter parameter : forward.getForwardParameters())
965                    {
966                        parameterMap.put(parameter.getName(), parameter);
967                    }
968                }
969            }
970            parameters = new ArrayList<FrontEndParameter>(parameterMap.values());
971        }
972
973        return parameters;
974    }
975
976    /**
977     * @return getActionForwards().getTarget()
978     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsAction#getTargetPages()
979     */
980    protected List<StateVertexFacade> handleGetTargetPages()
981    {
982        Collection<StateVertexFacade> targetPages = new LinkedHashSet<StateVertexFacade>();
983
984        for (final StrutsForward forward : getActionForwards())
985        {
986            if (forward.isEnteringPage())
987            {
988                targetPages.add(forward.getTarget());
989            }
990        }
991
992        return new ArrayList<StateVertexFacade>(targetPages);
993    }
994
995    /**
996     * @return new ArrayList(transitions)
997     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#getTransitions()
998     */
999    protected List<TransitionFacade> handleGetTransitions()
1000    {
1001        if (transitions == null)
1002        {
1003            initializeCollections();
1004        }
1005        return new ArrayList<TransitionFacade>(transitions);
1006    }
1007
1008    /**
1009     * @return getActionTrigger().getName() lowerCamelCaseName
1010     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsAction#getStyleId()
1011     */
1012    protected String handleGetStyleId()
1013    {
1014        String styleId = null;
1015
1016        StrutsTrigger trigger = getActionTrigger();
1017        if (trigger != null)
1018        {
1019            String triggerName = trigger.getName();
1020            styleId = StringUtilsHelper.lowerCamelCaseName(triggerName);
1021        }
1022        return styleId;
1023    }
1024
1025    /**
1026     * @return Bpm4StrutsProfile.TAGGEDVALUE_ACTION_REDIRECT
1027     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsAction#isRedirect()
1028     */
1029    protected boolean handleIsRedirect()
1030    {
1031        String redirect = (String) this.getConfiguredProperty(Bpm4StrutsGlobals.PROPERTY_DEFAULT_ACTION_REDIRECT);
1032        Object value = this.findTaggedValue(Bpm4StrutsProfile.TAGGEDVALUE_ACTION_REDIRECT);
1033        if (value != null)
1034        {
1035            redirect = (String) value;
1036        }
1037        return Boolean.valueOf(StringUtils.trimToEmpty(redirect));
1038    }
1039
1040    /**
1041     * @return getActionParameters().isShouldReset()
1042     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsAction#getResettableActionParameters()
1043     */
1044    protected List<StrutsParameter> handleGetResettableActionParameters()
1045    {
1046        return new ArrayList<StrutsParameter>(new FilteredCollection(this.getActionParameters())
1047        {
1048            private static final long serialVersionUID = 34L;
1049            public boolean evaluate(Object object)
1050            {
1051                return object != null && ((StrutsParameter)object).isShouldReset();
1052            }
1053        });
1054    }
1055
1056    /**
1057     * The "session" action form scope.
1058     */
1059    private static final String FORM_SCOPE_SESSION = "session";
1060
1061    /**
1062     * The "request" action form scope.
1063     */
1064    private static final String FORM_SCOPE_REQUEST = "request";
1065
1066    /**
1067     * The "none" action form scope.
1068     */
1069    private static final String FORM_SCOPE_NONE = "none";
1070
1071    /**
1072     * @return Bpm4StrutsProfile.TAGGEDVALUE_ACTION_FORM_SCOPE
1073     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsAction#getFormScope()
1074     */
1075    protected String handleGetFormScope()
1076    {
1077        String actionFormScope = String
1078            .valueOf(this.getConfiguredProperty(Bpm4StrutsGlobals.PROPERTY_ACTION_FORM_SCOPE));
1079        Object value = this.findTaggedValue(Bpm4StrutsProfile.TAGGEDVALUE_ACTION_FORM_SCOPE);
1080        if (value != null)
1081        {
1082            actionFormScope = String.valueOf(value);
1083        }
1084        return StringUtils.trimToEmpty(actionFormScope);
1085    }
1086
1087    /**
1088     * @return getFormScope().equalsIgnoreCase(FORM_SCOPE_SESSION)
1089     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsAction#isFormScopeSession()
1090     */
1091    protected boolean handleIsFormScopeSession()
1092    {
1093        return FORM_SCOPE_SESSION.equalsIgnoreCase(this.getFormScope());
1094    }
1095
1096    /**
1097     * @return getFormScope().equalsIgnoreCase(FORM_SCOPE_REQUEST)
1098     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsAction#isFormScopeRequest()
1099     */
1100    protected boolean handleIsFormScopeRequest()
1101    {
1102        return FORM_SCOPE_REQUEST.equalsIgnoreCase(this.getFormScope());
1103    }
1104
1105    /**
1106     * @return getFormScope().equalsIgnoreCase(FORM_SCOPE_NONE)
1107     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsAction#isFormScopeNone()
1108     */
1109    protected boolean handleIsFormScopeNone()
1110    {
1111        return this.getFormScope().equalsIgnoreCase(FORM_SCOPE_NONE);
1112    }
1113
1114    /**
1115     * @see org.andromda.cartridges.bpm4struts.metafacades.StrutsActionLogic#handleGetHiddenActionParameters()
1116     */
1117    protected List<StrutsParameter> handleGetHiddenActionParameters()
1118    {
1119        final List<StrutsParameter> hiddenActionParameters = new ArrayList<StrutsParameter>(this.getActionParameters());
1120        CollectionUtils.filter(hiddenActionParameters, new Predicate()
1121        {
1122            public boolean evaluate(final Object object)
1123            {
1124                return StrutsParameterLogicImpl.HIDDEN_INPUT_TYPE.equals(((StrutsParameter) object).getWidgetType());
1125            }
1126        });
1127        return hiddenActionParameters;
1128    }
1129}