001 /** 002 * Copyright 2005-2012 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 */ 016 package org.kuali.rice.kns.web.struts.action; 017 018 import org.apache.commons.lang.StringUtils; 019 import org.apache.struts.action.ActionForm; 020 import org.apache.struts.action.ActionForward; 021 import org.apache.struts.action.ActionMapping; 022 import org.kuali.rice.core.api.util.RiceConstants; 023 import org.kuali.rice.kim.api.KimConstants; 024 import org.kuali.rice.kim.api.services.KimApiServiceLocator; 025 import org.kuali.rice.kns.lookup.LookupUtils; 026 import org.kuali.rice.kns.lookup.Lookupable; 027 import org.kuali.rice.kns.service.DocumentHelperService; 028 import org.kuali.rice.kns.service.KNSServiceLocator; 029 import org.kuali.rice.kns.service.MaintenanceDocumentDictionaryService; 030 import org.kuali.rice.kns.web.struts.form.LookupForm; 031 import org.kuali.rice.kns.web.ui.Field; 032 import org.kuali.rice.kns.web.ui.ResultRow; 033 import org.kuali.rice.kns.web.ui.Row; 034 import org.kuali.rice.krad.exception.AuthorizationException; 035 import org.kuali.rice.krad.lookup.CollectionIncomplete; 036 import org.kuali.rice.krad.util.GlobalVariables; 037 import org.kuali.rice.krad.util.KRADConstants; 038 import org.kuali.rice.krad.util.KRADUtils; 039 import org.springframework.web.util.HtmlUtils; 040 041 import javax.servlet.ServletException; 042 import javax.servlet.http.HttpServletRequest; 043 import javax.servlet.http.HttpServletResponse; 044 import java.io.IOException; 045 import java.util.ArrayList; 046 import java.util.Collection; 047 import java.util.Collections; 048 import java.util.HashMap; 049 import java.util.Iterator; 050 import java.util.Map; 051 052 /** 053 * This class handles Actions for lookup flow 054 * 055 * 056 */ 057 058 public class KualiLookupAction extends KualiAction { 059 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(KualiLookupAction.class); 060 061 @Override 062 protected void checkAuthorization(ActionForm form, String methodToCall) throws AuthorizationException { 063 if (!(form instanceof LookupForm)) { 064 super.checkAuthorization(form, methodToCall); 065 } else { 066 try { 067 Class businessObjectClass = Class.forName(((LookupForm) form).getBusinessObjectClassName()); 068 if (!KimApiServiceLocator.getPermissionService().isAuthorizedByTemplate( 069 GlobalVariables.getUserSession().getPrincipalId(), KRADConstants.KNS_NAMESPACE, 070 KimConstants.PermissionTemplateNames.LOOK_UP_RECORDS, 071 KRADUtils.getNamespaceAndComponentSimpleName(businessObjectClass), 072 Collections.<String, String>emptyMap())) { 073 throw new AuthorizationException(GlobalVariables.getUserSession().getPerson().getPrincipalName(), 074 KimConstants.PermissionTemplateNames.LOOK_UP_RECORDS, 075 businessObjectClass.getSimpleName()); 076 } 077 } 078 catch (ClassNotFoundException e) { 079 LOG.warn("Unable to load BusinessObject class: " + ((LookupForm) form).getBusinessObjectClassName(), e); 080 super.checkAuthorization(form, methodToCall); 081 } 082 } 083 } 084 085 private static MaintenanceDocumentDictionaryService maintenanceDocumentDictionaryService; 086 private static DocumentHelperService documentHelperService; 087 private static MaintenanceDocumentDictionaryService getMaintenanceDocumentDictionaryService() { 088 if (maintenanceDocumentDictionaryService == null) { 089 maintenanceDocumentDictionaryService = KNSServiceLocator.getMaintenanceDocumentDictionaryService(); 090 } 091 return maintenanceDocumentDictionaryService; 092 } 093 private static DocumentHelperService getDocumentHelperService() { 094 if (documentHelperService == null) { 095 documentHelperService = KNSServiceLocator.getDocumentHelperService(); 096 } 097 return documentHelperService; 098 } 099 /** 100 * Checks if the user can create a document for this business object. Used to suppress the actions on the results. 101 * 102 * @param form 103 * @return 104 * @throws ClassNotFoundException 105 */ 106 protected void supressActionsIfNeeded( ActionForm form ) throws ClassNotFoundException { 107 if ((form instanceof LookupForm) && ( ((LookupForm)form).getBusinessObjectClassName() != null )) { 108 Class businessObjectClass = Class.forName( ((LookupForm)form).getBusinessObjectClassName() ); 109 // check if creating documents is allowed 110 String documentTypeName = getMaintenanceDocumentDictionaryService().getDocumentTypeName(businessObjectClass); 111 if ((documentTypeName != null) && !getDocumentHelperService().getDocumentAuthorizer(documentTypeName).canInitiate(documentTypeName, GlobalVariables.getUserSession().getPerson())) { 112 ((LookupForm)form).setSuppressActions( true ); 113 } 114 } 115 } 116 117 /** 118 * This method hides the criteria if set in parameter or lookupable 119 * 120 * @param form 121 */ 122 private void setCriteriaEnabled(ActionForm form) { 123 LookupForm lookupForm = (LookupForm) form; 124 if(lookupForm.isLookupCriteriaEnabled()) { 125 //only overide if it's enabled, if disabled don't call lookupable 126 } 127 } 128 /** 129 * This method hides actions that are not related to the maintenance (as opposed to supressActionsIfNeeded) 130 * 131 * @param form 132 */ 133 private void suppressNonMaintActionsIfNeeded(ActionForm form) { 134 LookupForm lookupForm = (LookupForm) form; 135 if(lookupForm.getLookupable()!=null) { 136 if(StringUtils.isNotEmpty(lookupForm.getLookupable().getSupplementalMenuBar())) { 137 lookupForm.setSupplementalActionsEnabled(true); 138 } 139 140 } 141 } 142 143 @Override 144 public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, 145 HttpServletResponse response) throws Exception { 146 LookupForm lookupForm = (LookupForm) form; 147 148 request.setAttribute(KRADConstants.PARAM_MAINTENANCE_VIEW_MODE, KRADConstants.PARAM_MAINTENANCE_VIEW_MODE_LOOKUP); 149 supressActionsIfNeeded(form); 150 suppressNonMaintActionsIfNeeded(form); 151 setCriteriaEnabled(form); 152 153 hideHeaderBarIfNeeded(form, request); 154 155 int numCols = KNSServiceLocator.getBusinessObjectDictionaryService().getLookupNumberOfColumns( 156 Class.forName(lookupForm.getBusinessObjectClassName())); 157 lookupForm.setNumColumns(numCols); 158 159 ActionForward forward = super.execute(mapping, form, request, response); 160 161 // apply conditional logic after all setting of field values has been completed 162 lookupForm.getLookupable().applyConditionalLogicForFieldDisplay(); 163 164 return forward; 165 } 166 167 private void hideHeaderBarIfNeeded(ActionForm form, HttpServletRequest request) { 168 if (!((LookupForm) form).isHeaderBarEnabled()) { 169 ((LookupForm) form).setHeaderBarEnabled(false); 170 } 171 } 172 173 174 /** 175 * Entry point to lookups, forwards to jsp for search render. 176 */ 177 public ActionForward start(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 178 return mapping.findForward(RiceConstants.MAPPING_BASIC); 179 } 180 181 /** 182 * search - sets the values of the data entered on the form on the jsp into a map and then searches for the results. 183 */ 184 public ActionForward search(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 185 LookupForm lookupForm = (LookupForm) form; 186 187 188 String methodToCall = findMethodToCall(form, request); 189 if (methodToCall.equalsIgnoreCase("search")) { 190 GlobalVariables.getUserSession().removeObjectsByPrefix(KRADConstants.SEARCH_METHOD); 191 } 192 193 194 195 Lookupable kualiLookupable = lookupForm.getLookupable(); 196 if (kualiLookupable == null) { 197 LOG.error("Lookupable is null."); 198 throw new RuntimeException("Lookupable is null."); 199 } 200 201 Collection displayList = new ArrayList(); 202 ArrayList<ResultRow> resultTable = new ArrayList<ResultRow>(); 203 204 // validate search parameters 205 kualiLookupable.validateSearchParameters(lookupForm.getFields()); 206 207 boolean bounded = true; 208 209 displayList = kualiLookupable.performLookup(lookupForm, resultTable, bounded); 210 211 if (kualiLookupable.isSearchUsingOnlyPrimaryKeyValues()) { 212 lookupForm.setSearchUsingOnlyPrimaryKeyValues(true); 213 lookupForm.setPrimaryKeyFieldLabels(kualiLookupable.getPrimaryKeyFieldLabels()); 214 } 215 else { 216 lookupForm.setSearchUsingOnlyPrimaryKeyValues(false); 217 lookupForm.setPrimaryKeyFieldLabels(KRADConstants.EMPTY_STRING); 218 } 219 220 if ( displayList instanceof CollectionIncomplete ){ 221 request.setAttribute("reqSearchResultsActualSize", ((CollectionIncomplete) displayList).getActualSizeIfTruncated()); 222 } else { 223 request.setAttribute("reqSearchResultsActualSize", displayList.size() ); 224 } 225 226 int resultsLimit = LookupUtils.getSearchResultsLimit(Class.forName(lookupForm.getBusinessObjectClassName())); 227 request.setAttribute("reqSearchResultsLimitedSize", resultsLimit); 228 229 // Determine if at least one table entry has an action available. If any non-breaking space ( or '\u00A0') characters 230 // exist in the URL's value, they will be converted to regular whitespace ('\u0020'). 231 boolean hasActionUrls = false; 232 for (Iterator<ResultRow> iterator = resultTable.iterator(); !hasActionUrls && iterator.hasNext();) { 233 if (StringUtils.isNotBlank(HtmlUtils.htmlUnescape(iterator.next().getActionUrls()).replace('\u00A0', '\u0020'))) { 234 hasActionUrls = true; 235 } 236 } 237 lookupForm.setActionUrlsExist(hasActionUrls); 238 239 request.setAttribute("reqSearchResults", resultTable); 240 241 if (request.getParameter(KRADConstants.SEARCH_LIST_REQUEST_KEY) != null) { 242 GlobalVariables.getUserSession().removeObject(request.getParameter(KRADConstants.SEARCH_LIST_REQUEST_KEY)); 243 } 244 245 request.setAttribute(KRADConstants.SEARCH_LIST_REQUEST_KEY, GlobalVariables.getUserSession().addObjectWithGeneratedKey(resultTable, KRADConstants.SEARCH_LIST_KEY_PREFIX)); 246 247 request.getParameter(KRADConstants.REFRESH_CALLER); 248 249 return mapping.findForward(RiceConstants.MAPPING_BASIC); 250 } 251 252 253 /** 254 * refresh - is called when one quickFinder returns to the previous one. Sets all the values and performs the new search. 255 */ 256 @Override 257 public ActionForward refresh(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 258 LookupForm lookupForm = (LookupForm) form; 259 Lookupable kualiLookupable = lookupForm.getLookupable(); 260 if (kualiLookupable == null) { 261 LOG.error("Lookupable is null."); 262 throw new RuntimeException("Lookupable is null."); 263 } 264 265 if(StringUtils.equals(lookupForm.getRefreshCaller(),"customLookupAction")) { 266 return this.customLookupableMethodCall(mapping, lookupForm, request, response); 267 } 268 269 Map<String, String> fieldValues = new HashMap(); 270 Map<String, String> values = lookupForm.getFields(); 271 272 for (Row row: kualiLookupable.getRows()) { 273 for (Field field: row.getFields()) { 274 if (field.getPropertyName() != null && !field.getPropertyName().equals("")) { 275 if (request.getParameter(field.getPropertyName()) != null) { 276 if(!Field.MULTI_VALUE_FIELD_TYPES.contains(field.getFieldType())) { 277 field.setPropertyValue(request.getParameter(field.getPropertyName())); 278 } else { 279 //multi value, set to values 280 field.setPropertyValues(request.getParameterValues(field.getPropertyName())); 281 } 282 } 283 } 284 else if (values.get(field.getPropertyName()) != null) { 285 field.setPropertyValue(values.get(field.getPropertyName())); 286 } 287 288 kualiLookupable.applyFieldAuthorizationsFromNestedLookups(field); 289 290 fieldValues.put(field.getPropertyName(), field.getPropertyValue()); 291 } 292 } 293 fieldValues.put("docFormKey", lookupForm.getFormKey()); 294 fieldValues.put("backLocation", lookupForm.getBackLocation()); 295 fieldValues.put("docNum", lookupForm.getDocNum()); 296 297 if (kualiLookupable.checkForAdditionalFields(fieldValues)) { 298 for (Row row: kualiLookupable.getRows()) { 299 for (Object element : row.getFields()) { 300 Field field = (Field) element; 301 if (field.getPropertyName() != null && !field.getPropertyName().equals("")) { 302 if (request.getParameter(field.getPropertyName()) != null) { 303 // field.setPropertyValue(request.getParameter(field.getPropertyName())); 304 if(!Field.MULTI_VALUE_FIELD_TYPES.contains(field.getFieldType())) { 305 field.setPropertyValue(request.getParameter(field.getPropertyName())); 306 } else { 307 //multi value, set to values 308 field.setPropertyValues(request.getParameterValues(field.getPropertyName())); 309 } 310 //FIXME: any reason this is inside this "if" instead of the outer one, like above - this seems inconsistent 311 fieldValues.put(field.getPropertyName(), request.getParameter(field.getPropertyName())); 312 } 313 else if (values.get(field.getPropertyName()) != null) { 314 field.setPropertyValue(values.get(field.getPropertyName())); 315 } 316 } 317 } 318 } 319 } 320 return mapping.findForward(RiceConstants.MAPPING_BASIC); 321 } 322 323 /** 324 * Just returns as if return with no value was selected. 325 */ 326 public ActionForward cancel(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 327 LookupForm lookupForm = (LookupForm) form; 328 329 String backUrl = lookupForm.getBackLocation() + "?methodToCall=refresh&docFormKey=" + lookupForm.getFormKey()+"&docNum="+lookupForm.getDocNum(); 330 return new ActionForward(backUrl, true); 331 } 332 333 334 /** 335 * clearValues - clears the values of all the fields on the jsp. 336 */ 337 public ActionForward clearValues(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { 338 LookupForm lookupForm = (LookupForm) form; 339 Lookupable kualiLookupable = lookupForm.getLookupable(); 340 if (kualiLookupable == null) { 341 LOG.error("Lookupable is null."); 342 throw new RuntimeException("Lookupable is null."); 343 } 344 345 kualiLookupable.performClear(lookupForm); 346 347 348 return mapping.findForward(RiceConstants.MAPPING_BASIC); 349 } 350 351 352 public ActionForward viewResults(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 353 LookupForm lookupForm = (LookupForm) form; 354 if (lookupForm.isSearchUsingOnlyPrimaryKeyValues()) { 355 lookupForm.setPrimaryKeyFieldLabels(lookupForm.getLookupable().getPrimaryKeyFieldLabels()); 356 } 357 request.setAttribute(KRADConstants.SEARCH_LIST_REQUEST_KEY, request.getParameter(KRADConstants.SEARCH_LIST_REQUEST_KEY)); 358 request.setAttribute("reqSearchResults", GlobalVariables.getUserSession().retrieveObject(request.getParameter( 359 KRADConstants.SEARCH_LIST_REQUEST_KEY))); 360 request.setAttribute("reqSearchResultsActualSize", request.getParameter("reqSearchResultsActualSize")); 361 return mapping.findForward(RiceConstants.MAPPING_BASIC); 362 } 363 364 public ActionForward customLookupableMethodCall(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 365 // lookupableMethodToCall 366 Lookupable kualiLookupable = ((LookupForm)form).getLookupable(); 367 if (kualiLookupable == null) { 368 LOG.error("Lookupable is null."); 369 throw new RuntimeException("Lookupable is null."); 370 } 371 372 boolean ignoreErrors=false; 373 if(StringUtils.equals(((LookupForm)form).getRefreshCaller(),"customLookupAction")) { 374 ignoreErrors=true; 375 } 376 377 if(kualiLookupable.performCustomAction(ignoreErrors)) { 378 //redo the search if the method comes back 379 return search(mapping, form, request, response); 380 } 381 return mapping.findForward(RiceConstants.MAPPING_BASIC); 382 383 } 384 385 }