001 /* 002 * Copyright 2005-2007 The Kuali Foundation 003 * 004 * 005 * Licensed under the Educational Community License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.opensource.org/licenses/ecl2.php 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.kuali.rice.kew.util; 018 019 import java.io.PrintWriter; 020 import java.io.StringWriter; 021 import java.net.InetAddress; 022 import java.net.UnknownHostException; 023 import java.sql.Timestamp; 024 import java.util.ArrayList; 025 import java.util.Calendar; 026 import java.util.Collection; 027 import java.util.Collections; 028 import java.util.Comparator; 029 import java.util.Date; 030 import java.util.HashMap; 031 import java.util.HashSet; 032 import java.util.List; 033 import java.util.Map; 034 import java.util.Set; 035 036 import org.apache.commons.collections.KeyValue; 037 import org.apache.commons.lang.StringUtils; 038 import org.apache.commons.lang.text.StrSubstitutor; 039 import org.kuali.rice.core.util.RiceConstants; 040 import org.kuali.rice.kew.actionrequest.ActionRequestValue; 041 import org.kuali.rice.kew.exception.WorkflowRuntimeException; 042 import org.kuali.rice.kim.util.KimConstants; 043 import org.kuali.rice.kns.bo.Parameter; 044 import org.kuali.rice.kns.service.KNSServiceLocator; 045 046 047 /** 048 * Various static utility methods. 049 * 050 * @author Kuali Rice Team (rice.collab@kuali.org) 051 */ 052 public class Utilities { 053 /** 054 * Commons-Lang StrSubstitor which substitutes variables specified like ${name} in strings, 055 * using a lookup implementation that pulls variables from the core config 056 */ 057 private static StrSubstitutor substitutor = new StrSubstitutor(new ConfigStringLookup()); 058 059 /** 060 * Performs variable substitution on the specified string, replacing variables specified like ${name} 061 * with the value of the corresponding config parameter obtained from the current context Config object. 062 * This version of the method also takes a namespace to qualify the parameter. 063 * @param namespace the namespace to use for qualifying the parameter 064 * @param string the string on which to perform variable substitution 065 * @return a string with any variables substituted with configuration parameter values 066 */ 067 public static String substituteConfigParameters(String namespace, String string) { 068 StrSubstitutor sub = new StrSubstitutor(new ConfigStringLookup(namespace)); 069 return sub.replace(string); 070 } 071 072 /** 073 * Performs variable substitution on the specified string, replacing variables specified like ${name} 074 * with the value of the corresponding config parameter obtained from the current context Config object 075 * @param string the string on which to perform variable substitution 076 * @return a string with any variables substituted with configuration parameter values 077 */ 078 public static String substituteConfigParameters(String string) { 079 return substitutor.replace(string); 080 } 081 082 public static String getKNSParameterValue(String nameSpace, String detailType, String name) { 083 Parameter parameter = KNSServiceLocator.getParameterService().retrieveParameter(nameSpace, detailType, name); 084 if (parameter == null) { 085 return null; 086 } 087 return parameter.getParameterValue(); 088 } 089 090 public static boolean getKNSParameterBooleanValue(String nameSpace, String detailType, String name) { 091 return getKNSParameterBooleanValue(nameSpace, detailType, name, false); 092 } 093 094 public static boolean getKNSParameterBooleanValue(String nameSpace, String detailType, String name, boolean defaultValue) { 095 Parameter parameter = KNSServiceLocator.getParameterService().retrieveParameter(nameSpace, detailType, name); 096 if (parameter == null || StringUtils.isBlank(parameter.getParameterValue())) { 097 return defaultValue; 098 } 099 if (parameter.getParameterValue().trim().equals("Y")) { 100 return true; 101 } else { 102 return false; 103 } 104 } 105 106 public static String parseGroupNamespaceCode(String namespaceAndNameCombo) { 107 if (namespaceAndNameCombo == null) { 108 return null; 109 } 110 String[] groupData = namespaceAndNameCombo.split(KEWConstants.KIM_GROUP_NAMESPACE_NAME_DELIMITER_CHARACTER); 111 if (groupData.length == 1) { 112 return KimConstants.KIM_GROUP_WORKFLOW_NAMESPACE_CODE; 113 } else if (groupData.length == 2) { 114 return groupData[0].trim(); 115 } else { 116 return null; 117 } 118 } 119 120 public static String parseGroupName(String namespaceAndNameCombo) { 121 if (namespaceAndNameCombo == null) { 122 return null; 123 } 124 String[] groupData = namespaceAndNameCombo.split(KEWConstants.KIM_GROUP_NAMESPACE_NAME_DELIMITER_CHARACTER); 125 if (groupData.length == 1) { 126 return groupData[0].trim(); 127 } else if (groupData.length == 2) { 128 return groupData[1].trim(); 129 } else { 130 return null; 131 } 132 } 133 134 public static boolean isEmpty(String value) { 135 return value == null || value.trim().equals(""); 136 } 137 138 public static boolean isEmpty(Collection collection) { 139 return collection == null || collection.isEmpty(); 140 } 141 142 public static boolean isEmpty(Object[] array) { 143 return array == null || array.length == 0; 144 } 145 146 public static boolean equals (Object a, Object b) { 147 return ((a == null && b == null) || (a != null && a.equals(b))); 148 } 149 150 public static String collectStackTrace(Throwable t) { 151 StringWriter sw = new StringWriter(); 152 PrintWriter pw = new PrintWriter(sw); 153 t.printStackTrace(pw); 154 pw.close(); 155 return sw.toString(); 156 } 157 158 public static Calendar convertTimestamp(Timestamp timestamp) { 159 if (timestamp == null) { 160 return null; 161 } 162 Calendar calendar = Calendar.getInstance(); 163 calendar.setTime(timestamp); 164 return calendar; 165 } 166 167 public static Timestamp convertCalendar(Calendar calendar) { 168 if (calendar == null) { 169 return null; 170 } 171 return new Timestamp(calendar.getTime().getTime()); 172 } 173 174 public static Set asSet(Object[] objects) { 175 Set set = new HashSet(); 176 if (objects != null) { 177 for (int index = 0; index < objects.length; index++) { 178 Object object = objects[index]; 179 set.add(object); 180 } 181 } 182 return set; 183 } 184 185 public static Set asSet(Object object) { 186 Set set = new HashSet(); 187 if (object != null) { 188 set.add(object); 189 } 190 return set; 191 } 192 193 public static List asList(Object object) { 194 List<Object> list = new ArrayList<Object>(1); 195 if (object != null) { 196 list.add(object); 197 } 198 return list; 199 } 200 201 /** 202 * 203 * Consider moving out of this class if this bugs 204 */ 205 public static class PrioritySorter implements Comparator<ActionRequestValue> { 206 public int compare(ActionRequestValue ar1, ActionRequestValue ar2) { 207 int value = ar1.getPriority().compareTo(ar2.getPriority()); 208 if (value == 0) { 209 value = ActionRequestValue.compareActionCode(ar1.getActionRequested(), ar2.getActionRequested(), true); 210 if (value == 0) { 211 if ( (ar1.getActionRequestId() != null) && (ar2.getActionRequestId() != null) ) { 212 value = ar1.getActionRequestId().compareTo(ar2.getActionRequestId()); 213 } else { 214 // if even one action request id is null at this point return that the two are equal 215 value = 0; 216 } 217 } 218 } 219 return value; 220 } 221 } 222 223 /** 224 * 225 * Consider moving out of this class if this bugs 226 */ 227 public static class RouteLogActionRequestSorter extends PrioritySorter implements Comparator<ActionRequestValue> { 228 public int compare(ActionRequestValue ar1, ActionRequestValue ar2) { 229 if (! ar1.getChildrenRequests().isEmpty()) { 230 Collections.sort(ar1.getChildrenRequests(), this); 231 } 232 if (! ar2.getChildrenRequests().isEmpty()) { 233 Collections.sort(ar2.getChildrenRequests(), this); 234 } 235 236 int routeLevelCompareVal = ar1.getRouteLevel().compareTo(ar2.getRouteLevel()); 237 if (routeLevelCompareVal != 0) { 238 return routeLevelCompareVal; 239 } 240 241 if (ar1.isActive() && ar2.isPending()) { 242 return -1; 243 } else if (ar2.isActive() && ar1.isPending()) { 244 return 1; 245 } 246 247 return super.compare(ar1, ar2); 248 } 249 } 250 251 public static boolean validateDate(String date, boolean dateOptional) { 252 if ((date == null) || date.trim().equals("")) { 253 if (dateOptional) { 254 return true; 255 } else { 256 return false; 257 } 258 } 259 260 try { 261 Date parsedDate = RiceConstants.getDefaultDateFormat().parse(date.trim()); 262 if (! RiceConstants.getDefaultDateFormat().format(parsedDate).equals(date)) return false; 263 Calendar calendar = Calendar.getInstance(); 264 calendar.setTime(parsedDate); 265 int yearInt = calendar.get(Calendar.YEAR); 266 if (yearInt <= 0 || yearInt > 2999) { 267 return false; 268 } 269 return true; 270 } catch (Exception ex) { 271 return false; 272 } 273 } 274 275 public static boolean checkDateRanges(String fromDate, String toDate) { 276 try { 277 Date parsedDate = KNSServiceLocator.getDateTimeService().convertToDate(fromDate.trim()); 278 Calendar fromCalendar = Calendar.getInstance(); 279 fromCalendar.setLenient(false); 280 fromCalendar.setTime(parsedDate); 281 fromCalendar.set(Calendar.HOUR_OF_DAY, 0); 282 fromCalendar.set(Calendar.MINUTE, 0); 283 fromCalendar.set(Calendar.SECOND, 0); 284 fromCalendar.set(Calendar.MILLISECOND, 0); 285 parsedDate = KNSServiceLocator.getDateTimeService().convertToDate(toDate.trim()); 286 Calendar toCalendar = Calendar.getInstance(); 287 toCalendar.setLenient(false); 288 toCalendar.setTime(parsedDate); 289 toCalendar.set(Calendar.HOUR_OF_DAY, 0); 290 toCalendar.set(Calendar.MINUTE, 0); 291 toCalendar.set(Calendar.SECOND, 0); 292 toCalendar.set(Calendar.MILLISECOND, 0); 293 if (fromCalendar.after(toCalendar)) { 294 return false; 295 } 296 return true; 297 } catch (Exception ex) { 298 return false; 299 } 300 } 301 302 /** 303 * Performs a "brute force" comparison of collections by testing whether the collections contain each other. 304 * This circuments any particular uniqueness or ordering constraints on the collections 305 * (for instance, lists that are unordered but contain the same elements, where a hashset would not suffice 306 * for comparison purposes because it enforces element uniqueness) 307 */ 308 public static boolean collectionsEquivalent(Collection a, Collection b) { 309 if (a == null && b == null) return true; 310 if (a == null ^ b == null) return false; 311 return a.containsAll(b) && b.containsAll(a); 312 } 313 314 public static String getIpNumber() { 315 try { 316 return InetAddress.getLocalHost().getHostAddress(); 317 } catch (UnknownHostException e) { 318 throw new WorkflowRuntimeException("Error retrieving ip number.", e); 319 } 320 } 321 322 public static String getHostName() { 323 try { 324 return InetAddress.getLocalHost().getHostName(); 325 } catch (UnknownHostException e) { 326 throw new WorkflowRuntimeException("Error retrieving host name.", e); 327 } 328 } 329 330 /** 331 * Helper method that takes a List of {@link KeyValue} and presents it as a Map 332 * @param <T> the key type 333 * @param <Z> the value type 334 * @param collection collection of {@link KeyValue} 335 * @return a Map<T,Z> representing the keys and values in the KeyValue collection 336 */ 337 public static <T,Z> Map<T, Z> getKeyValueCollectionAsMap(List<? extends KeyValue> collection) { 338 Map<T, Z> map = new HashMap<T, Z>(collection.size()); 339 for (KeyValue kv: collection) { 340 map.put((T) kv.getKey(), (Z) kv.getValue()); 341 } 342 return map; 343 } 344 345 /** 346 * Helper method that takes a List of {@link KeyValue} and presents it as a Map containing 347 * KeyValue values 348 * @param <T> the key type 349 * @param <Z> the collection/map value type, which must be a KeyValue 350 * @param collection collection of {@link KeyValue} 351 * @return a Map<T,Z> where keys of the KeyValues in the collection are mapped to their respective KeyValue object 352 */ 353 public static <T,Z extends KeyValue> Map<T, Z> getKeyValueCollectionAsLookupTable(List<Z> collection) { 354 Map<T, Z> map = new HashMap<T, Z>(collection.size()); 355 for (Z kv: collection) { 356 map.put((T) kv.getKey(), kv); 357 } 358 return map; 359 } 360 }