1 | |
|
2 | |
|
3 | |
|
4 | |
|
5 | |
|
6 | |
|
7 | |
|
8 | |
|
9 | |
|
10 | |
|
11 | |
|
12 | |
|
13 | |
|
14 | |
|
15 | |
|
16 | |
|
17 | |
package org.kuali.rice.kns.web.struts.pojo; |
18 | |
|
19 | |
import java.lang.reflect.InvocationTargetException; |
20 | |
import java.util.ArrayList; |
21 | |
import java.util.Collections; |
22 | |
import java.util.Enumeration; |
23 | |
import java.util.HashMap; |
24 | |
import java.util.HashSet; |
25 | |
import java.util.Hashtable; |
26 | |
import java.util.Iterator; |
27 | |
import java.util.List; |
28 | |
import java.util.Map; |
29 | |
import java.util.Set; |
30 | |
|
31 | |
import javax.servlet.http.HttpServletRequest; |
32 | |
|
33 | |
import org.apache.commons.beanutils.PropertyUtils; |
34 | |
import org.apache.commons.lang.StringUtils; |
35 | |
import org.apache.log4j.Logger; |
36 | |
import org.apache.struts.action.ActionForm; |
37 | |
import org.apache.struts.upload.MultipartRequestHandler; |
38 | |
import org.apache.struts.upload.MultipartRequestWrapper; |
39 | |
import org.kuali.rice.kns.exception.ValidationException; |
40 | |
import org.kuali.rice.kns.service.KNSServiceLocator; |
41 | |
import org.kuali.rice.kns.util.GlobalVariables; |
42 | |
import org.kuali.rice.kns.util.KNSConstants; |
43 | |
import org.kuali.rice.kns.util.ObjectUtils; |
44 | |
import org.kuali.rice.kns.util.Timer; |
45 | |
import org.kuali.rice.kns.util.WebUtils; |
46 | |
import org.kuali.rice.kns.web.format.EncryptionFormatter; |
47 | |
import org.kuali.rice.kns.web.format.FormatException; |
48 | |
import org.kuali.rice.kns.web.format.Formatter; |
49 | |
|
50 | |
|
51 | |
|
52 | |
|
53 | |
|
54 | |
|
55 | 0 | public class PojoFormBase extends ActionForm implements PojoForm { |
56 | |
private static final long serialVersionUID = 1L; |
57 | |
|
58 | |
|
59 | 0 | private static final Logger LOG = Logger.getLogger(PojoFormBase.class); |
60 | |
|
61 | |
private static final String PREVIOUS_REQUEST_EDITABLE_PROPERTIES_GUID = "editablePropertiesGuid"; |
62 | |
|
63 | |
|
64 | |
|
65 | |
|
66 | |
static final String CREATE_ERR_MSG = "Can't create formatter for keypath "; |
67 | |
static final String CONVERT_ERR_MSG = "Can't convert value for keypath: "; |
68 | |
|
69 | 0 | static Map classCache = Collections.synchronizedMap(new HashMap()); |
70 | |
|
71 | 0 | private Map unconvertedValues = new HashMap(); |
72 | 0 | private List unknownKeys = new ArrayList(); |
73 | 0 | private Map formatterTypes = new HashMap(); |
74 | 0 | private List<String> maxUploadFileSizes = new ArrayList<String>(); |
75 | 0 | private Set<String> editableProperties = new HashSet<String>(); |
76 | 0 | protected Set<String> requiredNonEditableProperties = new HashSet<String>(); |
77 | |
private String strutsActionMappingScope; |
78 | 0 | private boolean isNewForm = true; |
79 | |
|
80 | |
private String populateEditablePropertiesGuid; |
81 | |
private String actionEditablePropertiesGuid; |
82 | |
|
83 | |
|
84 | |
|
85 | |
|
86 | |
|
87 | |
|
88 | |
|
89 | |
|
90 | |
|
91 | |
|
92 | |
|
93 | |
|
94 | |
|
95 | |
|
96 | |
|
97 | |
|
98 | |
|
99 | |
|
100 | |
|
101 | |
|
102 | |
|
103 | |
|
104 | |
|
105 | |
|
106 | |
|
107 | |
|
108 | |
|
109 | |
|
110 | |
public void postprocessRequestParameters(Map requestParameters) { |
111 | |
|
112 | 0 | } |
113 | |
|
114 | |
|
115 | |
|
116 | |
|
117 | |
|
118 | |
|
119 | |
|
120 | |
|
121 | |
|
122 | |
public void populate(HttpServletRequest request) { |
123 | 0 | Timer t0 = new Timer("PojoFormBase.populate"); |
124 | 0 | unconvertedValues.clear(); |
125 | 0 | unknownKeys = new ArrayList(); |
126 | 0 | addRequiredNonEditableProperties(); |
127 | 0 | Map params = request.getParameterMap(); |
128 | |
|
129 | 0 | String contentType = request.getContentType(); |
130 | 0 | String method = request.getMethod(); |
131 | |
|
132 | 0 | if ("POST".equalsIgnoreCase(method) && contentType != null && contentType.startsWith("multipart/form-data")) { |
133 | 0 | Map fileElements = (HashMap)request.getAttribute(KNSConstants.UPLOADED_FILE_REQUEST_ATTRIBUTE_KEY); |
134 | 0 | Enumeration names = Collections.enumeration(fileElements.keySet()); |
135 | 0 | while (names.hasMoreElements()) { |
136 | 0 | String name = (String) names.nextElement(); |
137 | 0 | params.put(name, fileElements.get(name)); |
138 | 0 | } |
139 | |
} |
140 | |
|
141 | 0 | postprocessRequestParameters(params); |
142 | |
|
143 | |
|
144 | |
|
145 | |
|
146 | |
|
147 | |
|
148 | 0 | for (Iterator iter = params.keySet().iterator(); iter.hasNext();) { |
149 | 0 | String keypath = (String) iter.next(); |
150 | 0 | if (shouldPropertyBePopulatedInForm(keypath, request)) { |
151 | 0 | Object param = params.get(keypath); |
152 | |
|
153 | |
|
154 | 0 | populateForProperty(keypath, param, params); |
155 | |
} |
156 | 0 | } |
157 | 0 | this.registerIsNewForm(false); |
158 | 0 | t0.log(); |
159 | 0 | } |
160 | |
|
161 | |
|
162 | |
|
163 | |
|
164 | |
|
165 | |
|
166 | |
|
167 | |
|
168 | |
|
169 | |
protected void populateForProperty(String paramPath, Object paramValue, |
170 | |
Map params) { |
171 | |
|
172 | 0 | Class type = null; |
173 | |
try { |
174 | |
|
175 | |
|
176 | 0 | type = getPropertyType(paramPath); |
177 | |
} |
178 | 0 | catch (Exception e) { |
179 | |
|
180 | 0 | } |
181 | |
|
182 | |
|
183 | 0 | if (type == null) { |
184 | 0 | unknownKeys.add(paramPath); |
185 | |
} |
186 | |
else { |
187 | 0 | Formatter formatter = null; |
188 | |
try { |
189 | 0 | formatter = buildFormatter(paramPath, type, params); |
190 | |
|
191 | 0 | ObjectUtils.setObjectProperty(formatter, this, paramPath, type, paramValue); |
192 | |
} |
193 | 0 | catch (FormatException e1) { |
194 | 0 | GlobalVariables.getMessageMap().putError(paramPath, e1.getErrorKey(), e1.getErrorArgs()); |
195 | 0 | cacheUnconvertedValue(paramPath, paramValue); |
196 | |
} |
197 | 0 | catch (InvocationTargetException e1) { |
198 | 0 | if (e1.getTargetException().getClass().equals(FormatException.class)) { |
199 | |
|
200 | 0 | FormatException formatException = (FormatException) e1.getTargetException(); |
201 | 0 | GlobalVariables.getMessageMap().putError(paramPath, formatException.getErrorKey(), formatException.getErrorArgs()); |
202 | 0 | cacheUnconvertedValue(paramPath, paramValue); |
203 | 0 | } |
204 | |
else { |
205 | 0 | LOG.error("Error occurred in populate " + e1.getMessage()); |
206 | 0 | throw new RuntimeException(e1.getMessage(), e1); |
207 | |
} |
208 | |
} |
209 | 0 | catch (Exception e1) { |
210 | 0 | LOG.error("Error occurred in populate " + e1.getMessage()); |
211 | 0 | LOG.error("FormClass: " + this.getClass().getName() ); |
212 | 0 | LOG.error("keypath: " + paramPath ); |
213 | 0 | LOG.error("Detected Type: " + type.getName() ); |
214 | 0 | LOG.error( "Value: " + paramValue ); |
215 | 0 | if ( paramValue != null ) { |
216 | 0 | LOG.error( "Value Class: " + paramValue.getClass().getName() ); |
217 | |
} |
218 | 0 | throw new RuntimeException(e1.getMessage(), e1); |
219 | 0 | } |
220 | |
} |
221 | 0 | } |
222 | |
|
223 | |
|
224 | |
private Formatter buildFormatter(String keypath, Class propertyType, Map requestParams) { |
225 | 0 | Formatter formatter = buildFormatterForKeypath(keypath, propertyType, requestParams); |
226 | 0 | if (formatter == null) { |
227 | 0 | formatter = buildFormatterForType(propertyType); |
228 | |
} |
229 | 0 | return formatter; |
230 | |
} |
231 | |
|
232 | |
|
233 | |
|
234 | |
private Formatter buildFormatterForKeypath(String keypath, Class propertyType, Map requestParams) { |
235 | 0 | Formatter formatter = null; |
236 | |
|
237 | 0 | Class formatterClass = formatterClassForKeypath(keypath); |
238 | |
|
239 | 0 | if (formatterClass != null) { |
240 | |
try { |
241 | 0 | formatter = (Formatter) formatterClass.newInstance(); |
242 | |
} |
243 | 0 | catch (InstantiationException e) { |
244 | 0 | throw new FormatException("unable to instantiate formatter class '" + formatterClass.getName() + "'", e); |
245 | |
} |
246 | 0 | catch (IllegalAccessException e) { |
247 | 0 | throw new FormatException("unable to access formatter class '" + formatterClass.getName() + "'", e); |
248 | 0 | } |
249 | 0 | formatter.setPropertyType(propertyType); |
250 | |
} |
251 | 0 | return formatter; |
252 | |
} |
253 | |
|
254 | |
|
255 | |
|
256 | |
private Formatter buildFormatterForType(Class propertyType) { |
257 | 0 | Formatter formatter = null; |
258 | |
|
259 | 0 | if (Formatter.findFormatter(propertyType) != null) { |
260 | 0 | formatter = Formatter.getFormatter(propertyType); |
261 | |
} |
262 | 0 | return formatter; |
263 | |
} |
264 | |
|
265 | |
|
266 | |
|
267 | |
|
268 | |
|
269 | |
|
270 | |
|
271 | |
|
272 | |
|
273 | |
|
274 | |
|
275 | |
|
276 | |
|
277 | |
|
278 | |
private static Map getAllParametersForMultipartRequest(HttpServletRequest request, MultipartRequestHandler multipartHandler) { |
279 | 0 | Timer t0 = new Timer("PojoFormBase.getAllParametersForMultipartRequest"); |
280 | |
|
281 | 0 | Map parameters = new HashMap(); |
282 | 0 | Hashtable elements = multipartHandler.getAllElements(); |
283 | 0 | Enumeration e = elements.keys(); |
284 | 0 | while (e.hasMoreElements()) { |
285 | 0 | String key = (String) e.nextElement(); |
286 | 0 | parameters.put(key, elements.get(key)); |
287 | 0 | } |
288 | |
|
289 | 0 | if (request instanceof MultipartRequestWrapper) { |
290 | 0 | request = ((MultipartRequestWrapper) request).getRequest(); |
291 | 0 | e = request.getParameterNames(); |
292 | 0 | while (e.hasMoreElements()) { |
293 | 0 | String key = (String) e.nextElement(); |
294 | 0 | parameters.put(key, request.getParameterValues(key)); |
295 | 0 | } |
296 | |
} |
297 | |
else { |
298 | 0 | LOG.debug("Gathering multipart parameters for unwrapped request"); |
299 | |
} |
300 | |
|
301 | 0 | t0.log(); |
302 | 0 | return parameters; |
303 | |
} |
304 | |
|
305 | |
|
306 | |
|
307 | |
|
308 | |
|
309 | |
|
310 | |
|
311 | |
|
312 | |
|
313 | |
|
314 | |
protected Class getPropertyType(String keypath) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException { |
315 | 0 | Map propertyTypes = (Map) classCache.get(getClass()); |
316 | 0 | if (propertyTypes == null) { |
317 | 0 | propertyTypes = new HashMap(); |
318 | 0 | classCache.put(getClass(), propertyTypes); |
319 | |
} |
320 | |
|
321 | |
|
322 | 0 | if (!propertyTypes.containsKey(keypath)) { |
323 | 0 | Class type = ObjectUtils.easyGetPropertyType(this, keypath); |
324 | 0 | propertyTypes.put(keypath, type); |
325 | |
} |
326 | |
|
327 | 0 | Class propertyType = (Class) propertyTypes.get(keypath); |
328 | 0 | return propertyType; |
329 | |
} |
330 | |
|
331 | |
|
332 | |
|
333 | |
|
334 | |
|
335 | |
|
336 | |
|
337 | |
|
338 | |
|
339 | |
protected Formatter getFormatter(String keypath, Class propertyType) { |
340 | |
|
341 | 0 | Class type = formatterClassForKeypath(keypath); |
342 | |
|
343 | |
Formatter formatter; |
344 | 0 | if (type == null) { |
345 | |
|
346 | 0 | formatter = Formatter.getFormatter(propertyType); |
347 | |
} |
348 | |
else { |
349 | |
try { |
350 | 0 | formatter = (Formatter) type.newInstance(); |
351 | 0 | formatter.setPropertyType(propertyType); |
352 | |
} |
353 | 0 | catch (Exception e) { |
354 | 0 | throw new ValidationException(CREATE_ERR_MSG, e); |
355 | 0 | } |
356 | |
} |
357 | 0 | return formatter; |
358 | |
} |
359 | |
|
360 | |
|
361 | |
|
362 | |
|
363 | |
|
364 | |
|
365 | |
|
366 | |
|
367 | |
|
368 | |
protected Class formatterClassForKeypath(String keypath) { |
369 | |
|
370 | 0 | String indexlessKey = keypath.replaceAll("(\\[[0-9]*+\\]|\\(.*?\\))", ""); |
371 | |
|
372 | 0 | return (Class)formatterTypes.get( indexlessKey ); |
373 | |
} |
374 | |
|
375 | |
|
376 | |
|
377 | |
|
378 | |
|
379 | |
|
380 | |
|
381 | |
|
382 | |
|
383 | |
public Object formatValue(Object value, String keypath, Class type) { |
384 | |
|
385 | 0 | Formatter formatter = getFormatter(keypath, type); |
386 | 0 | if ( LOG.isDebugEnabled() ) { |
387 | 0 | LOG.debug("formatValue (value,keypath,type) = (" + value + "," + keypath + "," + type.getName() + ")"); |
388 | |
} |
389 | |
|
390 | |
try { |
391 | 0 | return Formatter.isSupportedType(type) ? formatter.formatForPresentation(value) : value; |
392 | |
} |
393 | 0 | catch (FormatException e) { |
394 | 0 | GlobalVariables.getMessageMap().putError(keypath, e.getErrorKey(), e.getErrorArgs()); |
395 | 0 | return value.toString(); |
396 | |
} |
397 | |
} |
398 | |
|
399 | |
|
400 | |
|
401 | |
|
402 | |
|
403 | |
public void setFormatterType(String keypath, Class type) { |
404 | 0 | formatterTypes.put(keypath, type); |
405 | 0 | } |
406 | |
|
407 | |
public Map getUnconvertedValues() { |
408 | 0 | return unconvertedValues; |
409 | |
} |
410 | |
|
411 | |
public void setUnconvertedValues(Map unconvertedValues) { |
412 | 0 | this.unconvertedValues = unconvertedValues; |
413 | 0 | } |
414 | |
|
415 | |
protected List getUnknownKeys() { |
416 | 0 | return unknownKeys; |
417 | |
} |
418 | |
|
419 | |
protected void cacheUnconvertedValue(String key, Object value) { |
420 | 0 | Class type = value.getClass(); |
421 | 0 | if (type.isArray()) { |
422 | 0 | value = Formatter.isEmptyValue(value) ? null : ((Object[]) value)[0]; |
423 | |
} |
424 | |
|
425 | 0 | unconvertedValues.put(key, value); |
426 | 0 | } |
427 | |
|
428 | |
|
429 | |
public void processValidationFail() { |
430 | |
|
431 | 0 | } |
432 | |
|
433 | |
|
434 | |
|
435 | |
|
436 | |
|
437 | |
|
438 | |
|
439 | |
|
440 | |
|
441 | |
public Map getFormatterTypes() { |
442 | 0 | return formatterTypes; |
443 | |
} |
444 | |
|
445 | |
|
446 | |
|
447 | |
|
448 | |
|
449 | |
|
450 | |
|
451 | |
|
452 | |
public void setFormatterTypes(Map formatterTypes) { |
453 | 0 | this.formatterTypes = formatterTypes; |
454 | 0 | } |
455 | |
|
456 | |
|
457 | |
|
458 | |
|
459 | |
|
460 | |
|
461 | |
|
462 | |
|
463 | |
|
464 | |
protected final void addMaxUploadSize( String sizeString ) { |
465 | 0 | maxUploadFileSizes.add( sizeString ); |
466 | 0 | } |
467 | |
|
468 | |
|
469 | |
|
470 | |
|
471 | |
|
472 | |
protected final void initMaxUploadSizes() { |
473 | 0 | if ( maxUploadFileSizes.isEmpty() ) { |
474 | 0 | customInitMaxUploadSizes(); |
475 | |
|
476 | 0 | if ( maxUploadFileSizes.isEmpty() ) { |
477 | 0 | addMaxUploadSize(KNSServiceLocator.getParameterService().getParameterValue(KNSConstants.KNS_NAMESPACE, KNSConstants.DetailTypes.ALL_DETAIL_TYPE, KNSConstants.MAX_UPLOAD_SIZE_PARM_NM)); |
478 | |
} |
479 | |
} |
480 | 0 | } |
481 | |
|
482 | |
|
483 | |
|
484 | |
|
485 | |
|
486 | |
protected void customInitMaxUploadSizes() { |
487 | |
|
488 | 0 | } |
489 | |
|
490 | |
public final List<String> getMaxUploadSizes() { |
491 | 0 | initMaxUploadSizes(); |
492 | |
|
493 | 0 | return maxUploadFileSizes; |
494 | |
} |
495 | |
|
496 | |
public void registerEditableProperty(String editablePropertyName){ |
497 | 0 | if ( LOG.isDebugEnabled() ) { |
498 | 0 | LOG.debug( "KualiSessionId: " + GlobalVariables.getUserSession().getKualiSessionId() + " -- Registering Property: " + editablePropertyName ); |
499 | |
} |
500 | 0 | editableProperties.add(editablePropertyName); |
501 | 0 | } |
502 | |
|
503 | |
public void registerRequiredNonEditableProperty(String requiredNonEditableProperty) { |
504 | 0 | requiredNonEditableProperties.add(requiredNonEditableProperty); |
505 | 0 | } |
506 | |
|
507 | |
public void clearEditablePropertyInformation(){ |
508 | 0 | if ( LOG.isDebugEnabled() ) { |
509 | 0 | LOG.debug( "KualiSessionId: " + GlobalVariables.getUserSession().getKualiSessionId() + " -- Clearing Editable Properties" ); |
510 | |
} |
511 | 0 | editableProperties = new HashSet<String>(); |
512 | 0 | } |
513 | |
|
514 | |
public Set<String> getEditableProperties(){ |
515 | 0 | return editableProperties; |
516 | |
} |
517 | |
|
518 | |
public boolean isPropertyEditable(String propertyName) { |
519 | 0 | final Set<String> populateEditableProperties = getPopulateEditableProperties(); |
520 | 0 | return WebUtils.isPropertyEditable(populateEditableProperties, propertyName); |
521 | |
} |
522 | |
|
523 | |
|
524 | |
|
525 | |
|
526 | |
public void addRequiredNonEditableProperties(){ |
527 | 0 | } |
528 | |
|
529 | |
public boolean isPropertyNonEditableButRequired(String propertyName) { |
530 | 0 | return WebUtils.isPropertyEditable(requiredNonEditableProperties, propertyName); |
531 | |
} |
532 | |
|
533 | |
protected String getParameter(HttpServletRequest request, String parameterName){ |
534 | 0 | return request.getParameter(parameterName); |
535 | |
} |
536 | |
|
537 | |
protected String[] getParameterValues(HttpServletRequest request, String parameterName){ |
538 | 0 | return request.getParameterValues(parameterName); |
539 | |
} |
540 | |
|
541 | |
public Set<String> getRequiredNonEditableProperties(){ |
542 | 0 | return requiredNonEditableProperties; |
543 | |
} |
544 | |
|
545 | |
|
546 | |
|
547 | |
|
548 | |
public void registerStrutsActionMappingScope(String strutsActionMappingScope) { |
549 | 0 | this.strutsActionMappingScope = strutsActionMappingScope; |
550 | 0 | } |
551 | |
|
552 | |
public String getStrutsActionMappingScope() { |
553 | 0 | return strutsActionMappingScope; |
554 | |
} |
555 | |
|
556 | |
|
557 | |
|
558 | |
|
559 | |
public void registerIsNewForm(boolean isNewForm) { |
560 | 0 | this.isNewForm = isNewForm; |
561 | 0 | } |
562 | |
|
563 | |
public boolean getIsNewForm() { |
564 | 0 | return this.isNewForm; |
565 | |
} |
566 | |
|
567 | |
|
568 | |
|
569 | |
|
570 | |
|
571 | |
public boolean shouldPropertyBePopulatedInForm(String requestParameterName, HttpServletRequest request) { |
572 | |
|
573 | 0 | if (requestParameterName.equals(PojoFormBase.PREVIOUS_REQUEST_EDITABLE_PROPERTIES_GUID)) { |
574 | 0 | return false; |
575 | |
} |
576 | 0 | else if (StringUtils.equalsIgnoreCase("session",getStrutsActionMappingScope()) && !getIsNewForm()) { |
577 | 0 | return isPropertyEditable(requestParameterName) || isPropertyNonEditableButRequired(requestParameterName); |
578 | |
} |
579 | 0 | return true; |
580 | |
|
581 | |
} |
582 | |
|
583 | |
|
584 | |
|
585 | |
|
586 | |
|
587 | |
|
588 | |
|
589 | |
public Set<String> getMethodToCallsToBypassSessionRetrievalForGETRequests() { |
590 | 0 | Set<String> defaultMethodToCalls = new HashSet<String>(); |
591 | 0 | defaultMethodToCalls.add(KNSConstants.START_METHOD); |
592 | 0 | return defaultMethodToCalls; |
593 | |
} |
594 | |
|
595 | |
|
596 | |
|
597 | |
|
598 | |
|
599 | |
|
600 | |
|
601 | |
|
602 | |
public void setPopulateEditablePropertiesGuid(String guid) { |
603 | 0 | this.populateEditablePropertiesGuid = guid; |
604 | 0 | } |
605 | |
|
606 | |
|
607 | |
|
608 | |
|
609 | |
public String getPopulateEditablePropertiesGuid() { |
610 | 0 | return this.populateEditablePropertiesGuid; |
611 | |
} |
612 | |
|
613 | |
|
614 | |
|
615 | |
|
616 | |
|
617 | |
public void setActionEditablePropertiesGuid(String guid) { |
618 | 0 | this.actionEditablePropertiesGuid = guid; |
619 | 0 | } |
620 | |
|
621 | |
|
622 | |
|
623 | |
|
624 | |
public String getActionEditablePropertiesGuid() { |
625 | 0 | return actionEditablePropertiesGuid; |
626 | |
} |
627 | |
|
628 | |
|
629 | |
|
630 | |
|
631 | |
public Set<String> getPopulateEditableProperties() { |
632 | 0 | return GlobalVariables.getUserSession().getEditablePropertiesHistoryHolder().getEditableProperties(getPopulateEditablePropertiesGuid()); |
633 | |
} |
634 | |
|
635 | |
|
636 | |
|
637 | |
|
638 | |
public void copyPopulateEditablePropertiesToActionEditableProperties() { |
639 | 0 | Set<String> populateEditableProperties = getPopulateEditableProperties(); |
640 | 0 | for (String property : populateEditableProperties) { |
641 | 0 | registerEditableProperty(property); |
642 | |
} |
643 | 0 | } |
644 | |
|
645 | |
|
646 | |
} |