001/**
002 * Copyright 2005-2016 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.rice.kew.util;
017
018import org.apache.commons.lang.text.StrSubstitutor;
019import org.kuali.rice.core.api.CoreApiServiceLocator;
020import org.kuali.rice.core.api.util.KeyValue;
021import org.kuali.rice.kew.actionrequest.ActionRequestValue;
022import org.kuali.rice.kew.api.KewApiConstants;
023import org.kuali.rice.kim.api.KimConstants;
024
025import java.util.Calendar;
026import java.util.Collections;
027import java.util.Comparator;
028import java.util.Date;
029import java.util.HashMap;
030import java.util.List;
031import java.util.Map;
032
033
034/**
035 * Various static utility methods.
036 *
037 * @author Kuali Rice Team (rice.collab@kuali.org)
038 */
039public final class Utilities {
040    /**
041     * Commons-Lang StrSubstitor which substitutes variables specified like ${name} in strings,
042     * using a lookup implementation that pulls variables from the core config
043     */
044    private static final StrSubstitutor SUBSTITUTOR = new StrSubstitutor(new ConfigStringLookup());
045    
046    private Utilities() {
047        throw new UnsupportedOperationException("do not call");
048    }
049
050    /**
051     * Performs variable substitution on the specified string, replacing variables specified like ${name}
052     * with the value of the corresponding config parameter obtained from the current context Config object.
053     * This version of the method also takes an application id to qualify the parameter.
054     * @param applicationId the application id to use for qualifying the parameter
055     * @param string the string on which to perform variable substitution
056     * @return a string with any variables substituted with configuration parameter values
057     */
058    public static String substituteConfigParameters(String applicationId, String string) {
059        StrSubstitutor sub = new StrSubstitutor(new ConfigStringLookup(applicationId));
060        return sub.replace(string);
061    }
062        
063    /**
064     * Performs variable substitution on the specified string, replacing variables specified like ${name}
065     * with the value of the corresponding config parameter obtained from the current context Config object
066     * @param string the string on which to perform variable substitution
067     * @return a string with any variables substituted with configuration parameter values
068     */
069    public static String substituteConfigParameters(String string) {
070        return SUBSTITUTOR.replace(string);
071    }
072
073    public static String parseGroupNamespaceCode(String namespaceAndNameCombo) {
074        if (namespaceAndNameCombo == null) {
075            return null;
076        }
077        String[] groupData = namespaceAndNameCombo.split(KewApiConstants.KIM_GROUP_NAMESPACE_NAME_DELIMITER_CHARACTER);
078        if (groupData.length == 1) {
079            return KimConstants.KIM_GROUP_WORKFLOW_NAMESPACE_CODE;
080        } else if (groupData.length == 2) {
081            return groupData[0].trim();
082        } else {
083            return null;
084        }
085    }
086
087    public static String parseGroupName(String namespaceAndNameCombo) {
088        if (namespaceAndNameCombo == null) {
089            return null;
090        }
091        String[] groupData = namespaceAndNameCombo.split(KewApiConstants.KIM_GROUP_NAMESPACE_NAME_DELIMITER_CHARACTER);
092        if (groupData.length == 1) {
093            return groupData[0].trim();
094        } else if (groupData.length == 2) {
095            return groupData[1].trim();
096        } else {
097            return null;
098        }
099    }
100
101    /**
102     *
103     *  Consider moving out of this class if this bugs
104     */
105    public static class PrioritySorter implements Comparator<ActionRequestValue> {
106        @Override
107                public int compare(ActionRequestValue ar1, ActionRequestValue ar2) {
108            int value = ar1.getPriority().compareTo(ar2.getPriority());
109            if (value == 0) {
110                value = ActionRequestValue.compareActionCode(ar1.getActionRequested(), ar2.getActionRequested(), true);
111                if (value == 0) {
112                    if ( (ar1.getActionRequestId() != null) && (ar2.getActionRequestId() != null) ) {
113                        value = ar1.getActionRequestId().compareTo(ar2.getActionRequestId());
114                    } else {
115                        // if even one action request id is null at this point return that the two are equal
116                        value = 0;
117                    }
118                }
119            }
120            return value;
121        }
122    }
123
124    /**
125     *
126     *  Consider moving out of this class if this bugs
127     */
128    public static class RouteLogActionRequestSorter extends PrioritySorter implements Comparator<ActionRequestValue> {
129        @Override
130                public int compare(ActionRequestValue ar1, ActionRequestValue ar2) {
131            if (! ar1.getChildrenRequests().isEmpty()) {
132                Collections.sort(ar1.getChildrenRequests(), this);
133            }
134            if (! ar2.getChildrenRequests().isEmpty()) {
135                Collections.sort(ar2.getChildrenRequests(), this);
136            }
137
138            int routeLevelCompareVal = ar1.getRouteLevel().compareTo(ar2.getRouteLevel());
139            if (routeLevelCompareVal != 0) {
140                return routeLevelCompareVal;
141            }
142
143            if (ar1.isActive() && ar2.isPending()) {
144                return -1;
145            } else if (ar2.isActive() && ar1.isPending()) {
146                return 1;
147            }
148
149            return super.compare(ar1, ar2);
150        }
151    }
152
153    public static boolean checkDateRanges(String fromDate, String toDate) {
154        try {
155            Date parsedDate = CoreApiServiceLocator.getDateTimeService().convertToDate(fromDate.trim());
156            Calendar fromCalendar = Calendar.getInstance();
157            fromCalendar.setLenient(false);
158            fromCalendar.setTime(parsedDate);
159            fromCalendar.set(Calendar.HOUR_OF_DAY, 0);
160            fromCalendar.set(Calendar.MINUTE, 0);
161            fromCalendar.set(Calendar.SECOND, 0);
162            fromCalendar.set(Calendar.MILLISECOND, 0);
163            parsedDate = CoreApiServiceLocator.getDateTimeService().convertToDate(toDate.trim());
164            Calendar toCalendar = Calendar.getInstance();
165            toCalendar.setLenient(false);
166            toCalendar.setTime(parsedDate);
167            toCalendar.set(Calendar.HOUR_OF_DAY, 0);
168            toCalendar.set(Calendar.MINUTE, 0);
169            toCalendar.set(Calendar.SECOND, 0);
170            toCalendar.set(Calendar.MILLISECOND, 0);
171            if (fromCalendar.after(toCalendar)) {
172                return false;
173            }
174            return true;
175        } catch (Exception ex) {
176            return false;
177        }
178    }
179
180    /**
181     * Helper method that takes a List of {@link KeyValue} and presents it as a Map
182     * @param collection collection of {@link KeyValue}
183     * @return a Map<String, String> representing the keys and values in the KeyValue collection
184     */
185    public static <T  extends KeyValue> Map<String, String> getKeyValueCollectionAsMap(List<T> collection) {
186        Map<String, String> map = new HashMap<String, String>(collection.size());
187        for (KeyValue kv: collection) {
188            map.put(kv.getKey(), kv.getValue());
189        }
190        return map;
191    }
192
193    /**
194     * Helper method that takes a List of {@link KeyValue} and presents it as a Map containing
195     * KeyValue values
196     * @param <T> the key type
197     * @param collection collection of {@link KeyValue}
198     * @return a Map<T,Z> where keys of the KeyValues in the collection are mapped to their respective KeyValue object
199     */
200    public static <T  extends KeyValue> Map<String, T> getKeyValueCollectionAsLookupTable(List<T> collection) {
201        Map<String, T> map = new HashMap<String, T>(collection.size());
202        for (T kv: collection) {
203            map.put(kv.getKey(), kv);
204        }
205        return map;
206    }
207}