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.krad.uif.util;
017
018import org.apache.commons.lang.StringUtils;
019import org.kuali.rice.coreservice.framework.CoreFrameworkServiceLocator;
020import org.kuali.rice.kim.api.identity.Person;
021import org.kuali.rice.kim.api.services.KimApiServiceLocator;
022import org.kuali.rice.krad.service.DataObjectMetaDataService;
023import org.kuali.rice.krad.service.KRADServiceLocator;
024import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
025import org.kuali.rice.krad.service.KualiModuleService;
026import org.kuali.rice.krad.service.ModuleService;
027import org.kuali.rice.krad.util.GlobalVariables;
028
029import java.util.ArrayList;
030import java.util.Arrays;
031import java.util.Date;
032import java.util.List;
033import java.util.Map;
034
035/**
036 * Defines functions that can be used in el expressions within
037 * the UIF dictionary files
038 *
039 * @author Kuali Rice Team (rice.collab@kuali.org)
040 */
041public class ExpressionFunctions {
042
043    /**
044     * Checks whether the given class parameter is assignable from the given object class
045     * parameter
046     *
047     * @param assignableClass class to use for assignable to
048     * @param objectClass class to use for assignable from
049     * @return true if the object class is of type assignable class, false if not
050     */
051    public static boolean isAssignableFrom(Class<?> assignableClass, Class<?> objectClass) {
052        return assignableClass.isAssignableFrom(objectClass);
053    }
054
055    /**
056     * Checks whether the given value is null or blank string
057     *
058     * @param value property value to check
059     * @return true if value is null or blank, false if not
060     */
061    public static boolean empty(Object value) {
062        return (value == null) || (StringUtils.isBlank(value.toString()));
063    }
064
065    /**
066     * Checks to see if the list is empty.  Throws a RuntimeException if list is not a List.
067     *
068     * @param value the list
069     * @return true if the list is null or empty, false otherwise
070     */
071    public static boolean emptyList(List<?> list) {
072        return (list == null) || list.isEmpty();
073    }
074
075    /**
076     * Check to see if the list contains the values passed in.
077     *
078     * <p>In the SpringEL call values can be single item or array due to the way the EL converts values.
079     * The values can be string or numeric and should match
080     * the content type being stored in the list.  If the list is String and the values passed in are not string,
081     * toString() conversion will be used.  Returns true if the values are in the list and both lists are non-empty,
082     * false otherwise.
083     * </p>
084     *
085     * @param list the list to be evaluated
086     * @param values the values to be to check for in the list
087     * @return true if all values exist in the list and both values and list are non-null/not-empty, false otherwise
088     */
089    public static boolean listContains(List<?> list, Object[] values) {
090        if (list != null && values != null && values.length > 0 && !list.isEmpty()) {
091            //conversion for if the values are non-string but the list is string (special case)
092            if (list.get(0) instanceof String && !(values[0] instanceof String)) {
093                String[] stringValues = new String[values.length];
094                for (int i = 0; i < values.length; i++) {
095                    stringValues[i] = values[i].toString();
096                }
097                return list.containsAll(Arrays.asList(stringValues));
098            } else if (list.get(0) instanceof Date && values[0] instanceof String) {
099                //TODO date conversion
100                return false;
101            } else if (!(list.get(0) instanceof String) && values[0] instanceof String) {
102                //values passed in are string but the list is of objects, use object's toString method
103                List<String> stringList = new ArrayList<String>();
104                for (Object value : list) {
105                    stringList.add(value.toString());
106                }
107                return stringList.containsAll(Arrays.asList(values));
108            } else {
109                //no conversion for if neither list is String, assume matching types (numeric case)
110                return list.containsAll(Arrays.asList(values));
111            }
112        }
113
114        //no cases satisfied, return false
115        return false;
116
117    }
118
119    /**
120     * Returns the name for the given class
121     *
122     * @param clazz class object to return name for
123     * @return class name or empty string if class is null
124     */
125    public static String getName(Class<?> clazz) {
126        if (clazz == null) {
127            return "";
128        } else {
129            return clazz.getName();
130        }
131    }
132
133    /**
134     * Retrieves the value of the parameter identified with the given namespace, component, and name
135     *
136     * @param namespaceCode namespace code for the parameter to retrieve
137     * @param componentCode component code for the parameter to retrieve
138     * @param parameterName name of the parameter to retrieve
139     * @return String value of parameter as a string or null if parameter does not exist
140     */
141    public static String getParm(String namespaceCode, String componentCode, String parameterName) {
142        return CoreFrameworkServiceLocator.getParameterService().getParameterValueAsString(namespaceCode, componentCode,
143                parameterName);
144    }
145
146    /**
147     * Retrieves the value of the parameter identified with the given namespace, component, and name and converts
148     * to a Boolean
149     *
150     * @param namespaceCode namespace code for the parameter to retrieve
151     * @param componentCode component code for the parameter to retrieve
152     * @param parameterName name of the parameter to retrieve
153     * @return Boolean value of parameter as a boolean or null if parameter does not exist
154     */
155    public static Boolean getParmInd(String namespaceCode, String componentCode, String parameterName) {
156        return CoreFrameworkServiceLocator.getParameterService().getParameterValueAsBoolean(namespaceCode,
157                componentCode, parameterName);
158    }
159
160    /**
161     * Indicates whether the current user has the permission identified by the given namespace and permission name
162     *
163     * @param namespaceCode namespace code for the permission to check
164     * @param permissionName name of the permission to check
165     * @return true if the current user has the permission, false if not or the permission does not exist
166     */
167    public static boolean hasPerm(String namespaceCode, String permissionName) {
168        Person user = GlobalVariables.getUserSession().getPerson();
169
170        return KimApiServiceLocator.getPermissionService().hasPermission(user.getPrincipalId(), namespaceCode,
171                permissionName);
172    }
173
174    /**
175     * Indicates whether the current user has the permission identified by the given namespace and permission name
176     * and with the given details and role qualification
177     *
178     * @param namespaceCode namespace code for the permission to check
179     * @param permissionName name of the permission to check
180     * @param permissionDetails details for the permission check
181     * @param roleQualifiers qualification for assigned roles
182     * @return true if the current user has the permission, false if not or the permission does not exist
183     */
184    public static boolean hasPermDtls(String namespaceCode, String permissionName,
185            Map<String, String> permissionDetails, Map<String, String> roleQualifiers) {
186        Person user = GlobalVariables.getUserSession().getPerson();
187
188        return KimApiServiceLocator.getPermissionService().isAuthorized(user.getPrincipalId(), namespaceCode,
189                permissionName, roleQualifiers);
190    }
191
192    /**
193     * Indicates whether the current user has the permission identified by the given namespace and template name
194     * and with the given details and role qualification
195     *
196     * @param namespaceCode namespace code for the permission to check
197     * @param templateName name of the permission template to find permissions for
198     * @param permissionDetails details for the permission check
199     * @param roleQualifiers qualification for assigned roles
200     * @return true if the current user has a permission with the given template, false if not or
201     *         the permission does not exist
202     */
203    public static boolean hasPermTmpl(String namespaceCode, String templateName, Map<String, String> permissionDetails,
204            Map<String, String> roleQualifiers) {
205        Person user = GlobalVariables.getUserSession().getPerson();
206
207        return KimApiServiceLocator.getPermissionService().isAuthorizedByTemplate(user.getPrincipalId(), namespaceCode,
208                templateName, permissionDetails, roleQualifiers);
209    }
210
211    /**
212     * Gets the next available number from a sequence
213     *
214     * @param sequenceName name of the sequence to retrieve from
215     * @return next sequence value
216     */
217    public static Long sequence(String sequenceName) {
218        return KRADServiceLocator.getSequenceAccessorService().getNextAvailableSequenceNumber(sequenceName);
219    }
220
221    /**
222     * Get the a primary key (valid for inquiry/maintenance view retrieval) for the dataObject by class name passed in
223     *
224     * @param dataObjectClassName the class name to get the key for
225     * @return a key valid for use as a request parameter for retrieving an inquiry or maintenance doc
226     */
227    public static String getDataObjectKey(String dataObjectClassName) {
228
229        if (StringUtils.isBlank(dataObjectClassName)) {
230            throw new RuntimeException("getDataObjectKey SpringEL function failed because the class name was blank");
231        }
232
233        Class dataObjectClass = null;
234
235        try {
236            dataObjectClass = Class.forName(dataObjectClassName);
237        } catch (ClassNotFoundException e) {
238            throw new RuntimeException(
239                    "getDataObjectKey SpringEL function failed when trying to find class " + dataObjectClassName, e);
240        }
241
242        DataObjectMetaDataService dataObjectMetaDataService = KRADServiceLocatorWeb.getDataObjectMetaDataService();
243
244        // build list of key values from the map parameters
245        List<String> pkPropertyNames = dataObjectMetaDataService.listPrimaryKeyFieldNames(dataObjectClass);
246
247        //return first primary key found
248        if (pkPropertyNames != null && !pkPropertyNames.isEmpty()) {
249            return pkPropertyNames.get(0);
250        }
251
252        //this likely won't be reached, as most should have a primary key (assumption)
253        KualiModuleService kualiModuleService = KRADServiceLocatorWeb.getKualiModuleService();
254        ModuleService moduleService = kualiModuleService.getResponsibleModuleService(dataObjectClass);
255
256        // some classes might have alternate keys defined for retrieving
257        List<List<String>> altKeys = null;
258        if (moduleService != null) {
259            altKeys = moduleService.listAlternatePrimaryKeyFieldNames(dataObjectClass);
260        }
261
262        if (altKeys != null && !altKeys.isEmpty()) {
263            for (List<String> list : altKeys) {
264                if (list != null && !list.isEmpty()) {
265                    //return any key first found
266                    return list.get(0);
267                }
268            }
269        }
270
271        return null;
272    }
273}