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.kns.util;
017
018import org.apache.commons.lang.StringUtils;
019import org.kuali.rice.core.api.CoreApiServiceLocator;
020import org.kuali.rice.krad.keyvalues.KeyValuesFinder;
021import org.kuali.rice.krad.keyvalues.PersistableBusinessObjectValuesFinder;
022import org.kuali.rice.krad.util.KRADConstants;
023
024import java.lang.reflect.Method;
025import java.security.GeneralSecurityException;
026import java.util.ArrayList;
027import java.util.HashMap;
028import java.util.List;
029
030/**
031 * Utility map for the action form to provide a way for calling functions through jstl.
032 *
033 *
034 */
035@SuppressWarnings("unchecked")
036public class ActionFormUtilMap extends HashMap {
037    private static final long serialVersionUID = 1L;
038        private boolean cacheValueFinderResults;
039
040    /**
041     * This method parses from the key the actual method to run.
042     *
043     * @see java.util.Map#get(java.lang.Object)
044     */
045    @Override
046        public Object get(Object key) {
047        if (cacheValueFinderResults) {
048            if (super.containsKey(key)) {
049                // doing a 2 step retrieval allows us to also cache the null key correctly
050                Object cachedObject = super.get(key);
051                return cachedObject;
052            }
053        }
054        String[] methodKey = StringUtils.split((String) key, KRADConstants.ACTION_FORM_UTIL_MAP_METHOD_PARM_DELIMITER);
055
056        String methodToCall = methodKey[0];
057
058        // handle method calls with more than one parameter
059        Object[] methodParms = new Object[methodKey.length - 1];
060        Class[] methodParmsPrototype = new Class[methodKey.length - 1];
061        for (int i=1;i<methodKey.length;i++) {
062            methodParms[i-1] = methodKey[i];
063            methodParmsPrototype[i-1] = Object.class;
064        }
065
066        Method method = null;
067        try {
068            method = ActionFormUtilMap.class.getMethod(methodToCall, methodParmsPrototype);
069        }
070        catch (SecurityException e) {
071            throw new RuntimeException("Unable to object handle on method given to ActionFormUtilMap: " + e.getMessage());
072        }
073        catch (NoSuchMethodException e1) {
074            throw new RuntimeException("Unable to object handle on method given to ActionFormUtilMap: " + e1.getMessage());
075        }
076
077        Object methodValue = null;
078        try {
079            methodValue = method.invoke(this, methodParms);
080        }
081        catch (Exception e) {
082            throw new RuntimeException("Unable to invoke method " + methodToCall,e);
083        }
084
085        if (cacheValueFinderResults) {
086            super.put(key, methodValue);
087        }
088
089        return methodValue;
090    }
091
092    /*
093     * Will take in a class name parameter and attempt to create a KeyValueFinder instance, then call the finder to return a list of
094     * KeyValue pairs. This is used by the htmlControlAttribute.tag to render select options from a given finder class specified in
095     * the data dictionary.
096     */
097        public Object getOptionsMap(Object key) {
098        List optionsList = new ArrayList();
099
100        if (StringUtils.isBlank((String) key)) {
101            return optionsList;
102        }
103
104        /*
105         * the class name has . replaced with | in the jsp to prevent struts from treating each part of the class name as a property
106         * substitute back here to get the correct name
107         */
108        key = StringUtils.replace((String) key, "|", ".");
109
110        KeyValuesFinder finder;
111        try {
112            Class finderClass = Class.forName((String) key);
113            finder = (KeyValuesFinder) finderClass.newInstance();
114            optionsList = finder.getKeyValues();
115        }
116        catch (ClassNotFoundException e) {
117            throw new RuntimeException(e.getMessage());
118        }
119        catch (InstantiationException e) {
120            throw new RuntimeException(e.getMessage());
121        }
122        catch (IllegalAccessException e) {
123            throw new RuntimeException(e.getMessage());
124        }
125
126        return optionsList;
127    }
128
129    // Method added to keep backward compatibility for non-kimTypeId cases
130    public Object getOptionsMap(Object key, Object boClass, Object keyAttribute, Object labelAttribute, Object includeKeyInLabel) {
131        return getOptionsMap(key, boClass, keyAttribute, labelAttribute, null, includeKeyInLabel );
132    }
133
134    /**
135     * This method will take in a key parameter (values finder class name - in this case the generic
136     * PersistableObjectValuesFinder) along with the related parameters required by this ValuesFinder,
137     * and attempt to create a KeyValueFinder instance, then call the finder to return a list of
138     * KeyValue pairs. This is used by the htmlControlAttribute.tag to render select options from
139     * a given finder class specified in the data dictionary.
140     *
141     * @param key values finder class name
142     * @param boClass BO class name
143     * @param keyAttribute name of BO attribute for key
144     * @param labelAttribute name of BO attribute for label
145     * @param includeKeyInLabel whether to include the key in the label or not
146     * @return list of KeyValue pairs
147     */
148        public Object getOptionsMap(Object key, Object boClass, Object keyAttribute, Object labelAttribute, Object includeBlankRow, Object includeKeyInLabel) {
149        List optionsList = new ArrayList();
150
151        if (StringUtils.isBlank((String) key)) {
152            return optionsList;
153        }
154
155        /*
156         * the class name has . replaced with | in the jsp to prevent struts from treating each part of the class name as a property
157         * substitute back here to get the correct name
158         */
159        key = StringUtils.replace((String) key, "|", ".");
160
161        KeyValuesFinder finder;
162        try {
163                Class finderClass = Class.forName((String) key);
164            finder = (KeyValuesFinder) finderClass.newInstance();
165            if (finder instanceof PersistableBusinessObjectValuesFinder) {
166                String businessObjectClassName = StringUtils.replace((String) boClass, "|", ".");
167                Class businessObjectClass = Class.forName((String) businessObjectClassName);
168                ((PersistableBusinessObjectValuesFinder) finder).setBusinessObjectClass(businessObjectClass);
169                ((PersistableBusinessObjectValuesFinder) finder).setKeyAttributeName((String)keyAttribute);
170                ((PersistableBusinessObjectValuesFinder) finder).setLabelAttributeName((String)labelAttribute);
171                ((PersistableBusinessObjectValuesFinder) finder).setIncludeBlankRow(Boolean.parseBoolean((String)includeBlankRow));
172                ((PersistableBusinessObjectValuesFinder) finder).setIncludeKeyInDescription(Boolean.parseBoolean((String)includeKeyInLabel));
173            }
174
175            optionsList = finder.getKeyValues();
176        }
177        catch (ClassNotFoundException e) {
178            throw new RuntimeException(e.getMessage(),e);
179        }
180        catch (InstantiationException e) {
181            throw new RuntimeException(e.getMessage(),e);
182        }
183        catch (IllegalAccessException e) {
184            throw new RuntimeException(e.getMessage(),e);
185        }
186
187        return optionsList;
188    }
189
190    /**
191     * Encrypts a value passed from the ui.
192     * @param value - clear text
193     * @return String - encrypted text
194     */
195    public String encryptValue(Object value) {
196        String encrypted = "";
197        if (value != null) {
198            encrypted = value.toString();
199        }
200
201        try {
202            if(CoreApiServiceLocator.getEncryptionService().isEnabled()) {
203                encrypted = CoreApiServiceLocator.getEncryptionService().encrypt(value);
204            }
205        }
206        catch (GeneralSecurityException e) {
207            throw new RuntimeException("Unable to encrypt value in action form: " + e.getMessage());
208        }
209
210        return encrypted;
211    }
212
213    public void setCacheValueFinderResults(boolean cacheValueFinderResults) {
214        this.cacheValueFinderResults = cacheValueFinderResults;
215    }
216
217
218}