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}