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