KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > enterprise > tools > jsfext > component > ComponentUtil


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23 /*
24  * ComponentUtil.java
25  *
26  * Created on November 24, 2004, 3:06 PM
27  */

28 package com.sun.enterprise.tools.jsfext.component;
29
30 import com.sun.enterprise.tools.jsfext.el.VariableResolver;
31 import com.sun.enterprise.tools.jsfext.layout.descriptor.ComponentType;
32 import com.sun.enterprise.tools.jsfext.layout.descriptor.LayoutComponent;
33 import com.sun.enterprise.tools.jsfext.layout.descriptor.LayoutElement;
34
35 import java.util.HashMap JavaDoc;
36 import java.util.Iterator JavaDoc;
37 import java.util.Map JavaDoc;
38 import java.util.Properties JavaDoc;
39
40 import javax.faces.component.UIComponent;
41 import javax.faces.context.FacesContext;
42 import javax.faces.el.ValueBinding;
43 import javax.faces.webapp.UIComponentTag;
44
45
46 /**
47  * <p> Utility class that contains helper methods for components.</p>
48  *
49  * @author Ken Paulsen (ken.paulsen@sun.com)
50  */

51 public class ComponentUtil {
52
53     /**
54      * <p> This constructor is here to prevent this class from being
55      * instantiated. It only contains static methods.</p>
56      */

57     private ComponentUtil() {
58     }
59
60     /**
61      * <p> Return a child with the specified component id from the specified
62      * component. If not found, return <code>null</code>.</p>
63      *
64      * <p> This method will NOT create a new <code>UIComponent</code>.</p>
65      *
66      * @param parent <code>UIComponent</code> to be searched
67      * @param id Component id (or facet name) to search for
68      *
69      * @return The child <code>UIComponent</code> if it exists, null otherwise.
70      */

71     public static UIComponent getChild(UIComponent parent, String JavaDoc id) {
72     return findChild(parent, id, id);
73     }
74
75     /**
76      * <p> Return a child with the specified component id (or facetName) from
77      * the specified component. If not found, return <code>null</code>.
78      * <code>facetName</code> or <code>id</code> may be null to avoid
79      * searching the facet Map or the <code>parent</code>'s children.</p>
80      *
81      * <p> This method will NOT create a new <code>UIComponent</code>.</p>
82      *
83      * @param parent <code>UIComponent</code> to be searched
84      * @param id id to search for
85      * @param facetName Facet name to search for
86      *
87      * @return The child <code>UIComponent</code> if it exists, null otherwise.
88      */

89     public static UIComponent findChild(UIComponent parent, String JavaDoc id, String JavaDoc facetName) {
90     // Sanity Check
91
if (parent == null) {
92         return null;
93     }
94
95     // First search for facet
96
UIComponent child = null;
97     if (facetName != null) {
98         child = (UIComponent) parent.getFacets().get(facetName);
99         if (child != null) {
100         return child;
101         }
102     }
103
104     // Search for component by id
105
if (id != null) {
106         Iterator JavaDoc it = parent.getChildren().iterator();
107         while (it.hasNext()) {
108         child = (UIComponent) it.next();
109         if (id.equals(child.getId())) {
110             return (child);
111         }
112         }
113     }
114
115     // Not found, return null
116
return null;
117     }
118
119     /**
120      * <p> This method finds or creates a child <code>UIComponent</code>
121      * identified by the given id. If the child is not found, it will
122      * attempt to create it using the provided
123      * {@link com.sun.enterprise.tools.jsfext.component.factory.ComponentFactory}
124      * (<code>factoryClass</code>).</p>
125      *
126      * <p> If there are <code>Properties</code> to be set on the UIComponent,
127      * this method should generally be avoided. It is preferable to use
128      * the {@link #getChild(UIComponent, String, String, Properties)}
129      * form of <code>getChild</code>.</p>
130      *
131      * <p> <code>
132      * // Example (no properties):<br>
133      * UIComponent child = Util.getChild(component, "jklLabel", "{@link com.sun.enterprise.tools.jsfext.component.factory.basic.LabelFactory}");<br>
134      * ((Label)child).setText("JKL Label:");<br>
135      * ((Label)child).setFor("jkl");<br>
136      * <br>
137      * {@link LayoutComponent#encodeChild(FacesContext, UIComponent) LayoutComponent.encodeChild}(context, child);
138      * </code></p>
139      *
140      * @param parent Parent <code>UIComponent</code>
141      * @param id Identifier for child <code>UIComponent</code>
142      * @param factoryClass Full {@link com.sun.enterprise.tools.jsfext.component.factory.ComponentFactory} class name
143      *
144      * @return The child UIComponent that was found or created.
145      *
146      * @see #getChild(UIComponent, String, String, Properties)
147      */

148     public static UIComponent getChild(UIComponent parent, String JavaDoc id, String JavaDoc factoryClass) {
149     return getChild(parent, id, factoryClass, id);
150     }
151
152     /**
153      * <p> Same as {@link #getChild(UIComponent, String, String)} except that
154      * it allows you to specify a facetName different than the id. If
155      * null is supplied, it won't save the component as a facet.</p>
156      *
157      * @param parent Parent <code>UIComponent</code>
158      * @param id Identifier for the child <code>UIComponent</code>
159      * @param factoryClass Full {@link com.sun.enterprise.tools.jsfext.component.factory.ComponentFactory} class name
160      * @param facetName The facet name (null means don't store it)
161      *
162      * @return The child UIComponent that was found or created.
163      *
164      * @see #getChild(UIComponent, String, String)
165      */

166     public static UIComponent getChild(UIComponent parent, String JavaDoc id, String JavaDoc factoryClass, String JavaDoc facetName) {
167     return getChild(parent, id, getComponentType(factoryClass),
168         null, facetName);
169     }
170
171     /**
172      * <p> This method finds or creates a child <code>UIComponent</code>
173      * identified by the given id. If the child is not found, it will
174      * attempt to create it using the provided
175      * {@link com.sun.enterprise.tools.jsfext.component.factory.ComponentFactory}
176      * (<code>factoryClass</code>). It will also initialize the
177      * <code>UIComponent</code> using the provided set of
178      * <code>Properties</code>.</p>
179      *
180      * <p> <code>
181      * // Example (with properties):<br>
182      * Properties props = new Properties();<br>
183      * props.setProperty("text", "ABC Label:");<br>
184      * props.setProperty("for", "abc");<br>
185      * UIComponent child = Util.getChild(component, "abcLabel", "{@link com.sun.enterprise.tools.jsfext.component.factory.LabelFactory}", props);<br>
186      * <br>
187      * {@link LayoutComponent#encodeChild(FacesContext, UIComponent) LayoutComponent.encodeChild}(context, child);
188      * </code></p>
189      *
190      * @param parent Parent <code>UIComponent</code>
191      * @param id Identifier for the child <code>UIComponent</code>
192      * @param factoryClass Full {@link com.sun.enterprise.tools.jsfext.component.factory.ComponentFactory} class name
193      * @param properties <code>java.util.Properties</code> needed to
194      * create and/or initialize the
195      * <code>UIComponent</code>
196      *
197      * @return The child UIComponent that was found or created.
198      */

199     public static UIComponent getChild(UIComponent parent, String JavaDoc id, String JavaDoc factoryClass, Properties JavaDoc properties) {
200     return getChild(parent, id, factoryClass, properties, id);
201     }
202
203     /**
204      * <p> Same as {@link #getChild(UIComponent, String, String, Properties)}
205      * except that it allows you to specify a facetName different than the
206      * id. If null is supplied, it won't save the component as a
207      * facet.</p>
208      *
209      * @param parent Parent <code>UIComponent</code>
210      * @param id Identifier for the child <code>UIComponent</code>
211      * @param factoryClass Full {@link com.sun.enterprise.tools.jsfext.component.factory.ComponentFactory} class name
212      * @param properties <code>java.util.Properties</code> needed to
213      * create and/or initialize the
214      * <code>UIComponent</code>
215      * @param facetName The facet name (null means don't store it)
216      *
217      * @return The child UIComponent that was found or created.
218      */

219     public static UIComponent getChild(UIComponent parent, String JavaDoc id, String JavaDoc factoryClass, Properties JavaDoc properties, String JavaDoc facetName) {
220     return getChild(parent, id, getComponentType(factoryClass),
221         properties, facetName);
222     }
223
224     /**
225      * <p> This method finds or creates a child <code>UIComponent</code>
226      * identified by the given id. If the child is not found, it will
227      * attempt to create it using the provided {@link ComponentType}
228      * (<code>type</code>). It will also initialize the
229      * <code>UIComponent</code> using the provided set of
230      * <code>properties</code>.</p>
231      *
232      * @param parent Parent <code>UIComponent</code>
233      * @param id Identifier for the child
234      * <code>UIComponent</code>
235      * @param type The <code>ComponentType</code> class name
236      * @param properties Properties needed to create and/or initialize
237      * the <code>UIComponent</code>
238      * @param facetName The facet name (null means don't store it)
239      *
240      * @return The child <code>UIComponent</code> that was found or created.
241      */

242     private static UIComponent getChild(UIComponent parent, String JavaDoc id, ComponentType type, Properties JavaDoc properties, String JavaDoc facetName) {
243     LayoutComponent desc = new LayoutComponent(null, id, type);
244     if (properties != null) {
245         desc.setOptions(properties);
246     }
247     if (facetName != null) {
248         // Add the facetName to use
249
// FIXME: Decide if this should have its own method
250
desc.addOption(LayoutComponent.FACET_NAME, facetName);
251     }
252
253     return getChild(parent, desc);
254     }
255
256     /**
257      * <p> This method creates a {@link ComponentType} instance from the given
258      * <code>factoryClass</code>. It will first check its cache to see if
259      * one has already been created. If not, it will create one and add
260      * to the cache for future use.</p>
261      *
262      * <p> This method sets <code>factoryClass</code> for the
263      * {@link ComponentType} id.</p>
264      *
265      * @param facatoryClass The full classname of the
266      * {@link com.sun.enterprise.tools.jsfext.component.factory.ComponentFactory}.
267      *
268      * @return A ComponentType instance for <code>factoryClass</code>.
269      */

270     private static ComponentType getComponentType(String JavaDoc factoryClass) {
271     // Check the cache
272
ComponentType type = (ComponentType) _types.get(factoryClass);
273     if (type == null) {
274         // Not in the cache... add it...
275
type = new ComponentType(factoryClass, factoryClass);
276         Map JavaDoc newMap = new HashMap JavaDoc(_types);
277         newMap.put(factoryClass, type);
278         _types = newMap;
279     }
280
281     // Return the ComponentType
282
return type;
283     }
284
285     /**
286      * <p> This method finds or creates a child <code>UIComponent</code>
287      * identified by the given id. If the child is not found, it will
288      * attempt to create it using the provided {@link LayoutComponent}
289      * (<code>descriptor</code>). It will also initialize the
290      * <code>UIComponent</code> using the options set on the
291      * {@link LayoutComponent}.</p>
292      *
293      * <p> If <code>parent</code> implements {@link ChildManager}, then the
294      * responsibility of finding and creating the child will be delegated
295      * to the {@link ChildManager} <code>UIComponent</code>.</p>
296      *
297      * <p> If you are constructing and populating a LayoutComponent before
298      * calling this method, there are a few features that should be noted.
299      * Besides <code>id</code> and <code>type</code> which can be set in
300      * the LayoutComponent constructor, you can also set
301      * <code>options</code>, and
302      * {@link com.sun.enterprise.tools.jsfext.component.event.Handler}'s.</p>
303      *
304      * <p> <code>Options</code> may be set via
305      * {@link LayoutComponent#setOptions(Map)}. These options will be
306      * applied to the <code>UIComponent</code> and may also be used by the
307      * {@link com.sun.enterprise.tools.jsfext.component.factory.ComponentFactory}
308      * while instantiating the <code>UIComponent</code>.</p>
309      *
310      * <p> {@link com.sun.enterprise.tools.jsfext.event.handlers.Handler}'s
311      * can be supplied by calling
312      * {@link LayoutComponent#setHandlers(String, List)}. The
313      * <code>type</code> must match the event name which invokes the
314      * <code>List</code> of handlers you provide. The
315      * <code>Renderer</code> for this <code>UIComponent</code> is
316      * responsible for declaring and dispatching events.
317      * {@link com.sun.enterprise.tools.jsfext.renderer.template.TemplateRenderer}
318      * will invoke <code>beforeCreate</code> and <code>afterCreate</code>
319      * events for each child it creates (such as the one being requested
320      * here).</p>
321      *
322      * <p> <code>
323      * // Example (with LayoutComponent):<br>
324      * {@link ComponentType} type = new {@link ComponentType#ComponentType(String, String) ComponentType}("LabelFactory", "{@link com.sun.enterprise.tools.jsfext.component.factory.basic.LabelFactory}");<br>
325      * {@link LayoutComponent} descriptor = new {@link LayoutComponent#LayoutComponent(LayoutElement, String, ComponentType) LayoutComponent}(null, "abcLabel", type);<br>
326      * {@link LayoutComponent#addOption(String, Object) descriptor.addOption}("text", "ABC Label:");<br>
327      * {@link LayoutComponent#addOption(String, Object) descriptor.addOption}("for", "abc");<br>
328      * UIComponent child = Util.getChild(component, descriptor);<br>
329      * <br>
330      * {@link LayoutComponent#encodeChild(FacesContext, UIComponent) LayoutComponent.encodeChild}(context, child);
331      * </code></p>
332      *
333      * @param parent Parent <code>UIComponent</code>
334      * @param descriptor The {@link LayoutComponent} describing the
335      * <code>UIComponent</code>
336      *
337      * @return The child <code>UIComponent</code> that was found or created.
338      */

339     public static UIComponent getChild(UIComponent parent, LayoutComponent descriptor) {
340     FacesContext context = FacesContext.getCurrentInstance();
341     // First check to see if the UIComponent can create its own children
342
if (parent instanceof ChildManager) {
343         return ((ChildManager) parent).getChild(
344         context, descriptor);
345     }
346
347     // Make sure it doesn't already exist
348
String JavaDoc childId = descriptor.getId(context, parent);
349     UIComponent childComponent = findChild(parent, childId,
350         (String JavaDoc) descriptor.getEvaluatedOption(
351         context, LayoutComponent.FACET_NAME, null));
352     if (childComponent != null) {
353         return childComponent;
354     }
355
356     // Not found, create a new UIComponent
357
return createChildComponent(context, descriptor, parent);
358     }
359
360     /**
361      * <p> This method creates a child <code>UIComponent</code> by using the
362      * provided {@link LayoutComponent} (<code>descriptor</code>). It
363      * will associate the parent and the newly created
364      * <code>UIComponent</code>.</p>
365      *
366      * <p> It is recommended that this method NOT be called from a Renderer.
367      * It should not be called if you have not yet checked to see if a
368      * child UIComponent with the requested ID already exists.</p>
369      *
370      * @param context The <code>FacesContext</code> object.
371      * @param descriptor The {@link LayoutComponent} describing the
372      * <code>UIComponent</code> to be created.
373      * @param parent Parent <code>UIComponent</code>.
374      *
375      * @return A new <code>UIComponent</code> based on the provided
376      * {@link LayoutComponent}.
377      *
378      * @throws IllegalArgumentException Thrown if descriptor equals null.
379      *
380      * @see #getChild(UIComponent, LayoutComponent)
381      * @see #getChild(UIComponent, String, String, Properties)
382      * @see LayoutComponent#getType()
383      * @see ComponentType#getFactory()
384      * @see com.sun.enterprise.tools.jsfext.component.factory.ComponentFactory#create(FacesContext, LayoutComponent, UIComponent)
385      */

386     public static UIComponent createChildComponent(FacesContext context, LayoutComponent descriptor, UIComponent parent) {
387     // Make sure a LayoutComponent was provided.
388
if (descriptor == null) {
389         throw new IllegalArgumentException JavaDoc("'descriptor' cannot be null!");
390     }
391
392     // Create & return the child UIComponent
393
return descriptor.getType().getFactory().create(
394             context, descriptor, parent);
395     }
396
397     /**
398      * <p> This util method will set the given key/value on the
399      * <code>UIComponent</code>. It will resolve all $...{...}
400      * expressions, and convert the String into a
401      * <code>ValueBinding</code> if a <code>ValueBinding</code> is
402      * detected. The return value will be a <code>ValueBinding</code> or
403      * the value.</p>
404      *
405      * @param context <code>FacesContext</code>
406      * @param key The Property name to set
407      * @param value The Property value to set
408      * @param desc The {@link LayoutElement} associated with the
409      * <code>UIComponent</code>
410      * @param component The <code>UIComponent</code>
411      *
412      * @return A ValueBinding, or the evaulated value (if no value binding is
413      * present).
414      */

415     public static Object JavaDoc setOption(FacesContext context, String JavaDoc key, Object JavaDoc value, LayoutElement desc, UIComponent component) {
416     // Invoke our own EL. This is needed b/c JSF's EL is designed for
417
// Bean getters only. It does not get CONSTANTS or pull data from
418
// other sources (such as session, request attributes, etc., etc.)
419
// Resolve our variables now because we cannot depend on the
420
// individual components to do this. We may want to find a way to
421
// make this work as a regular ValueBinding expression... but for
422
// now, we'll just resolve it here.
423
value = VariableResolver.resolveVariables(
424         context, desc, component, value);
425     if (value == null) {
426         // It is possible to resolve an expression to null
427
return null;
428     }
429
430     // Next check to see if the value contains a JSF ValueBinding
431
String JavaDoc strVal = value.toString();
432     if (UIComponentTag.isValueReference(strVal)) {
433         ValueBinding vb =
434         context.getApplication().createValueBinding(strVal);
435         if (component != null) {
436         component.setValueBinding(key, vb);
437         }
438         value = vb;
439     } else {
440         // In JSF, you must directly modify the attribute Map
441
if (component != null) {
442         component.getAttributes().put(key, value);
443         }
444     }
445     return value;
446     }
447
448     /**
449      * <p> This method will attempt to resolve EL strings in the given
450      * value.</p>
451      *
452      * @param context The <code>FacesContext</code>
453      * @param elt The LayoutElement associated w/ the expression
454      * @param parent The parent <code>UIComponent</code>. This is used
455      * because the current UIComponent is typically
456      * unknown (or not even created yet).
457      * @param value The String to resolve
458      *
459      * @return The evaluated value (may be null).
460      */

461     public static Object JavaDoc resolveValue(FacesContext context, LayoutElement elt, UIComponent parent, String JavaDoc value) {
462     // Invoke our own EL. This is needed b/c JSF's EL is designed for
463
// Bean getters only. It does not get CONSTANTS or pull data from
464
// other sources without adding a custom VariableResolver and/or
465
// PropertyResolver. Eventually we may want to find a good way to
466
// make this work as a regular ValueBinding expression... but for
467
// now, we'll just resolve it this way.
468
Object JavaDoc result = VariableResolver.resolveVariables(
469         context, elt, parent, value);
470
471     // Next check to see if the value contains a JSF ValueBinding
472
if (result != null) {
473         String JavaDoc strVal = result.toString();
474         if (UIComponentTag.isValueReference(strVal)) {
475         ValueBinding vb =
476             context.getApplication().createValueBinding(strVal);
477         result = vb.getValue(context);
478         }
479     }
480
481     // Return the result
482
return result;
483     }
484
485     /**
486      * <p> This Map caches ComponentTypes by their factoryClass name.</p>
487      */

488     private static Map JavaDoc _types = new HashMap JavaDoc();
489 }
490
Popular Tags