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: ComponentHandler.java 1187700 2011-10-22 12:19:37Z bommel $
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 }