001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package com.sun.rave.web.ui.component.util.descriptors;
042:
043: import com.sun.rave.web.ui.component.util.Util;
044: import com.sun.rave.web.ui.component.ChildManager;
045: import com.sun.rave.web.ui.component.util.event.AfterCreateEvent;
046: import com.sun.rave.web.ui.component.util.event.BeforeCreateEvent;
047: import com.sun.rave.web.ui.util.VariableResolver;
048:
049: import java.io.IOException;
050: import java.util.ArrayList;
051: import java.util.HashMap;
052: import java.util.Iterator;
053: import java.util.List;
054: import java.util.Map;
055:
056: import javax.faces.context.FacesContext;
057: import javax.faces.context.ResponseWriter;
058: import javax.faces.component.UIColumn;
059: import javax.faces.component.UIComponent;
060: import javax.faces.component.UIData;
061: import javax.faces.component.UIViewRoot;
062: import javax.faces.render.Renderer;
063:
064: /**
065: * <p> This class defines a LayoutComponent. A LayoutComponent describes a
066: * UIComponent to be instantiated. The method {@link #getType()} provides
067: * a {@link ComponentType} descriptor that is capable of providing a
068: * {@link com.sun.rave.web.ui.component.util.factories.ComponentFactory} to
069: * perform the actual instantiation. This class also stores properties
070: * and facets (children) to be set on a newly instantiated instance.</p>
071: *
072: * @author Ken Paulsen (ken.paulsen@sun.com)
073: */
074: public class LayoutComponent extends LayoutElementBase implements
075: LayoutElement {
076:
077: /**
078: * <p> Constructor.</p>
079: */
080: public LayoutComponent(LayoutElement parent, String id,
081: ComponentType type) {
082: super (parent, id);
083: _type = type;
084: }
085:
086: /**
087: * <p> Accessor for type.</p>
088: */
089: public ComponentType getType() {
090: return _type;
091: }
092:
093: /**
094: * <p> Determines if this component should be created even if there is
095: * already an existing <code>UIComponent</code>. It will "overwrite"
096: * the existing component if this property is true.</p>
097: */
098: public void setOverwrite(boolean value) {
099: _overwrite = value;
100: }
101:
102: /**
103: * <p> Determines if this component should be created even if there is
104: * already an existing <code>UIComponent</code>. It will "overwrite"
105: * the existing component if this property is true.</p>
106: */
107: public boolean isOverwrite() {
108: return _overwrite;
109: }
110:
111: /**
112: * <p> This method overrides LayoutElementBase.addChildLayoutElement().
113: * Child LayoutElements for LayoutComponent are limited to LayoutFacet
114: * objects. This method ensures that only LayoutFacet objects are
115: * added. If any other types are added, an IllegalArgumentException
116: * will be thrown.</p>
117: *
118: * @param element The LayoutElement to add.
119: *
120: * @throws IllegalArgumentException Thrown if LayoutElement is not a
121: * LayoutFacet
122: */
123: public void addChildLayoutElement(LayoutElement element) {
124: if (!(element instanceof LayoutComponent)
125: && !(element instanceof LayoutFacet)) {
126: throw new IllegalArgumentException(
127: "Only LayoutComponent and "
128: + "LayoutFacet LayoutElements may be added as children to "
129: + "a LayoutComponent!");
130: }
131: super .addChildLayoutElement(element);
132: }
133:
134: /**
135: * <p> This method adds an option to the LayoutComponent. Options may be
136: * useful in constructing the LayoutComponent.</p>
137: *
138: * @param name The name of the option
139: * @param value The value of the option (may be List or String)
140: */
141: public void addOption(String name, Object value) {
142: _options.put(name, value);
143: }
144:
145: /**
146: * <p> This method adds all the options in the given Map to the
147: * LayoutComponent. Options may be useful in constructing the
148: * LayoutComponent.</p>
149: *
150: * @param map The map of options to add.
151: */
152: public void addOptions(Map map) {
153: _options.putAll(map);
154: }
155:
156: /**
157: * <p> Accessor method for an option. This method does not evaluate
158: * expressions.</p>
159: *
160: * @param name The option name to retrieve.
161: *
162: * @return The option value (List or String), or null if not found.
163: *
164: * @see #getEvaluatedOption(FacesContext, String, UIComponent)
165: */
166: public Object getOption(String name) {
167: return _options.get(name);
168: }
169:
170: /**
171: * <p> Accessor method for an option. This method evaluates our own
172: * expressions (not JSF expressions).</p>
173: *
174: * @param name The option name to retrieve
175: * @param ctx The FacesContext
176: * @param component The UIComponent (may be null)
177: *
178: * @return The option value (List or String), or null if not found.
179: *
180: * @see #getOption(String)
181: */
182: public Object getEvaluatedOption(FacesContext ctx, String name,
183: UIComponent component) {
184: // Get the option value
185: Object value = getOption(name);
186:
187: // Invoke our own EL. This is needed b/c JSF's EL is designed for
188: // Bean getters only. It does not get CONSTANTS or pull data from
189: // other sources (such as session, request attributes, etc., etc.)
190: // Resolve our variables now because we cannot depend on the
191: // individual components to do this. We may want to find a way to
192: // make this work as a regular ValueBinding expression... but for
193: // now, we'll just resolve it here.
194: return VariableResolver.resolveVariables(ctx, this , component,
195: value);
196: }
197:
198: /**
199: * <p> This method returns true/false based on whether the given option
200: * name has been set.</p>
201: *
202: * @param name The option name to look for.
203: *
204: * @return true/false depending on whether the options exists.
205: */
206: public boolean containsOption(String name) {
207: return _options.containsKey(name);
208: }
209:
210: /**
211: * <p> This method sets the Map of options.</p>
212: *
213: * @param options Map of options.
214: */
215: public void setOptions(Map options) {
216: _options = options;
217: }
218:
219: /**
220: * <p> This method returns the options as a Map. This method does not
221: * evaluate expressions.</p>
222: *
223: * @return Map of options.
224: */
225: public Map getOptions() {
226: return _options;
227: }
228:
229: /**
230: * <p> This method allows each LayoutElement to provide it's own encode
231: * functionality. If the LayoutComponent should render its children,
232: * this method should return true. Otherwise, this method should
233: * return false.</p>
234: *
235: * @param context The FacesContext
236: * @param component The UIComponent
237: *
238: * @return true if children are to be rendered, false otherwise.
239: */
240: protected boolean encodeThis(FacesContext context,
241: UIComponent component) throws IOException {
242: // If overwrite...
243: if (isOverwrite()) {
244: String id = getId(context, component);
245: if (component.getFacets().remove(id) == null) {
246: UIComponent child = Util.findChild(component, id, null);
247: if (child != null) {
248: // Not a facet, try child...
249: component.getChildren().remove(child);
250: }
251: }
252: }
253:
254: // Display this UIComponent
255: // First find the UIComponent
256: UIComponent childComponent = null;
257: if (component instanceof ChildManager) {
258: // If we have a ChildManager, take advantage of it...
259: childComponent = ((ChildManager) component).getChild(
260: context, this );
261: } else {
262: // Use local util method for finding / creating child component...
263: childComponent = getChild(context, component);
264: }
265:
266: // Render the child UIComponent
267: encodeChild(context, childComponent);
268:
269: // We return false here b/c it is up to the renderer above to decide
270: // how to deal w/ children. The renderer that called this method is
271: // not responsible for rendering the children any further than this.
272: return false;
273: }
274:
275: /**
276: * <p> This method will find or create a <code>UIComponent</code> as
277: * described by this <code>LayoutComponent</code> descriptor. If the
278: * component already exists as a child or facet, it will be returned.
279: * If it creates a new <code>UIComponent</code>, it will typically be
280: * added to the given parent <code>UIComponent</code> as a facet (this
281: * actually depends on the factory that instantiates the
282: * <code>UIComponent</code>).</p>
283: *
284: * @param context The <code>FacesContext</code>
285: * @param parent The <code>UIComponent</code> to serve as the parent to
286: * search and to store the new <code>UIComponent</code>.
287: *
288: * @return The <code>UIComponent</code> requested (found or newly created)
289: */
290: public UIComponent getChild(FacesContext context, UIComponent parent)
291: throws IOException {
292: UIComponent childComponent = null;
293:
294: // First pull off the id from the descriptor
295: String id = this .getId(context, parent);
296: if ((id != null) && !(id.trim().equals(""))) {
297: // We have an id, use it to search for an already-created child
298: childComponent = Util.findChild(parent, id, id);
299: if (childComponent != null) {
300: return childComponent;
301: }
302: }
303:
304: // No id, or the component hasn't been created. In either case, we
305: // create a new component (moral: always have an id)
306:
307: // Invoke "beforeCreate" handlers
308: this .beforeCreate(context, parent);
309:
310: // Create UIComponent
311: childComponent = Util.createChildComponent(context, this ,
312: parent);
313:
314: // Invoke "afterCreate" handlers
315: this .afterCreate(context, childComponent);
316:
317: // Add the new child (perhaps we shouldn't add it if it doesn't have
318: // an id... what would this mean?)
319: // FIXME: I added this to the factory... this information is needed at create
320: // FIXME: time.
321: // getChildren().add(childComponent);
322:
323: // Return the newly created UIComponent
324: return childComponent;
325: }
326:
327: /**
328: * <p> This method is invoked before the Component described by this
329: * LayoutComponent is created. This allows handlers registered for
330: * "beforeCreate" functionality to be invoked.</p>
331: *
332: * @param context The FacesContext
333: *
334: * @return The result of invoking the handlers (null by default)
335: */
336: public Object beforeCreate(FacesContext context, UIComponent parent) {
337: // Invoke "beforeCreate" handlers
338: return dispatchHandlers(context, BEFORE_CREATE,
339: new BeforeCreateEvent(parent));
340: }
341:
342: /**
343: * <p> This method is invoked after the Component described by this
344: * LayoutComponent is created. This allows handlers registered for
345: * "afterCreate" functionality to be invoked.</p>
346: *
347: * @param context The FacesContext
348: *
349: * @return The result of invoking the handlers (null by default)
350: */
351: public Object afterCreate(FacesContext context,
352: UIComponent component) {
353: // Invoke "afterCreate" handlers
354: return dispatchHandlers(context, AFTER_CREATE,
355: new AfterCreateEvent(component));
356: }
357:
358: /**
359: * <p> This method returns true if the child should be added to the parent
360: * component as a facet. Otherwise, it returns false indicating that
361: * it should exist as a real child. The default is true.</p>
362: *
363: * @return True if the child UIComponent should be added as a facet.
364: */
365: public boolean isFacetChild() {
366: return _isFacetChild;
367: }
368:
369: /**
370: * <p> This method sets whether the child <code>UIComponent</code> should
371: * be set as a facet or a real child.</p>
372: *
373: * @param facetChild True if the child <code>UIComponent</code> should
374: * be added as a facet.
375: */
376: public void setFacetChild(boolean facetChild) {
377: _isFacetChild = facetChild;
378: }
379:
380: /**
381: * <p> Component type</p>
382: */
383: private ComponentType _type = null;
384:
385: /**
386: * <p> Determines if this component should be created even if there is
387: * already an existing <code>UIComponent</code>. It will "overwrite"
388: * the existing component if this property is true.</p>
389: */
390: private boolean _overwrite = false;
391:
392: /**
393: * <p> Map of options.</p>
394: */
395: private Map _options = new HashMap();
396:
397: /**
398: *
399: */
400: private boolean _isFacetChild = true;
401:
402: /**
403: * <p> This is the "type" for handlers to be invoked to handle
404: * "afterCreate" functionality for this element.</p>
405: */
406: public static final String AFTER_CREATE = "afterCreate";
407:
408: /**
409: * <p> This is the "type" for handlers to be invoked to handle
410: * "beforeCreate" functionality for this element.</p>
411: */
412: public static final String BEFORE_CREATE = "beforeCreate";
413:
414: /**
415: * <p> This defines the property key for specifying the facet name in
416: * which the component should be stored under in its parent
417: * UIComponent.</p>
418: */
419: public static final String FACET_NAME = "_facetName";
420: }
|