View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.view.facelets.tag.jsf;
20  
21  import javax.el.MethodExpression;
22  import javax.faces.component.EditableValueHolder;
23  import javax.faces.component.UIComponent;
24  import javax.faces.context.FacesContext;
25  import javax.faces.event.MethodExpressionValueChangeListener;
26  import javax.faces.event.ValueChangeEvent;
27  import javax.faces.validator.MethodExpressionValidator;
28  import javax.faces.view.facelets.FaceletContext;
29  import javax.faces.view.facelets.MetaRule;
30  import javax.faces.view.facelets.Metadata;
31  import javax.faces.view.facelets.MetadataTarget;
32  import javax.faces.view.facelets.TagAttribute;
33  
34  import org.apache.myfaces.view.facelets.FaceletCompositionContext;
35  
36  /**
37   * 
38   * @author Jacob Hookom
39   * @version $Id$
40   */
41  public final class EditableValueHolderRule extends MetaRule
42  {
43  
44      final static class LiteralValidatorMetadata extends Metadata
45      {
46  
47          private final String validatorId;
48  
49          public LiteralValidatorMetadata(String validatorId)
50          {
51              this.validatorId = validatorId;
52          }
53  
54          public void applyMetadata(FaceletContext ctx, Object instance)
55          {
56              ((EditableValueHolder) instance).addValidator(ctx.getFacesContext().getApplication()
57                      .createValidator(this.validatorId));
58          }
59      }
60  
61      final static class ValueChangedExpressionMetadata extends Metadata
62      {
63          private final TagAttribute attr;
64  
65          public ValueChangedExpressionMetadata(TagAttribute attr)
66          {
67              this.attr = attr;
68          }
69  
70          public void applyMetadata(FaceletContext ctx, Object instance)
71          {
72              // From JSF 2.0 it is possible to have valueChangeListener method without ValueChangeEvent parameter. 
73              // It seems that MethodExpressionValueChangeListener from API contains support for it but there is one big
74              // problem - one-arg constructor will not preserve the current VariableMapper.
75              // This is a problem when using facelets and <ui:decorate/> with EL params (see MYFACES-2541 for details).
76              // So we must create two MethodExpressions here - both are created from the current 
77              // facelets context and thus variable mapping will work.
78              final MethodExpression methodExpressionOneArg = attr.getMethodExpression(ctx, null, VALUECHANGE_SIG);
79              final MethodExpression methodExpressionZeroArg = attr.getMethodExpression(ctx, null, EMPTY_CLASS_ARRAY);
80              if (FaceletCompositionContext.getCurrentInstance(ctx).isUsingPSSOnThisView())
81              {
82                  ((EditableValueHolder) instance).addValueChangeListener(
83                        new PartialMethodExpressionValueChangeListener(methodExpressionOneArg, methodExpressionZeroArg));
84              }
85              else
86              {
87                  ((EditableValueHolder) instance).addValueChangeListener(
88                          new MethodExpressionValueChangeListener(methodExpressionOneArg, methodExpressionZeroArg));
89              }
90          }
91      }
92  
93      final static class ValidatorExpressionMetadata extends Metadata
94      {
95          private final TagAttribute attr;
96  
97          public ValidatorExpressionMetadata(TagAttribute attr)
98          {
99              this.attr = attr;
100         }
101 
102         public void applyMetadata(FaceletContext ctx, Object instance)
103         {
104             if (FaceletCompositionContext.getCurrentInstance(ctx).isUsingPSSOnThisView())
105             {
106                 ((EditableValueHolder) instance).addValidator(new PartialMethodExpressionValidator(this.attr
107                         .getMethodExpression(ctx, null, VALIDATOR_SIG)));
108             }
109             else
110             {
111                 ((EditableValueHolder) instance).addValidator(new MethodExpressionValidator(this.attr
112                         .getMethodExpression(ctx, null, VALIDATOR_SIG)));
113             }
114         }
115     }
116 
117     private final static Class<?>[] VALIDATOR_SIG = new Class[] { FacesContext.class, UIComponent.class, Object.class };
118 
119     private final static Class<?>[] VALUECHANGE_SIG = new Class[] { ValueChangeEvent.class };
120     
121     private final static Class<?>[] EMPTY_CLASS_ARRAY = new Class[0];
122 
123     public final static EditableValueHolderRule INSTANCE = new EditableValueHolderRule();
124 
125     public Metadata applyRule(String name, TagAttribute attribute, MetadataTarget meta)
126     {
127 
128         if (meta.isTargetInstanceOf(EditableValueHolder.class))
129         {
130 
131             if ("validator".equals(name))
132             {
133                 if (attribute.isLiteral())
134                 {
135                     return new LiteralValidatorMetadata(attribute.getValue());
136                 }
137                 else
138                 {
139                     return new ValidatorExpressionMetadata(attribute);
140                 }
141             }
142 
143             if ("valueChangeListener".equals(name))
144             {
145                 return new ValueChangedExpressionMetadata(attribute);
146             }
147 
148         }
149         return null;
150     }
151 
152 }