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.ELException;
25  import javax.el.ValueExpression;
26  import javax.faces.FacesException;
27  import javax.faces.component.ActionSource;
28  import javax.faces.component.UIComponent;
29  import javax.faces.context.FacesContext;
30  import javax.faces.event.AbortProcessingException;
31  import javax.faces.event.ActionEvent;
32  import javax.faces.event.ActionListener;
33  import javax.faces.view.ActionSource2AttachedObjectHandler;
34  import javax.faces.view.facelets.ComponentHandler;
35  import javax.faces.view.facelets.FaceletContext;
36  import javax.faces.view.facelets.FaceletException;
37  import javax.faces.view.facelets.TagAttribute;
38  import javax.faces.view.facelets.TagAttributeException;
39  import javax.faces.view.facelets.TagConfig;
40  import javax.faces.view.facelets.TagException;
41  import javax.faces.view.facelets.TagHandler;
42  
43  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFFaceletAttribute;
44  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFFaceletTag;
45  import org.apache.myfaces.shared.renderkit.JSFAttr;
46  import org.apache.myfaces.view.facelets.FaceletCompositionContext;
47  import org.apache.myfaces.view.facelets.util.ReflectionUtil;
48  
49  /**
50   * Register an ActionListener instance on the UIComponent associated with the closest parent UIComponent custom action.
51   * <p/> See <a target="_new"
52   * href="http://java.sun.com/j2ee/javaserverfaces/1.1_01/docs/tlddocs/f/actionListener.html">tag documentation</a>.
53   * 
54   * @see javax.faces.event.ActionListener
55   * @see javax.faces.component.ActionSource
56   * @author Jacob Hookom
57   * @version $Id$
58   */
59  @JSFFaceletTag(
60              name = "f:actionListener",
61              bodyContent = "empty", 
62              tagClass="org.apache.myfaces.taglib.core.ActionListenerTag")
63  public final class ActionListenerHandler extends TagHandler
64      implements ActionSource2AttachedObjectHandler 
65  {
66  
67      private final static class LazyActionListener implements ActionListener, Serializable
68      {
69  
70          private static final long serialVersionUID = -9202120013153262119L;
71  
72          private final String type;
73          private final ValueExpression binding;
74  
75          public LazyActionListener(String type, ValueExpression binding)
76          {
77              this.type = type;
78              this.binding = binding;
79          }
80  
81          public void processAction(ActionEvent event) throws AbortProcessingException
82          {
83              ActionListener instance = null;
84              FacesContext faces = FacesContext.getCurrentInstance();
85              if (faces == null)
86              {
87                  return;
88              }
89              if (this.binding != null)
90              {
91                  instance = (ActionListener) binding.getValue(faces.getELContext());
92              }
93              if (instance == null && this.type != null)
94              {
95                  try
96                  {
97                      instance = (ActionListener) ReflectionUtil.forName(this.type).newInstance();
98                  }
99                  catch (Exception e)
100                 {
101                     throw new AbortProcessingException("Couldn't Lazily instantiate ValueChangeListener", e);
102                 }
103                 if (this.binding != null)
104                 {
105                     binding.setValue(faces.getELContext(), instance);
106                 }
107             }
108             if (instance != null)
109             {
110                 instance.processAction(event);
111             }
112         }
113     }
114 
115     private final TagAttribute binding;
116 
117     private final String listenerType;
118 
119     /**
120      * @param config
121      */
122     public ActionListenerHandler(TagConfig config)
123     {
124         super(config);
125         this.binding = this.getAttribute("binding");
126         TagAttribute type = this.getAttribute("type");
127         if (type != null)
128         {
129             if (!type.isLiteral())
130             {
131                 throw new TagAttributeException(type, "Must be a literal class name of type ActionListener");
132             }
133             else
134             {
135                 // test it out
136                 try
137                 {
138                     ReflectionUtil.forName(type.getValue());
139                 }
140                 catch (ClassNotFoundException e)
141                 {
142                     throw new TagAttributeException(type, "Couldn't qualify ActionListener", e);
143                 }
144             }
145             this.listenerType = type.getValue();
146         }
147         else
148         {
149             this.listenerType = null;
150         }
151     }
152 
153     /*
154      * (non-Javadoc)
155      * 
156      * @see javax.faces.view.facelets.FaceletHandler#apply(javax.faces.view.facelets.FaceletContext, javax.faces.component.UIComponent)
157      */
158     public void apply(FaceletContext ctx, UIComponent parent) throws IOException, FacesException, FaceletException,
159             ELException
160     {
161         //Apply only if we are creating a new component
162         if (!ComponentHandler.isNew(parent))
163         {
164             return;
165         }
166         if (parent instanceof ActionSource)
167         {
168             applyAttachedObject(ctx.getFacesContext(), parent);
169         }
170         else if (UIComponent.isCompositeComponent(parent))
171         {
172             if (getAttribute(JSFAttr.FOR_ATTR) == null)
173             {
174                 throw new TagException(tag, "is nested inside a composite component"
175                         + " but does not have a for attribute.");
176             }
177             FaceletCompositionContext mctx = FaceletCompositionContext.getCurrentInstance(ctx);
178             mctx.addAttachedObjectHandler(parent, this);
179         }
180         else
181         {
182             throw new TagException(this.tag,
183                     "Parent is not composite component or of type ActionSource, type is: " + parent);
184         }
185     }
186 
187     public void applyAttachedObject(FacesContext context, UIComponent parent)
188     {
189         // Retrieve the current FaceletContext from FacesContext object
190         FaceletContext faceletContext = (FaceletContext) context.getAttributes().get(
191                 FaceletContext.FACELET_CONTEXT_KEY);
192 
193         ActionSource as = (ActionSource) parent;
194         ValueExpression b = null;
195         if (this.binding != null)
196         {
197             b = this.binding.getValueExpression(faceletContext, ActionListener.class);
198         }
199         ActionListener listener = new LazyActionListener(this.listenerType, b);
200         as.addActionListener(listener);
201     }
202 
203     /**
204      * TODO: Document me!
205      */
206     @JSFFaceletAttribute
207     public String getFor()
208     {
209         TagAttribute forAttribute = getAttribute("for");
210         
211         if (forAttribute == null)
212         {
213             return null;
214         }
215         else
216         {
217             return forAttribute.getValue();
218         }
219     }
220 }