Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/sun/facelets/tag/jsf/ComponentHandler.java


1   /**
2    * Licensed under the Common Development and Distribution License,
3    * you may not use this file except in compliance with the License.
4    * You may obtain a copy of the License at
5    * 
6    *   http://www.sun.com/cddl/
7    *   
8    * Unless required by applicable law or agreed to in writing, software
9    * distributed under the License is distributed on an "AS IS" BASIS,
10   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 
11   * implied. See the License for the specific language governing
12   * permissions and limitations under the License.
13   */
14  
15  package com.sun.facelets.tag.jsf;
16  
17  import java.io.IOException;
18  import java.util.logging.Level;
19  import java.util.logging.Logger;
20  
21  import javax.el.ELException;
22  import javax.el.MethodExpression;
23  import javax.el.ValueExpression;
24  import javax.faces.FacesException;
25  import javax.faces.application.Application;
26  import javax.faces.component.ActionSource;
27  import javax.faces.component.ActionSource2;
28  import javax.faces.component.EditableValueHolder;
29  import javax.faces.component.UIComponent;
30  import javax.faces.component.UIViewRoot;
31  import javax.faces.component.ValueHolder;
32  import javax.faces.context.FacesContext;
33  import javax.faces.convert.Converter;
34  import javax.faces.el.ValueBinding;
35  import javax.faces.event.ActionEvent;
36  import javax.faces.event.MethodExpressionActionListener;
37  import javax.faces.event.MethodExpressionValueChangeListener;
38  import javax.faces.event.ValueChangeEvent;
39  import javax.faces.validator.MethodExpressionValidator;
40  
41  import com.sun.facelets.FaceletContext;
42  import com.sun.facelets.el.ELAdaptor;
43  import com.sun.facelets.el.LegacyMethodBinding;
44  import com.sun.facelets.el.LegacyValueBinding;
45  import com.sun.facelets.tag.MetaTagHandler;
46  import com.sun.facelets.tag.TagAttribute;
47  import com.sun.facelets.tag.Metadata;
48  import com.sun.facelets.tag.TagException;
49  import com.sun.facelets.tag.TagHandler;
50  import com.sun.facelets.tag.MetaRuleset;
51  import com.sun.facelets.util.FacesAPI;
52  
53  /**
54   * Implementation of the tag logic used in the JSF specification. This is your
55   * golden hammer for wiring UIComponents to Facelets.
56   * 
57   * @author Jacob Hookom
58   * @version $Id: ComponentHandler.java,v 1.14 2006/03/29 15:01:22 jhook Exp $
59   */
60  public class ComponentHandler extends MetaTagHandler {
61  
62      private final static Logger log = Logger
63              .getLogger("facelets.tag.component");
64      
65      private final TagAttribute binding;
66  
67      private final String componentType;
68  
69      private final TagAttribute id;
70  
71      private final String rendererType;
72  
73      public ComponentHandler(ComponentConfig config) {
74          super(config);
75          this.componentType = config.getComponentType();
76          this.rendererType = config.getRendererType();
77          this.id = this.getAttribute("id");
78          this.binding = this.getAttribute("binding");
79      }
80  
81      /**
82       * Method handles UIComponent tree creation in accordance with the JSF 1.2
83       * spec.
84       * <ol>
85       * <li>First determines this UIComponent's id by calling
86       * {@link #getId(FaceletContext) getId(FaceletContext)}.</li>
87       * <li>Search the parent for an existing UIComponent of the id we just
88       * grabbed</li>
89       * <li>If found, {@link #markForDeletion(UIComponent) mark} its children
90       * for deletion.</li>
91       * <li>If <i>not</i> found, call
92       * {@link #createComponent(FaceletContext) createComponent}.
93       * <ol>
94       * <li>Only here do we apply
95       * {@link ObjectHandler#setAttributes(FaceletContext, Object) attributes}</li>
96       * <li>Set the UIComponent's id</li>
97       * <li>Set the RendererType of this instance</li>
98       * </ol>
99       * </li>
100      * <li>Now apply the nextHandler, passing the UIComponent we've
101      * created/found.</li>
102      * <li>Now add the UIComponent to the passed parent</li>
103      * <li>Lastly, if the UIComponent already existed (found), then
104      * {@link #finalizeForDeletion(UIComponent) finalize} for deletion.</li>
105      * </ol>
106      * 
107      * @see com.sun.facelets.FaceletHandler#apply(com.sun.facelets.FaceletContext,
108      *      javax.faces.component.UIComponent)
109      * 
110      * @throws TagException
111      *             if the UIComponent parent is null
112      */
113     public final void apply(FaceletContext ctx, UIComponent parent)
114             throws IOException, FacesException, ELException {
115         // make sure our parent is not null
116         if (parent == null) {
117             throw new TagException(this.tag, "Parent UIComponent was null");
118         }
119 
120         // our id
121         String id = ctx.generateUniqueId(this.tagId);
122 
123         // grab our component
124         UIComponent c = ComponentSupport.findChildByTagId(parent, id);
125         boolean componentFound = false;
126         if (c != null) {
127             componentFound = true;
128             // mark all children for cleaning
129             if (log.isLoggable(Level.FINE)) {
130                 log.fine(this.tag
131                         + " Component["+id+"] Found, marking children for cleanup");
132             }
133             ComponentSupport.markForDeletion(c);
134         } else {
135             c = this.createComponent(ctx);
136             if (log.isLoggable(Level.FINE)) {
137                 log.fine(this.tag + " Component["+id+"] Created: "
138                         + c.getClass().getName());
139             }
140             this.setAttributes(ctx, c);
141             
142             // mark it owned by a facelet instance
143             c.getAttributes().put(ComponentSupport.MARK_CREATED, id);
144             
145             // assign our unique id
146             if (this.id != null) {
147                 c.setId(this.id.getValue(ctx));
148             } else {
149                 UIViewRoot root = ComponentSupport.getViewRoot(ctx, parent);
150                 if (root != null) {
151                     String uid = root.createUniqueId();
152                     c.setId(uid);
153                 }
154             }
155             
156             if (this.rendererType != null) {
157                 c.setRendererType(this.rendererType);
158             }
159             
160             // hook method
161             this.onComponentCreated(ctx, c, parent);
162         }
163 
164         // first allow c to get populated
165         this.applyNextHandler(ctx, c);
166 
167         // finish cleaning up orphaned children
168         if (componentFound) {
169             ComponentSupport.finalizeForDeletion(c);
170             parent.getChildren().remove(c);
171         }
172         
173 
174         this.onComponentPopulated(ctx, c, parent);
175 
176         // add to the tree afterwards
177         // this allows children to determine if it's
178         // been part of the tree or not yet
179         parent.getChildren().add(c);
180     }
181 
182     /**
183      * If the binding attribute was specified, use that in conjuction with our
184      * componentType String variable to call createComponent on the Application,
185      * otherwise just pass the componentType String.
186      * <p />
187      * If the binding was used, then set the ValueExpression "binding" on the
188      * created UIComponent.
189      * 
190      * @see Application#createComponent(javax.faces.el.ValueBinding,
191      *      javax.faces.context.FacesContext, java.lang.String)
192      * @see Application#createComponent(java.lang.String)
193      * @param ctx
194      *            FaceletContext to use in creating a component
195      * @return
196      */
197     protected UIComponent createComponent(FaceletContext ctx) {
198         UIComponent c = null;
199         FacesContext faces = ctx.getFacesContext();
200         Application app = faces.getApplication();
201         if (this.binding != null) {
202             ValueExpression ve = this.binding.getValueExpression(ctx,
203                     Object.class);
204             if (FacesAPI.getVersion() >= 12) {
205                 c = app.createComponent(ve, faces, this.componentType);
206                 if (c != null) {
207                     // Make sure the component supports 1.2
208                     if (FacesAPI.getComponentVersion(c) >= 12) {
209                         c.setValueExpression("binding", ve);
210                     } else {
211                         ValueBinding vb = new LegacyValueBinding(ve);
212                         c.setValueBinding("binding", vb);
213                     }
214 
215                 }
216             } else {
217                 ValueBinding vb = new LegacyValueBinding(ve);
218                 c = app.createComponent(vb, faces, this.componentType);
219                 if (c != null) {
220                     c.setValueBinding("binding", vb);
221                 }
222             }
223         } else {
224             c = app.createComponent(this.componentType);
225         }
226         return c;
227     }
228 
229     /**
230      * If the id TagAttribute was specified, get it's value, otherwise generate
231      * a unique id from our tagId.
232      * 
233      * @see TagAttribute#getValue(FaceletContext)
234      * @param ctx
235      *            FaceletContext to use
236      * @return what should be a unique Id
237      */
238     protected String getId(FaceletContext ctx) {
239         if (this.id != null) {
240             return this.id.getValue(ctx);
241         }
242         return ctx.generateUniqueId(this.tagId);
243     }
244 
245     protected MetaRuleset createMetaRuleset(Class type) {
246         MetaRuleset m = super.createMetaRuleset(type);
247         
248         // ignore standard component attributes
249         m.ignore("binding").ignore("id");
250         
251         // add auto wiring for attributes
252         m.addRule(ComponentRule.Instance);
253         
254         // if it's an ActionSource
255         if (ActionSource.class.isAssignableFrom(type)) {
256             m.addRule(ActionSourceRule.Instance);
257         }
258         
259         // if it's a ValueHolder
260         if (ValueHolder.class.isAssignableFrom(type)) {
261             m.addRule(ValueHolderRule.Instance);
262             
263             // if it's an EditableValueHolder
264             if (EditableValueHolder.class.isAssignableFrom(type)) {
265                 m.ignore("submittedValue");
266                 m.ignore("valid");
267                 m.addRule(EditableValueHolderRule.Instance);
268             }
269         }
270         
271         return m;
272     }
273     
274     /**
275      * A hook method for allowing developers to do additional processing once Facelets
276      * creates the component.  The 'setAttributes' method is still perferred, but this
277      * method will provide the parent UIComponent before it's been added to the tree and
278      * before any children have been added to the newly created UIComponent.
279      * 
280      * @param ctx
281      * @param c
282      * @param parent
283      */
284     protected void onComponentCreated(FaceletContext ctx, UIComponent c, UIComponent parent) {
285         // do nothing
286     }
287 
288     protected void onComponentPopulated(FaceletContext ctx, UIComponent c, UIComponent parent) {
289         // do nothing
290     }
291 
292     protected void applyNextHandler(FaceletContext ctx, UIComponent c) 
293             throws IOException, FacesException, ELException {
294         // first allow c to get populated
295         this.nextHandler.apply(ctx, c);
296     }
297 }