1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.trinidad.webapp;
20
21 import java.text.DateFormat;
22 import java.text.ParseException;
23 import java.text.SimpleDateFormat;
24
25 import java.util.Calendar;
26 import java.util.Date;
27 import java.util.Map;
28 import java.util.TimeZone;
29 import java.util.concurrent.atomic.AtomicInteger;
30
31 import java.util.logging.Level;
32
33 import javax.el.MethodExpression;
34 import javax.el.ValueExpression;
35
36 import javax.faces.component.UIComponent;
37 import javax.faces.component.UIViewRoot;
38 import javax.faces.context.FacesContext;
39 import javax.faces.webapp.UIComponentClassicTagBase;
40 import javax.faces.webapp.UIComponentELTag;
41
42 import javax.servlet.jsp.JspException;
43
44 import org.apache.myfaces.trinidad.bean.FacesBean;
45 import org.apache.myfaces.trinidad.bean.PropertyKey;
46 import org.apache.myfaces.trinidad.component.UIXComponent;
47 import org.apache.myfaces.trinidad.context.RequestContext;
48 import org.apache.myfaces.trinidad.logging.TrinidadLogger;
49 import org.apache.myfaces.trinidad.util.ComponentUtils;
50
51
52
53
54
55
56 abstract public class UIXComponentELTag extends UIComponentELTag
57 {
58
59
60
61 protected enum CheckExecutionResult
62 {
63
64 ACCEPT,
65
66
67 REJECT
68 }
69
70 public UIXComponentELTag()
71 {
72 }
73
74 public void setAttributeChangeListener(MethodExpression attributeChangeListener)
75 {
76 _attributeChangeListener = attributeChangeListener;
77 }
78
79 @Override
80 public int doStartTag() throws JspException
81 {
82 FacesContext context = getFacesContext();
83 Map<String, Object> reqMap = context.getExternalContext().getRequestMap();
84
85 Map<Object, Object> facesContextAttributes = getFacesContext().getAttributes();
86
87
88
89
90
91
92 if (!_isProcessingStampingComponentTag(facesContextAttributes))
93 {
94 UIComponentClassicTagBase parentTagBase = getParentUIComponentClassicTagBase(pageContext);
95 if (parentTagBase instanceof UIXComponentELTag)
96 {
97 UIXComponentELTag parentTag = (UIXComponentELTag)parentTagBase;
98 String facetName = getFacetName();
99
100
101 if (parentTag.checkChildTagExecution(this, facetName) ==
102 CheckExecutionResult.REJECT)
103 {
104 _skipEndTagSuperCall = true;
105 return SKIP_BODY;
106 }
107 }
108 }
109
110 _skipEndTagSuperCall = false;
111
112 int retVal;
113 try
114 {
115 retVal = super.doStartTag();
116 }
117 catch (RuntimeException rte)
118 {
119 _logSevereTagProcessingError(context, rte);
120 throw rte;
121 }
122 catch (JspException jspe)
123 {
124 _logSevereTagProcessingError(context, jspe);
125 throw jspe;
126 }
127
128
129
130 if (_validationError != null)
131 throw new JspException(_validationError);
132
133 _checkStartingStampingTag(facesContextAttributes);
134
135 return retVal;
136 }
137
138 @Override
139 public int doEndTag()
140 throws JspException
141 {
142 if (_skipEndTagSuperCall)
143 {
144 _skipEndTagSuperCall = false;
145 return EVAL_PAGE;
146 }
147 else
148 {
149 _checkEndingStampingTag();
150 return super.doEndTag();
151 }
152 }
153
154
155
156
157
158
159 protected boolean isProcessingStampingComponentTag()
160 {
161 return _isProcessingStampingComponentTag(getFacesContext().getAttributes());
162 }
163
164
165
166
167
168 protected boolean isStampingTag()
169 {
170 return false;
171 }
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200 protected CheckExecutionResult checkChildTagExecution(
201 @SuppressWarnings("unused") UIComponentELTag childTag,
202 @SuppressWarnings("unused") String facetName)
203 {
204 return CheckExecutionResult.ACCEPT;
205 }
206
207
208
209
210
211
212
213 @Override
214 protected UIComponent createComponent(FacesContext context, String newId)
215 throws JspException
216 {
217 UIComponent component = null;
218 if (RequestContext.isInComponentBindingContext(context) && hasBinding())
219 {
220
221 ValueExpression binding = _getBinding();
222 binding.setValue(getELContext(), null);
223 }
224
225 component = super.createComponent(context, newId);
226
227
228 if (component != null && component.getParent() != null)
229 _logStaleParent(context, component, component.getParent());
230
231 return component;
232 }
233
234 @Override
235 public void release()
236 {
237 this._binding = null;
238 super.release();
239 }
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262 public CheckExecutionResult checkChildTagExecution(
263 @SuppressWarnings("unused") UIComponent childComponent)
264 {
265 return CheckExecutionResult.ACCEPT;
266 }
267
268 protected final void setProperties(UIComponent component)
269 {
270 if (component instanceof UIViewRoot)
271 {
272 throw new IllegalStateException(
273 "<f:view> was not present on this page; tag " + this +
274 "encountered without an <f:view> being processed.");
275 }
276
277 super.setProperties(component);
278
279 UIXComponent uixComponent = (UIXComponent) component;
280
281 if (_attributeChangeListener != null)
282 {
283 uixComponent.setAttributeChangeListener(_attributeChangeListener);
284 }
285
286 setProperties(uixComponent.getFacesBean());
287 }
288
289 protected void setProperty(
290 FacesBean bean,
291 PropertyKey key,
292 ValueExpression expression)
293 {
294 if (expression == null)
295 return;
296
297 if (expression.isLiteralText())
298 {
299 bean.setProperty(key, expression.getValue(FacesContext.getCurrentInstance().getELContext()));
300 }
301 else
302 {
303 bean.setValueExpression(key, expression);
304 }
305 }
306
307
308
309
310
311
312
313
314 protected void setStringArrayProperty(
315 FacesBean bean,
316 PropertyKey key,
317 ValueExpression expression)
318 {
319 if (expression == null)
320 return;
321
322 if (expression.isLiteralText())
323 {
324 bean.setProperty(key, TagUtils.parseNameTokens(
325 expression.getValue(FacesContext.getCurrentInstance().getELContext())));
326 }
327 else
328 {
329
330 expression = new StringArrayValueExpression(expression);
331 bean.setValueExpression(key, expression);
332 }
333 }
334
335
336
337
338
339
340
341
342 protected void setStringListProperty(
343 FacesBean bean,
344 PropertyKey key,
345 ValueExpression expression)
346 {
347 if (expression == null)
348 return;
349
350 if (expression.isLiteralText())
351 {
352 bean.setProperty(key, TagUtils.parseNameTokensAsList(
353 expression.getValue(FacesContext.getCurrentInstance().getELContext())));
354 }
355 else
356 {
357 bean.setValueExpression(key, expression);
358 }
359 }
360
361
362
363
364
365
366
367
368 protected void setStringSetProperty(
369 FacesBean bean,
370 PropertyKey key,
371 ValueExpression expression)
372 {
373 if (expression == null)
374 return;
375
376 if (expression.isLiteralText())
377 {
378 bean.setProperty(key, TagUtils.parseNameTokensAsSet(
379 expression.getValue(FacesContext.getCurrentInstance().getELContext())));
380 }
381 else
382 {
383 bean.setValueExpression(key, expression);
384 }
385 }
386
387
388
389
390
391
392
393 protected void setNumberProperty(
394 FacesBean bean,
395 PropertyKey key,
396 ValueExpression expression)
397 {
398 if (expression == null)
399 return;
400
401 if (expression.isLiteralText())
402 {
403 Object value = expression.getValue(FacesContext.getCurrentInstance().getELContext());
404 if (value != null)
405 {
406 if (value instanceof Number)
407 {
408 bean.setProperty(key, value);
409 }
410 else
411 {
412 String valueStr = value.toString();
413 if(valueStr.indexOf('.') == -1)
414 bean.setProperty(key, Integer.valueOf(valueStr));
415 else
416 bean.setProperty(key, Double.valueOf(valueStr));
417 }
418 }
419 }
420 else
421 {
422 bean.setValueExpression(key, expression);
423 }
424 }
425
426
427
428
429
430
431
432
433 protected void setIntArrayProperty(
434 FacesBean bean,
435 PropertyKey key,
436 ValueExpression expression)
437 {
438 if (expression == null)
439 return;
440
441 if (expression.isLiteralText())
442 {
443 Object value = expression.getValue(FacesContext.getCurrentInstance().getELContext());
444 if (value != null)
445 {
446 String[] strings = TagUtils.parseNameTokens(value);
447 final int[] ints;
448 if (strings != null)
449 {
450 try
451 {
452 ints = new int[strings.length];
453 for(int i=0; i<strings.length; i++)
454 {
455 int j = Integer.parseInt(strings[i]);
456 ints[i] = j;
457 }
458 }
459 catch (NumberFormatException e)
460 {
461 _LOG.severe("CANNOT_CONVERT_INTO_INT_ARRAY",value);
462 _LOG.severe(e);
463 return;
464 }
465 }
466 }
467 }
468 else
469 {
470 bean.setValueExpression(key, expression);
471 }
472 }
473
474 @Override
475 public void setBinding(ValueExpression valueExpression)
476 throws JspException
477 {
478 this._binding = valueExpression;
479 super.setBinding(valueExpression);
480 }
481
482 private ValueExpression _getBinding()
483 {
484 return _binding;
485 }
486
487
488
489
490
491
492
493
494 protected void setDateProperty(
495 FacesBean bean,
496 PropertyKey key,
497 ValueExpression expression)
498 {
499 if (expression == null)
500 return;
501
502 if (expression.isLiteralText())
503 {
504 bean.setProperty(key, _parseISODate(
505 expression.getValue(FacesContext.getCurrentInstance().getELContext())));
506 }
507 else
508 {
509 bean.setValueExpression(key, expression);
510 }
511 }
512
513
514
515
516
517
518
519
520 protected void setMaxDateProperty(
521 FacesBean bean,
522 PropertyKey key,
523 ValueExpression expression)
524 {
525 if (expression == null)
526 return;
527
528 if (expression.isLiteralText())
529 {
530 Date d = _parseISODate(expression.getValue(FacesContext.getCurrentInstance().getELContext()));
531 Calendar c = Calendar.getInstance();
532 TimeZone tz = RequestContext.getCurrentInstance().getTimeZone();
533 if (tz != null)
534 c.setTimeZone(tz);
535 c.setTime(d);
536
537
538 c.set (Calendar.HOUR_OF_DAY, 23);
539 c.set (Calendar.MINUTE, 59);
540 c.set (Calendar.SECOND, 59);
541 c.set (Calendar.MILLISECOND, 999);
542 bean.setProperty(key, c.getTime());
543 }
544 else
545 {
546 bean.setValueExpression(key, expression);
547 }
548 }
549
550 protected void setProperties(
551 @SuppressWarnings("unused")
552 FacesBean bean)
553 {
554
555
556
557 }
558
559
560
561
562
563
564
565 protected void setValidationError(String validationError)
566 {
567 _validationError = validationError;
568 }
569
570
571
572
573
574
575
576
577
578 private void _checkStartingStampingTag(
579 Map<Object, Object> facesContextAttributes)
580 {
581 if (isStampingTag())
582 {
583 AtomicInteger count = (AtomicInteger)facesContextAttributes.get(_STAMPING_COUNT_KEY);
584 if (count == null)
585 {
586
587
588
589 facesContextAttributes.put(_STAMPING_COUNT_KEY, new AtomicInteger(1));
590 }
591 else
592 {
593
594
595 count.set(count.get() + 1);
596 }
597 }
598 }
599
600
601
602
603
604
605
606 private void _checkEndingStampingTag()
607 {
608 if (isStampingTag())
609 {
610 Map<Object, Object> facesContextAttributes = getFacesContext().getAttributes();
611 AtomicInteger count = (AtomicInteger)facesContextAttributes.get(_STAMPING_COUNT_KEY);
612 if (count.get() == 1)
613 {
614 facesContextAttributes.remove(_STAMPING_COUNT_KEY);
615 }
616 else
617 {
618 count.set(count.get() - 1);
619 }
620 }
621 }
622
623
624
625
626
627
628
629
630 private boolean _isProcessingStampingComponentTag(
631 Map<Object, Object> facesContextAttributes)
632 {
633 return facesContextAttributes.containsKey(_STAMPING_COUNT_KEY);
634 }
635
636
637
638
639
640
641 private void _logSevereTagProcessingError(FacesContext context, Throwable e)
642 {
643 UIViewRoot viewRoot = context.getViewRoot();
644 UIComponent component = this.getComponentInstance();
645 String scopedId = _getScopedId(component, viewRoot);
646 String parentScopedId = _getParentScopedId(viewRoot);
647
648 String message = _LOG.getMessage("ERROR_PARSING_COMPONENT_TAG",
649 new Object[] {scopedId, parentScopedId});
650 _LOG.severe(message, e);
651 }
652
653 private String _getScopedId(UIComponent component, UIViewRoot viewRoot)
654 {
655 if (component == null)
656 {
657
658 return this.getId();
659 }
660 else
661 {
662 return ComponentUtils.getScopedIdForComponent(component, viewRoot);
663 }
664 }
665
666
667
668
669
670
671
672 private void _logStaleParent(FacesContext context,
673 UIComponent child,
674 UIComponent oldParent)
675 {
676 _logStaleParentAtLevel(context, child, oldParent, Level.INFO);
677 }
678
679
680
681
682
683
684
685
686 private void _logStaleParentAtLevel(FacesContext context,
687 UIComponent child,
688 UIComponent oldParent,
689 Level level)
690 {
691 if (_LOG.isLoggable(level))
692 {
693 UIViewRoot viewRoot = context.getViewRoot();
694
695 String scopedId = ComponentUtils.getScopedIdForComponent(child, viewRoot);
696 String oldParentScopedId = ComponentUtils.getScopedIdForComponent(oldParent, viewRoot);
697 String newParentScopedId = _getParentScopedId(viewRoot);
698
699 String bindingEL = _getBindingExpression();
700
701 _LOG.log(level, "ERROR_CREATE_COMPONENT_STALE",
702 new Object[] {scopedId, oldParentScopedId, newParentScopedId, bindingEL});
703 }
704 }
705
706
707
708
709
710 private String _getBindingExpression()
711 {
712 if (_getBinding() != null)
713 {
714 if (_bindingExpression == null)
715 _bindingExpression = _getBinding().getExpressionString();
716
717 return _bindingExpression;
718 }
719
720 return null;
721 }
722
723
724
725
726
727
728 private String _getParentScopedId(UIViewRoot viewRoot)
729 {
730 UIComponentClassicTagBase parentTag =
731 UIComponentClassicTagBase.getParentUIComponentClassicTagBase(pageContext);
732 if (parentTag != null)
733 {
734 UIComponent parent = parentTag.getComponentInstance();
735 return ComponentUtils.getScopedIdForComponent(parent, viewRoot);
736 }
737
738 return null;
739 }
740
741
742
743
744
745 static private final Date _parseISODate(Object o)
746 {
747 if (o == null)
748 return null;
749
750 String stringValue = o.toString();
751 try
752 {
753 return _getDateFormat().parse(stringValue);
754 }
755 catch (ParseException pe)
756 {
757 _LOG.info("CANNOT_PARSE_VALUE_INTO_DATE", stringValue);
758 return null;
759 }
760 }
761
762
763 private static DateFormat _getDateFormat()
764 {
765 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
766 TimeZone tz = RequestContext.getCurrentInstance().getTimeZone();
767 if (tz != null)
768 sdf.setTimeZone(tz);
769 return sdf;
770 }
771
772 private static final TrinidadLogger _LOG =
773 TrinidadLogger.createTrinidadLogger(UIXComponentELTag.class);
774
775
776 @Deprecated
777 public static final String DOCUMENT_CREATED_KEY = "org.apache.myfaces.trinidad.DOCUMENTCREATED";
778
779 private final static String _STAMPING_COUNT_KEY = UIXComponentELTag.class.getName() + ".STAMPING";
780
781 private MethodExpression _attributeChangeListener;
782 private String _validationError;
783 private String _bindingExpression;
784 private boolean _skipEndTagSuperCall = false;
785
786
787
788
789 private ValueExpression _binding;
790 }