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;
042:
043: import com.sun.rave.web.ui.component.util.Util;
044: import com.sun.rave.web.ui.component.util.descriptors.LayoutComponent;
045: import com.sun.rave.web.ui.component.util.descriptors.LayoutDefinition;
046: import com.sun.rave.web.ui.component.util.descriptors.LayoutElement;
047: import com.sun.rave.web.ui.renderer.template.LayoutDefinitionManager;
048:
049: import java.util.Iterator;
050:
051: import javax.faces.component.UIComponent;
052: import javax.faces.component.UIComponentBase;
053: import javax.faces.context.FacesContext;
054:
055: /**
056: * <P> This abstract class provides base functionality for components that
057: * work in conjunction with the
058: * {@link com.sun.rave.web.ui.renderer.template.TemplateRenderer}. It
059: * provides a default implementation of the {@link com.sun.rave.web.ui.component.TemplateComponent}
060: * interface.</P>
061: *
062: * @see com.sun.rave.web.ui.renderer.template.TemplateRenderer
063: * @see com.sun.rave.web.ui.component.TemplateComponent
064: *
065: * @author Ken Paulsen (ken.paulsen@sun.com)
066: */
067: public abstract class TemplateComponentBase extends UIComponentBase
068: implements TemplateComponent {
069:
070: /**
071: * This method will find the request child UIComponent by id. If it is
072: * not found, it will attempt to create it if it can find a LayoutElement
073: * describing it.
074: *
075: * @param context The FacesContext
076: * @param id The UIComponent id to search for
077: *
078: * @return The requested UIComponent
079: */
080: public UIComponent getChild(FacesContext context, String id) {
081: if ((id == null) || (id.trim().equals(""))) {
082: // No id, no LayoutComponent, nothing we can do.
083: return null;
084: }
085:
086: // We have an id, use it to search for an already-created child
087: // FIXME: I am doing this 2x if it falls through to create the child... think about optimizing this
088: UIComponent childComponent = Util.findChild(this , id, id);
089: if (childComponent != null) {
090: return childComponent;
091: }
092:
093: // If we're still here, then we need to create it... hopefully we have
094: // a LayoutComponent to tell us how to do this!
095: LayoutDefinition ld = getLayoutDefinition(context);
096: if (ld == null) {
097: // No LayoutDefinition to tell us how to create it... return null
098: return null;
099: }
100:
101: // Attempt to find a LayoutComponent matching the id
102: LayoutElement elt = LayoutDefinition.getChildLayoutElementById(
103: context, id, ld, this );
104:
105: // Create the child from the LayoutComponent
106: return getChild(context, (LayoutComponent) elt);
107: }
108:
109: /**
110: * This method will find the request child UIComponent by id (the id is
111: * obtained from the given LayoutComponent). If it is not found, it will
112: * attempt to create it from the supplied LayoutElement.
113: *
114: * @param descriptor The LayoutElement describing the UIComponent
115: *
116: * @return The requested UIComponent
117: */
118: public UIComponent getChild(FacesContext context,
119: LayoutComponent descriptor) {
120: UIComponent childComponent = null;
121:
122: // Sanity check
123: if (descriptor == null) {
124: throw new IllegalArgumentException(
125: "The LayoutComponent is null!");
126: }
127:
128: // First pull off the id from the descriptor
129: String id = descriptor.getId(context, this );
130: if ((id != null) && !(id.trim().equals(""))) {
131: // We have an id, use it to search for an already-created child
132: childComponent = Util.findChild(this , id, id);
133: if (childComponent != null) {
134: return childComponent;
135: }
136: }
137:
138: // No id, or the component hasn't been created. In either case, we
139: // create a new component (moral: always have an id)
140:
141: // Invoke "beforeCreate" handlers
142: descriptor.beforeCreate(context, this );
143:
144: // Create UIComponent
145: childComponent = Util.createChildComponent(context, descriptor,
146: this );
147:
148: // Invoke "afterCreate" handlers
149: descriptor.afterCreate(context, childComponent);
150:
151: // Add the new child (perhaps we shouldn't add it if it doesn't have
152: // an id... what would this mean?)
153: // FIXME: I added this to the factory... this information is needed at create
154: // FIXME: time.
155: // getChildren().add(childComponent);
156:
157: // Return the newly created UIComponent
158: return childComponent;
159: }
160:
161: /**
162: * This method returns the LayoutDefinition associated with this component.
163: *
164: * @param context The FacesContext
165: *
166: * @return LayoutDefinition associated with this component.
167: */
168: public LayoutDefinition getLayoutDefinition(FacesContext context) {
169: // Make sure we don't already have it...
170: if (_layoutDefinition != null) {
171: return _layoutDefinition;
172: }
173:
174: // Get the LayoutDefinitionManager key
175: String key = getLayoutDefinitionKey();
176: if (key == null) {
177: throw new NullPointerException(
178: "LayoutDefinition key is null!");
179: }
180:
181: // Get the LayoutDefinitionManager
182: LayoutDefinitionManager ldm = LayoutDefinitionManager
183: .getManager(context);
184:
185: // Save the LayoutDefinition for future calls to this method
186: _layoutDefinition = ldm.getLayoutDefinition(key);
187:
188: // Return the LayoutDefinition (if found)
189: return _layoutDefinition;
190: }
191:
192: /**
193: * This method saves the state for this component. It relies on the
194: * super class to save its own sate, this method will invoke
195: * super.saveState().
196: *
197: * @param context The FacesContext
198: *
199: * @return The serialized State
200: */
201: public Object saveState(FacesContext context) {
202: Object values[] = new Object[2];
203: values[0] = super .saveState(context);
204: values[1] = _ldmKey;
205: return values;
206: }
207:
208: /**
209: * This method restores the state for this component. It will invoke the
210: * super class to restore its state.
211: *
212: * @param context The FacesContext
213: * @param state The serialized State
214: *
215: */
216: public void restoreState(FacesContext context, Object state) {
217: Object values[] = (Object[]) state;
218: super .restoreState(context, values[0]);
219: _ldmKey = (java.lang.String) values[1];
220: }
221:
222: /**
223: * This method returns the LayoutDefinitionKey for this component.
224: *
225: * @return key The key to use in the LayoutDefinitionManager
226: */
227: public String getLayoutDefinitionKey() {
228: return _ldmKey;
229: }
230:
231: /**
232: * This method sets the LayoutDefinition key for this component.
233: *
234: * @param key The key to use in the LayoutDefinitionManager
235: */
236: public void setLayoutDefinitionKey(String key) {
237: _ldmKey = key;
238: }
239:
240: /**
241: * This is the LayoutDefinition key for this component. This is
242: * typically set by the Tag. The Component may also provide a default
243: * by setting it in its constructor.
244: */
245: private String _ldmKey = null;
246:
247: /**
248: * This is a cached reference to the LayoutDefinition used by this
249: * UIComponent.
250: */
251: private transient LayoutDefinition _layoutDefinition = null;
252: }
|