001package org.andromda.cartridges.jsf.metafacades;
002
003import java.util.ArrayList;
004import java.util.Collection;
005import java.util.HashMap;
006import java.util.HashSet;
007import java.util.Iterator;
008import java.util.LinkedHashMap;
009import java.util.LinkedHashSet;
010import java.util.List;
011import java.util.Map;
012import java.util.Set;
013import org.andromda.cartridges.jsf.JSFGlobals;
014import org.andromda.cartridges.jsf.JSFProfile;
015import org.andromda.cartridges.jsf.JSFUtils;
016import org.andromda.metafacades.uml.AssociationEndFacade;
017import org.andromda.metafacades.uml.AttributeFacade;
018import org.andromda.metafacades.uml.ClassifierFacade;
019import org.andromda.metafacades.uml.EventFacade;
020import org.andromda.metafacades.uml.FrontEndAction;
021import org.andromda.metafacades.uml.FrontEndActivityGraph;
022import org.andromda.metafacades.uml.FrontEndForward;
023import org.andromda.metafacades.uml.FrontEndParameter;
024import org.andromda.metafacades.uml.FrontEndView;
025import org.andromda.metafacades.uml.ModelElementFacade;
026import org.andromda.metafacades.uml.TransitionFacade;
027import org.andromda.metafacades.uml.UseCaseFacade;
028import org.andromda.utils.StringUtilsHelper;
029import org.apache.commons.lang.ObjectUtils;
030import org.apache.commons.lang.StringUtils;
031
032/**
033 * MetafacadeLogic implementation for org.andromda.cartridges.jsf.metafacades.JSFParameter.
034 *
035 * @see org.andromda.cartridges.jsf.metafacades.JSFParameter
036 */
037public class JSFParameterLogicImpl
038    extends JSFParameterLogic
039{
040    private static final long serialVersionUID = 34L;
041    /**
042     * @param metaObject
043     * @param context
044     */
045    public JSFParameterLogicImpl(
046        Object metaObject,
047        String context)
048    {
049        super(metaObject, context);
050    }
051
052    /**
053     * Overridden to make sure it's not an inputTable.
054     *
055     * @see org.andromda.metafacades.uml.FrontEndParameter#isTable()
056     */
057    public boolean isTable()
058    {
059        return (super.isTable() || this.isPageableTable()) && !this.isSelectable()
060            && !this.isInputTable() && !this.isInputHidden();
061    }
062
063    /**
064     * @return isPageableTable
065     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#isPageableTable()
066     */
067    protected boolean handleIsPageableTable()
068    {
069        final Object value = this.findTaggedValue(JSFProfile.TAGGEDVALUE_TABLE_PAGEABLE);
070        return Boolean.valueOf(ObjectUtils.toString(value)).booleanValue();
071    }
072
073    /**
074     * @return messageKey
075     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#getMessageKey()
076     */
077    protected String handleGetMessageKey()
078    {
079        final StringBuilder messageKey = new StringBuilder();
080
081        if (!this.isNormalizeMessages())
082        {
083            if (this.isActionParameter())
084            {
085                final JSFAction action = (JSFAction)this.getAction();
086                if (action != null)
087                {
088                    messageKey.append(action.getMessageKey());
089                    messageKey.append('.');
090                }
091            }
092            else
093            {
094                final JSFView view = (JSFView)this.getView();
095                if (view != null)
096                {
097                    messageKey.append(view.getMessageKey());
098                    messageKey.append('.');
099                }
100            }
101            messageKey.append("param.");
102        }
103
104        messageKey.append(StringUtilsHelper.toResourceMessageKey(super.getName()));
105        return messageKey.toString();
106    }
107
108    /**
109     * @return getMessageKey() + '.' + JSFGlobals.DOCUMENTATION_MESSAGE_KEY_SUFFIX
110     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#getDocumentationKey()
111     */
112    protected String handleGetDocumentationKey()
113    {
114        return getMessageKey() + '.' + JSFGlobals.DOCUMENTATION_MESSAGE_KEY_SUFFIX;
115    }
116
117    /**
118     * @return documentationValue
119     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#getDocumentationValue()
120     */
121    protected String handleGetDocumentationValue()
122    {
123        final String value = StringUtilsHelper.toResourceMessage(this.getDocumentation(
124                    "",
125                    64,
126                    false));
127        return value == null ? "" : value;
128    }
129
130    /**
131     * Indicates whether or not we should normalize messages.
132     *
133     * @return true/false
134     */
135    private boolean isNormalizeMessages()
136    {
137        final String normalizeMessages = (String)getConfiguredProperty(JSFGlobals.NORMALIZE_MESSAGES);
138        return Boolean.valueOf(normalizeMessages).booleanValue();
139    }
140
141    /**
142     * @return messageValue
143     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#getMessageValue()
144     */
145    protected String handleGetMessageValue()
146    {
147        return StringUtilsHelper.toPhrase(super.getName()); // the actual name is used for displaying
148    }
149
150    /**
151     * @param columnName
152     * @return tableColumnMessageKey
153     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#getTableColumnMessageKey(String)
154     */
155    protected String handleGetTableColumnMessageKey(final String columnName)
156    {
157        StringBuilder messageKey = new StringBuilder();
158        if (!this.isNormalizeMessages())
159        {
160            final JSFView view = (JSFView)this.getView();
161            if (view != null)
162            {
163                messageKey.append(this.getMessageKey());
164                messageKey.append('.');
165            }
166        }
167        messageKey.append(StringUtilsHelper.toResourceMessageKey(columnName));
168        return messageKey.toString();
169    }
170
171    /**
172     * @param columnName
173     * @return StringUtilsHelper.toPhrase(columnName)
174     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#getTableColumnMessageValue(String)
175     */
176    protected String handleGetTableColumnMessageValue(final String columnName)
177    {
178        return StringUtilsHelper.toPhrase(columnName);
179    }
180
181    /**
182     * @return getTableActions(true)
183     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#getTableHyperlinkActions()
184     */
185    protected List<JSFAction> handleGetTableHyperlinkActions()
186    {
187        return this.getTableActions(true);
188    }
189
190    /**
191     * If this is a table this method returns all those actions that are declared to work
192     * on this table.
193     *
194     * @param hyperlink denotes on which type of actions to filter
195     */
196    private List<JSFAction> getTableActions(boolean hyperlink)
197    {
198        final Set<JSFAction> actions = new LinkedHashSet<JSFAction>();
199        final String name = StringUtils.trimToNull(getName());
200        if (name != null && isTable())
201        {
202            final JSFView view = (JSFView)this.getView();
203
204            final Collection<UseCaseFacade> allUseCases = getModel().getAllUseCases();
205            for (final UseCaseFacade useCase : allUseCases)
206            {
207                if (useCase instanceof JSFUseCase)
208                {
209                    final FrontEndActivityGraph graph = ((JSFUseCase)useCase).getActivityGraph();
210                    if (graph != null)
211                    {
212                        final Collection<TransitionFacade> transitions = graph.getTransitions();
213                        for (final TransitionFacade transition : transitions)
214                        {
215                            if (transition.getSource().equals(view) && transition instanceof JSFAction)
216                            {
217                                final JSFAction action = (JSFAction)transition;
218                                if (action.isTableLink() && name.equals(action.getTableLinkName()))
219                                {
220                                    if (hyperlink == action.isHyperlink())
221                                    {
222                                        actions.add(action);
223                                    }
224                                }
225                            }
226                        }
227                    }
228                }
229            }
230        }
231        return new ArrayList<JSFAction>(actions);
232    }
233
234    /**
235     * @return getTableActions(false)
236     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#getTableFormActions()
237     */
238    protected List<JSFAction> handleGetTableFormActions()
239    {
240        return this.getTableActions(false);
241    }
242
243    /**
244     * @see org.andromda.metafacades.uml.FrontEndParameter#getTableColumns()
245     */
246    // TODO tableColumns can be either String or JSFParameter. Should use a single return type in Collection.
247    public Collection getTableColumns()
248    {
249        final Collection tableColumns = super.getTableColumns();
250        if (tableColumns.isEmpty())
251        {
252            // try to preserve the order of the elements encountered
253            //final Map<String, JSFParameter> tableColumnsMap = new LinkedHashMap<String, JSFParameter>();
254            final Map tableColumnsMap = new LinkedHashMap();
255
256            // order is important
257            final List<JSFAction> actions = new ArrayList<JSFAction>();
258
259            // all table actions need the exact same parameters, just not always all of them
260            actions.addAll(this.getTableFormActions());
261
262            // if there are any actions that are hyperlinks then their parameters get priority
263            // the user should not have modeled it that way (constraints will warn him/her)
264            actions.addAll(this.getTableHyperlinkActions());
265
266            for (final JSFAction action : actions)
267            {
268                for (final FrontEndParameter actionParameter : action.getParameters())
269                {
270                    if (actionParameter instanceof JSFParameter)
271                    {
272                        final JSFParameter parameter = (JSFParameter)actionParameter;
273                        final String parameterName = parameter.getName();
274                        if (parameterName != null)
275                        {
276                            // never overwrite column specific table links
277                            // the hyperlink table links working on a real column get priority
278                            final Object existingObject = tableColumnsMap.get(parameterName);
279                            if (existingObject instanceof JSFParameter)
280                            {
281                                if (action.isHyperlink() && parameterName.equals(action.getTableLinkColumnName()))
282                                {
283                                    tableColumnsMap.put(
284                                        parameterName,
285                                        parameter);
286                                }
287                            }
288                        }
289                    }
290                }
291            }
292
293            // for any missing parameters we just add the name of the column
294            for (final String columnName : this.getTableColumnNames())
295            {
296                if (!tableColumnsMap.containsKey(columnName))
297                {
298                    tableColumnsMap.put(
299                        columnName,
300                        columnName);
301                }
302            }
303
304            // return everything in the same order as it has been modeled (using the table tagged value)
305            for (final String columnObject : this.getTableColumnNames())
306            {
307                tableColumns.add(tableColumnsMap.get(columnObject));
308            }
309        }
310        return tableColumns;
311    }
312
313    /**
314     * @return the default date format pattern as defined using the configured property
315     */
316    private String getDefaultDateFormat()
317    {
318        return (String)this.getConfiguredProperty(JSFGlobals.PROPERTY_DEFAULT_DATEFORMAT);
319    }
320
321    /**
322     * @return format
323     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#getFormat()
324     */
325    protected String handleGetFormat()
326    {
327        return JSFUtils.getFormat(
328            (ModelElementFacade)this.THIS(),
329            this.getType(),
330            this.getDefaultDateFormat(),
331            this.getDefaultTimeFormat());
332    }
333
334    /**
335     * @return the default time format pattern as defined using the configured property
336     */
337    private String getDefaultTimeFormat()
338    {
339        return (String)this.getConfiguredProperty(JSFGlobals.PROPERTY_DEFAULT_TIMEFORMAT);
340    }
341
342    /**
343     * @return JSFUtils.isStrictDateFormat((ModelElementFacade)this.THIS())
344     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#isStrictDateFormat()
345     */
346    protected boolean handleIsStrictDateFormat()
347    {
348        return JSFUtils.isStrictDateFormat((ModelElementFacade)this.THIS());
349    }
350
351    /**
352     * @return dateFormatter
353     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#getDateFormatter()
354     */
355    protected String handleGetDateFormatter()
356    {
357        final ClassifierFacade type = this.getType();
358        return type != null && type.isDateType() ? this.getName() + "DateFormatter" : null;
359    }
360
361    /**
362     * @return timeFormatter
363     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#getTimeFormatter()
364     */
365    protected String handleGetTimeFormatter()
366    {
367        final ClassifierFacade type = this.getType();
368        return type != null && type.isTimeType() ? this.getName() + "TimeFormatter" : null;
369    }
370
371    /**
372     * Gets the current value of the specified input type (or an empty string
373     * if one isn't specified).
374     *
375     * @return the input type name.
376     */
377    private String getInputType()
378    {
379        return ObjectUtils.toString(this.findTaggedValue(JSFProfile.TAGGEDVALUE_INPUT_TYPE)).trim();
380    }
381
382    /**
383     * Indicates whether or not this parameter is of the given input type.
384     *
385     * @param inputType the name of the input type to check for.
386     * @return true/false
387     */
388    private boolean isInputType(final String inputType)
389    {
390        return inputType.equalsIgnoreCase(this.getInputType());
391    }
392
393    /**
394     * @return isInputType(JSFGlobals.INPUT_TEXTAREA)
395     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#isInputTextarea()
396     */
397    protected boolean handleIsInputTextarea()
398    {
399        return this.isInputType(JSFGlobals.INPUT_TEXTAREA);
400    }
401
402    /**
403     * @return isInputType(JSFGlobals.INPUT_SELECT)
404     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#isInputSelect()
405     */
406    protected boolean handleIsInputSelect()
407    {
408        return this.isInputType(JSFGlobals.INPUT_SELECT);
409    }
410
411    /**
412     * @return isInputType(JSFGlobals.INPUT_PASSWORD)
413     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#isInputSecret()
414     */
415    protected boolean handleIsInputSecret()
416    {
417        return this.isInputType(JSFGlobals.INPUT_PASSWORD);
418    }
419
420    /**
421     * @return isInputType(JSFGlobals.INPUT_HIDDEN)
422     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#isInputHidden()
423     */
424    protected boolean handleIsInputHidden()
425    {
426        return this.isInputType(JSFGlobals.INPUT_HIDDEN);
427    }
428
429    /**
430     * @return isInputType(JSFGlobals.PLAIN_TEXT)
431     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#isPlaintext()
432     */
433    protected boolean handleIsPlaintext()
434    {
435        return this.isInputType(JSFGlobals.PLAIN_TEXT);
436    }
437
438    /**
439     * @return isInputTable
440     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#isInputTable()
441     */
442    protected boolean handleIsInputTable()
443    {
444        return this.getInputTableIdentifierColumns().length() > 0 || this.isInputType(JSFGlobals.INPUT_TABLE);
445    }
446
447    /**
448     * @return isInputType(JSFGlobals.INPUT_RADIO)
449     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#isInputRadio()
450     */
451    protected boolean handleIsInputRadio()
452    {
453        return this.isInputType(JSFGlobals.INPUT_RADIO);
454    }
455
456    /**
457     * @return isInputType(JSFGlobals.INPUT_TEXT)
458     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#isInputText()
459     */
460    protected boolean handleIsInputText()
461    {
462        return this.isInputType(JSFGlobals.INPUT_TEXT);
463    }
464
465    /**
466     * @return isInputType(JSFGlobals.INPUT_MULTIBOX)
467     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#isInputMultibox()
468     */
469    protected boolean handleIsInputMultibox()
470    {
471        return this.isInputType(JSFGlobals.INPUT_MULTIBOX);
472    }
473
474    /**
475     * @return isInputCheckbox
476     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#isInputCheckbox()
477     */
478    protected boolean handleIsInputCheckbox()
479    {
480        boolean checkbox = this.isInputType(JSFGlobals.INPUT_CHECKBOX);
481        if (!checkbox && this.getInputType().length() == 0)
482        {
483            final ClassifierFacade type = this.getType();
484            checkbox = type != null ? type.isBooleanType() : false;
485        }
486        return checkbox;
487    }
488
489    /**
490     * @return isInputFile
491     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#isInputFile()
492     */
493    protected boolean handleIsInputFile()
494    {
495        boolean file = false;
496        ClassifierFacade type = getType();
497        if (type != null)
498        {
499            file = type.isFileType();
500        }
501        return file;
502    }
503
504    /**
505     * @return backingListName
506     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#getBackingListName()
507     */
508    protected String handleGetBackingListName()
509    {
510        return ObjectUtils.toString(this.getConfiguredProperty(JSFGlobals.BACKING_LIST_PATTERN)).replaceAll(
511            "\\{0\\}",
512            this.getName());
513    }
514
515    /**
516     * @return backingValueName
517     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#getBackingValueName()
518     */
519    protected String handleGetBackingValueName()
520    {
521        return ObjectUtils.toString(this.getConfiguredProperty(JSFGlobals.BACKING_VALUE_PATTERN)).replaceAll(
522            "\\{0\\}",
523            this.getName());
524    }
525
526    /**
527     * @return valueListName
528     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#getValueListName()
529     */
530    protected String handleGetValueListName()
531    {
532        return ObjectUtils.toString(this.getConfiguredProperty(JSFGlobals.VALUE_LIST_PATTERN)).replaceAll(
533            "\\{0\\}",
534            this.getName());
535    }
536
537    /**
538     * @return labelListName
539     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#getLabelListName()
540     */
541    protected String handleGetLabelListName()
542    {
543        return ObjectUtils.toString(this.getConfiguredProperty(JSFGlobals.LABEL_LIST_PATTERN)).replaceAll(
544            "\\{0\\}",
545            this.getName());
546    }
547
548    /**
549     * @return isSelectable
550     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#isSelectable()
551     */
552    protected boolean handleIsSelectable()
553    {
554        boolean selectable = false;
555        if (this.isActionParameter())
556        {
557            selectable = this.isInputMultibox() || this.isInputSelect() || this.isInputRadio();
558            final ClassifierFacade type = this.getType();
559
560            if (!selectable && type != null)
561            {
562                final String name = this.getName();
563                final String typeName = type.getFullyQualifiedName();
564
565                // - if the parameter is not selectable but on a targeting page it IS selectable we must
566                //   allow the user to set the backing list too
567                final Collection<FrontEndView> views = this.getAction().getTargetViews();
568                for (final Iterator<FrontEndView> iterator = views.iterator(); iterator.hasNext() && !selectable;)
569                {
570                    final Collection<FrontEndParameter> parameters = iterator.next().getAllActionParameters();
571                    for (final Iterator<FrontEndParameter> parameterIterator = parameters.iterator();
572                        parameterIterator.hasNext() && !selectable;)
573                    {
574                        final Object object = parameterIterator.next();
575                        if (object instanceof JSFParameter)
576                        {
577                            final JSFParameter parameter = (JSFParameter)object;
578                            final String parameterName = parameter.getName();
579                            final ClassifierFacade parameterType = parameter.getType();
580                            if (parameterType != null)
581                            {
582                                final String parameterTypeName = parameterType.getFullyQualifiedName();
583                                if (name.equals(parameterName) && typeName.equals(parameterTypeName))
584                                {
585                                    selectable =
586                                        parameter.isInputMultibox() || parameter.isInputSelect() ||
587                                        parameter.isInputRadio();
588                                }
589                            }
590                        }
591                    }
592                }
593            }
594        }
595        else if (this.isControllerOperationArgument())
596        {
597            final String name = this.getName();
598            final Collection actions = this.getControllerOperation().getDeferringActions();
599            for (final Iterator actionIterator = actions.iterator(); actionIterator.hasNext();)
600            {
601                final JSFAction action = (JSFAction)actionIterator.next();
602                final Collection<FrontEndParameter>  formFields = action.getFormFields();
603                for (final Iterator<FrontEndParameter>  fieldIterator = formFields.iterator();
604                    fieldIterator.hasNext() && !selectable;)
605                {
606                    final Object object = fieldIterator.next();
607                    if (object instanceof JSFParameter)
608                    {
609                        final JSFParameter parameter = (JSFParameter)object;
610                        if (!parameter.equals(this))
611                        {
612                            if (name.equals(parameter.getName()))
613                            {
614                                selectable = parameter.isSelectable();
615                            }
616                        }
617                    }
618                }
619            }
620        }
621        return selectable;
622    }
623
624    /**
625     * Stores the initial value of each type.
626     */
627    private final Map<String, String> initialValues = new HashMap<String, String>();
628
629    /**
630     * @return constructDummyArray()
631     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#getValueListDummyValue()
632     */
633    protected String handleGetValueListDummyValue()
634    {
635        return this.constructDummyArray();
636    }
637
638    /**
639     * @return dummyValue
640     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#getDummyValue()
641     */
642    protected String handleGetDummyValue()
643    {
644        final ClassifierFacade type = this.getType();
645        final String typeName = type != null ? type.getFullyQualifiedName() : "";
646        String initialValue = null;
647        if (type != null)
648        {
649            if (type.isSetType())
650            {
651                initialValue =
652                    "new java.util.LinkedHashSet(java.util.Arrays.asList(" + this.constructDummyArray() + "))";
653            }
654            else if (type.isCollectionType())
655            {
656                initialValue = "java.util.Arrays.asList(" + this.constructDummyArray() + ")";
657            }
658            else if (type.isArrayType())
659            {
660                initialValue = this.constructDummyArray();
661            }
662            final String name = this.getName() != null ? this.getName() : "";
663            if (this.initialValues.isEmpty())
664            {
665                initialValues.put(
666                    boolean.class.getName(),
667                    "false");
668                initialValues.put(
669                    int.class.getName(),
670                    "(int)" + name.hashCode());
671                initialValues.put(
672                    long.class.getName(),
673                    "(long)" + name.hashCode());
674                initialValues.put(
675                    short.class.getName(),
676                    "(short)" + name.hashCode());
677                initialValues.put(
678                    byte.class.getName(),
679                    "(byte)" + name.hashCode());
680                initialValues.put(
681                    float.class.getName(),
682                    "(float)" + name.hashCode());
683                initialValues.put(
684                    double.class.getName(),
685                    "(double)" + name.hashCode());
686                initialValues.put(
687                    char.class.getName(),
688                    "(char)" + name.hashCode());
689
690                initialValues.put(
691                    String.class.getName(),
692                    "\"" + name + "-test" + "\"");
693                initialValues.put(
694                    java.util.Date.class.getName(),
695                    "new java.util.Date()");
696                initialValues.put(
697                    java.sql.Date.class.getName(),
698                    "new java.util.Date()");
699                initialValues.put(
700                    java.sql.Timestamp.class.getName(),
701                    "new java.util.Date()");
702
703                initialValues.put(
704                    Integer.class.getName(),
705                    "new Integer((int)" + name.hashCode() + ")");
706                initialValues.put(
707                    Boolean.class.getName(),
708                    "Boolean.FALSE");
709                initialValues.put(
710                    Long.class.getName(),
711                    "new Long((long)" + name.hashCode() + ")");
712                initialValues.put(
713                    Character.class.getName(),
714                    "new Character(char)" + name.hashCode() + ")");
715                initialValues.put(
716                    Float.class.getName(),
717                    "new Float((float)" + name.hashCode() / hashCode() + ")");
718                initialValues.put(
719                    Double.class.getName(),
720                    "new Double((double)" + name.hashCode() / hashCode() + ")");
721                initialValues.put(
722                    Short.class.getName(),
723                    "new Short((short)" + name.hashCode() + ")");
724                initialValues.put(
725                    Byte.class.getName(),
726                    "new Byte((byte)" + name.hashCode() + ")");
727            }
728            if (initialValue == null)
729            {
730                initialValue = this.initialValues.get(typeName);
731            }
732        }
733        if (initialValue == null)
734        {
735            initialValue = "null";
736        }
737        return initialValue;
738    }
739
740    /**
741     * Constructs a string representing an array initialization in Java.
742     *
743     * @return A String representing Java code for the initialization of an array.
744     */
745    private String constructDummyArray()
746    {
747        return JSFUtils.constructDummyArrayDeclaration(
748            this.getName(),
749            JSFGlobals.DUMMY_ARRAY_COUNT);
750    }
751
752    /**
753     * @return getName() + "SortColumn"
754     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#getTableSortColumnProperty()
755     */
756    protected String handleGetTableSortColumnProperty()
757    {
758        return this.getName() + "SortColumn";
759    }
760
761    /**
762     * @return getName() + "SortAscending"
763     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#getTableSortAscendingProperty()
764     */
765    protected String handleGetTableSortAscendingProperty()
766    {
767        return this.getName() + "SortAscending";
768    }
769
770    /**
771     * @return getName() + "Set"
772     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#getFormAttributeSetProperty()
773     */
774    protected String handleGetFormAttributeSetProperty()
775    {
776        return this.getName() + "Set";
777    }
778
779    //TODO remove after 3.4 release
780    /**
781     * Hack to keep the compatibility with Andromda 3.4
782     */
783    /**
784     * @see org.andromda.metafacades.uml.FrontEndParameter#getView()
785     */
786    public FrontEndView getView()
787    {
788        Object view = null;
789        final EventFacade event = this.getEvent();
790        if (event != null)
791        {
792            final TransitionFacade transition = event.getTransition();
793            if (transition instanceof JSFActionLogicImpl)
794            {
795                final JSFActionLogicImpl action = (JSFActionLogicImpl)transition;
796                view = action.getInput();
797            }
798            else if (transition instanceof FrontEndForward)
799            {
800                final FrontEndForward forward = (FrontEndForward)transition;
801                if (forward.isEnteringView())
802                {
803                    view = forward.getTarget();
804                }
805            }
806        }
807        return (FrontEndView)view;
808    }
809
810    /**
811     * @return validationRequired
812     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#isValidationRequired()
813     */
814    protected boolean handleIsValidationRequired()
815    {
816        boolean required = !this.getValidatorTypes().isEmpty();
817        if (!required)
818        {
819            // - look for any attributes
820            for (final Iterator<JSFAttribute> iterator = this.getAttributes().iterator(); iterator.hasNext();)
821            {
822                required = !iterator.next().getValidatorTypes().isEmpty();
823                if (required)
824                {
825                    break;
826                }
827            }
828
829            // - look for any table columns
830            if (!required)
831            {
832                for (final Iterator iterator = this.getTableColumns().iterator(); iterator.hasNext();)
833                {
834                    final Object object = iterator.next();
835                    if (object instanceof JSFAttribute)
836                    {
837                        final JSFAttribute attribute = (JSFAttribute)object;
838                        required = !attribute.getValidatorTypes().isEmpty();
839                        if (required)
840                        {
841                            break;
842                        }
843                    }
844                }
845            }
846        }
847        return required;
848    }
849
850    /**
851     * @return validatorTypes
852     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#getValidatorTypes()
853     */
854    protected Collection handleGetValidatorTypes()
855    {
856        return JSFUtils.getValidatorTypes(
857            (ModelElementFacade)this.THIS(),
858            this.getType());
859    }
860
861    /**
862     * @return JSFUtils.getValidWhen(this)
863     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#getValidWhen()
864     */
865    protected String handleGetValidWhen()
866    {
867        return JSFUtils.getValidWhen(this);
868    }
869
870    /**
871     * Overridden to have the same behavior as bpm4struts.
872     *
873     * @see org.andromda.metafacades.uml.ParameterFacade#isRequired()
874     */
875    public boolean isRequired()
876    {
877        if("org.omg.uml.foundation.core".equals(metaObject.getClass().getPackage().getName()))
878        {
879            //if uml 1.4, keep the old behavior (like bpm4struts)
880            final Object value = this.findTaggedValue(JSFProfile.TAGGEDVALUE_INPUT_REQUIRED);
881            return Boolean.valueOf(ObjectUtils.toString(value)).booleanValue();
882        }
883        else
884        {
885            //if >= uml 2, default behavior
886            return super.isRequired();
887        }
888    }
889
890    /**
891     * @return JSFUtils.isReadOnly(this)
892     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#isReadOnly()
893     */
894    protected boolean handleIsReadOnly()
895    {
896        return JSFUtils.isReadOnly(this);
897    }
898
899    /**
900     * @param validatorType
901     * @return validatorArgs
902     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#getValidatorArgs(String)
903     */
904    protected Collection handleGetValidatorArgs(final String validatorType)
905    {
906        return JSFUtils.getValidatorArgs(
907            (ModelElementFacade)this.THIS(),
908            validatorType);
909    }
910
911    /**
912     * @return validatorVars
913     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#getValidatorVars()
914     */
915    protected Collection handleGetValidatorVars()
916    {
917        return JSFUtils.getValidatorVars(
918            (ModelElementFacade)this.THIS(),
919            this.getType(),
920            null);
921    }
922
923    /**
924     * @return reset
925     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#isReset()
926     */
927    protected boolean handleIsReset()
928    {
929        boolean reset =
930            Boolean.valueOf(ObjectUtils.toString(this.findTaggedValue(JSFProfile.TAGGEDVALUE_INPUT_RESET)))
931                   .booleanValue();
932        if (!reset)
933        {
934            final JSFAction action = (JSFAction)this.getAction();
935            reset = action != null && action.isFormReset();
936        }
937        return reset;
938    }
939
940    /**
941     * @return complex
942     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#isComplex()
943     */
944    protected boolean handleIsComplex()
945    {
946        boolean complex = false;
947        final ClassifierFacade type = this.getType();
948        if (type != null)
949        {
950            complex = !type.getAttributes().isEmpty();
951            if (!complex)
952            {
953                complex = !type.getAssociationEnds().isEmpty();
954            }
955        }
956        return complex;
957    }
958
959    /**
960     * @return attributes
961     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#getAttributes()
962     */
963    protected Collection<AttributeFacade> handleGetAttributes()
964    {
965        Collection<AttributeFacade> attributes = null;
966        ClassifierFacade type = this.getType();
967        if (type != null)
968        {
969            if (type.isArrayType())
970            {
971                type = type.getNonArray();
972            }
973            if (type != null)
974            {
975                attributes = type.getAttributes(true);
976            }
977        }
978        return attributes == null ? new ArrayList<AttributeFacade>() : attributes;
979    }
980
981    /**
982     * @return navigableAssociationEnds
983     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#getNavigableAssociationEnds()
984     */
985    protected Collection<AssociationEndFacade> handleGetNavigableAssociationEnds()
986    {
987        Collection<AssociationEndFacade> associationEnds = null;
988        ClassifierFacade type = this.getType();
989        if (type != null)
990        {
991            if (type.isArrayType())
992            {
993                type = type.getNonArray();
994            }
995            if (type != null)
996            {
997                associationEnds = type.getNavigableConnectingEnds();
998            }
999        }
1000        return associationEnds == null ? new ArrayList<AssociationEndFacade>() : associationEnds;
1001    }
1002
1003    /**
1004     * @return isEqualValidator
1005     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#isEqualValidator()
1006     */
1007    protected boolean handleIsEqualValidator()
1008    {
1009        final String equal = JSFUtils.getEqual((ModelElementFacade)this.THIS());
1010        return equal != null && equal.trim().length() > 0;
1011    }
1012
1013    /**
1014     * @return isBackingValueRequired
1015     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#isEqualValidator()
1016     */
1017    protected boolean handleIsBackingValueRequired()
1018    {
1019        boolean required = false;
1020        if (this.isActionParameter())
1021        {
1022            required = this.isInputTable();
1023            final ClassifierFacade type = this.getType();
1024
1025            if (!required && type != null)
1026            {
1027                final String name = this.getName();
1028                final String typeName = type.getFullyQualifiedName();
1029
1030                // - if the backing value is not required for this parameter but on
1031                //   a targeting page it IS selectable we must allow the user to set the backing value as well
1032                final Collection<FrontEndView> views = this.getAction().getTargetViews();
1033                for (final Iterator<FrontEndView> iterator = views.iterator(); iterator.hasNext() && !required;)
1034                {
1035                    final Collection<FrontEndParameter> parameters = iterator.next().getAllActionParameters();
1036                    for (final Iterator<FrontEndParameter> parameterIterator = parameters.iterator();
1037                        parameterIterator.hasNext() && !required;)
1038                    {
1039                        final FrontEndParameter object = parameterIterator.next();
1040                        if (object instanceof JSFParameter)
1041                        {
1042                            final JSFParameter parameter = (JSFParameter)object;
1043                            final String parameterName = parameter.getName();
1044                            final ClassifierFacade parameterType = parameter.getType();
1045                            if (parameterType != null)
1046                            {
1047                                final String parameterTypeName = parameterType.getFullyQualifiedName();
1048                                if (name.equals(parameterName) && typeName.equals(parameterTypeName))
1049                                {
1050                                    required = parameter.isInputTable();
1051                                }
1052                            }
1053                        }
1054                    }
1055                }
1056            }
1057        }
1058        else if (this.isControllerOperationArgument())
1059        {
1060            final String name = this.getName();
1061            final Collection<FrontEndAction> actions = this.getControllerOperation().getDeferringActions();
1062            for (final Iterator<FrontEndAction> actionIterator = actions.iterator(); actionIterator.hasNext();)
1063            {
1064                final JSFAction action = (JSFAction)actionIterator.next();
1065                final Collection<FrontEndParameter> formFields = action.getFormFields();
1066                for (final Iterator<FrontEndParameter> fieldIterator = formFields.iterator();
1067                    fieldIterator.hasNext() && !required;)
1068                {
1069                    final Object object = fieldIterator.next();
1070                    if (object instanceof JSFParameter)
1071                    {
1072                        final JSFParameter parameter = (JSFParameter)object;
1073                        if (!parameter.equals(this))
1074                        {
1075                            if (name.equals(parameter.getName()))
1076                            {
1077                                required = parameter.isBackingValueRequired();
1078                            }
1079                        }
1080                    }
1081                }
1082            }
1083        }
1084        return required;
1085    }
1086
1087    /**
1088     * @return findTaggedValue(JSFProfile.TAGGEDVALUE_INPUT_TABLE_IDENTIFIER_COLUMNS)
1089     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#getInputTableIdentifierColumns()
1090     */
1091    protected String handleGetInputTableIdentifierColumns()
1092    {
1093        return ObjectUtils.toString(this.findTaggedValue(JSFProfile.TAGGEDVALUE_INPUT_TABLE_IDENTIFIER_COLUMNS)).trim();
1094    }
1095
1096    /**
1097     * @param columnName
1098     * @return tableColumnActions
1099     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#getTableColumnActions(String)
1100     */
1101    protected List<JSFAction> handleGetTableColumnActions(final String columnName)
1102    {
1103        final List<JSFAction> columnActions = new ArrayList<JSFAction>();
1104
1105        if (columnName != null)
1106        {
1107            final Set<JSFAction> actions = new LinkedHashSet<JSFAction>(this.getTableHyperlinkActions());
1108            actions.addAll(this.getTableFormActions());
1109            for (final JSFAction action : actions)
1110            {
1111                if (columnName.equals(action.getTableLinkColumnName()))
1112                {
1113                    columnActions.add(action);
1114                }
1115            }
1116        }
1117
1118        return columnActions;
1119    }
1120
1121    /**
1122     * @return maxLength
1123     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#getMaxLength()
1124     */
1125    protected String handleGetMaxLength()
1126    {
1127        final Collection<Collection> vars=getValidatorVars();
1128        if(vars == null)
1129        {
1130            return null;
1131        }
1132        for(Iterator<Collection> it=vars.iterator(); it.hasNext();)
1133        {
1134            final Object[] values=(it.next()).toArray();
1135            if("maxlength".equals(values[0]))
1136            {
1137                return values[1].toString();
1138            }
1139        }
1140        return null;
1141    }
1142
1143    //to be used in the range validator: "range - 1000" or "range 20 -".
1144    /** - */
1145    static final String UNDEFINED_BOUND="-";
1146    /** javax.validation.constraints.NotNull */
1147    static final String AN_REQUIRED = "@javax.validation.constraints.NotNull";
1148    /** org.hibernate.validator.constraints.URL */
1149    static final String AN_URL = "@org.hibernate.validator.constraints.URL";
1150    /** org.apache.myfaces.extensions.validator.baseval.annotation.LongRange */
1151    static final String AN_LONG_RANGE = "@org.apache.myfaces.extensions.validator.baseval.annotation.LongRange";
1152    /** org.apache.myfaces.extensions.validator.baseval.annotation.DoubleRange */
1153    static final String AN_DOUBLE_RANGE = "@org.apache.myfaces.extensions.validator.baseval.annotation.DoubleRange";
1154    /** org.hibernate.validator.constraints.Email */
1155    static final String AN_EMAIL = "@org.hibernate.validator.constraints.Email";
1156    /** org.hibernate.validator.constraints.CreditCardNumber */
1157    static final String AN_CREDIT_CARD = "@org.hibernate.validator.constraints.CreditCardNumber";
1158    /** javax.validation.constraints.Size */
1159    static final String AN_LENGTH = "@javax.validation.constraints.Size";
1160    /** org.apache.myfaces.extensions.validator.baseval.annotation.Pattern */
1161    static final String AN_PATTERN = "@org.apache.myfaces.extensions.validator.baseval.annotation.Pattern";
1162    /** org.apache.myfaces.extensions.validator.crossval.annotation.Equals */
1163    static final String AN_EQUALS = "@org.apache.myfaces.extensions.validator.crossval.annotation.Equals";
1164
1165    /**
1166     * @return the annotations
1167     * @see org.andromda.cartridges.jsf.metafacades.JSFParameter#getMaxLength()
1168     */
1169    @Override
1170    protected Collection<String> handleGetAnnotations()
1171    {
1172        final Collection<String> result=new HashSet<String>();
1173        boolean requiredAdded=false;
1174        for(String vt: (Collection<String>)getValidatorTypes())
1175        {
1176            if(vt.startsWith("@")) //add the annotation
1177            {
1178                result.add(vt);
1179            }
1180            if(JSFUtils.VT_REQUIRED.equals(vt))
1181            {
1182                requiredAdded=true;
1183                result.add(AN_REQUIRED);
1184            }
1185            else if(JSFUtils.VT_URL.equals(vt))
1186            {
1187                result.add(AN_URL);
1188            }
1189            else if(JSFUtils.VT_INT_RANGE.equals(vt))
1190            {
1191                final StringBuilder sb=new StringBuilder(AN_LONG_RANGE+"(");
1192                final String format = JSFUtils.getInputFormat((ModelElementFacade)this.THIS());
1193                final String rangeStart = JSFUtils.getRangeStart(format);
1194                boolean addComma=false;
1195                if(StringUtils.isNotBlank(rangeStart) && !rangeStart.equals(UNDEFINED_BOUND))
1196                {
1197                    sb.append("minimum="+rangeStart);
1198                    addComma=true;
1199                }
1200                final String rangeEnd = JSFUtils.getRangeEnd(format);
1201                if(StringUtils.isNotBlank(rangeEnd) && !rangeEnd.equals(UNDEFINED_BOUND))
1202                {
1203                    if(addComma)
1204                    {
1205                        sb.append(",");
1206                    }
1207                    sb.append("maximum="+rangeEnd);
1208                }
1209                sb.append(")");
1210                result.add(sb.toString());
1211            }
1212            else if(JSFUtils.VT_FLOAT_RANGE.equals(vt) || JSFUtils.VT_DOUBLE_RANGE.equals(vt))
1213            {
1214                final StringBuilder sb=new StringBuilder(AN_DOUBLE_RANGE+"(");
1215                final String format = JSFUtils.getInputFormat(((ModelElementFacade)this.THIS()));
1216                final String rangeStart = JSFUtils.getRangeStart(format);
1217                boolean addComma=false;
1218                if(StringUtils.isNotBlank(rangeStart) && !rangeStart.equals(UNDEFINED_BOUND))
1219                {
1220                    sb.append("minimum="+rangeStart);
1221                    addComma=true;
1222                }
1223                final String rangeEnd = JSFUtils.getRangeEnd(format);
1224                if(StringUtils.isNotBlank(rangeEnd) && !rangeEnd.equals(UNDEFINED_BOUND))
1225                {
1226                    if(addComma)
1227                    {
1228                        sb.append(",");
1229                    }
1230                    sb.append("maximum="+rangeEnd);
1231                }
1232                sb.append(")");
1233                result.add(sb.toString());
1234            }
1235            else if(JSFUtils.VT_EMAIL.equals(vt))
1236            {
1237                result.add(AN_EMAIL);
1238            }
1239            else if(JSFUtils.VT_CREDIT_CARD.equals(vt))
1240            {
1241                result.add(AN_CREDIT_CARD);
1242            }
1243            else if(JSFUtils.VT_MIN_LENGTH.equals(vt) || JSFUtils.VT_MAX_LENGTH.equals(vt))
1244            {
1245                final StringBuilder sb=new StringBuilder(AN_LENGTH+"(");
1246                final Collection formats = this.findTaggedValues(JSFProfile.TAGGEDVALUE_INPUT_FORMAT);
1247                boolean addComma=false;
1248                for (final Iterator formatIterator = formats.iterator(); formatIterator.hasNext();)
1249                {
1250                    final String additionalFormat = String.valueOf(formatIterator.next());
1251                    if (JSFUtils.isMinLengthFormat(additionalFormat))
1252                    {
1253                        if(addComma)
1254                        {
1255                            sb.append(",");
1256                        }
1257                        sb.append("min=");
1258                        sb.append(JSFUtils.getMinLengthValue(additionalFormat));
1259                        addComma=true;
1260                    }
1261                    else if (JSFUtils.isMaxLengthFormat(additionalFormat))
1262                    {
1263                        if(addComma)
1264                        {
1265                            sb.append(",");
1266                        }
1267                        sb.append("max=");
1268                        sb.append(JSFUtils.getMinLengthValue(additionalFormat));
1269                        addComma=true;
1270                    }
1271                }
1272                sb.append(")");
1273                result.add(sb.toString());
1274            }
1275            else if(JSFUtils.VT_MASK.equals(vt))
1276            {
1277                final Collection formats = this.findTaggedValues(JSFProfile.TAGGEDVALUE_INPUT_FORMAT);
1278                for (final Iterator formatIterator = formats.iterator(); formatIterator.hasNext();)
1279                {
1280                    final String additionalFormat = String.valueOf(formatIterator.next());
1281                    if (JSFUtils.isPatternFormat(additionalFormat))
1282                    {
1283                        result.add(AN_PATTERN+"(\""+JSFUtils.getPatternValue(additionalFormat)+"\")");
1284                    }
1285                }
1286            }
1287            else if(JSFUtils.VT_VALID_WHEN.equals(vt))
1288            {
1289                result.add("");
1290            }
1291            else if(JSFUtils.VT_EQUAL.equals(vt))
1292            {
1293                result.add(AN_EQUALS+"(\""+JSFUtils.getEqual((ModelElementFacade)this.THIS())+"\")");
1294            }
1295        }
1296        if(!requiredAdded && getLower() > 0)
1297        {
1298            result.add(AN_REQUIRED);
1299        }
1300        return result;
1301    }
1302}