001package org.andromda.cartridges.jsf.metafacades;
002
003import java.util.Collection;
004import java.util.Iterator;
005import org.andromda.cartridges.jsf.JSFGlobals;
006import org.andromda.cartridges.jsf.JSFProfile;
007import org.andromda.cartridges.jsf.JSFUtils;
008import org.andromda.metafacades.uml.ClassifierFacade;
009import org.andromda.metafacades.uml.ModelElementFacade;
010import org.andromda.metafacades.uml.ParameterFacade;
011import org.andromda.utils.StringUtilsHelper;
012import org.apache.commons.lang.ObjectUtils;
013import org.apache.commons.lang.StringUtils;
014
015/**
016 * MetafacadeLogic implementation for org.andromda.cartridges.jsf.metafacades.JSFManageableEntityAttribute.
017 *
018 * @see org.andromda.cartridges.jsf.metafacades.JSFManageableEntityAttribute
019 */
020public class JSFManageableEntityAttributeLogicImpl
021    extends JSFManageableEntityAttributeLogic
022{
023    private static final long serialVersionUID = 34L;
024    /**
025     * @param metaObject
026     * @param context
027     */
028    public JSFManageableEntityAttributeLogicImpl(Object metaObject, String context)
029    {
030        super(metaObject, context);
031    }
032
033    /**
034     * @return messageKey
035     * @see org.andromda.cartridges.jsf.metafacades.JSFManageableEntityAttribute#getMessageKey()
036     */
037    protected String handleGetMessageKey()
038    {
039        String titleKey = "";
040
041        final ClassifierFacade owner = getOwner();
042        if (owner != null)
043        {
044            titleKey += owner.getName() + '.';
045        }
046
047        return StringUtilsHelper.toResourceMessageKey(titleKey + getName());
048    }
049
050    /**
051     * @return StringUtilsHelper.toPhrase(getName())
052     * @see org.andromda.cartridges.jsf.metafacades.JSFManageableEntityAttribute#getMessageValue()
053     */
054    protected String handleGetMessageValue()
055    {
056        return StringUtilsHelper.toPhrase(getName());
057    }
058
059    /**
060     * @return dateFormat
061     * @see org.andromda.cartridges.jsf.metafacades.JSFManageableEntityAttribute#getDateFormat()
062     */
063    protected String handleGetDateFormat()
064    {
065        String dateFormat = this.internalGetDateFormat();
066
067        if (dateFormat != null)
068        {
069            final String[] tokens = dateFormat.split("[\\s]+");
070            int tokenIndex = 0;
071            if (tokenIndex < tokens.length && "strict".equals(tokens[tokenIndex].trim()))
072            {
073                tokenIndex++;
074            }
075            if (tokenIndex < tokens.length)
076            {
077                dateFormat = tokens[tokenIndex].trim();
078            }
079        }
080
081        return dateFormat;
082    }
083
084    /**
085     * @return getType().isBlobType()
086     * @see org.andromda.cartridges.jsf.metafacades.JSFManageableEntityAttribute#isNeedsFileUpload()
087     */
088    protected boolean handleIsNeedsFileUpload()
089    {
090        return this.getType() != null && this.getType().isBlobType();
091    }
092
093    /**
094     * @return isHidden
095     * @see org.andromda.cartridges.jsf.metafacades.JSFManageableEntityAttribute#isHidden()
096     */
097    protected boolean handleIsHidden()
098    {
099        return !this.isDisplay() || JSFProfile.TAGGEDVALUE_INPUT_TYPE_HIDDEN.equals(this.getWidgetType());
100    }
101
102    /**
103     * @return widgetType
104     * @see org.andromda.cartridges.jsf.metafacades.JSFManageableEntityAttribute#getWidgetType()
105     */
106    protected String handleGetWidgetType()
107    {
108        final Object widgetTag = findTaggedValue(JSFProfile.TAGGEDVALUE_INPUT_TYPE);
109        return (widgetTag == null) ? JSFProfile.TAGGEDVALUE_INPUT_TYPE_TEXT : widgetTag.toString();
110    }
111
112    /**
113     * @return isStrictDateFormat
114     * @see org.andromda.cartridges.jsf.metafacades.JSFManageableEntityAttribute#isStrictDateFormat()
115     */
116    protected boolean handleIsStrictDateFormat()
117    {
118        final String dateFormat = this.internalGetDateFormat();
119        return (dateFormat != null && dateFormat.trim().startsWith("strict"));
120    }
121
122    /**
123     * @return getMessageKey() + ".online.help"
124     * @see org.andromda.cartridges.jsf.metafacades.JSFManageableEntityAttribute#getOnlineHelpKey()
125     */
126    protected String handleGetOnlineHelpKey()
127    {
128        return this.getMessageKey() + ".online.help";
129    }
130
131    /**
132     * @return getDocumentation
133     * @see org.andromda.cartridges.jsf.metafacades.JSFManageableEntityAttribute#getOnlineHelpValue()
134     */
135    protected String handleGetOnlineHelpValue()
136    {
137        final String value = StringUtilsHelper.toResourceMessage(this.getDocumentation("", 64, false));
138        return (value == null) ? "No field documentation has been specified" : value;
139    }
140
141    /**
142     * @return format
143     * @see org.andromda.cartridges.jsf.metafacades.JSFManageableEntityAttribute#getFormat()
144     */
145    protected String handleGetFormat()
146    {
147        return JSFUtils.getFormat(
148            (ModelElementFacade)this.THIS(),
149            this.getType(),
150            this.getDefaultDateFormat(),
151            this.getDefaultTimeFormat());
152    }
153
154    /**
155     * @return getConfiguredProperty(JSFGlobals.PROPERTY_DEFAULT_DATEFORMAT)
156     * @see org.andromda.cartridges.jsf.metafacades.JSFManageableEntityAttribute#getDefaultDateFormat()
157     */
158    protected String handleGetDefaultDateFormat()
159    {
160        return (String)this.getConfiguredProperty(JSFGlobals.PROPERTY_DEFAULT_DATEFORMAT);
161    }
162
163    /**
164     * @return getConfiguredProperty(JSFGlobals.PROPERTY_DEFAULT_TIMEFORMAT)
165     * @see org.andromda.cartridges.jsf.metafacades.JSFManageableEntityAttribute#getDefaultTimeFormat()
166     */
167    protected String handleGetDefaultTimeFormat()
168    {
169        return (String)this.getConfiguredProperty(JSFGlobals.PROPERTY_DEFAULT_TIMEFORMAT);
170    }
171
172    /**
173     * @return dateFormatter
174     * @see org.andromda.cartridges.jsf.metafacades.JSFManageableEntityAttribute#getDateFormatter()
175     */
176    protected String handleGetDateFormatter()
177    {
178        final ClassifierFacade type = this.getType();
179        return type != null && type.isDateType() ? this.getName() + "DateFormatter" : null;
180    }
181
182    /**
183     * @return timeFormatter
184     * @see org.andromda.cartridges.jsf.metafacades.JSFManageableEntityAttribute#getTimeFormatter()
185     */
186    protected String handleGetTimeFormatter()
187    {
188        final ClassifierFacade type = this.getType();
189        return type != null && type.isTimeType() ? this.getName() + "TimeFormatter" : null;
190    }
191
192    /**
193     * @return backingListName
194     * @see org.andromda.cartridges.jsf.metafacades.JSFManageableEntityAttribute#getBackingListName()
195     */
196    protected String handleGetBackingListName()
197    {
198        final String backingListName =
199            StringUtils.replace(
200                ObjectUtils.toString(this.getConfiguredProperty(JSFGlobals.BACKING_LIST_PATTERN)),
201                "{0}",
202                this.getName());
203        return org.andromda.utils.StringUtilsHelper.lowerCamelCaseName(backingListName);
204    }
205
206    /**
207     * @return valueListName
208     * @see org.andromda.cartridges.jsf.metafacades.JSFManageableEntityAttribute#getValueListName()
209     */
210    protected String handleGetValueListName()
211    {
212        return ObjectUtils.toString(this.getConfiguredProperty(JSFGlobals.VALUE_LIST_PATTERN)).replaceAll(
213            "\\{0\\}",
214            this.getName());
215    }
216
217    /**
218     * @return labelListName
219     * @see org.andromda.cartridges.jsf.metafacades.JSFManageableEntityAttribute#getLabelListName()
220     */
221    protected String handleGetLabelListName()
222    {
223        return ObjectUtils.toString(this.getConfiguredProperty(JSFGlobals.LABEL_LIST_PATTERN)).replaceAll(
224            "\\{0\\}",
225            this.getName());
226    }
227
228    /**
229     * @return validatorTypes
230     * @see org.andromda.cartridges.jsf.metafacades.JSFManageableEntityAttribute#getValidatorTypes()
231     */
232    protected Collection handleGetValidatorTypes()
233    {
234        return JSFUtils.getValidatorTypes(
235            (ModelElementFacade)this.THIS(),
236            this.getType());
237    }
238
239    /**
240     * @return !getValidatorTypes().isEmpty()
241     * @see org.andromda.cartridges.jsf.metafacades.JSFManageableEntityAttribute#isValidationRequired()
242     */
243    protected boolean handleIsValidationRequired()
244    {
245        return !this.getValidatorTypes().isEmpty();
246    }
247
248    /**
249     * @return validatorVars
250     * @see org.andromda.cartridges.jsf.metafacades.JSFManageableEntityAttribute#getValidatorVars()
251     */
252    protected Collection handleGetValidatorVars()
253    {
254        return JSFUtils.getValidatorVars(
255            (ModelElementFacade)this.THIS(),
256            this.getType(),
257            null);
258    }
259
260    /**
261     * @return JSFUtils.getValidWhen(this)
262     * @see org.andromda.cartridges.jsf.metafacades.JSFManageableEntityAttribute#getValidWhen()
263     */
264    protected String handleGetValidWhen()
265    {
266        return JSFUtils.getValidWhen(this);
267    }
268
269    /**
270     * @return checkbox
271     * @see org.andromda.cartridges.jsf.metafacades.JSFManageableEntityAttribute#isInputCheckbox()
272     */
273    protected boolean handleIsInputCheckbox()
274    {
275        boolean checkbox = this.isInputType(JSFGlobals.INPUT_CHECKBOX);
276        if (!checkbox && this.getInputType().length() == 0)
277        {
278            final ClassifierFacade type = this.getType();
279            checkbox = type != null ? type.isBooleanType() : false;
280        }
281        return checkbox;
282    }
283
284    /**
285     * @return file
286     * @see org.andromda.cartridges.jsf.metafacades.JSFManageableEntityAttribute#isInputFile()
287     */
288    protected boolean handleIsInputFile()
289    {
290        boolean file = false;
291        ClassifierFacade type = getType();
292        if (type != null)
293        {
294            file = type.isFileType() || type.isBlobType();
295        }
296        return file;
297    }
298
299    /**
300     * @return isInputType(JSFGlobals.INPUT_HIDDEN)
301     * @see org.andromda.cartridges.jsf.metafacades.JSFManageableEntityAttribute#isInputHidden()
302     */
303    protected boolean handleIsInputHidden()
304    {
305        return this.isInputType(JSFGlobals.INPUT_HIDDEN);
306    }
307
308    /**
309     * @return isInputType(JSFGlobals.INPUT_MULTIBOX)
310     * @see org.andromda.cartridges.jsf.metafacades.JSFManageableEntityAttribute#isInputMultibox()
311     */
312    protected boolean handleIsInputMultibox()
313    {
314        return this.isInputType(JSFGlobals.INPUT_MULTIBOX);
315    }
316
317    /**
318     * @return isInputType(JSFGlobals.INPUT_RADIO)
319     * @see org.andromda.cartridges.jsf.metafacades.JSFManageableEntityAttribute#isInputRadio()
320     */
321    protected boolean handleIsInputRadio()
322    {
323        return this.isInputType(JSFGlobals.INPUT_RADIO);
324    }
325
326    /**
327     * @return isInputType(JSFGlobals.INPUT_PASSWORD)
328     * @see org.andromda.cartridges.jsf.metafacades.JSFManageableEntityAttribute#isInputSecret()
329     */
330    protected boolean handleIsInputSecret()
331    {
332        return this.isInputType(JSFGlobals.INPUT_PASSWORD);
333    }
334
335    /**
336     * @return isInputType(JSFGlobals.INPUT_SELECT)
337     * @see org.andromda.cartridges.jsf.metafacades.JSFManageableEntityAttribute#isInputSelect()
338     */
339    protected boolean handleIsInputSelect()
340    {
341        return this.isInputType(JSFGlobals.INPUT_SELECT);
342    }
343
344    /**
345     * @return isInputTable
346     * @see org.andromda.cartridges.jsf.metafacades.JSFManageableEntityAttribute#isInputTable()
347     */
348    protected boolean handleIsInputTable()
349    {
350        return this.getInputTableIdentifierColumns().length() > 0 || this.isInputType(JSFGlobals.INPUT_TABLE);
351    }
352
353    /**
354     * @return inputTableIdentifierColumns
355     * @see org.andromda.cartridges.jsf.metafacades.JSFManageableEntityAttribute#getInputTableIdentifierColumns()
356     */
357    protected String handleGetInputTableIdentifierColumns()
358    {
359        return ObjectUtils.toString(this.findTaggedValue(JSFProfile.TAGGEDVALUE_INPUT_TABLE_IDENTIFIER_COLUMNS)).trim();
360    }
361
362    /**
363     * @return isInputText
364     * @see org.andromda.cartridges.jsf.metafacades.JSFManageableEntityAttribute#isInputText()
365     */
366    protected boolean handleIsInputText()
367    {
368        return this.isInputType(JSFGlobals.INPUT_TEXT);
369    }
370
371    /**
372     * @return isInputTextarea
373     * @see org.andromda.cartridges.jsf.metafacades.JSFManageableEntityAttribute#isInputTextarea()
374     */
375    protected boolean handleIsInputTextarea()
376    {
377        return this.isInputType(JSFGlobals.INPUT_TEXTAREA);
378    }
379
380    /**
381     * @return isInputTypePresent
382     * @see org.andromda.cartridges.jsf.metafacades.JSFManageableEntityAttribute#isInputTypePresent()
383     */
384    protected boolean handleIsInputTypePresent()
385    {
386        boolean present = false;
387        final ClassifierFacade type = this.getType();
388        if (type != null)
389        {
390            present =
391                (StringUtils.isNotBlank(this.getInputType()) || type.isDateType() || type.isBooleanType()) &&
392                !this.isPlaintext();
393        }
394        return present;
395    }
396
397    /**
398     * @return dummyValue
399     * @see org.andromda.cartridges.jsf.metafacades.JSFManageableEntityAttribute#getDummyValue()
400     */
401    protected String handleGetDummyValue()
402    {
403        final ClassifierFacade type = this.getType();
404        if (type != null)
405        {
406            final String typeName = type.getFullyQualifiedName();
407            final String name = this.getName();
408            if ("String".equals(typeName))
409            {
410                return "\"" + name + "-test" + "\"";
411            }
412            if ("java.util.Date".equals(typeName))
413            {
414                return "new java.util.Date()";
415            }
416            if ("java.sql.Date".equals(typeName))
417            {
418                return "new java.sql.Date(new java.util.Date().getTime())";
419            }
420            if ("java.sql.Timestamp".equals(typeName))
421            {
422                return "new java.sql.Timestamp(new Date().getTime())";
423            }
424            if ("java.util.Calendar".equals(typeName))
425            {
426                return "java.util.Calendar.getInstance()";
427            }
428            if ("int".equals(typeName))
429            {
430                return "(int)" + name.hashCode();
431            }
432            if ("boolean".equals(typeName))
433            {
434                return "false";
435            }
436            if ("long".equals(typeName))
437            {
438                return "(long)" + name.hashCode();
439            }
440            if ("char".equals(typeName))
441            {
442                return "(char)" + name.hashCode();
443            }
444            if ("float".equals(typeName))
445            {
446                return "(float)" + name.hashCode() / hashCode();
447            }
448            if ("double".equals(typeName))
449            {
450                return "(double)" + name.hashCode() / hashCode();
451            }
452            if ("short".equals(typeName))
453            {
454                return "(short)" + name.hashCode();
455            }
456            if ("byte".equals(typeName))
457            {
458                return "(byte)" + name.hashCode();
459            }
460            if ("java.lang.Integer".equals(typeName) || "Integer".equals(typeName))
461            {
462                return "new Integer((int)" + name.hashCode() + ")";
463            }
464            if ("java.lang.Boolean".equals(typeName) || "Boolean".equals(typeName))
465            {
466                return "Boolean.FALSE";
467            }
468            if ("java.lang.Long".equals(typeName) || "Long".equals(typeName))
469            {
470                return "new Long((long)" + name.hashCode() + ")";
471            }
472            if ("java.lang.Character".equals(typeName) || "Character".equals(typeName))
473            {
474                return "new Character(char)" + name.hashCode() + ")";
475            }
476            if ("java.lang.Float".equals(typeName) || "Float".equals(typeName))
477            {
478                return "new Float((float)" + name.hashCode() / hashCode() + ")";
479            }
480            if ("java.lang.Double".equals(typeName) || "Double".equals(typeName))
481            {
482                return "new Double((double)" + name.hashCode() / hashCode() + ")";
483            }
484            if ("java.lang.Short".equals(typeName) || "Short".equals(typeName))
485            {
486                return "new Short((short)" + name.hashCode() + ")";
487            }
488            if ("java.lang.Byte".equals(typeName) || "Byte".equals(typeName))
489            {
490                return "new Byte((byte)" + name.hashCode() + ")";
491            }
492
493            //if (type.isArrayType()) return constructDummyArray();
494            if (type.isSetType())
495            {
496                return "new java.util.HashSet(java.util.Arrays.asList(" + constructDummyArray() + "))";
497            }
498            if (type.isCollectionType())
499            {
500                return "java.util.Arrays.asList(" + constructDummyArray() + ")";
501            }
502
503            // maps and others types will simply not be treated
504        }
505        return "null";
506    }
507
508    /**
509     * @return isEqualValidator
510     * @see org.andromda.cartridges.jsf.metafacades.JSFManageableEntityAttribute#isEqualValidator()
511     */
512    protected boolean handleIsEqualValidator()
513    {
514        final String equal = JSFUtils.getEqual((ModelElementFacade)this.THIS());
515        return equal != null && equal.trim().length() > 0;
516    }
517
518    /**
519     * @return isInputType(JSFGlobals.PLAIN_TEXT)
520     * @see org.andromda.cartridges.jsf.metafacades.JSFManageableEntityAttribute#isPlaintext()
521     */
522    protected boolean handleIsPlaintext()
523    {
524        return this.isInputType(JSFGlobals.PLAIN_TEXT);
525    }
526
527    /**
528     * @return constructDummyArray()
529     * @see org.andromda.cartridges.jsf.metafacades.JSFManageableEntityAttribute#getValueListDummyValue()
530     */
531    protected String handleGetValueListDummyValue()
532    {
533        return this.constructDummyArray();
534    }
535
536    /**
537     * @param validatorType
538     * @return getValidatorArgs
539     * @see org.andromda.cartridges.jsf.metafacades.JSFManageableEntityAttribute#getValidatorArgs(String)
540     */
541    protected Collection handleGetValidatorArgs(String validatorType)
542    {
543        return JSFUtils.getValidatorArgs(
544            (ModelElementFacade)this.THIS(),
545            validatorType);
546    }
547
548    /**
549     * Gets the current value of the specified input type (or an empty string
550     * if one isn't specified).
551     *
552     * @return the input type name.
553     */
554    private String getInputType()
555    {
556        return ObjectUtils.toString(this.findTaggedValue(JSFProfile.TAGGEDVALUE_INPUT_TYPE)).trim();
557    }
558
559    /**
560     * Indicates whether or not this parameter is of the given input type.
561     *
562     * @param inputType the name of the input type to check for.
563     * @return true/false
564     */
565    private boolean isInputType(final String inputType)
566    {
567        return inputType.equalsIgnoreCase(this.getInputType());
568    }
569
570    /**
571     * Overridden to provide consistent behavior with {@link JSFParameter#isReadOnly()}.
572     *
573     * @see org.andromda.metafacades.uml.AttributeFacade#isReadOnly()
574     */
575    public boolean isReadOnly()
576    {
577        return JSFUtils.isReadOnly(this);
578    }
579
580    /**
581     * Constructs a string representing an array initialization in Java.
582     *
583     * @return A String representing Java code for the initialization of an array.
584     */
585    private String constructDummyArray()
586    {
587        return JSFUtils.constructDummyArrayDeclaration(
588            this.getName(),
589            JSFGlobals.DUMMY_ARRAY_COUNT);
590    }
591
592    private String internalGetDateFormat()
593    {
594        String dateFormat = null;
595
596        if (this.getType() != null && this.getType().isDateType())
597        {
598            final Object taggedValueObject = this.findTaggedValue(JSFProfile.TAGGEDVALUE_INPUT_FORMAT);
599            if (taggedValueObject == null)
600            {
601                dateFormat = (String)this.getConfiguredProperty(JSFGlobals.PROPERTY_DEFAULT_DATEFORMAT);
602            }
603            else
604            {
605                dateFormat = taggedValueObject.toString();
606            }
607        }
608
609        return dateFormat;
610    }
611
612    /**
613     * @param ownerParameter
614     * @return propertyName
615     * @see JSFAttribute#getFormPropertyName(org.andromda.metafacades.uml.ParameterFacade)
616     */
617    protected String handleGetFormPropertyName(final ParameterFacade ownerParameter)
618    {
619        final StringBuilder propertyName = new StringBuilder();
620        if (ownerParameter != null)
621        {
622            propertyName.append(ownerParameter.getName());
623            propertyName.append('.');
624        }
625        final String name = this.getName();
626        if (name != null && name.trim().length() > 0)
627        {
628            propertyName.append(name);
629        }
630        return propertyName.toString();
631    }
632
633    /**
634     * @param ownerParameter
635     * @return StringUtilsHelper.lowerCamelCaseName(this.getFormPropertyName(ownerParameter))
636     * @see JSFAttribute#getFormPropertyId(ParameterFacade)
637     */
638    protected String handleGetFormPropertyId(final ParameterFacade ownerParameter)
639    {
640        return StringUtilsHelper.lowerCamelCaseName(this.getFormPropertyName(ownerParameter));
641    }
642
643    //TODO remove after 3.4 release
644    /**
645     * Hack to keep the compatibility with Andromda 3.4
646     * @return defaultValue
647     */
648    public String getDefaultValue()
649    {
650        String defaultValue = super.getDefaultValue();
651        // Put single or double quotes around default in case modeler forgot to do it. Most templates
652        // declare Type attribute = $attribute.defaultValue, requiring quotes around the value
653        if (defaultValue!=null && defaultValue.length()>0 && !super.isMany())
654        {
655            String typeName = getType().getName();
656            if ("String".equals(typeName) && defaultValue.indexOf('"')<0)
657            {
658                defaultValue = '"' + defaultValue + '"';
659            }
660            else if (("char".equals(typeName) || "Character".equals(typeName))
661                && !defaultValue.contains("'"))
662            {
663                defaultValue = "'" + defaultValue.charAt(0) + "'";
664            }
665        }
666        if (defaultValue==null)
667        {
668            defaultValue="";
669        }
670        return defaultValue;
671    }
672
673    /**
674     * @return getColumnLength()
675     * @see org.andromda.cartridges.jsf.metafacades.JSFManageableEntityAttribute#getMaxLength()
676     */
677    protected String handleGetMaxLength()
678    {
679        final Collection vars=getValidatorVars();
680        if(vars == null)
681        {
682            return getColumnLength();
683        }
684        for(Iterator<Collection> it=vars.iterator(); it.hasNext(); )
685        {
686            final Object[] values=(it.next()).toArray();
687            if("maxlength".equals(values[0]))
688            {
689                return values[1].toString();
690            }
691        }
692        return getColumnLength();
693    }
694}