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 }