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  import java.util.ArrayList;
24  import java.util.Arrays;
25  import java.util.Collection;
26  import java.util.Collections;
27  import java.util.List;
28  import javax.el.ELException;
29  import javax.el.ValueExpression;
30  import javax.faces.FacesException;
31  import javax.faces.component.ActionSource;
32  import javax.faces.component.UIComponent;
33  import javax.faces.component.UIViewRoot;
34  import javax.faces.context.FacesContext;
35  import javax.faces.event.AbortProcessingException;
36  import javax.faces.event.ActionEvent;
37  import javax.faces.event.ActionListener;
38  import javax.faces.view.ActionSource2AttachedObjectHandler;
39  import javax.faces.view.AttachedObjectHandler;
40  import javax.faces.view.Location;
41  import javax.faces.view.facelets.ComponentHandler;
42  import javax.faces.view.facelets.FaceletContext;
43  import javax.faces.view.facelets.FaceletException;
44  import javax.faces.view.facelets.TagAttribute;
45  import javax.faces.view.facelets.TagConfig;
46  import javax.faces.view.facelets.TagException;
47  import javax.faces.view.facelets.TagHandler;
48  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFFaceletAttribute;
49  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFFaceletTag;
50  import org.apache.myfaces.shared.renderkit.JSFAttr;
51  import org.apache.myfaces.view.facelets.FaceletCompositionContext;
52  import org.apache.myfaces.view.facelets.el.CompositeComponentELUtils;
53  
54  /**
55   *
56   * @author Leonardo Uribe
57   */
58  @JSFFaceletTag(
59              name = "f:resetValues",
60              bodyContent = "empty")
61  public class ResetValuesActionListenerHandler extends TagHandler
62      implements ActionSource2AttachedObjectHandler
63  {
64      /**
65       * 
66       */
67      @JSFFaceletAttribute(name = "render", className = "javax.el.ValueExpression",
68                           deferredValueType = "java.lang.Object")
69      private final TagAttribute _render;
70      
71      private final Collection<String> _clientIds;
72  
73      public ResetValuesActionListenerHandler(TagConfig config)
74      {
75          super(config);
76          _render = getRequiredAttribute("render");
77          if (_render.isLiteral())
78          {
79              String value = _render.getValue();
80              if (value == null)
81              {
82                  _clientIds = Collections.emptyList();
83              }
84              else
85              {
86                  String[] arrValue = value.split(" ");
87                  _clientIds = Arrays.asList(arrValue);
88              }
89          }
90          else
91          {
92              _clientIds = null;
93          }
94      }
95  
96      /*
97       * (non-Javadoc)
98       * 
99       * @see javax.faces.view.facelets.FaceletHandler#apply(javax.faces.view.facelets.FaceletContext, javax.faces.component.UIComponent)
100      */
101     public void apply(FaceletContext ctx, UIComponent parent) throws IOException, FacesException, FaceletException,
102             ELException
103     {
104         //Apply only if we are creating a new component
105         if (!ComponentHandler.isNew(parent))
106         {
107             return;
108         }
109         if (parent instanceof ActionSource)
110         {
111             applyAttachedObject(ctx.getFacesContext(), parent, false);
112         }
113         else if (UIComponent.isCompositeComponent(parent))
114         {
115             if (getAttribute(JSFAttr.FOR_ATTR) == null)
116             {
117                 throw new TagException(tag, "is nested inside a composite component"
118                         + " but does not have a for attribute.");
119             }
120             FaceletCompositionContext mctx = FaceletCompositionContext.getCurrentInstance(ctx);
121             mctx.addAttachedObjectHandler(parent, this);
122         }
123         else
124         {
125             throw new TagException(this.tag,
126                     "Parent is not composite component or of type ActionSource, type is: " + parent);
127         }
128     }
129 
130     public void applyAttachedObject(FacesContext context, UIComponent parent)
131     {
132         applyAttachedObject(context, parent, true);
133     }
134     
135     public void applyAttachedObject(FacesContext context, UIComponent parent, boolean checkForParentCC)
136     {
137         UIComponent topParentComponent = null;
138         // Retrieve the current FaceletContext from FacesContext object
139         FaceletContext faceletContext = (FaceletContext) context.getAttributes().get(
140                 FaceletContext.FACELET_CONTEXT_KEY);
141         
142         if (checkForParentCC)
143         {
144             FaceletCompositionContext mctx = FaceletCompositionContext.getCurrentInstance(faceletContext);
145             UIComponent parentComponent = parent;
146             while (parentComponent != null)
147             {
148                 if (UIComponent.isCompositeComponent(parentComponent))
149                 {
150                     List<AttachedObjectHandler> handlerList = mctx.getAttachedObjectHandlers(parentComponent);
151                     if (handlerList != null && handlerList.contains(this))
152                     {
153                         //Found, but we need to go right to the top for it. 
154                         topParentComponent = parentComponent;
155                     }
156                 }
157                 parentComponent = parentComponent.getParent();
158             }
159         }
160 
161         ActionSource as = (ActionSource) parent;
162         ActionListener listener = null;
163         if (_render.isLiteral())
164         {
165             listener = new LiteralResetValuesActionListener(_clientIds,
166                 topParentComponent != null ? 
167                 (Location) topParentComponent.getAttributes().get(
168                     CompositeComponentELUtils.LOCATION_KEY) : null);
169         }
170         else
171         {
172             listener = new ResetValuesActionListener(_render
173                 .getValueExpression(faceletContext, Object.class) ,
174                 topParentComponent != null ? 
175                 (Location) topParentComponent.getAttributes().get(
176                     CompositeComponentELUtils.LOCATION_KEY) : null);
177         }
178         as.addActionListener(listener);
179     }
180 
181     /**
182      * TODO: Document me!
183      */
184     @JSFFaceletAttribute
185     public String getFor()
186     {
187         TagAttribute forAttribute = getAttribute("for");
188         
189         if (forAttribute == null)
190         {
191             return null;
192         }
193         else
194         {
195             return forAttribute.getValue();
196         }
197     }
198     
199     private final static class ResetValuesActionListener implements ActionListener, Serializable
200     {
201         private static final long serialVersionUID = -9200000013153262119L;
202 
203         private ValueExpression renderExpression;
204         
205         private Location topCompositeComponentReference;
206         
207         private ResetValuesActionListener()
208         {
209         }
210         
211         public ResetValuesActionListener(ValueExpression renderExpression, Location location)
212         {
213             this.renderExpression = renderExpression;
214             this.topCompositeComponentReference = location;
215         }
216 
217         public void processAction(ActionEvent event) throws AbortProcessingException
218         {
219             FacesContext faces = FacesContext.getCurrentInstance();
220             if (faces == null)
221             {
222                 return;
223             }
224             UIViewRoot root = faces.getViewRoot();
225             if (root == null)
226             {
227                 return;
228             }
229             Object value = renderExpression.getValue(faces.getELContext());
230             Collection<String> clientIds = null;
231             if (value == null)
232             {
233                 value = Collections.emptyList();
234             }
235             if (value instanceof Collection)
236             {
237                 clientIds = (Collection) value;
238             }
239             else if (value instanceof String)
240             {
241                 String[] arrValue = ((String)value).split(" ");
242                 clientIds = Arrays.asList(arrValue);
243             }
244             else
245             {
246                 throw new IllegalArgumentException("Type " + value.getClass()
247                         + " not supported for attribute render");
248             }
249             
250             // Calculate the final clientIds
251             UIComponent contextComponent = null;
252             if (topCompositeComponentReference != null)
253             {
254                 contextComponent = CompositeComponentELUtils.getCompositeComponentBasedOnLocation(
255                     faces, event.getComponent(), topCompositeComponentReference);
256                 if (contextComponent == null)
257                 {
258                     contextComponent = event.getComponent();
259                 }
260                 else
261                 {
262                     contextComponent = contextComponent.getParent();
263                 }
264             }
265             else
266             {
267                 contextComponent = event.getComponent();
268             }
269             List<String> list = new ArrayList<String>();
270             for (String id : clientIds)
271             {
272                 list.add(getComponentId(faces, contextComponent, id));
273             }
274             
275             // Call resetValues
276             root.resetValues(faces, list);
277         }
278     }
279     
280     private final static class LiteralResetValuesActionListener implements ActionListener, Serializable
281     {
282         private static final long serialVersionUID = -9200000013153262119L;
283 
284         private Collection<String> clientIds;
285         
286         private Location topCompositeComponentReference;
287         
288         private LiteralResetValuesActionListener()
289         {
290         }
291         
292         public LiteralResetValuesActionListener(Collection<String> clientIds, Location location)
293         {
294             this.clientIds = clientIds;
295             this.topCompositeComponentReference = location;
296         }
297 
298         public void processAction(ActionEvent event) throws AbortProcessingException
299         {
300             FacesContext faces = FacesContext.getCurrentInstance();
301             if (faces == null)
302             {
303                 return;
304             }
305             UIViewRoot root = faces.getViewRoot();
306             if (root == null)
307             {
308                 return;
309             }
310             
311             // Calculate the final clientIds
312             UIComponent contextComponent = null;
313             if (topCompositeComponentReference != null)
314             {
315                 contextComponent = CompositeComponentELUtils.getCompositeComponentBasedOnLocation(
316                     faces, event.getComponent(), topCompositeComponentReference);
317                 if (contextComponent == null)
318                 {
319                     contextComponent = event.getComponent();
320                 }
321                 else
322                 {
323                     contextComponent = contextComponent.getParent();
324                 }
325             }
326             else
327             {
328                 contextComponent = event.getComponent();
329             }
330             List<String> list = new ArrayList<String>();
331             for (String id : clientIds)
332             {
333                 list.add(getComponentId(faces, contextComponent, id));
334             }
335             
336             root.resetValues(faces, list);
337         }
338     }
339     
340     private static final String getComponentId(FacesContext facesContext, 
341         UIComponent contextComponent, String id)
342     {
343         UIComponent target = contextComponent.findComponent(id);
344         if (target == null)
345         {
346             target = contextComponent.findComponent(
347                 facesContext.getNamingContainerSeparatorChar() + id);
348         }
349         if (target != null)
350         {
351             return target.getClientId(facesContext);
352         }
353         return id;
354     }
355 }