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