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    }