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.core;
20  
21  import java.io.IOException;
22  import java.io.Serializable;
23  
24  import javax.el.ELContext;
25  import javax.el.ELException;
26  import javax.el.ExpressionFactory;
27  import javax.el.ValueExpression;
28  import javax.faces.FacesException;
29  import javax.faces.component.ActionSource;
30  import javax.faces.component.UIComponent;
31  import javax.faces.context.FacesContext;
32  import javax.faces.event.AbortProcessingException;
33  import javax.faces.event.ActionEvent;
34  import javax.faces.event.ActionListener;
35  import javax.faces.view.ActionSource2AttachedObjectHandler;
36  import javax.faces.view.Location;
37  import javax.faces.view.facelets.ComponentHandler;
38  import javax.faces.view.facelets.FaceletContext;
39  import javax.faces.view.facelets.FaceletException;
40  import javax.faces.view.facelets.TagAttribute;
41  import javax.faces.view.facelets.TagConfig;
42  import javax.faces.view.facelets.TagException;
43  import javax.faces.view.facelets.TagHandler;
44  
45  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFFaceletAttribute;
46  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFFaceletTag;
47  import org.apache.myfaces.view.facelets.FaceletCompositionContext;
48  import org.apache.myfaces.view.facelets.el.ContextAware;
49  import org.apache.myfaces.view.facelets.el.ContextAwareELException;
50  
51  @JSFFaceletTag(
52          name = "f:setPropertyActionListener",
53          bodyContent = "empty", 
54          tagClass="org.apache.myfaces.taglib.core.SetPropertyActionListenerTag")
55  public class SetPropertyActionListenerHandler extends TagHandler
56      implements ActionSource2AttachedObjectHandler 
57  {
58      private final TagAttribute _target;
59      private final TagAttribute _value;
60  
61      public SetPropertyActionListenerHandler(TagConfig config)
62      {
63          super(config);
64          this._value = this.getRequiredAttribute("value");
65          this._target = this.getRequiredAttribute("target");
66      }
67  
68      public void apply(FaceletContext ctx, UIComponent parent)
69              throws IOException, FacesException, FaceletException, ELException
70      {
71          //Apply only if we are creating a new component
72          if (!ComponentHandler.isNew(parent))
73          {
74              return;
75          }
76          if (parent instanceof ActionSource)
77          {
78              applyAttachedObject(ctx.getFacesContext(), parent);
79          }
80          else if (UIComponent.isCompositeComponent(parent))
81          {
82              FaceletCompositionContext mctx = FaceletCompositionContext.getCurrentInstance(ctx);
83              mctx.addAttachedObjectHandler(parent, this);
84          }
85          else
86          {
87              throw new TagException(this.tag,
88                      "Parent is not composite component or of type ActionSource, type is: " + parent);
89          }
90      }
91  
92      private static class SetPropertyListener implements ActionListener, Serializable
93      {
94          private ValueExpression _target;
95          private ValueExpression _value;
96  
97          public SetPropertyListener()
98          {
99          };
100 
101         public SetPropertyListener(ValueExpression value, ValueExpression target)
102         {
103             _value = value;
104             _target = target;
105         }
106 
107         public void processAction(ActionEvent evt) throws AbortProcessingException
108         {
109             FacesContext facesContext = FacesContext.getCurrentInstance();
110             
111             ELContext elContext = facesContext.getELContext();
112             
113             // Spec f:setPropertyActionListener: 
114             
115             // Call getValue() on the "value" ValueExpression.
116             Object value = _value.getValue(elContext);
117             
118             // If value of the "value" expression is null, call setValue() on the "target" ValueExpression with the null
119             
120             // If the value of the "value" expression is not null, call getType()on the "value" and "target"
121             // ValueExpressions to determine their property types.
122             if (value != null)
123             {
124                 Class<?> targetType = _target.getType(elContext);
125                 // Spec says: "all getType() on the "value" to determine  property type" but it is not necessary
126                 // beacuse type we have objValue already
127 
128                 //   Coerce the value of the "value" expression to
129                 // the "target" expression value type following the Expression
130                 // Language coercion rules. 
131                 ExpressionFactory expressionFactory = facesContext.getApplication().getExpressionFactory();
132                 try
133                 {
134                     value = expressionFactory.coerceToType(value, targetType);
135                 }
136                 catch (ELException e)
137                 {
138                     // Happens when type of attribute "value" is not convertible to type of attribute "target"
139                     // by EL coercion rules. 
140                     // For example: value="#{10}" target="#{bean.booleanProperty}" 
141                     // In this case is not sure if problematic attribute is "value" or "target". But EL
142                     // impls say:
143                     // JUEL: "Cannot coerce from class java.lang.Long to class java.lang.Boolean"
144                     // Tomcat EL: Cannot convert 10 of type class java.long.Long to class java.lang.Boolean
145                     // Thus we report "value" attribute as exception source - that should be enough for user
146                     // to solve the problem.
147                     Location location = null;
148                     // Wrapping of ValueExpressions to org.apache.myfaces.view.facelets.el.ContextAware
149                     // can be disabled:
150                     if (_value instanceof ContextAware)
151                     {
152                         ContextAware contextAware = (ContextAware) _value;
153                         location = contextAware.getLocation();
154                     }
155                     throw new ContextAwareELException(location,
156                             _value.getExpressionString(), "value", e);
157                 }
158             }
159 
160             // Call setValue()on the "target" ValueExpression with the resulting value.
161             _target.setValue(elContext, value);
162         }
163     }
164 
165     public void applyAttachedObject(FacesContext context, UIComponent parent)
166     {
167         // Retrieve the current FaceletContext from FacesContext object
168         FaceletContext faceletContext = (FaceletContext) context.getAttributes().get(
169                 FaceletContext.FACELET_CONTEXT_KEY);
170 
171         ActionSource src = (ActionSource) parent;
172         ValueExpression valueExpr = _value.getValueExpression(faceletContext, Object.class);
173         ValueExpression targetExpr = _target.getValueExpression(faceletContext, Object.class);
174 
175         src.addActionListener(new SetPropertyListener(valueExpr, targetExpr));
176     }
177 
178     /**
179      * TODO: Document me!
180      */
181     @JSFFaceletAttribute
182     public String getFor()
183     {
184         TagAttribute forAttribute = getAttribute("for");
185         
186         if (forAttribute == null)
187         {
188             return null;
189         }
190         else
191         {
192             return forAttribute.getValue();
193         }
194     }
195 }