001package org.andromda.cartridges.jsf2;
002
003import java.security.MessageDigest;
004import java.security.NoSuchAlgorithmException;
005import java.util.ArrayList;
006import java.util.Arrays;
007import java.util.Collection;
008import java.util.Date;
009import java.util.Iterator;
010import java.util.LinkedHashMap;
011import java.util.List;
012import java.util.Map;
013import java.util.regex.Pattern;
014import org.andromda.cartridges.jsf2.metafacades.JSFAttribute;
015import org.andromda.cartridges.jsf2.metafacades.JSFManageableEntityAttribute;
016import org.andromda.cartridges.jsf2.metafacades.JSFParameter;
017import org.andromda.metafacades.uml.AttributeFacade;
018import org.andromda.metafacades.uml.ClassifierFacade;
019import org.andromda.metafacades.uml.FrontEndAction;
020import org.andromda.metafacades.uml.FrontEndParameter;
021import org.andromda.metafacades.uml.ModelElementFacade;
022import org.andromda.metafacades.uml.OperationFacade;
023import org.andromda.metafacades.uml.ParameterFacade;
024import org.andromda.metafacades.uml.UMLMetafacadeUtils;
025import org.andromda.utils.StringUtilsHelper;
026import org.apache.commons.lang.ObjectUtils;
027import org.apache.commons.lang.StringUtils;
028import org.apache.commons.lang.time.FastDateFormat;
029
030/**
031 * Utilities for use within the JSF cartridge.
032 *
033 * @author Chad Brandon
034 */
035public class JSFUtils
036{
037    /**
038     * Converts the argument into a web resource name, this means: all lowercase
039     * characters and words are separated with dashes.
040     *
041     * @param string any string
042     * @return the string converted to a value that would be well-suited for a
043     *         web file name
044     */
045    public static String toWebResourceName(final String string)
046    {
047        return StringUtilsHelper.separate(
048            string,
049            "-").toLowerCase();
050    }
051
052    private static final Pattern VALIDATOR_TAGGEDVALUE_PATTERN =
053        Pattern.compile("\\w+(\\(\\w+=[^,)]*(,\\w+=[^,)]*)*\\))?");
054
055    private static final String ANNOTATION_VALIDATOR_PREFIX = "@";
056
057    /**
058     * Reads the validator arguments from the the given tagged value.
059     * @param validatorTaggedValue
060     * @return returns a list of String instances or an empty list
061     * @throws IllegalArgumentException when the input string does not match the required pattern
062     */
063    public static List<String> parseValidatorArgs(String validatorTaggedValue)
064    {
065        if (validatorTaggedValue == null)
066        {
067            throw new IllegalArgumentException("Validator tagged value cannot be null");
068        }
069
070        final List<String> validatorArgs = new ArrayList<String>();
071
072        //isn't it an annotation ?
073        if(!StringUtils.startsWith(validatorTaggedValue,ANNOTATION_VALIDATOR_PREFIX))
074        {
075
076            // check if the input tagged value matches the required pattern
077            if (!VALIDATOR_TAGGEDVALUE_PATTERN.matcher(validatorTaggedValue).matches())
078            {
079                throw new IllegalArgumentException(
080                    "Illegal validator tagged value (this tag is used to specify custom validators " +
081                    "and might look like myValidator(myVar=myArg,myVar2=myArg2), perhaps you wanted to use " +
082                    "andromda_presentation_view_field_format?): " + validatorTaggedValue);
083            }
084
085            // only keep what is between parentheses (if any)
086            int left = validatorTaggedValue.indexOf('(');
087            if (left > -1)
088            {
089                final int right = validatorTaggedValue.indexOf(')');
090                validatorTaggedValue = validatorTaggedValue.substring(
091                        left + 1,
092                        right);
093
094                final String[] pairs = validatorTaggedValue.split(",");
095                for (int i = 0; i < pairs.length; i++)
096                {
097                    final String pair = pairs[i];
098                    final int equalsIndex = pair.indexOf('=');
099
100                    // it's possible the argument is the empty string
101                    if (equalsIndex < pair.length() - 1)
102                    {
103                        validatorArgs.add(pair.substring(equalsIndex + 1));
104                    }
105                    else
106                    {
107                        validatorArgs.add("");
108                    }
109                }
110            }
111        }
112        return validatorArgs;
113    }
114
115    /**
116     * Reads the validator variable names from the the given tagged value.
117     * @param validatorTaggedValue
118     * @return never null, returns a list of String instances
119     * @throws IllegalArgumentException when the input string does not match the required pattern
120     */
121    public static List<String> parseValidatorVars(String validatorTaggedValue)
122    {
123        if (validatorTaggedValue == null)
124        {
125            throw new IllegalArgumentException("Validator tagged value cannot be null");
126        }
127
128        final List<String> validatorVars = new ArrayList<String>();
129
130        //isn't it an annotation ?
131        if(!StringUtils.startsWith(validatorTaggedValue,ANNOTATION_VALIDATOR_PREFIX))
132        {
133
134            // check if the input tagged value matches the required pattern
135            if (!VALIDATOR_TAGGEDVALUE_PATTERN.matcher(validatorTaggedValue).matches())
136            {
137                throw new IllegalArgumentException("Illegal validator tagged value: " + validatorTaggedValue);
138            }
139
140            // only keep what is between parentheses (if any)
141            int left = validatorTaggedValue.indexOf('(');
142            if (left > -1)
143            {
144                int right = validatorTaggedValue.indexOf(')');
145                validatorTaggedValue = validatorTaggedValue.substring(
146                        left + 1,
147                        right);
148
149                final String[] pairs = validatorTaggedValue.split(",");
150                for (int i = 0; i < pairs.length; i++)
151                {
152                    final String pair = pairs[i];
153                    final int equalsIndex = pair.indexOf('=');
154                    validatorVars.add(pair.substring(
155                            0,
156                            equalsIndex));
157                }
158            }
159        }
160        return validatorVars;
161    }
162
163    /**
164     * Parses the validator name for a tagged value.
165     * @param validatorTaggedValue
166     * @return validatorTaggedValue
167     * @throws IllegalArgumentException when the input string does not match the required pattern
168     */
169    public static String parseValidatorName(final String validatorTaggedValue)
170    {
171        if (validatorTaggedValue == null)
172        {
173            throw new IllegalArgumentException("Validator tagged value cannot be null");
174        }
175
176        //isn't it an annotation ?
177        if(StringUtils.startsWith(validatorTaggedValue, ANNOTATION_VALIDATOR_PREFIX))
178        {
179            return validatorTaggedValue;
180        }
181
182        // check if the input tagged value matches the required pattern
183        if (!VALIDATOR_TAGGEDVALUE_PATTERN.matcher(validatorTaggedValue).matches())
184        {
185            throw new IllegalArgumentException("Illegal validator tagged value: " + validatorTaggedValue);
186        }
187
188        final int leftParen = validatorTaggedValue.indexOf('(');
189        return (leftParen == -1) ? validatorTaggedValue : validatorTaggedValue.substring(
190            0,
191            leftParen);
192    }
193
194    /**
195     * Constructs a string representing an array initialization in Java.
196     *
197     * @param name the name to give the array.
198     * @param count the number of items to give the array.
199     * @return A String representing Java code for the initialization of an array.
200     */
201    public static String constructDummyArrayDeclaration(
202        final String name,
203        final int count)
204    {
205        final StringBuilder array = new StringBuilder("new Object[] {");
206        for (int ctr = 1; ctr <= count; ctr++)
207        {
208            array.append("\"" + name + "-" + ctr + "\"");
209            if (ctr != count)
210            {
211                array.append(", ");
212            }
213        }
214        array.append("}");
215        return array.toString();
216    }
217
218    /**
219     * @param format
220     * @return this field's date format
221     */
222    public static String getDateFormat(String format)
223    {
224        format = StringUtils.trimToEmpty(format);
225        return format.endsWith(STRICT) ? getToken(format, 1, 2) : getToken(format, 0, 1);
226    }
227
228    private static String defaultDateFormat = "MM/dd/yyyy HH:mm:ssZ";
229    private static FastDateFormat df = FastDateFormat.getInstance(defaultDateFormat);
230
231    /**
232     * Returns the current Date in the specified format.
233     *
234     * @param format The format for the output date
235     * @return the current date in the specified format.
236     */
237    public static String getDate(String format)
238    {
239        if (df == null || !format.equals(df.getPattern()))
240        {
241            df = FastDateFormat.getInstance(format);
242        }
243        return df.format(new Date());
244    }
245
246    /**
247     * Returns the current Date
248     *
249     * @return the current date in the default format.
250     */
251    public static String getDate()
252    {
253        return getDate(defaultDateFormat);
254    }
255
256    private static final String STRICT = "strict";
257
258    /**
259     * @param format
260     * @return <code>true</code> if this field's value needs to conform to a
261     * strict date format, <code>false</code> otherwise
262     */
263    public static boolean isStrictDateFormat(String format)
264    {
265        return strictDateTimeFormat ? strictDateTimeFormat : STRICT.equalsIgnoreCase(getToken(
266                format,
267                0,
268                2));
269    }
270
271    /**
272     * Indicates if the given <code>format</code> is an email format.
273     * @param format
274     * @return <code>true</code> if this field is to be formatted as an email
275     * address, <code>false</code> otherwise
276     */
277    public static boolean isEmailFormat(String format)
278    {
279        return "email".equalsIgnoreCase(JSFUtils.getToken(
280                format,
281                0,
282                2));
283    }
284
285    /**
286     * Indicates if the given <code>format</code> is an equal format.
287     * @param format
288     * @return <code>true</code> if this field is to be formatted as an
289     * email address, <code>false</code> otherwise
290     */
291    public static boolean isEqualFormat(String format)
292    {
293        return "equal".equalsIgnoreCase(JSFUtils.getToken(format, 0, 2));
294    }
295
296    /**
297     * Indicates if the given <code>format</code> is a credit card format.
298     * @param format
299     * @return <code>true</code> if this field is to be formatted as a credit card, <code>false</code> otherwise
300     */
301    public static boolean isCreditCardFormat(final String format)
302    {
303        return "creditcard".equalsIgnoreCase(JSFUtils.getToken(format, 0, 2));
304    }
305
306    /**
307     * Indicates if the given <code>format</code> is a pattern format.
308     * @param format
309     * @return <code>true</code> if this field's value needs to respect a certain pattern, <code>false</code> otherwise
310     */
311    public static boolean isPatternFormat(final String format)
312    {
313        return "pattern".equalsIgnoreCase(JSFUtils.getToken(format, 0, 2));
314    }
315
316    /**
317     * Indicates if the given <code>format</code> is a minlength format.
318     * @param format
319     * @return <code>true</code> if this field's value needs to consist of at least a certain
320     *         number of characters, <code>false</code> otherwise
321     */
322    public static boolean isMinLengthFormat(final String format)
323    {
324        return "minlength".equalsIgnoreCase(JSFUtils.getToken(
325                format,
326                0,
327                2));
328    }
329
330    /**
331     * Indicates if the given <code>format</code> is a maxlength format.
332     * @param format
333     * @return <code>true</code> if this field's value needs to consist of at maximum a certain
334     *         number of characters, <code>false</code> otherwise
335     */
336    public static boolean isMaxLengthFormat(String format)
337    {
338        return "maxlength".equalsIgnoreCase(JSFUtils.getToken(
339                format,
340                0,
341                2));
342    }
343
344    /**
345     * @param string
346     * @param index
347     * @param limit
348     * @return the i-th space delimited token read from the argument String, where i does not exceed the specified limit
349     */
350    public static String getToken(
351        String string,
352        int index,
353        int limit)
354    {
355        String token = null;
356        if (string != null && string.length() > 0)
357        {
358            final String[] tokens = string.split(
359                    "[\\s]+",
360                    limit);
361            token = index >= tokens.length ? null : tokens[index];
362        }
363        return token;
364    }
365
366    /**
367     * Retrieves the input format (if one is defined), for the given
368     * <code>element</code>.
369     * @param element the model element for which to retrieve the input format.
370     * @return the input format.
371     */
372    public static String getInputFormat(final ModelElementFacade element)
373    {
374        final Object value = element.findTaggedValue(JSFProfile.TAGGEDVALUE_INPUT_FORMAT);
375        final String format = value == null ? null : String.valueOf(value);
376        return format == null ? null : format.trim();
377    }
378
379    /**
380     * Indicates if the given <code>format</code> is a range format.
381     * @param format
382     * @return <code>true</code> if this field's value needs to be in a specific range, <code>false</code> otherwise
383     */
384    public static boolean isRangeFormat(final String format)
385    {
386        return "range".equalsIgnoreCase(JSFUtils.getToken(
387                format,
388                0,
389                2));
390    }
391
392    /**
393     * @param type
394     * @return <code>true</code> if the type of this field is a byte, <code>false</code> otherwise
395     */
396    public static boolean isByte(final ClassifierFacade type)
397    {
398        return isType(
399            type,
400            JSFProfile.BYTE_TYPE_NAME);
401    }
402
403    /**
404     * @param type
405     * @return <code>true</code> if the type of this field is a short, <code>false</code> otherwise
406     */
407    public static boolean isShort(final ClassifierFacade type)
408    {
409        return isType(
410            type,
411            JSFProfile.SHORT_TYPE_NAME);
412    }
413
414    /**
415     * @param type
416     * @return <code>true</code> if the type of this field is an integer, <code>false</code> otherwise
417     */
418    public static boolean isInteger(final ClassifierFacade type)
419    {
420        return isType(
421            type,
422            JSFProfile.INTEGER_TYPE_NAME);
423    }
424
425    /**
426     * @param type
427     * @return <code>true</code> if the type of this field is a long integer, <code>false</code> otherwise
428     */
429    public static boolean isLong(final ClassifierFacade type)
430    {
431        return isType(
432            type,
433            JSFProfile.LONG_TYPE_NAME);
434    }
435
436    /**
437     * @param type
438     * @return <code>true</code> if the type of this field is a floating point, <code>false</code> otherwise
439     */
440    public static boolean isFloat(final ClassifierFacade type)
441    {
442        return isType(
443            type,
444            JSFProfile.FLOAT_TYPE_NAME);
445    }
446
447    /**
448     * @param type
449     * @return <code>true</code> if the type of this field is a double precision floating point,
450     * <code>false</code> otherwise
451     */
452    public static boolean isDouble(final ClassifierFacade type)
453    {
454        return isType(
455            type,
456            JSFProfile.DOUBLE_TYPE_NAME);
457    }
458
459    /**
460     * @param type
461     * @return <code>true</code> if the type of this field is a date, <code>false</code> otherwise
462     */
463    public static boolean isDate(final ClassifierFacade type)
464    {
465        return type != null && type.isDateType();
466    }
467
468    /**
469     * @param type
470     * @return <code>true</code> if the type of this field is a time, <code>false</code> otherwise
471     */
472    public static boolean isTime(final ClassifierFacade type)
473    {
474        return isType(
475            type,
476            JSFProfile.TIME_TYPE_NAME);
477    }
478
479    /**
480     * @param type
481     * @return <code>true</code> if the type of this field is a URL, <code>false</code> otherwise
482     */
483    public static boolean isUrl(final ClassifierFacade type)
484    {
485        return isType(
486            type,
487            JSFProfile.URL_TYPE_NAME);
488    }
489
490    private static boolean isType(final ClassifierFacade type, String typeName)
491    {
492        boolean isType = UMLMetafacadeUtils.isType(
493            type,
494            typeName);
495        if (!isType)
496        {
497            // - handle abstract types that are mapped to java types
498            if (type.getLanguageMappings() != null)
499            {
500                final String javaTypeName = type.getLanguageMappings()
501                    .getTo(type.getFullyQualifiedName(true));
502                if (javaTypeName != null)
503                {
504                    isType = javaTypeName.replaceAll(".*\\.", "").equalsIgnoreCase(
505                        type.getLanguageMappings().getTo(typeName));
506                }
507            }
508        }
509        return isType;
510    }
511
512    /**
513     * @param type
514     * @return <code>true</code> if the type of this field is a String,
515     * <code>false</code> otherwise
516     */
517    public static boolean isString(final ClassifierFacade type)
518    {
519        return type != null && type.isStringType();
520    }
521
522    /**
523     * Indicates if the given element is read-only or not.
524     *
525     * @param element the element to check.
526     * @return true/false
527     */
528    public static boolean isReadOnly(final ModelElementFacade element)
529    {
530        boolean readOnly = false;
531        if (element != null)
532        {
533            final Object value = element.findTaggedValue(JSFProfile.TAGGEDVALUE_INPUT_READONLY);
534            readOnly = Boolean.valueOf(ObjectUtils.toString(value)).booleanValue();
535        }
536        return readOnly;
537    }
538
539    /**
540     * Retrieves the "equal" value from the given element (if one is present).
541     *
542     * @param element the element from which to retrieve the equal value.
543     * @return the "equal" value.
544     */
545    public static String getEqual(final ModelElementFacade element)
546    {
547        String equal = null;
548        if (element != null)
549        {
550            final Object value = element.findTaggedValue(JSFProfile.TAGGEDVALUE_INPUT_EQUAL);
551            equal = value == null ? null : value.toString();
552        }
553        return equal;
554    }
555
556    /**
557     * Retrieves the "equal" value from the given element (if one is present).
558     *
559     * @param element the element from which to retrieve the equal value.
560     * @param ownerParameter the optional owner parameter (specified if the element is an attribute).
561     * @return the "equal" value.
562     */
563    public static String getEqual(final ModelElementFacade element, final ParameterFacade ownerParameter)
564    {
565        String equal = null;
566        if (element != null)
567        {
568            final Object value = element.findTaggedValue(JSFProfile.TAGGEDVALUE_INPUT_EQUAL);
569            equal = value == null ? null : value.toString();
570            if (StringUtils.isNotBlank(equal) && ownerParameter != null)
571            {
572                equal = ownerParameter.getName() + StringUtilsHelper.upperCamelCaseName(equal);
573            }
574        }
575        return equal;
576    }
577
578    /**
579     * Retrieves the "validwhen" value from the given element (if one is present).
580     *
581     * @param element the element from which to retrieve the validwhen value.
582     * @return the "validwhen" value.
583     */
584    public static String getValidWhen(final ModelElementFacade element)
585    {
586        String validWhen = null;
587        if (element != null)
588        {
589            final Object value = element.findTaggedValue(JSFProfile.TAGGEDVALUE_INPUT_VALIDWHEN);
590            validWhen = value == null ? null : '(' + value.toString() + ')';
591        }
592        return validWhen;
593    }
594
595    /**
596     * @param format
597     * @return the lower limit for this field's value's range
598     */
599    public static String getRangeStart(final String format)
600    {
601        return JSFUtils.getToken(
602            format,
603            1,
604            3);
605    }
606
607    /**
608     * @param format
609     * @return the upper limit for this field's value's range
610     */
611    public static String getRangeEnd(final String format)
612    {
613        return JSFUtils.getToken(
614            format,
615            2,
616            3);
617    }
618
619    /**
620     * @param format
621     * @return the minimum number of characters this field's value must consist of
622     */
623    public static String getMinLengthValue(final String format)
624    {
625        return JSFUtils.getToken(
626            format,
627            1,
628            2);
629    }
630
631    /**
632     * @param format
633     * @return the maximum number of characters this field's value must consist of
634     */
635    public static String getMaxLengthValue(final String format)
636    {
637        return JSFUtils.getToken(
638            format,
639            1,
640            2);
641    }
642
643    /**
644     * @param format
645     * @return the pattern this field's value must respect
646     */
647    public static String getPatternValue(final String format)
648    {
649        return '^' + JSFUtils.getToken(
650            format,
651            1,
652            2) + '$';
653    }
654
655    //validator strings
656    /** "required" */
657    public static final String VT_REQUIRED="required";
658    /** "url" */
659    public static final String VT_URL="url";
660    /** "intRange" */
661    public static final String VT_INT_RANGE="intRange";
662    /** "floatRange" */
663    public static final String VT_FLOAT_RANGE="floatRange";
664    /** "doubleRange" */
665    public static final String VT_DOUBLE_RANGE="doubleRange";
666    /** "email" */
667    public static final String VT_EMAIL="email";
668    /** "creditCard" */
669    public static final String VT_CREDIT_CARD="creditCard";
670    /** "minlength" */
671    public static final String VT_MIN_LENGTH="minlength";
672    /** "maxlength" */
673    public static final String VT_MAX_LENGTH="maxlength";
674    /** "mask" */
675    public static final String VT_MASK="mask";
676    /** "validwhen" */
677    public static final String VT_VALID_WHEN="validwhen";
678    /** "equal" */
679    public static final String VT_EQUAL="equal";
680
681    /**
682     * Retrieves the validator types as a collection from the given
683     * <code>element</code> (if any can be retrieved).
684     *
685     * @param element the element from which to retrieve the types.
686     * @param type the type of the element.
687     * @return the collection of validator types.
688     */
689    public static Collection<String> getValidatorTypes(
690        final ModelElementFacade element,
691        final ClassifierFacade type)
692    {
693        final Collection<String> validatorTypesList = new ArrayList<String>();
694        if (element != null && type != null)
695        {
696            final String format = JSFUtils.getInputFormat(element);
697            final boolean isRangeFormat = format != null && isRangeFormat(format);
698            if (element instanceof AttributeFacade)
699            {
700                if (((AttributeFacade)element).isRequired())
701                {
702                    validatorTypesList.add(VT_REQUIRED);
703                }
704            }
705            else if (element instanceof JSFParameter)
706            {
707                if (((JSFParameter)element).isRequired())
708                {
709                    validatorTypesList.add(VT_REQUIRED);
710                }
711            }
712            if (JSFUtils.isByte(type))
713            {
714                validatorTypesList.add("byte");
715            }
716            else if (JSFUtils.isShort(type))
717            {
718                validatorTypesList.add("short");
719            }
720            else if (JSFUtils.isInteger(type))
721            {
722                validatorTypesList.add("integer");
723            }
724            else if (JSFUtils.isLong(type))
725            {
726                validatorTypesList.add("long");
727            }
728            else if (JSFUtils.isFloat(type))
729            {
730                validatorTypesList.add("float");
731            }
732            else if (JSFUtils.isDouble(type))
733            {
734                validatorTypesList.add("double");
735            }
736            else if (JSFUtils.isDate(type))
737            {
738                validatorTypesList.add("date");
739            }
740            else if (JSFUtils.isTime(type))
741            {
742                validatorTypesList.add("time");
743            }
744            else if (JSFUtils.isUrl(type))
745            {
746                validatorTypesList.add(VT_URL);
747            }
748
749            if (isRangeFormat)
750            {
751                if (JSFUtils.isInteger(type) || JSFUtils.isShort(type) || JSFUtils.isLong(type))
752                {
753                    validatorTypesList.add(VT_INT_RANGE);
754                }
755                if (JSFUtils.isFloat(type))
756                {
757                    validatorTypesList.add(VT_FLOAT_RANGE);
758                }
759                if (JSFUtils.isDouble(type))
760                {
761                    validatorTypesList.add(VT_DOUBLE_RANGE);
762                }
763            }
764
765            if (format != null)
766            {
767                if (JSFUtils.isString(type) && JSFUtils.isEmailFormat(format))
768                {
769                    validatorTypesList.add(VT_EMAIL);
770                }
771                else if (JSFUtils.isString(type) && JSFUtils.isCreditCardFormat(format))
772                {
773                    validatorTypesList.add(VT_CREDIT_CARD);
774                }
775                else
776                {
777                    Collection formats = element.findTaggedValues(JSFProfile.TAGGEDVALUE_INPUT_FORMAT);
778                    for (final Iterator formatIterator = formats.iterator(); formatIterator.hasNext();)
779                    {
780                        String additionalFormat = String.valueOf(formatIterator.next());
781                        if (JSFUtils.isMinLengthFormat(additionalFormat))
782                        {
783                            validatorTypesList.add(VT_MIN_LENGTH);
784                        }
785                        else if (JSFUtils.isMaxLengthFormat(additionalFormat))
786                        {
787                            validatorTypesList.add(VT_MAX_LENGTH);
788                        }
789                        else if (JSFUtils.isPatternFormat(additionalFormat))
790                        {
791                            validatorTypesList.add(VT_MASK);
792                        }
793                    }
794                }
795            }
796            if (JSFUtils.getValidWhen(element) != null)
797            {
798                validatorTypesList.add(VT_VALID_WHEN);
799            }
800            if (JSFUtils.getEqual(element) != null)
801            {
802                validatorTypesList.add(VT_EQUAL);
803            }
804
805            // - custom (paramterized) validators are allowed here
806            final Collection taggedValues = element.findTaggedValues(JSFProfile.TAGGEDVALUE_INPUT_VALIDATORS);
807            for (final Iterator iterator = taggedValues.iterator(); iterator.hasNext();)
808            {
809                String validator = String.valueOf(iterator.next());
810                validatorTypesList.add(JSFUtils.parseValidatorName(validator));
811            }
812        }
813        return validatorTypesList;
814    }
815
816    /**
817     * Gets the validator variables for the given <code>element</code> (if they can
818     * be retrieved).
819     *
820     * @param element the element from which to retrieve the variables
821     * @param type the type of the element.
822     * @param ownerParameter the optional owner parameter (if the element is an attribute for example).
823     * @return the collection of validator variables.
824     */
825    public static Collection<List<String>> getValidatorVars(
826        final ModelElementFacade element,
827        final ClassifierFacade type,
828        final ParameterFacade ownerParameter)
829    {
830        final Map<String, List<String>> vars = new LinkedHashMap<String, List<String>>();
831        if (element != null && type != null)
832        {
833            final String format = JSFUtils.getInputFormat(element);
834            if (format != null)
835            {
836                final boolean isRangeFormat = JSFUtils.isRangeFormat(format);
837
838                if (isRangeFormat)
839                {
840                    final String min = "min";
841                    final String max = "max";
842                    vars.put(
843                        min,
844                        Arrays.asList(min, JSFUtils.getRangeStart(format)));
845                    vars.put(
846                        max,
847                        Arrays.asList(max, JSFUtils.getRangeEnd(format)));
848                }
849                else
850                {
851                    final Collection formats = element.findTaggedValues(JSFProfile.TAGGEDVALUE_INPUT_FORMAT);
852                    for (final Iterator formatIterator = formats.iterator(); formatIterator.hasNext();)
853                    {
854                        final String additionalFormat = String.valueOf(formatIterator.next());
855                        final String minlength = "minlength";
856                        final String maxlength = "maxlength";
857                        final String mask = "mask";
858                        if (JSFUtils.isMinLengthFormat(additionalFormat))
859                        {
860                            vars.put(
861                                minlength,
862                                Arrays.asList(minlength, JSFUtils.getMinLengthValue(additionalFormat)));
863                        }
864                        else if (JSFUtils.isMaxLengthFormat(additionalFormat))
865                        {
866                            vars.put(
867                                maxlength,
868                                Arrays.asList(maxlength, JSFUtils.getMaxLengthValue(additionalFormat)));
869                        }
870                        else if (JSFUtils.isPatternFormat(additionalFormat))
871                        {
872                            vars.put(
873                                mask,
874                                Arrays.asList(mask, JSFUtils.getPatternValue(additionalFormat)));
875                        }
876                    }
877                }
878            }
879            String inputFormat;
880            if (element instanceof JSFAttribute)
881            {
882                inputFormat = ((JSFAttribute)element).getFormat();
883            }
884            else if (element instanceof JSFParameter)
885            {
886                inputFormat = ((JSFParameter)element).getFormat();
887            }
888            else if (element instanceof JSFManageableEntityAttribute)
889            {
890                inputFormat = ((JSFManageableEntityAttribute)element).getFormat();
891            }
892            else
893            {
894                throw new RuntimeException("'element' is an invalid type, it must be either an instance of '" +
895                    JSFAttribute.class.getName() + "' or '" + JSFParameter.class.getName() + "'");
896            }
897            if (JSFUtils.isDate(type))
898            {
899                final String datePatternStrict = "datePatternStrict";
900                if (format != null && JSFUtils.isStrictDateFormat(format))
901                {
902                    vars.put(
903                        datePatternStrict,
904                        Arrays.asList(datePatternStrict, inputFormat));
905                }
906                else
907                {
908                    final String datePattern = "datePattern";
909                    vars.put(
910                        datePattern,
911                        Arrays.asList(datePattern, inputFormat));
912                }
913            }
914            if (JSFUtils.isTime(type))
915            {
916                final String timePattern = "timePattern";
917                vars.put(
918                    timePattern,
919                    Arrays.asList(timePattern, inputFormat));
920            }
921
922            final String validWhen = JSFUtils.getValidWhen(element);
923            if (validWhen != null)
924            {
925                final String test = "test";
926                vars.put(
927                    test,
928                    Arrays.asList(test, validWhen));
929            }
930
931            final String equal = JSFUtils.getEqual(element, ownerParameter);
932            if (equal != null)
933            {
934                final String fieldName = "fieldName";
935                vars.put(
936                    fieldName,
937                    Arrays.asList(fieldName, equal));
938            }
939
940            // - custom (parameterized) validators are allowed here
941            //   in this case we will reuse the validator arg values
942            final Collection taggedValues = element.findTaggedValues(JSFProfile.TAGGEDVALUE_INPUT_VALIDATORS);
943            for (final Object value : taggedValues)
944            {
945                final String validator = String.valueOf(value);
946
947                // - guaranteed to be of the same length
948                final List<String> validatorVars = JSFUtils.parseValidatorVars(validator);
949                final List<String> validatorArgs = JSFUtils.parseValidatorArgs(validator);
950
951                for (int ctr = 0; ctr < validatorVars.size(); ctr++)
952                {
953                    vars.put(validatorVars.get(ctr),
954                        Arrays.asList(validatorVars.get(ctr), validatorArgs.get(ctr)));
955                }
956            }
957        }
958        return vars.values();
959    }
960
961    /**
962     * Gets the validator args for the <code>element</code> and the given <code>validatorType</code>.
963     *
964     * @param element the element for which to retrieve the arguments.
965     * @param validatorType the validator type name.
966     * @return the validator args as a collection.
967     */
968    public static java.util.Collection getValidatorArgs(
969        final ModelElementFacade element,
970        final String validatorType)
971    {
972        final Collection<Object> args = new ArrayList<Object>();
973        if ("intRange".equals(validatorType) || "floatRange".equals(validatorType) ||
974            "doubleRange".equals(validatorType))
975        {
976            args.add("${var:min}");
977            args.add("${var:max}");
978        }
979        else if ("minlength".equals(validatorType))
980        {
981            args.add("${var:minlength}");
982        }
983        else if ("maxlength".equals(validatorType))
984        {
985            args.add("${var:maxlength}");
986        }
987        else if ("date".equals(validatorType))
988        {
989            final String validatorFormat = JSFUtils.getInputFormat(element);
990            if (JSFUtils.isStrictDateFormat(validatorFormat))
991            {
992                args.add("${var:datePatternStrict}");
993            }
994            else
995            {
996                args.add("${var:datePattern}");
997            }
998        }
999        else if ("time".equals(validatorType))
1000        {
1001            args.add("${var:timePattern}");
1002        }
1003        else if ("equal".equals(validatorType))
1004        {
1005            ModelElementFacade equalParameter = null;
1006            final String equal = JSFUtils.getEqual(element);
1007            if (element instanceof ParameterFacade)
1008            {
1009                final FrontEndParameter parameter = (FrontEndParameter)element;
1010                final OperationFacade operation = parameter.getOperation();
1011                if (operation != null)
1012                {
1013                    equalParameter = operation.findParameter(equal);
1014                }
1015                if (equalParameter == null)
1016                {
1017                    final FrontEndAction action = parameter.getAction();
1018                    if (action != null)
1019                    {
1020                        equalParameter = action.findParameter(equal);
1021                    }
1022                }
1023            }
1024            else if (element instanceof AttributeFacade)
1025            {
1026                final AttributeFacade attribute = (AttributeFacade)element;
1027                final ClassifierFacade owner = attribute.getOwner();
1028                if (owner != null)
1029                {
1030                    equalParameter = owner.findAttribute(equal);
1031                }
1032            }
1033            args.add(equalParameter);
1034            args.add("${var:fieldName}");
1035        }
1036
1037        // custom (paramterized) validators are allowed here
1038        final Collection taggedValues = element.findTaggedValues(JSFProfile.TAGGEDVALUE_INPUT_VALIDATORS);
1039        for (final Iterator iterator = taggedValues.iterator(); iterator.hasNext();)
1040        {
1041            final String validator = String.valueOf(iterator.next());
1042            if (validatorType.equals(JSFUtils.parseValidatorName(validator)))
1043            {
1044                args.addAll(JSFUtils.parseValidatorArgs(validator));
1045            }
1046        }
1047        return args;
1048    }
1049
1050    /**
1051     * Whether or not date patterns should be treated as strict.
1052     */
1053    private static boolean strictDateTimeFormat;
1054
1055    /**
1056     * Sets whether or not the date patterns should be treated as strict.
1057     *
1058     * @param strictDateTimeFormat
1059     */
1060    public void setStrictDateTimeFormat(final boolean strictDateTimeFormat)
1061    {
1062        JSFUtils.strictDateTimeFormat = strictDateTimeFormat;
1063    }
1064
1065    /**
1066     * Indicates whether or not the format for this element is a strict date
1067     * format.
1068     * @param element
1069     * @return true/false
1070     */
1071    public static boolean isStrictDateFormat(final ModelElementFacade element)
1072    {
1073        final String format = JSFUtils.getInputFormat(element);
1074        return JSFUtils.isStrictDateFormat(format);
1075    }
1076
1077    /**
1078     * Gets the format string for the given <code>element</code>.
1079     *
1080     * @param element the element for which to retrieve the format.
1081     * @param type the type of the element.
1082     * @param defaultDateFormat
1083     * @param defaultTimeFormat
1084     * @return the format string (if one is present otherwise null).
1085     */
1086    public static String getFormat(
1087        final ModelElementFacade element,
1088        final ClassifierFacade type,
1089        final String defaultDateFormat,
1090        final String defaultTimeFormat)
1091    {
1092        String format = null;
1093        if (element != null && type != null)
1094        {
1095            format = JSFUtils.getInputFormat(element);
1096            if (format == null)
1097            {
1098                if(type.isDateType() && type.isTimeType())
1099                {
1100                    format = defaultDateFormat+" "+defaultTimeFormat;
1101                }
1102                else if (type.isTimeType())
1103                {
1104                    format = defaultTimeFormat;
1105                }
1106                else if (type.isDateType())
1107                {
1108                    format = defaultDateFormat;
1109                }
1110            }
1111            else if (type.isDateType())
1112            {
1113                format = JSFUtils.getDateFormat(format);
1114            }
1115        }
1116        return format;
1117    }
1118
1119    /**
1120     * The XHTML extension.
1121     */
1122    private static final String EXTENSION_XHTML = "xhtml";
1123
1124    /**
1125     * Gets the extension for the view type.
1126     *
1127     * @return the view type extension.
1128     */
1129    public String getViewExtension()
1130    {
1131        return EXTENSION_XHTML;
1132    }
1133
1134    //TODO remover
1135    private boolean isPortlet()
1136    {
1137        return false;
1138    }
1139
1140    /**
1141     * @return className
1142     */
1143    public String getRequestClassName()
1144    {
1145        final String className;
1146        if (this.isPortlet())
1147        {
1148            className = "javax.portlet.PortletRequest";
1149        }
1150        else
1151        {
1152            className = "javax.servlet.http.HttpServletRequest";
1153        }
1154        return className;
1155    }
1156
1157    /**
1158     * @return className
1159     */
1160    public String getResponseClassName()
1161    {
1162        final String className;
1163        if (this.isPortlet())
1164        {
1165            className = "javax.portlet.PortletResponse";
1166        }
1167        else
1168        {
1169            className = "javax.servlet.http.HttpServletResponse";
1170        }
1171        return className;
1172    }
1173
1174    /**
1175     * @return className
1176     */
1177    public String getSessionClassName()
1178    {
1179        final String className;
1180        if (this.isPortlet())
1181        {
1182            className = "javax.portlet.PortletSession";
1183        }
1184        else
1185        {
1186            className = "javax.servlet.http.HttpSession";
1187        }
1188        return className;
1189    }
1190
1191    /**
1192     * @param buffer
1193     * @return the calculated SerialVersionUID
1194     */
1195    public static String calcSerialVersionUID(StringBuilder buffer)
1196    {
1197        final String signature = buffer.toString();
1198        String serialVersionUID = String.valueOf(0L);
1199        try
1200        {
1201            MessageDigest md = MessageDigest.getInstance("SHA");
1202            byte[] hashBytes = md.digest(signature.getBytes());
1203
1204            long hash = 0;
1205            for (int ctr = Math.min(
1206                        hashBytes.length,
1207                        8) - 1; ctr >= 0; ctr--)
1208            {
1209                hash = (hash << 8) | (hashBytes[ctr] & 0xFF);
1210            }
1211            serialVersionUID = String.valueOf(hash);
1212        }
1213        catch (final NoSuchAlgorithmException exception)
1214        {
1215            throw new RuntimeException("Error performing JSFAction.getFormSerialVersionUID",exception);
1216        }
1217
1218        return serialVersionUID;
1219    }
1220
1221    /**
1222     * @param string
1223     * @return Integer.valueOf(string) * 6000
1224     */
1225    public int calculateIcefacesTimeout(String string)
1226    {
1227        return string != null ? Integer.valueOf(string) * 6000 : 0;
1228    }
1229}