001 /**
002 * Copyright 2005-2011 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.krad.web.form;
017
018 import org.apache.commons.lang.StringUtils;
019 import org.codehaus.jackson.map.ObjectMapper;
020 import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
021 import org.kuali.rice.krad.uif.UifConstants;
022 import org.kuali.rice.krad.uif.UifParameters;
023 import org.kuali.rice.krad.uif.view.History;
024 import org.kuali.rice.krad.uif.view.View;
025 import org.kuali.rice.krad.uif.service.ViewService;
026 import org.kuali.rice.krad.uif.view.ViewModel;
027 import org.kuali.rice.krad.util.KRADUtils;
028 import org.springframework.web.multipart.MultipartFile;
029 import org.kuali.rice.krad.uif.UifConstants.ViewType;
030
031 import javax.servlet.http.HttpServletRequest;
032 import java.io.IOException;
033 import java.util.ArrayList;
034 import java.util.HashMap;
035 import java.util.List;
036 import java.util.Map;
037 import java.util.Properties;
038 import java.util.Set;
039 import java.util.UUID;
040
041 /**
042 * Base form class for views within the KRAD User Interface Framework
043 *
044 * <p>
045 * Holds properties necessary to determine the <code>View</code> instance that
046 * will be used to render the UI
047 * </p>
048 *
049 * @author Kuali Rice Team (rice.collab@kuali.org)
050 */
051 public class UifFormBase implements ViewModel {
052 private static final long serialVersionUID = 8432543267099454434L;
053
054 // current view
055 protected String viewId;
056 protected String viewName;
057 protected ViewType viewTypeName;
058 protected String pageId;
059 protected String methodToCall;
060 protected String formKey;
061 protected String jumpToId;
062 protected String jumpToName;
063 protected String focusId;
064 protected String formPostUrl;
065
066 protected boolean defaultsApplied;
067
068 protected View view;
069 protected View previousView;
070
071 protected Map<String, String> viewRequestParameters;
072 protected List<String> readOnlyFieldsList;
073
074 protected Map<String, Object> newCollectionLines;
075 protected Map<String, String> actionParameters;
076 protected Map<String, Object> clientStateForSyncing;
077 protected Map<String, Set<String>> selectedCollectionLines;
078
079 protected MultipartFile attachmentFile;
080
081 // navigation
082 protected String returnLocation;
083 protected String returnFormKey;
084
085 protected History formHistory;
086
087 protected boolean renderFullView;
088 protected boolean validateDirty;
089
090 public UifFormBase() {
091 formKey = generateFormKey();
092 renderFullView = true;
093 defaultsApplied = false;
094
095 readOnlyFieldsList = new ArrayList<String>();
096 viewRequestParameters = new HashMap<String, String>();
097 newCollectionLines = new HashMap<String, Object>();
098 actionParameters = new HashMap<String, String>();
099 clientStateForSyncing = new HashMap<String, Object>();
100 selectedCollectionLines = new HashMap<String, Set<String>>();
101 }
102
103 /**
104 * Creates the unique id used to store this "conversation" in the session.
105 * The default method generates a java UUID.
106 *
107 * @return
108 */
109 protected String generateFormKey() {
110 return UUID.randomUUID().toString();
111 }
112
113 /**
114 * Called after Spring binds the request to the form and before the
115 * controller method is invoked.
116 *
117 * @param request - request object containing the query parameters
118 */
119 public void postBind(HttpServletRequest request) {
120 // default form post URL to request URL
121 formPostUrl = request.getRequestURL().toString();
122
123 // get any sent client view state and parse into map
124 if (request.getParameterMap().containsKey(UifParameters.CLIENT_VIEW_STATE)) {
125 String clientStateJSON = request.getParameter(UifParameters.CLIENT_VIEW_STATE);
126 if (StringUtils.isNotBlank(clientStateJSON)) {
127 // change single quotes to double quotes (necessary because the reverse was done for sending)
128 clientStateJSON = StringUtils.replace(clientStateJSON, "'", "\"");
129
130 ObjectMapper mapper = new ObjectMapper();
131 try {
132 clientStateForSyncing = mapper.readValue(clientStateJSON, Map.class);
133 } catch (IOException e) {
134 throw new RuntimeException("Unable to decode client side state JSON", e);
135 }
136 }
137 }
138
139 // populate read only fields list
140 if (request.getParameter(UifParameters.READ_ONLY_FIELDS) != null) {
141 String readOnlyFields = request.getParameter(UifParameters.READ_ONLY_FIELDS);
142 setReadOnlyFieldsList(KRADUtils.convertStringParameterToList(readOnlyFields));
143 }
144 }
145
146 /**
147 * @see org.kuali.rice.krad.uif.view.ViewModel#getViewId()
148 */
149 public String getViewId() {
150 return this.viewId;
151 }
152
153 /**
154 * @see org.kuali.rice.krad.uif.view.ViewModel#setViewId(java.lang.String)
155 */
156 public void setViewId(String viewId) {
157 this.viewId = viewId;
158 }
159
160 /**
161 * @see org.kuali.rice.krad.uif.view.ViewModel#getViewName()
162 */
163 public String getViewName() {
164 return this.viewName;
165 }
166
167 /**
168 * @see org.kuali.rice.krad.uif.view.ViewModel#setViewName(java.lang.String)
169 */
170 public void setViewName(String viewName) {
171 this.viewName = viewName;
172 }
173
174 /**
175 * @see org.kuali.rice.krad.uif.view.ViewModel#getViewTypeName()
176 */
177 public ViewType getViewTypeName() {
178 return this.viewTypeName;
179 }
180
181 /**
182 * @see org.kuali.rice.krad.uif.view.ViewModel#setViewTypeName(org.kuali.rice.krad.uif.UifConstants.ViewType)
183 */
184 public void setViewTypeName(ViewType viewTypeName) {
185 this.viewTypeName = viewTypeName;
186 }
187
188 /**
189 * @see org.kuali.rice.krad.uif.view.ViewModel#getPageId()
190 */
191 public String getPageId() {
192 return this.pageId;
193 }
194
195 /**
196 * @see org.kuali.rice.krad.uif.view.ViewModel#setPageId(java.lang.String)
197 */
198 public void setPageId(String pageId) {
199 this.pageId = pageId;
200 }
201
202 /**
203 * @see org.kuali.rice.krad.uif.view.ViewModel#getFormPostUrl()
204 */
205 public String getFormPostUrl() {
206 return this.formPostUrl;
207 }
208
209 /**
210 * @see org.kuali.rice.krad.uif.view.ViewModel#setFormPostUrl(java.lang.String)
211 */
212 public void setFormPostUrl(String formPostUrl) {
213 this.formPostUrl = formPostUrl;
214 }
215
216 public String getReturnLocation() {
217 return this.returnLocation;
218 }
219
220 public void setReturnLocation(String returnLocation) {
221 this.returnLocation = returnLocation;
222 }
223
224 public String getReturnFormKey() {
225 return this.returnFormKey;
226 }
227
228 public void setReturnFormKey(String returnFormKey) {
229 this.returnFormKey = returnFormKey;
230 }
231
232 /**
233 * Identifies the controller method that should be invoked to fulfill a
234 * request. The value will be matched up against the 'params' setting on the
235 * <code>RequestMapping</code> annotation for the controller method
236 *
237 * @return String method to call
238 */
239 public String getMethodToCall() {
240 return this.methodToCall;
241 }
242
243 /**
244 * Setter for the method to call
245 *
246 * @param methodToCall
247 */
248 public void setMethodToCall(String methodToCall) {
249 this.methodToCall = methodToCall;
250 }
251
252 /**
253 * @see org.kuali.rice.krad.uif.view.ViewModel#getViewRequestParameters()
254 */
255 public Map<String, String> getViewRequestParameters() {
256 return this.viewRequestParameters;
257 }
258
259 /**
260 * @see org.kuali.rice.krad.uif.view.ViewModel#setViewRequestParameters(java.util.Map<java.lang.String,java.lang.String>)
261 */
262 public void setViewRequestParameters(Map<String, String> viewRequestParameters) {
263 this.viewRequestParameters = viewRequestParameters;
264 }
265
266 /**
267 * @see org.kuali.rice.krad.uif.view.ViewModel#getReadOnlyFieldsList()
268 */
269 public List<String> getReadOnlyFieldsList() {
270 return readOnlyFieldsList;
271 }
272
273 /**
274 * @see org.kuali.rice.krad.uif.view.ViewModel#setReadOnlyFieldsList(java.util.List<java.lang.String>)
275 */
276 public void setReadOnlyFieldsList(List<String> readOnlyFieldsList) {
277 this.readOnlyFieldsList = readOnlyFieldsList;
278 }
279
280 /**
281 * @see org.kuali.rice.krad.uif.view.ViewModel#getNewCollectionLines()
282 */
283 public Map<String, Object> getNewCollectionLines() {
284 return this.newCollectionLines;
285 }
286
287 /**
288 * @see org.kuali.rice.krad.uif.view.ViewModel#setNewCollectionLines(java.util.Map<java.lang.String,java.lang.Object>)
289 */
290 public void setNewCollectionLines(Map<String, Object> newCollectionLines) {
291 this.newCollectionLines = newCollectionLines;
292 }
293
294 /**
295 * @see org.kuali.rice.krad.uif.view.ViewModel#getActionParameters()
296 */
297 public Map<String, String> getActionParameters() {
298 return this.actionParameters;
299 }
300
301 /**
302 * Returns the action parameters map as a <code>Properties</code> instance
303 *
304 * @return Properties action parameters
305 */
306 public Properties getActionParametersAsProperties() {
307 Properties actionProperties = new Properties();
308
309 if (actionParameters != null) {
310 for (Map.Entry<String, String> actionParameter : actionParameters.entrySet()) {
311 actionProperties.put(actionParameter.getKey(), actionParameter.getValue());
312 }
313 }
314
315 return actionProperties;
316 }
317
318 /**
319 * @see org.kuali.rice.krad.uif.view.ViewModel#setActionParameters(java.util.Map<java.lang.String,java.lang.String>)
320 */
321 public void setActionParameters(Map<String, String> actionParameters) {
322 this.actionParameters = actionParameters;
323 }
324
325 /**
326 * Retrieves the value for the given action parameter, or empty string if
327 * not found
328 *
329 * @param actionParameterName - name of the action parameter to retrieve value for
330 * @return String parameter value or empty string
331 */
332 public String getActionParamaterValue(String actionParameterName) {
333 if ((actionParameters != null) && actionParameters.containsKey(actionParameterName)) {
334 return actionParameters.get(actionParameterName);
335 }
336
337 return "";
338 }
339
340 /**
341 * Returns the action event that was sent in the action parameters (if any)
342 *
343 * <p>
344 * The action event is a special action parameter that can be sent to indicate a type of action being taken. This
345 * can be looked at by the view or components to render differently
346 * </p>
347 *
348 * TODO: make sure action parameters are getting reinitialized on each request
349 *
350 * @return String action event name or blank if action event was not sent
351 */
352 public String getActionEvent() {
353 if ((actionParameters != null) && actionParameters.containsKey(UifConstants.UrlParams.ACTION_EVENT)) {
354 return actionParameters.get(UifConstants.UrlParams.ACTION_EVENT);
355 }
356
357 return "";
358 }
359
360 /**
361 * @see org.kuali.rice.krad.uif.view.ViewModel#getClientStateForSyncing()
362 */
363 public Map<String, Object> getClientStateForSyncing() {
364 return clientStateForSyncing;
365 }
366
367 /**
368 * @see org.kuali.rice.krad.uif.view.ViewModel#getSelectedCollectionLines()
369 */
370 public Map<String, Set<String>> getSelectedCollectionLines() {
371 return selectedCollectionLines;
372 }
373
374 /**
375 * @see org.kuali.rice.krad.uif.view.ViewModel#setSelectedCollectionLines(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)
376 */
377 public void setSelectedCollectionLines(Map<String, Set<String>> selectedCollectionLines) {
378 this.selectedCollectionLines = selectedCollectionLines;
379 }
380
381 /**
382 * Key string that identifies the form instance in session storage
383 *
384 * <p>
385 * When the view is posted, the previous form instance is retrieved and then
386 * populated from the request parameters. This key string is retrieve the
387 * session form from the session service
388 * </p>
389 *
390 * @return String form session key
391 */
392 public String getFormKey() {
393 return this.formKey;
394 }
395
396 /**
397 * Setter for the form's session key
398 *
399 * @param formKey
400 */
401 public void setFormKey(String formKey) {
402 this.formKey = formKey;
403 }
404
405 /**
406 * @see org.kuali.rice.krad.uif.view.ViewModel#isDefaultsApplied()
407 */
408 public boolean isDefaultsApplied() {
409 return this.defaultsApplied;
410 }
411
412 /**
413 * @see org.kuali.rice.krad.uif.view.ViewModel#setDefaultsApplied(boolean)
414 */
415 public void setDefaultsApplied(boolean defaultsApplied) {
416 this.defaultsApplied = defaultsApplied;
417 }
418
419 /**
420 * Holder for files that are attached through the view
421 *
422 * @return MultipartFile representing the attachment
423 */
424 public MultipartFile getAttachmentFile() {
425 return this.attachmentFile;
426 }
427
428 /**
429 * Setter for the form's attachment file
430 *
431 * @param attachmentFile
432 */
433 public void setAttachmentFile(MultipartFile attachmentFile) {
434 this.attachmentFile = attachmentFile;
435 }
436
437 /**
438 * @return the renderFullView
439 */
440 public boolean isRenderFullView() {
441 return this.renderFullView;
442 }
443
444 /**
445 * @param renderFullView
446 */
447 public void setRenderFullView(boolean renderFullView) {
448 this.renderFullView = renderFullView;
449 }
450
451 /**
452 * @see org.kuali.rice.krad.uif.view.ViewModel#getView()
453 */
454 public View getView() {
455 return this.view;
456 }
457
458 /**
459 * @see org.kuali.rice.krad.uif.view.ViewModel#setView(org.kuali.rice.krad.uif.view.View)
460 */
461 public void setView(View view) {
462 this.view = view;
463 }
464
465 /**
466 * @see org.kuali.rice.krad.uif.view.ViewModel#getPreviousView()
467 */
468 public View getPreviousView() {
469 return this.previousView;
470 }
471
472 /**
473 * @see org.kuali.rice.krad.uif.view.ViewModel#setPreviousView(org.kuali.rice.krad.uif.view.View)
474 */
475 public void setPreviousView(View previousView) {
476 this.previousView = previousView;
477 }
478
479 /**
480 * Instance of the <code>ViewService</code> that can be used to retrieve
481 * <code>View</code> instances
482 *
483 * @return ViewService implementation
484 */
485 protected ViewService getViewService() {
486 return KRADServiceLocatorWeb.getViewService();
487 }
488
489 /**
490 * The jumpToId for this form, the element with this id will be jumped to automatically
491 * when the form is loaded in the view.
492 * Using "TOP" or "BOTTOM" will jump to the top or the bottom of the resulting page.
493 * jumpToId always takes precedence over jumpToName, if set.
494 *
495 * @return the jumpToId
496 */
497 public String getJumpToId() {
498 return this.jumpToId;
499 }
500
501 /**
502 * @param jumpToId the jumpToId to set
503 */
504 public void setJumpToId(String jumpToId) {
505 this.jumpToId = jumpToId;
506 }
507
508 /**
509 * The jumpToName for this form, the element with this name will be jumped to automatically
510 * when the form is loaded in the view.
511 * WARNING: jumpToId always takes precedence over jumpToName, if set.
512 *
513 * @return the jumpToName
514 */
515 public String getJumpToName() {
516 return this.jumpToName;
517 }
518
519 /**
520 * @param jumpToName the jumpToName to set
521 */
522 public void setJumpToName(String jumpToName) {
523 this.jumpToName = jumpToName;
524 }
525
526 /**
527 * Field to place focus on when the page loads
528 * An empty focusId will result in focusing on the first visible input element by default.
529 *
530 * @return the focusId
531 */
532 public String getFocusId() {
533 return this.focusId;
534 }
535
536 /**
537 * @param focusId the focusId to set
538 */
539 public void setFocusId(String focusId) {
540 this.focusId = focusId;
541 }
542
543 /**
544 * History parameter representing the History of views that have come before the
545 * viewing of the current view
546 *
547 * <p>
548 * Used for breadcrumb widget generation on the view and also for navigating back
549 * to previous or hub locations
550 * </p>
551 *
552 * @return History instance giving current history
553 */
554 public History getFormHistory() {
555 return formHistory;
556 }
557
558 /**
559 * Setter for the current History object
560 *
561 * @param history the history to set
562 */
563 public void setFormHistory(History history) {
564 this.formHistory = history;
565 }
566
567 /**
568 * Indicates whether the form should be validated for dirtyness
569 *
570 * <p>
571 * For FormView, it's necessary to validate when the user tries to navigate out of the form. If set, all the
572 * InputFields will be validated on refresh, navigate, cancel or close Action or on form
573 * unload and if dirty, displays a message and user can decide whether to continue with
574 * the action or stay on the form
575 * </p>
576 *
577 * @return boolean true if dirty validation should be enabled
578 */
579 public boolean isValidateDirty() {
580 return this.validateDirty;
581 }
582
583 /**
584 * Setter for dirty validation indicator
585 *
586 * @param validateDirty
587 */
588 public void setValidateDirty(boolean validateDirty) {
589 this.validateDirty = validateDirty;
590 }
591
592 }