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.ActionSource;
23  import javax.faces.component.ActionSource2;
24  import javax.faces.event.ActionEvent;
25  import javax.faces.event.MethodExpressionActionListener;
26  import javax.faces.view.facelets.FaceletContext;
27  import javax.faces.view.facelets.MetaRule;
28  import javax.faces.view.facelets.Metadata;
29  import javax.faces.view.facelets.MetadataTarget;
30  import javax.faces.view.facelets.TagAttribute;
31  
32  import org.apache.myfaces.view.facelets.AbstractFaceletContext;
33  import org.apache.myfaces.view.facelets.FaceletCompositionContext;
34  import org.apache.myfaces.view.facelets.el.LegacyMethodBinding;
35  
36  /**
37   * 
38   * @author Jacob Hookom
39   * @version $Id: ActionSourceRule.java 1187700 2011-10-22 12:19:37Z bommel $
40   */
41  public final class ActionSourceRule extends MetaRule
42  {
43      public final static Class<?>[] ACTION_SIG = new Class[0];
44  
45      public final static Class<?>[] ACTION_LISTENER_SIG = new Class<?>[] { ActionEvent.class };
46  
47      final static class ActionMapper extends Metadata {
48  
49          private final TagAttribute attr;
50  
51          public ActionMapper(TagAttribute attr) {
52              this.attr = attr;
53          }
54  
55          public void applyMetadata(FaceletContext ctx, Object instance) {
56              ((ActionSource) instance).setAction(new LegacyMethodBinding(
57                      this.attr.getMethodExpression(ctx, null,
58                              ActionSourceRule.ACTION_SIG)));
59          }
60      }
61      
62      final static class ActionMapper2 extends Metadata
63      {
64          private final TagAttribute _attr;
65  
66          public ActionMapper2(TagAttribute attr)
67          {
68              this._attr = attr;
69          }
70  
71          public void applyMetadata(FaceletContext ctx, Object instance)
72          {
73              MethodExpression expr = _attr.getMethodExpression(ctx, null, ActionSourceRule.ACTION_SIG);
74              ((ActionSource2) instance).setActionExpression(expr);
75          }
76      }
77  
78      final static class ActionListenerMapper extends Metadata {
79  
80          private final TagAttribute attr;
81  
82          public ActionListenerMapper(TagAttribute attr) {
83              this.attr = attr;
84          }
85  
86          public void applyMetadata(FaceletContext ctx, Object instance) {
87              ((ActionSource) instance)
88                      .setActionListener(new LegacyMethodBinding(this.attr
89                              .getMethodExpression(ctx, null,
90                                      ActionSourceRule.ACTION_LISTENER_SIG)));
91          }
92  
93      }
94  
95      final static class ActionListenerMapper2 extends Metadata
96      {
97          private final TagAttribute _attr;
98  
99          public ActionListenerMapper2(TagAttribute attr)
100         {
101             _attr = attr;
102         }
103 
104         public void applyMetadata(FaceletContext ctx, Object instance)
105         {
106             // From JSF 2.0 it is possible to have actionListener method without ActionEvent parameter. 
107             // It seems that MethodExpressionActionListener from API contains support for it but there is one big
108             // problem - one-arg constructor will not preserve the current VariableMapper.
109             // This is a problem when using facelets and <ui:decorate/> with EL params (see MYFACES-2541 for details).
110             // So we must create two MethodExpressions here - both are created from the current 
111             // facelets context and thus varibale mapping will work.
112             final MethodExpression methodExpressionOneArg = _attr.getMethodExpression(ctx, null, ActionSourceRule.ACTION_LISTENER_SIG);
113             final MethodExpression methodExpressionZeroArg = _attr.getMethodExpression(ctx, null, ActionSourceRule.ACTION_SIG);
114             if (FaceletCompositionContext.getCurrentInstance(ctx).isUsingPSSOnThisView())
115             {
116                 ((ActionSource2) instance).addActionListener(
117                         new PartialMethodExpressionActionListener(methodExpressionOneArg, methodExpressionZeroArg));
118             }
119             else
120             {
121                 ((ActionSource2) instance).addActionListener(
122                         new MethodExpressionActionListener(methodExpressionOneArg, methodExpressionZeroArg));
123             }
124         }
125     }
126 
127     public final static ActionSourceRule Instance = new ActionSourceRule();
128 
129     public ActionSourceRule()
130     {
131         super();
132     }
133 
134     public Metadata applyRule(String name, TagAttribute attribute, MetadataTarget meta)
135     {
136         if (meta.isTargetInstanceOf(ActionSource.class))
137         {
138             if ("action".equals(name))
139             {
140                 if (meta.isTargetInstanceOf(ActionSource2.class))
141                 {
142                     return new ActionMapper2(attribute);
143                 }
144                 else
145                 {
146                     return new ActionMapper(attribute);
147                 }
148             }
149 
150             if ("actionListener".equals(name))
151             {
152                 if (meta.isTargetInstanceOf(ActionSource2.class))
153                 {
154                     return new ActionListenerMapper2(attribute);
155                 }
156                 else
157                 {
158                     return new ActionListenerMapper(attribute);
159                 }
160             }
161         }
162         
163         return null;
164     }
165 }