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 java.io.IOException;
22  import java.util.logging.Level;
23  import java.util.logging.Logger;
24  
25  import javax.el.ELException;
26  import javax.el.ValueExpression;
27  import javax.faces.FacesException;
28  import javax.faces.application.Application;
29  import javax.faces.component.ActionSource;
30  import javax.faces.component.EditableValueHolder;
31  import javax.faces.component.UIComponent;
32  import javax.faces.component.UIViewRoot;
33  import javax.faces.component.ValueHolder;
34  import javax.faces.context.FacesContext;
35  import javax.faces.view.facelets.ComponentConfig;
36  import javax.faces.view.facelets.FaceletContext;
37  import javax.faces.view.facelets.MetaRuleset;
38  import javax.faces.view.facelets.MetaTagHandler;
39  import javax.faces.view.facelets.TagAttribute;
40  import javax.faces.view.facelets.TagException;
41  
42  import org.apache.myfaces.view.facelets.tag.MetaRulesetImpl;
43  
44  /**
45   * Implementation of the tag logic used in the JSF specification. This is your golden hammer for wiring UIComponents to
46   * Facelets.
47   * 
48   * @deprecated Use javax.faces.view.facelets.ComponentHandler instead
49   * @author Jacob Hookom
50   * @version $Id$
51   */
52  @Deprecated
53  public class ComponentHandler extends MetaTagHandler
54  {
55  
56      //private final static Logger log = Logger.getLogger("facelets.tag.component");
57      private final static Logger log = Logger.getLogger(ComponentHandler.class.getName());
58  
59      private final TagAttribute binding;
60  
61      private final String componentType;
62  
63      private final TagAttribute id;
64  
65      private final String rendererType;
66  
67      public ComponentHandler(ComponentConfig config)
68      {
69          super(config);
70          this.componentType = config.getComponentType();
71          this.rendererType = config.getRendererType();
72          this.id = this.getAttribute("id");
73          this.binding = this.getAttribute("binding");
74      }
75  
76      /**
77       * Method handles UIComponent tree creation in accordance with the JSF 1.2 spec.
78       * <ol>
79       * <li>First determines this UIComponent's id by calling {@link #getId(FaceletContext) getId(FaceletContext)}.</li>
80       * <li>Search the parent for an existing UIComponent of the id we just grabbed</li>
81       * <li>If found, {@link #markForDeletion(UIComponent) mark} its children for deletion.</li>
82       * <li>If <i>not</i> found, call {@link #createComponent(FaceletContext) createComponent}.
83       * <ol>
84       * <li>Only here do we apply {@link ObjectHandler#setAttributes(FaceletContext, Object) attributes}</li>
85       * <li>Set the UIComponent's id</li>
86       * <li>Set the RendererType of this instance</li>
87       * </ol>
88       * </li>
89       * <li>Now apply the nextHandler, passing the UIComponent we've created/found.</li>
90       * <li>Now add the UIComponent to the passed parent</li>
91       * <li>Lastly, if the UIComponent already existed (found), then {@link #finalizeForDeletion(UIComponent) finalize}
92       * for deletion.</li>
93       * </ol>
94       * 
95       * @see javax.faces.view.facelets.FaceletHandler#apply(javax.faces.view.facelets.FaceletContext, javax.faces.component.UIComponent)
96       * 
97       * @throws TagException
98       *             if the UIComponent parent is null
99       */
100     public final void apply(FaceletContext ctx, UIComponent parent) throws IOException, FacesException, ELException
101     {
102         // make sure our parent is not null
103         if (parent == null)
104         {
105             throw new TagException(this.tag, "Parent UIComponent was null");
106         }
107 
108         // possible facet scoped
109         String facetName = this.getFacetName(ctx, parent);
110 
111         // our id
112         String id = ctx.generateUniqueId(this.tagId);
113 
114         // grab our component
115         UIComponent c = ComponentSupport.findChildByTagId(parent, id);
116         boolean componentFound = false;
117         if (c != null)
118         {
119             componentFound = true;
120             // mark all children for cleaning
121             if (log.isLoggable(Level.FINE))
122             {
123                 log.fine(this.tag + " Component[" + id + "] Found, marking children for cleanup");
124             }
125             ComponentSupport.markForDeletion(c);
126         }
127         else
128         {
129             c = this.createComponent(ctx);
130             if (log.isLoggable(Level.FINE))
131             {
132                 log.fine(this.tag + " Component[" + id + "] Created: " + c.getClass().getName());
133             }
134             this.setAttributes(ctx, c);
135 
136             // mark it owned by a facelet instance
137             c.getAttributes().put(ComponentSupport.MARK_CREATED, id);
138 
139             // assign our unique id
140             if (this.id != null)
141             {
142                 c.setId(this.id.getValue(ctx));
143             }
144             else
145             {
146                 UIViewRoot root = ComponentSupport.getViewRoot(ctx, parent);
147                 if (root != null)
148                 {
149                     String uid = root.createUniqueId();
150                     c.setId(uid);
151                 }
152             }
153 
154             if (this.rendererType != null)
155             {
156                 c.setRendererType(this.rendererType);
157             }
158 
159             // hook method
160             this.onComponentCreated(ctx, c, parent);
161         }
162 
163         // first allow c to get populated
164         this.applyNextHandler(ctx, c);
165 
166         // finish cleaning up orphaned children
167         if (componentFound)
168         {
169             ComponentSupport.finalizeForDeletion(c);
170 
171             if (facetName == null)
172             {
173                 parent.getChildren().remove(c);
174             }
175         }
176 
177         this.onComponentPopulated(ctx, c, parent);
178 
179         // add to the tree afterwards
180         // this allows children to determine if it's
181         // been part of the tree or not yet
182         if (facetName == null)
183         {
184             parent.getChildren().add(c);
185         }
186         else
187         {
188             parent.getFacets().put(facetName, c);
189         }
190     }
191 
192     /**
193      * Return the Facet name we are scoped in, otherwise null
194      * 
195      * @param ctx
196      * @return
197      */
198     protected final String getFacetName(FaceletContext ctx, UIComponent parent)
199     {
200         // TODO: REFACTOR - "facelets.FACET_NAME" should be a constant somewhere, used to be in FacetHandler
201         //                  from real Facelets
202         return (String) parent.getAttributes().get("facelets.FACET_NAME");
203     }
204 
205     /**
206      * If the binding attribute was specified, use that in conjuction with our componentType String variable to call
207      * createComponent on the Application, otherwise just pass the componentType String. <p /> If the binding was used,
208      * then set the ValueExpression "binding" on the created UIComponent.
209      * 
210      * @see Application#createComponent(javax.faces.el.ValueBinding, javax.faces.context.FacesContext, java.lang.String)
211      * @see Application#createComponent(java.lang.String)
212      * @param ctx
213      *            FaceletContext to use in creating a component
214      * @return
215      */
216     protected UIComponent createComponent(FaceletContext ctx)
217     {
218         UIComponent c = null;
219         FacesContext faces = ctx.getFacesContext();
220         Application app = faces.getApplication();
221         if (this.binding != null)
222         {
223             ValueExpression ve = this.binding.getValueExpression(ctx, Object.class);
224             
225             c = app.createComponent(ve, faces, this.componentType);
226             if (c != null)
227             {
228                 c.setValueExpression("binding", ve);
229             }
230         }
231         else
232         {
233             c = app.createComponent(this.componentType);
234         }
235         return c;
236     }
237 
238     /**
239      * If the id TagAttribute was specified, get it's value, otherwise generate a unique id from our tagId.
240      * 
241      * @see TagAttribute#getValue(FaceletContext)
242      * @param ctx
243      *            FaceletContext to use
244      * @return what should be a unique Id
245      */
246     protected String getId(FaceletContext ctx)
247     {
248         if (this.id != null)
249         {
250             return this.id.getValue(ctx);
251         }
252         return ctx.generateUniqueId(this.tagId);
253     }
254 
255     @Override
256     protected MetaRuleset createMetaRuleset(Class type)
257     {
258         /*MetaRuleset m = super.createMetaRuleset(type);
259 
260         // ignore standard component attributes
261         m.ignore("binding").ignore("id");
262 
263         // add auto wiring for attributes
264         m.addRule(ComponentRule.Instance);
265 
266         // if it's an ActionSource
267         if (ActionSource.class.isAssignableFrom(type))
268         {
269             m.addRule(ActionSourceRule.Instance);
270         }
271 
272         // if it's a ValueHolder
273         if (ValueHolder.class.isAssignableFrom(type))
274         {
275             m.addRule(ValueHolderRule.Instance);
276 
277             // if it's an EditableValueHolder
278             if (EditableValueHolder.class.isAssignableFrom(type))
279             {
280                 m.ignore("submittedValue");
281                 m.ignore("valid");
282                 m.addRule(EditableValueHolderRule.Instance);
283             }
284         }
285 
286         return m;*/
287         
288         // FIXME: Implement correctly
289         // temporally restore code
290         MetaRuleset m = new MetaRulesetImpl(this.tag, type);
291         // ignore standard component attributes
292         m.ignore("binding").ignore("id");
293 
294         // add auto wiring for attributes
295         m.addRule(ComponentRule.INSTANCE);
296 
297         // if it's an ActionSource
298         if (ActionSource.class.isAssignableFrom(type))
299         {
300             m.addRule(ActionSourceRule.INSTANCE);
301         }
302 
303         // if it's a ValueHolder
304         if (ValueHolder.class.isAssignableFrom(type))
305         {
306             m.addRule(ValueHolderRule.INSTANCE);
307 
308             // if it's an EditableValueHolder
309             if (EditableValueHolder.class.isAssignableFrom(type))
310             {
311                 m.ignore("submittedValue");
312                 m.ignore("valid");
313                 m.addRule(EditableValueHolderRule.INSTANCE);
314             }
315         }
316         
317         return m;
318     }
319 
320     /**
321      * A hook method for allowing developers to do additional processing once Facelets creates the component. The
322      * 'setAttributes' method is still perferred, but this method will provide the parent UIComponent before it's been
323      * added to the tree and before any children have been added to the newly created UIComponent.
324      * 
325      * @param ctx
326      * @param c
327      * @param parent
328      */
329     protected void onComponentCreated(FaceletContext ctx, UIComponent c, UIComponent parent)
330     {
331         // do nothing
332     }
333 
334     protected void onComponentPopulated(FaceletContext ctx, UIComponent c, UIComponent parent)
335     {
336         // do nothing
337     }
338 
339     protected void applyNextHandler(FaceletContext ctx, UIComponent c) throws IOException, FacesException, ELException
340     {
341         // first allow c to get populated
342         this.nextHandler.apply(ctx, c);
343     }
344 }