View Javadoc
1   /**
2    * Copyright 2005-2016 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.krad.web.controller;
17  
18  import java.net.MalformedURLException;
19  import java.net.URL;
20  import java.util.Collection;
21  import java.util.HashMap;
22  import java.util.Map;
23  import java.util.Properties;
24  import java.util.Set;
25  
26  import javax.servlet.http.HttpServletRequest;
27  import javax.servlet.http.HttpServletResponse;
28  
29  import org.apache.commons.lang.StringUtils;
30  import org.kuali.rice.core.api.exception.RiceRuntimeException;
31  import org.kuali.rice.core.api.util.RiceConstants;
32  import org.kuali.rice.core.api.util.RiceKeyConstants;
33  import org.kuali.rice.krad.lookup.CollectionIncomplete;
34  import org.kuali.rice.krad.lookup.LookupUtils;
35  import org.kuali.rice.krad.lookup.Lookupable;
36  import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
37  import org.kuali.rice.krad.service.ModuleService;
38  import org.kuali.rice.krad.uif.UifConstants;
39  import org.kuali.rice.krad.uif.UifParameters;
40  import org.kuali.rice.krad.uif.UifPropertyPaths;
41  import org.kuali.rice.krad.util.GlobalVariables;
42  import org.kuali.rice.krad.util.KRADConstants;
43  import org.kuali.rice.krad.util.KRADUtils;
44  import org.kuali.rice.krad.util.UrlFactory;
45  import org.kuali.rice.krad.web.form.LookupForm;
46  import org.kuali.rice.krad.web.form.UifFormBase;
47  import org.springframework.stereotype.Controller;
48  import org.springframework.validation.BindingResult;
49  import org.springframework.web.bind.annotation.ModelAttribute;
50  import org.springframework.web.bind.annotation.RequestMapping;
51  import org.springframework.web.bind.annotation.RequestMethod;
52  import org.springframework.web.servlet.ModelAndView;
53  import org.springframework.web.servlet.mvc.support.RedirectAttributes;
54  
55  /**
56   * Controller that handles requests coming from a <code>LookupView</code>
57   *
58   * @author Kuali Rice Team (rice.collab@kuali.org)
59   */
60  @Controller
61  @RequestMapping(value = "/lookup")
62  public class LookupController extends UifControllerBase {
63      private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(LookupController.class);
64  
65      /**
66       * @see org.kuali.rice.krad.web.controller.UifControllerBase#createInitialForm(javax.servlet.http.HttpServletRequest)
67       */
68      @Override
69      protected LookupForm createInitialForm(HttpServletRequest request) {
70          return new LookupForm();
71      }
72  
73      /**
74       * Invoked to request an lookup view for a data object class
75       *
76       * <p>
77       * Checks if the data object is externalizable and we need to redirect to the appropriate lookup URL, else
78       * continues with the lookup view display
79       * </p>
80       */
81      @RequestMapping(params = "methodToCall=start")
82      @Override
83      public ModelAndView start(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
84              HttpServletRequest request, HttpServletResponse response) {
85          LookupForm lookupForm = (LookupForm) form;
86  
87          Lookupable lookupable = lookupForm.getLookupable();
88          if (lookupable == null) {
89              LOG.error("Lookupable is null.");
90              throw new RuntimeException("Lookupable is null.");
91          }
92          lookupable.initSuppressAction(lookupForm);
93  
94          if (request.getParameter(UifParameters.MESSAGE_TO_DISPLAY) != null) {
95              lookupable.generateErrorMessageForResults(lookupForm, request.getParameter(
96                      UifParameters.MESSAGE_TO_DISPLAY));
97          }
98  
99          // if request is not a redirect, determine if we need to redirect for an externalizable object lookup
100         if (!lookupForm.isRedirectedLookup()) {
101             Class lookupObjectClass = null;
102             try {
103                 lookupObjectClass = Class.forName(lookupForm.getDataObjectClassName());
104             } catch (ClassNotFoundException e) {
105                 throw new RiceRuntimeException("Unable to get class for name: " + lookupForm.getDataObjectClassName());
106             }
107 
108             ModuleService responsibleModuleService =
109                     KRADServiceLocatorWeb.getKualiModuleService().getResponsibleModuleService(lookupObjectClass);
110             if (responsibleModuleService != null && responsibleModuleService.isExternalizable(lookupObjectClass)) {
111                 String lookupUrl = responsibleModuleService.getExternalizableDataObjectLookupUrl(lookupObjectClass,
112                         KRADUtils.convertRequestMapToProperties(request.getParameterMap()));
113 
114                 Properties redirectUrlProps = new Properties();
115                 redirectUrlProps.put(UifParameters.REDIRECTED_LOOKUP, "true");
116 
117                 // clear current form from session
118                 GlobalVariables.getUifFormManager().removeSessionForm(form);
119 
120                 return performRedirect(form, lookupUrl, redirectUrlProps);
121             }
122         }
123 
124         return super.start(lookupForm, result, request, response);
125     }
126 
127     /**
128      * Just returns as if return with no value was selected
129      */
130     @Override
131     @RequestMapping(method = RequestMethod.POST, params = "methodToCall=cancel")
132     public ModelAndView cancel(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
133             HttpServletRequest request, HttpServletResponse response) {
134         LookupForm lookupForm = (LookupForm) form;
135 
136         Lookupable lookupable = lookupForm.getLookupable();
137         if (lookupable == null) {
138             LOG.error("Lookupable is null.");
139             throw new RuntimeException("Lookupable is null.");
140         }
141         lookupable.initSuppressAction(lookupForm);
142 
143         Properties props = new Properties();
144         props.put(UifParameters.METHOD_TO_CALL, UifConstants.MethodToCallNames.REFRESH);
145         if (StringUtils.isNotBlank(lookupForm.getReturnFormKey())) {
146             props.put(UifParameters.FORM_KEY, lookupForm.getReturnFormKey());
147         }
148         if (StringUtils.isNotBlank(lookupForm.getDocNum())) {
149             props.put(UifParameters.DOC_NUM, lookupForm.getDocNum());
150         }
151 
152         // clear current form from session
153         GlobalVariables.getUifFormManager().removeSessionForm(form);
154 
155         return performRedirect(lookupForm, lookupForm.getReturnLocation(), props);
156     }
157 
158     /**
159      * clearValues - clears the values of all the fields on the jsp.
160      */
161     @RequestMapping(method = RequestMethod.POST, params = "methodToCall=clearValues")
162     public ModelAndView clearValues(@ModelAttribute("KualiForm") LookupForm lookupForm, BindingResult result,
163             HttpServletRequest request, HttpServletResponse response) {
164 
165         Lookupable lookupable = lookupForm.getLookupable();
166         if (lookupable == null) {
167             LOG.error("Lookupable is null.");
168             throw new RuntimeException("Lookupable is null.");
169         }
170         lookupable.initSuppressAction(lookupForm);
171         lookupForm.setLookupCriteria(lookupable.performClear(lookupForm, lookupForm.getLookupCriteria()));
172 
173         return getUIFModelAndView(lookupForm);
174     }
175 
176     /**
177      * search - sets the values of the data entered on the form on the jsp into a map and then searches for the
178      * results.
179      */
180     @RequestMapping(params = "methodToCall=search")
181     public ModelAndView search(@ModelAttribute("KualiForm") LookupForm lookupForm, BindingResult result,
182             HttpServletRequest request, HttpServletResponse response) {
183 
184         Lookupable lookupable = lookupForm.getLookupable();
185         if (lookupable == null) {
186             LOG.error("Lookupable is null.");
187             throw new RuntimeException("Lookupable is null.");
188         }
189         lookupable.initSuppressAction(lookupForm);
190         // Need to process date range fields before validating
191         Map<String, String> searchCriteria = LookupUtils.preprocessDateFields(lookupForm.getLookupCriteria());
192         // validate search parameters
193         boolean searchValid = lookupable.validateSearchParameters(lookupForm, searchCriteria);
194 
195         if (searchValid) {
196             Collection<?> displayList = lookupable.performSearch(lookupForm, searchCriteria, true);
197 
198             if (displayList instanceof CollectionIncomplete<?>) {
199                 request.setAttribute("reqSearchResultsActualSize",
200                         ((CollectionIncomplete<?>) displayList).getActualSizeIfTruncated());
201             } else {
202                 request.setAttribute("reqSearchResultsActualSize", new Integer(displayList.size()));
203             }
204 
205             lookupForm.setLookupResults(displayList);
206         }
207 
208         return getUIFModelAndView(lookupForm);
209     }
210 
211     /**
212      * Invoked from the UI to return the selected lookup results lines, parameters are collected to build a URL to
213      * the caller and then a redirect is performed
214      *
215      * @param lookupForm - lookup form instance containing the selected results and lookup configuration
216      */
217     @RequestMapping(method = RequestMethod.POST, params = "methodToCall=returnSelected")
218     public String returnSelected(@ModelAttribute("KualiForm") LookupForm lookupForm, BindingResult result,
219             HttpServletRequest request, HttpServletResponse response, final RedirectAttributes redirectAttributes) {
220 
221         Properties parameters = new Properties();
222 
223         // build string of select line identifiers
224         String selectedLineValues = "";
225         Set<String> selectedLines = lookupForm.getSelectedCollectionLines().get(UifPropertyPaths.LOOKUP_RESULTS);
226         if (selectedLines != null) {
227             for (String selectedLine : selectedLines) {
228                 selectedLineValues += selectedLine + ",";
229             }
230             selectedLineValues = StringUtils.removeEnd(selectedLineValues, ",");
231         }
232 
233         //check to see what the redirect URL length would be
234         parameters.put(UifParameters.SELECTED_LINE_VALUES, selectedLineValues);
235         parameters.putAll(lookupForm.getInitialRequestParameters());
236         String redirectUrl = UrlFactory.parameterizeUrl(lookupForm.getReturnLocation(), parameters);
237 
238         boolean lookupCameFromDifferentServer = areDifferentDomains(lookupForm.getReturnLocation(),
239                 lookupForm.getRequestUrl());
240 
241         if (redirectUrl.length() > RiceConstants.MAXIMUM_URL_LENGTH && !lookupCameFromDifferentServer) {
242             redirectAttributes.addFlashAttribute(UifParameters.SELECTED_LINE_VALUES, selectedLineValues);
243         }
244 
245         if (redirectUrl.length() > RiceConstants.MAXIMUM_URL_LENGTH && lookupCameFromDifferentServer) {
246             HashMap<String, String> parms = (HashMap<String, String>) lookupForm.getInitialRequestParameters();
247             parms.remove(UifParameters.RETURN_FORM_KEY);
248 
249             //add an error message to display to the user
250             redirectAttributes.mergeAttributes(parms);
251             redirectAttributes.addAttribute(UifParameters.MESSAGE_TO_DISPLAY,
252                     RiceKeyConstants.INFO_LOOKUP_RESULTS_MV_RETURN_EXCEEDS_LIMIT);
253 
254             String formKeyParam = request.getParameter(UifParameters.FORM_KEY);
255             redirectAttributes.addAttribute(UifParameters.FORM_KEY, formKeyParam);
256 
257             return UifConstants.REDIRECT_PREFIX + lookupForm.getRequestUrl();
258         }
259 
260         if (redirectUrl.length() < RiceConstants.MAXIMUM_URL_LENGTH) {
261             redirectAttributes.addAttribute(UifParameters.SELECTED_LINE_VALUES, selectedLineValues);
262         }
263 
264         redirectAttributes.addAttribute(KRADConstants.DISPATCH_REQUEST_PARAMETER, KRADConstants.RETURN_METHOD_TO_CALL);
265 
266         if (StringUtils.isNotBlank(lookupForm.getReturnFormKey())) {
267             redirectAttributes.addAttribute(UifParameters.FORM_KEY, lookupForm.getReturnFormKey());
268         }
269 
270         redirectAttributes.addAttribute(KRADConstants.REFRESH_CALLER, lookupForm.getView().getId());
271         redirectAttributes.addAttribute(KRADConstants.REFRESH_CALLER_TYPE,
272                 UifConstants.RefreshCallerTypes.MULTI_VALUE_LOOKUP);
273         redirectAttributes.addAttribute(KRADConstants.REFRESH_DATA_OBJECT_CLASS, lookupForm.getDataObjectClassName());
274 
275         if (StringUtils.isNotBlank(lookupForm.getDocNum())) {
276             redirectAttributes.addAttribute(UifParameters.DOC_NUM, lookupForm.getDocNum());
277         }
278 
279         if (StringUtils.isNotBlank(lookupForm.getLookupCollectionName())) {
280             redirectAttributes.addAttribute(UifParameters.LOOKUP_COLLECTION_NAME, lookupForm.getLookupCollectionName());
281         }
282 
283         if (StringUtils.isNotBlank(lookupForm.getReferencesToRefresh())) {
284             redirectAttributes.addAttribute(KRADConstants.REFERENCES_TO_REFRESH, lookupForm.getReferencesToRefresh());
285         }
286 
287         // clear current form from session
288         GlobalVariables.getUifFormManager().removeSessionForm(lookupForm);
289 
290         return UifConstants.REDIRECT_PREFIX + lookupForm.getReturnLocation();
291     }
292 
293     /**
294      * Convenience method for determining whether two URLs point at the same domain
295      *
296      * @param firstDomain
297      * @param secondDomain
298      * @return true if the domains are different, false otherwise
299      */
300     private boolean areDifferentDomains(String firstDomain, String secondDomain) {
301         try {
302             URL urlOne = new URL(firstDomain.toLowerCase());
303             URL urlTwo = new URL(secondDomain.toLowerCase());
304             if(urlOne.getHost().equals(urlTwo.getHost())){
305                 LOG.debug("Hosts " + urlOne.getHost() + " of domains " + firstDomain
306                         + " and " + secondDomain + " were determined to be equal");
307                 return false;
308             }
309             else {
310                 LOG.debug("Hosts " + urlOne.getHost() + " of domains " + firstDomain
311                         + " and " + secondDomain + " are not equal");
312                 return true;
313             }
314         } catch (MalformedURLException mue) {
315             LOG.error("Unable to successfully compare domains " + firstDomain + " and " + secondDomain);
316         }
317         return true;
318     }
319 }