View Javadoc

1   /**
2    * Copyright 2005-2011 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.kns.web.struts.action;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.apache.struts.action.ActionForm;
20  import org.apache.struts.action.ActionForward;
21  import org.apache.struts.action.ActionMapping;
22  import org.kuali.rice.core.api.util.RiceConstants;
23  import org.kuali.rice.kim.api.KimConstants;
24  import org.kuali.rice.kim.api.services.KimApiServiceLocator;
25  import org.kuali.rice.kns.lookup.LookupUtils;
26  import org.kuali.rice.kns.lookup.Lookupable;
27  import org.kuali.rice.kns.service.DocumentHelperService;
28  import org.kuali.rice.kns.service.KNSServiceLocator;
29  import org.kuali.rice.kns.service.MaintenanceDocumentDictionaryService;
30  import org.kuali.rice.kns.web.struts.form.LookupForm;
31  import org.kuali.rice.kns.web.ui.Field;
32  import org.kuali.rice.kns.web.ui.ResultRow;
33  import org.kuali.rice.kns.web.ui.Row;
34  import org.kuali.rice.krad.exception.AuthorizationException;
35  import org.kuali.rice.krad.lookup.CollectionIncomplete;
36  import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
37  import org.kuali.rice.krad.util.GlobalVariables;
38  import org.kuali.rice.krad.util.KRADConstants;
39  import org.kuali.rice.krad.util.KRADUtils;
40  import org.springframework.web.util.HtmlUtils;
41  
42  import javax.servlet.ServletException;
43  import javax.servlet.http.HttpServletRequest;
44  import javax.servlet.http.HttpServletResponse;
45  import java.io.IOException;
46  import java.util.ArrayList;
47  import java.util.Collection;
48  import java.util.Collections;
49  import java.util.HashMap;
50  import java.util.Iterator;
51  import java.util.Map;
52  
53  /**
54   * This class handles Actions for lookup flow
55   *
56   *
57   */
58  
59  public class KualiLookupAction extends KualiAction {
60      private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(KualiLookupAction.class);
61  
62      @Override
63      protected void checkAuthorization(ActionForm form, String methodToCall) throws AuthorizationException {
64          if (!(form instanceof LookupForm)) {
65              super.checkAuthorization(form, methodToCall);
66          } else {
67              try {
68                  Class businessObjectClass = Class.forName(((LookupForm) form).getBusinessObjectClassName());
69                  if (!KimApiServiceLocator.getPermissionService().isAuthorizedByTemplateName(GlobalVariables.getUserSession().getPrincipalId(), KRADConstants.KRAD_NAMESPACE, KimConstants.PermissionTemplateNames.LOOK_UP_RECORDS,
70                          KRADUtils.getNamespaceAndComponentSimpleName(businessObjectClass), Collections.<String, String>emptyMap())) {
71                      throw new AuthorizationException(GlobalVariables.getUserSession().getPerson().getPrincipalName(),
72                              KimConstants.PermissionTemplateNames.LOOK_UP_RECORDS,
73                              businessObjectClass.getSimpleName());
74                  }
75              }
76              catch (ClassNotFoundException e) {
77                  LOG.warn("Unable to load BusinessObject class: " + ((LookupForm) form).getBusinessObjectClassName(), e);
78                  super.checkAuthorization(form, methodToCall);
79              }
80          }
81      }
82  
83      private static MaintenanceDocumentDictionaryService maintenanceDocumentDictionaryService;
84      private static DocumentHelperService documentHelperService;
85      private static MaintenanceDocumentDictionaryService getMaintenanceDocumentDictionaryService() {
86          if (maintenanceDocumentDictionaryService == null) {
87              maintenanceDocumentDictionaryService = KNSServiceLocator.getMaintenanceDocumentDictionaryService();
88          }
89          return maintenanceDocumentDictionaryService;
90      }
91      private static DocumentHelperService getDocumentHelperService() {
92          if (documentHelperService == null) {
93              documentHelperService = KNSServiceLocator.getDocumentHelperService();
94          }
95          return documentHelperService;
96      }
97      /**
98       * Checks if the user can create a document for this business object.  Used to suppress the actions on the results.
99       *
100      * @param form
101      * @return
102      * @throws ClassNotFoundException
103      */
104     protected void supressActionsIfNeeded( ActionForm form ) throws ClassNotFoundException {
105         if ((form instanceof LookupForm) && ( ((LookupForm)form).getBusinessObjectClassName() != null )) {
106             Class businessObjectClass = Class.forName( ((LookupForm)form).getBusinessObjectClassName() );
107             // check if creating documents is allowed
108             String documentTypeName = getMaintenanceDocumentDictionaryService().getDocumentTypeName(businessObjectClass);
109             if ((documentTypeName != null) && !getDocumentHelperService().getDocumentAuthorizer(documentTypeName).canInitiate(documentTypeName, GlobalVariables.getUserSession().getPerson())) {
110                 ((LookupForm)form).setSuppressActions( true );
111             }
112         }
113     }
114 
115     /**
116      * This method hides the criteria if set in parameter or lookupable
117      *
118      * @param form
119      */
120     private void setCriteriaEnabled(ActionForm form) {
121          LookupForm lookupForm = (LookupForm) form;
122          if(lookupForm.isLookupCriteriaEnabled()) {
123              //only overide if it's enabled, if disabled don't call lookupable
124          }
125     }
126     /**
127      * This method hides actions that are not related to the maintenance (as opposed to supressActionsIfNeeded)
128      *
129      * @param form
130      */
131     private void suppressNonMaintActionsIfNeeded(ActionForm form) {
132         LookupForm lookupForm = (LookupForm) form;
133         if(lookupForm.getLookupable()!=null) {
134             if(StringUtils.isNotEmpty(lookupForm.getLookupable().getSupplementalMenuBar())) {
135                 lookupForm.setSupplementalActionsEnabled(true);
136             }
137 
138         }
139     }
140 
141     @Override
142     public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request,
143             HttpServletResponse response) throws Exception {
144         LookupForm lookupForm = (LookupForm) form;
145 
146         request.setAttribute(KRADConstants.PARAM_MAINTENANCE_VIEW_MODE, KRADConstants.PARAM_MAINTENANCE_VIEW_MODE_LOOKUP);
147         supressActionsIfNeeded(form);
148         suppressNonMaintActionsIfNeeded(form);
149         setCriteriaEnabled(form);
150 
151         hideHeaderBarIfNeeded(form, request);
152 
153         int numCols = KNSServiceLocator.getBusinessObjectDictionaryService().getLookupNumberOfColumns(
154                 Class.forName(lookupForm.getBusinessObjectClassName()));
155         lookupForm.setNumColumns(numCols);
156 
157         ActionForward forward = super.execute(mapping, form, request, response);
158 
159         // apply conditional logic after all setting of field values has been completed
160         lookupForm.getLookupable().applyConditionalLogicForFieldDisplay();
161 
162         return forward;
163     }
164 
165     private void hideHeaderBarIfNeeded(ActionForm form, HttpServletRequest request) {
166         if (!((LookupForm) form).isHeaderBarEnabled()) {
167             ((LookupForm) form).setHeaderBarEnabled(false);
168         }
169     }
170 
171 
172     /**
173      * Entry point to lookups, forwards to jsp for search render.
174      */
175     public ActionForward start(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
176         return mapping.findForward(RiceConstants.MAPPING_BASIC);
177     }
178 
179     /**
180      * search - sets the values of the data entered on the form on the jsp into a map and then searches for the results.
181      */
182     public ActionForward search(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
183         LookupForm lookupForm = (LookupForm) form;
184 
185 
186         String methodToCall = findMethodToCall(form, request);
187         if (methodToCall.equalsIgnoreCase("search")) {
188             GlobalVariables.getUserSession().removeObjectsByPrefix(KRADConstants.SEARCH_METHOD);
189         }
190 
191 
192 
193         Lookupable kualiLookupable = lookupForm.getLookupable();
194         if (kualiLookupable == null) {
195             LOG.error("Lookupable is null.");
196             throw new RuntimeException("Lookupable is null.");
197         }
198 
199         Collection displayList = new ArrayList();
200         ArrayList<ResultRow> resultTable = new ArrayList<ResultRow>();
201 
202         // validate search parameters
203         kualiLookupable.validateSearchParameters(lookupForm.getFields());
204 
205         boolean bounded = true;
206 
207         displayList = kualiLookupable.performLookup(lookupForm, resultTable, bounded);
208 
209         if (kualiLookupable.isSearchUsingOnlyPrimaryKeyValues()) {
210             lookupForm.setSearchUsingOnlyPrimaryKeyValues(true);
211             lookupForm.setPrimaryKeyFieldLabels(kualiLookupable.getPrimaryKeyFieldLabels());
212         }
213         else {
214             lookupForm.setSearchUsingOnlyPrimaryKeyValues(false);
215             lookupForm.setPrimaryKeyFieldLabels(KRADConstants.EMPTY_STRING);
216         }
217 
218         if ( displayList instanceof CollectionIncomplete ){
219             request.setAttribute("reqSearchResultsActualSize", ((CollectionIncomplete) displayList).getActualSizeIfTruncated());
220         } else {
221             request.setAttribute("reqSearchResultsActualSize", displayList.size() );
222         }
223         
224         int resultsLimit = LookupUtils.getSearchResultsLimit(Class.forName(lookupForm.getBusinessObjectClassName()));
225         request.setAttribute("reqSearchResultsLimitedSize", resultsLimit);
226 
227         // Determine if at least one table entry has an action available. If any non-breaking space (&nbsp; or '\u00A0') characters
228         // exist in the URL's value, they will be converted to regular whitespace ('\u0020').
229         boolean hasActionUrls = false;
230         for (Iterator<ResultRow> iterator = resultTable.iterator(); !hasActionUrls && iterator.hasNext();) {
231             if (StringUtils.isNotBlank(HtmlUtils.htmlUnescape(iterator.next().getActionUrls()).replace('\u00A0', '\u0020'))) {
232                 hasActionUrls = true;
233             }
234         }
235         lookupForm.setActionUrlsExist(hasActionUrls);
236 
237         request.setAttribute("reqSearchResults", resultTable);
238 
239         if (request.getParameter(KRADConstants.SEARCH_LIST_REQUEST_KEY) != null) {
240             GlobalVariables.getUserSession().removeObject(request.getParameter(KRADConstants.SEARCH_LIST_REQUEST_KEY));
241         }
242 
243         request.setAttribute(KRADConstants.SEARCH_LIST_REQUEST_KEY, GlobalVariables.getUserSession().addObjectWithGeneratedKey(resultTable, KRADConstants.SEARCH_LIST_KEY_PREFIX));
244 
245         request.getParameter(KRADConstants.REFRESH_CALLER);
246 
247         return mapping.findForward(RiceConstants.MAPPING_BASIC);
248     }
249 
250 
251     /**
252      * refresh - is called when one quickFinder returns to the previous one. Sets all the values and performs the new search.
253      */
254     @Override
255     public ActionForward refresh(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
256         LookupForm lookupForm = (LookupForm) form;
257         Lookupable kualiLookupable = lookupForm.getLookupable();
258         if (kualiLookupable == null) {
259             LOG.error("Lookupable is null.");
260             throw new RuntimeException("Lookupable is null.");
261         }
262 
263         if(StringUtils.equals(lookupForm.getRefreshCaller(),"customLookupAction")) {
264             return this.customLookupableMethodCall(mapping, lookupForm, request, response);
265         }
266 
267         Map fieldValues = new HashMap();
268         Map values = lookupForm.getFields();
269 
270         for (Row row: kualiLookupable.getRows()) {
271             for (Field field: row.getFields()) {
272                 if (field.getPropertyName() != null && !field.getPropertyName().equals("")) {
273                     if (request.getParameter(field.getPropertyName()) != null) {
274                         if(!Field.MULTI_VALUE_FIELD_TYPES.contains(field.getFieldType())) {
275                             field.setPropertyValue(request.getParameter(field.getPropertyName()));
276                         } else {
277                             //multi value, set to values
278                             field.setPropertyValues(request.getParameterValues(field.getPropertyName()));
279                         }
280                     }
281                 }
282                 else if (values.get(field.getPropertyName()) != null) {
283                     field.setPropertyValue(values.get(field.getPropertyName()));
284                 }
285 
286                 kualiLookupable.applyFieldAuthorizationsFromNestedLookups(field);
287 
288                 fieldValues.put(field.getPropertyName(), field.getPropertyValue());
289             }
290         }
291         fieldValues.put("docFormKey", lookupForm.getFormKey());
292         fieldValues.put("backLocation", lookupForm.getBackLocation());
293         fieldValues.put("docNum", lookupForm.getDocNum());
294 
295         if (kualiLookupable.checkForAdditionalFields(fieldValues)) {
296             for (Row row: kualiLookupable.getRows()) {
297                 for (Object element : row.getFields()) {
298                     Field field = (Field) element;
299                     if (field.getPropertyName() != null && !field.getPropertyName().equals("")) {
300                         if (request.getParameter(field.getPropertyName()) != null) {
301 //                            field.setPropertyValue(request.getParameter(field.getPropertyName()));
302                             if(!Field.MULTI_VALUE_FIELD_TYPES.contains(field.getFieldType())) {
303                                 field.setPropertyValue(request.getParameter(field.getPropertyName()));
304                             } else {
305                                 //multi value, set to values
306                                 field.setPropertyValues(request.getParameterValues(field.getPropertyName()));
307                             }
308                             //FIXME: any reason this is inside this "if" instead of the outer one, like above - this seems inconsistent
309                             fieldValues.put(field.getPropertyName(), request.getParameter(field.getPropertyName()));
310                         }
311                         else if (values.get(field.getPropertyName()) != null) {
312                             field.setPropertyValue(values.get(field.getPropertyName()));
313                         }
314                     }
315                 }
316             }
317         }
318         return mapping.findForward(RiceConstants.MAPPING_BASIC);
319     }
320 
321     /**
322      * Just returns as if return with no value was selected.
323      */
324     public ActionForward cancel(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
325         LookupForm lookupForm = (LookupForm) form;
326 
327         String backUrl = lookupForm.getBackLocation() + "?methodToCall=refresh&docFormKey=" + lookupForm.getFormKey()+"&docNum="+lookupForm.getDocNum();
328         return new ActionForward(backUrl, true);
329     }
330 
331 
332     /**
333      * clearValues - clears the values of all the fields on the jsp.
334      */
335     public ActionForward clearValues(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
336         LookupForm lookupForm = (LookupForm) form;
337         Lookupable kualiLookupable = lookupForm.getLookupable();
338         if (kualiLookupable == null) {
339             LOG.error("Lookupable is null.");
340             throw new RuntimeException("Lookupable is null.");
341         }
342 
343         kualiLookupable.performClear(lookupForm);
344 
345 
346         return mapping.findForward(RiceConstants.MAPPING_BASIC);
347     }
348 
349 
350     public ActionForward viewResults(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
351         LookupForm lookupForm = (LookupForm) form;
352         if (lookupForm.isSearchUsingOnlyPrimaryKeyValues()) {
353             lookupForm.setPrimaryKeyFieldLabels(lookupForm.getLookupable().getPrimaryKeyFieldLabels());
354         }
355         request.setAttribute(KRADConstants.SEARCH_LIST_REQUEST_KEY, request.getParameter(KRADConstants.SEARCH_LIST_REQUEST_KEY));
356         request.setAttribute("reqSearchResults", GlobalVariables.getUserSession().retrieveObject(request.getParameter(
357                 KRADConstants.SEARCH_LIST_REQUEST_KEY)));
358         request.setAttribute("reqSearchResultsActualSize", request.getParameter("reqSearchResultsActualSize"));
359         return mapping.findForward(RiceConstants.MAPPING_BASIC);
360     }
361 
362     public ActionForward customLookupableMethodCall(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
363 //      lookupableMethodToCall
364         Lookupable kualiLookupable = ((LookupForm)form).getLookupable();
365         if (kualiLookupable == null) {
366             LOG.error("Lookupable is null.");
367             throw new RuntimeException("Lookupable is null.");
368         }
369 
370         boolean ignoreErrors=false;
371         if(StringUtils.equals(((LookupForm)form).getRefreshCaller(),"customLookupAction")) {
372             ignoreErrors=true;
373         }
374 
375         if(kualiLookupable.performCustomAction(ignoreErrors)) {
376             //redo the search if the method comes back
377             return search(mapping, form, request, response);
378         }
379         return mapping.findForward(RiceConstants.MAPPING_BASIC);
380 
381     }
382 
383 }