001package org.andromda.cartridges.bpm4struts;
002
003import java.io.Serializable;
004import java.util.ArrayList;
005import java.util.Collection;
006import java.util.Collections;
007import java.util.Comparator;
008import java.util.Enumeration;
009import java.util.Iterator;
010import java.util.List;
011import java.util.regex.Pattern;
012import org.andromda.metafacades.uml.ManageableEntity;
013import org.andromda.utils.StringUtilsHelper;
014import org.apache.commons.lang.StringUtils;
015
016/**
017 * Contains utilities for bpm4struts.
018 *
019 * @author Wouter Zoons
020 */
021public final class Bpm4StrutsUtils
022{
023    /**
024     * Creates and returns a List from an <code>enumeration</code>.
025     *
026     * @param enumeration the enumeration from which to create the List.
027     * @return the new List.
028     */
029    public static List listEnumeration(Enumeration enumeration)
030    {
031        List list;
032        if (enumeration == null)
033        {
034            list = Collections.emptyList();
035        }
036        else
037        {
038            list = Collections.list(enumeration);
039        }
040        return list;
041    }
042
043    private static final Pattern VALIDATOR_TAGGEDVALUE_PATTERN = Pattern.compile(
044        "\\w+(\\(\\w+=[^,)]*(,\\w+=[^,)]*)*\\))?");
045
046    /**
047     * Reads the validator arguments from the the given tagged value.
048     * @param validatorTaggedValue
049     * @return never null, returns a list of String instances
050     * @throws IllegalArgumentException when the input string does not match the required pattern
051     */
052    public static List<String> parseValidatorArgs(String validatorTaggedValue)
053    {
054        if (validatorTaggedValue == null)
055        {
056            throw new IllegalArgumentException("Validator tagged value cannot be null");
057        }
058
059        // check if the input tagged value matches the required pattern
060        if (!VALIDATOR_TAGGEDVALUE_PATTERN.matcher(validatorTaggedValue).matches())
061        {
062            throw new IllegalArgumentException(
063                "Illegal validator tagged value (this tag is used to specify custom validators " +
064                    "and might look like myValidator(myVar=myArg,myVar2=myArg2), perhaps you wanted to use " +
065                    "andromda_presentation_view_field_format?): " + validatorTaggedValue);
066        }
067
068        final List<String> validatorArgs = new ArrayList<String>();
069
070        // only keep what is between parentheses (if any)
071        int left = validatorTaggedValue.indexOf('(');
072        if (left > -1)
073        {
074            final int right = validatorTaggedValue.indexOf(')');
075            validatorTaggedValue = validatorTaggedValue.substring(left + 1, right);
076
077            final String[] pairs = validatorTaggedValue.split(",");
078            for (int i = 0; i < pairs.length; i++)
079            {
080                final String pair = pairs[i];
081                final int equalsIndex = pair.indexOf('=');
082                // it's possible the argument is the empty string
083                if (equalsIndex < pair.length() - 1)
084                {
085                    validatorArgs.add(pair.substring(equalsIndex + 1));
086                }
087                else
088                {
089                    validatorArgs.add("");
090                }
091            }
092        }
093        return validatorArgs;
094    }
095
096    /**
097     * Reads the validator variable names from the the given tagged value.
098     *
099     * @param validatorTaggedValue
100     * @return never null, returns a list of String instances
101     * @throws IllegalArgumentException when the input string does not match the required pattern
102     */
103    public static List<String> parseValidatorVars(String validatorTaggedValue)
104    {
105        if (validatorTaggedValue == null)
106        {
107            throw new IllegalArgumentException("Validator tagged value cannot be null");
108        }
109
110        // check if the input tagged value matches the required pattern
111        if (!VALIDATOR_TAGGEDVALUE_PATTERN.matcher(validatorTaggedValue).matches())
112        {
113            throw new IllegalArgumentException("Illegal validator tagged value: " + validatorTaggedValue);
114        }
115
116        final List<String> validatorVars = new ArrayList<String>();
117
118        // only keep what is between parentheses (if any)
119        int left = validatorTaggedValue.indexOf('(');
120        if (left > -1)
121        {
122            int right = validatorTaggedValue.indexOf(')');
123            validatorTaggedValue = validatorTaggedValue.substring(left + 1, right);
124
125            final String[] pairs = validatorTaggedValue.split(",");
126            for (int i = 0; i < pairs.length; i++)
127            {
128                final String pair = pairs[i];
129                final int equalsIndex = pair.indexOf('=');
130                validatorVars.add(pair.substring(0, equalsIndex));
131            }
132        }
133        return validatorVars;
134    }
135
136    /**
137     * Parses the validator name for a tagged value.
138     *
139     * @param validatorTaggedValue
140     * @return validatorTaggedValue.substring(0, leftParen
141     * @throws IllegalArgumentException when the input string does not match the required pattern
142     */
143    public static String parseValidatorName(String validatorTaggedValue)
144    {
145        if (validatorTaggedValue == null)
146        {
147            throw new IllegalArgumentException("Validator tagged value cannot be null");
148        }
149
150        // check if the input tagged value matches the required pattern
151        if (!VALIDATOR_TAGGEDVALUE_PATTERN.matcher(validatorTaggedValue).matches())
152        {
153            throw new IllegalArgumentException("Illegal validator tagged value: " + validatorTaggedValue);
154        }
155
156        final int leftParen = validatorTaggedValue.indexOf('(');
157        return (leftParen == -1) ? validatorTaggedValue : validatorTaggedValue.substring(0, leftParen);
158    }
159
160    /**
161     * Sorts a collection of Manageable entities according to their 'manageableName' property.
162     * Returns a new collection.
163     * @param collection
164     * @return Collections.sort(sorted, new ManageableEntityComparator())
165     */
166    public static Collection sortManageables(Collection collection)
167    {
168        final List sorted = new ArrayList(collection);
169        Collections.sort(sorted, new ManageableEntityComparator());
170        return sorted;
171    }
172
173    /**
174     * Converts the argument into a web file name, this means: all lowercase
175     * characters and words are separated with dashes.
176     *
177     * @param string any string
178     * @return the string converted to a value that would be well-suited for a
179     *         web file name
180     */
181    public static String toWebFileName(final String string)
182    {
183        return StringUtilsHelper.toPhrase(string).replace(' ', '-').toLowerCase();
184    }
185
186    /**
187     * Returns <code>true</code> if the argument name will not cause any troubles with the Jakarta commons-beanutils
188     * library, which basically means it does not start with an lowercase characters followed by an uppercase character.
189     * This means there's a bug in that specific library that causes an incompatibility with the Java Beans
190     * specification as implemented in the JDK.
191     *
192     * @param name the name to test, may be <code>null</code>
193     * @return <code>true</code> if the name is safe to use with the Jakarta libraries, <code>false</code> otherwise
194     */
195    public static boolean isSafeName(final String name)
196    {
197        boolean safe = true;
198
199        if (name != null && name.length() > 1)
200        {
201            safe = !(Character.isLowerCase(name.charAt(0)) && Character.isUpperCase(name.charAt(1)));
202        }
203
204        return safe;
205    }
206
207    /**
208     * Returns a sequence of file formats representing the desired export types for the display tag tables
209     * used for the argument element.
210     *
211     * @param taggedValues the collection of tagged values representing the export types, should only contain
212     *  <code>String</code> instances and must never be <code>null</code>
213     * @param defaultValue the default value to use in case the tagged values are empty
214     * @return a space separated list of formats, never <code>null</code>
215     */
216    public static String getDisplayTagExportTypes(final Collection taggedValues, final String defaultValue)
217    {
218        String exportTypes;
219
220        if (taggedValues.isEmpty())
221        {
222            exportTypes = defaultValue;
223        }
224        else
225        {
226            if (taggedValues.contains("none"))
227            {
228                exportTypes = "none";
229            }
230            else
231            {
232                final StringBuilder buffer = new StringBuilder();
233                for (final Iterator iterator = taggedValues.iterator(); iterator.hasNext();)
234                {
235                    final String exportType = StringUtils.trimToNull(String.valueOf(iterator.next()));
236                    if ("csv".equalsIgnoreCase(exportType) ||
237                        "pdf".equalsIgnoreCase(exportType) ||
238                        "xml".equalsIgnoreCase(exportType) ||
239                        "excel".equalsIgnoreCase(exportType))
240                    {
241                        buffer.append(exportType);
242                        buffer.append(' ');
243                    }
244                }
245                exportTypes = buffer.toString().trim();
246            }
247        }
248
249        return exportTypes;
250    }
251
252    /**
253     * Convenient method to detect whether or not a String instance represents a boolean <code>true</code> value.
254     * @param string
255     * @return true if yes, true, on, 1
256     */
257    public static boolean isTrue(String string)
258    {
259        return "yes".equalsIgnoreCase(string) ||
260            "true".equalsIgnoreCase(string) ||
261            "on".equalsIgnoreCase(string) ||
262            "1".equalsIgnoreCase(string);
263    }
264
265    /**
266     *
267     */
268    static final class ManageableEntityComparator
269        implements Comparator, Serializable
270    {
271        private static final long serialVersionUID = 1L;
272        /**
273         * @see java.util.Comparator#compare(Object, Object)
274         */
275        public int compare(
276            Object left,
277            Object right)
278        {
279            final ManageableEntity leftEntity = (ManageableEntity)left;
280            final ManageableEntity rightEntity = (ManageableEntity)right;
281            return StringUtils.trimToEmpty(leftEntity.getName()).compareTo(
282                StringUtils.trimToEmpty(rightEntity.getName()));
283        }
284    }
285}