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