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 Development
008: * and Distribution License("CDDL") (collectively, the "License"). You
009: * may not use this file except in compliance with the License. You can obtain
010: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
011: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
012: * language governing permissions and limitations under the License.
013: *
014: * When distributing the software, include this License Header Notice in each
015: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
016: * Sun designates this particular file as subject to the "Classpath" exception
017: * as provided by Sun in the GPL Version 2 section of the License file that
018: * accompanied this code. If applicable, add the following below the License
019: * Header, with the fields enclosed by brackets [] replaced by your own
020: * identifying information: "Portions Copyrighted [year]
021: * [name of copyright owner]"
022: *
023: * Contributor(s):
024: *
025: * If you wish your version of this file to be governed by only the CDDL or
026: * only the GPL Version 2, indicate your decision by adding "[Contributor]
027: * elects to include this software in this distribution under the [CDDL or GPL
028: * Version 2] license." If you don't indicate a single choice of license, a
029: * recipient has the option to distribute your version of this file under
030: * either the CDDL, the GPL Version 2 or to extend the choice of license to
031: * its licensees as provided above. However, if you add GPL Version 2 code
032: * and therefore, elected the GPL Version 2 license, then the option applies
033: * only if the new code is made subject to such option by the copyright
034: * holder.
035: */
036: package com.sun.jbi.jsf.factory;
037:
038: import com.sun.jsftemplating.annotation.UIComponentFactory;
039: import com.sun.jsftemplating.component.ComponentUtil;
040: import com.sun.jsftemplating.component.factory.ComponentFactoryBase;
041: import com.sun.jsftemplating.layout.descriptors.LayoutComponent;
042: import com.sun.jsftemplating.layout.descriptors.handler.Handler;
043: import com.sun.jsftemplating.util.Util;
044:
045: import java.lang.reflect.InvocationTargetException;
046: import java.util.Iterator;
047: import java.util.List;
048: import java.util.Map;
049: import java.util.Properties;
050:
051: import javax.faces.context.FacesContext;
052: import javax.faces.component.UIComponent;
053:
054: import com.sun.webui.jsf.component.StaticText;
055:
056: /**
057: * <p> Some property sheet are non-static, or Dynamic. By this it is meant
058: * that some of the property elements can only be determined at Runtime.
059: * The goal of this factory is to provide a means for dynamic property
060: * components to be defined. </p>
061: *
062: * <p> The {@link com.sun.jsftemplating.layout.descriptors.ComponentType}
063: * id for this factory is: "dynamicPropertySheet".</p>
064: *
065: */
066: @UIComponentFactory("dynamicPropertySheet")
067: public class DynamicPropertySheetFactory extends ComponentFactoryBase {
068:
069: /**
070: * Constructor
071: */
072: public DynamicPropertySheetFactory() {
073: }
074:
075: /**
076: * <p> This is the factory method responsible for creating the
077: * <code>UIComponent</code>.</p>
078: *
079: * @param context The <code>FacesContext</code>
080: * @param descriptor The {@link LayoutComponent} descriptor associated
081: * with the requested <code>UIComponent</code>.
082: * @param parent The parent <code>UIComponent</code>
083: *
084: * @return The newly created component.
085: */
086: public UIComponent create(FacesContext context,
087: LayoutComponent descriptor, UIComponent parent) {
088:
089: // Get the PropertySheetAdaptor which should be used
090: PropertySheetAdaptor propertySheetAdaptor = getPropertySheetAdaptor(
091: context, descriptor, parent);
092:
093: // Initialize the PropertySheetAdaptor instance
094: propertySheetAdaptor.init();
095:
096: // Create the Property Sheet
097: //String propertySheetId = propertySheetAdaptor.getPropertySheetId();
098: String propertySheetId = propertySheetAdaptor.getId();
099: return createPropertySheet(context, propertySheetAdaptor,
100: propertySheetId, parent);
101: }
102:
103: /**
104: * <p> This method gets the <code>PropertySheetAdaptor</code> by looking at the
105: * {@link #PROPERTY_SHEET_ADAPTOR_CLASS} option and invoking
106: * <code>getInstance</code> on the specified <code>PropertySheetAdaptor</code>
107: * implementation.</p>
108: */
109: protected PropertySheetAdaptor getPropertySheetAdaptor(
110: FacesContext ctx, LayoutComponent desc, UIComponent parent) {
111: PropertySheetAdaptor adaptor = null;
112: Object cls = desc.getEvaluatedOption(ctx,
113: PROPERTY_SHEET_ADAPTOR_CLASS, parent);
114: if (cls == null) {
115: throw new IllegalArgumentException("'"
116: + PROPERTY_SHEET_ADAPTOR_CLASS
117: + "' must be specified!");
118: }
119: try {
120: Class adaptorClass = Util.getClass(cls);
121: adaptor = (PropertySheetAdaptor) adaptorClass
122: .getMethod(
123: "getInstance",
124: (Class[]) new Class[] { FacesContext.class,
125: LayoutComponent.class,
126: UIComponent.class })
127: .invoke(
128: (Object) null,
129: (Object[]) new Object[] { ctx, desc, parent });
130: } catch (ClassNotFoundException ex) {
131: throw new RuntimeException(ex);
132: } catch (NoSuchMethodException ex) {
133: throw new RuntimeException(ex);
134: } catch (IllegalAccessException ex) {
135: throw new RuntimeException(ex);
136: } catch (InvocationTargetException ex) {
137: throw new RuntimeException(ex);
138: }
139:
140: // Return the PropertySheetAdaptor
141: return adaptor;
142: }
143:
144: /**
145: * <p> This method creates the </code>PropertySheet</code>
146: */
147: protected UIComponent createPropertySheet(FacesContext ctx,
148: PropertySheetAdaptor adaptor, String propertySheetId,
149: UIComponent parent) {
150: // String id = adaptor.getPropertySheetId();
151: String id = adaptor.getId();
152: String factoryClass = adaptor.getFactoryClass();
153: Map<String, Object> props = adaptor.getFactoryOptions();
154: Properties properties = Util.mapToProperties(props);
155:
156: // Create "this" Property Sheet component that will have
157: // the property sheet section and property(s) added to it
158: UIComponent sheet = ComponentUtil.getChild(
159: (UIComponent) parent, id, factoryClass, properties);
160:
161: // Use the adaptor class "getPropertySheetComponent" to generate
162: // the dynamic property sheet. Note, the parent PropertySheet "sheet"
163: // is passed into the adaptor method and the property sheet section
164: // and property(s) are generated and added to this property sheet.
165: sheet = adaptor.getPropertySheet(sheet);
166:
167: // Add the Facets and Handlers
168: configurePropertySheet(ctx, adaptor, sheet, propertySheetId);
169:
170: // Add the newly created PropertySheet to the parent class.
171: parent.getChildren().add(sheet);
172: return sheet;
173: }
174:
175: /**
176: * <p> Adds on facets and handlers.</p>
177: */
178: protected void configurePropertySheet(FacesContext ctx,
179: PropertySheetAdaptor adaptor, UIComponent propertySheet,
180: Object currentObj) {
181: // Add facets (such as "content" and "image")
182: Map<String, UIComponent> facets = adaptor.getFacets(
183: propertySheet, currentObj);
184: if (facets != null) {
185: Map<String, UIComponent> propertySheetFacets = propertySheet
186: .getFacets();
187: Iterator<String> it = facets.keySet().iterator();
188: String facetName;
189: UIComponent facetValue;
190: while (it.hasNext()) {
191: facetName = it.next();
192: facetValue = facets.get(facetName);
193: if (facetValue != null) {
194: propertySheetFacets.put(facetName, facetValue);
195: }
196: }
197: }
198:
199: // Add instance handlers
200: Map<String, List<Handler>> handlersByType = adaptor
201: .getHandlersByType(propertySheet, currentObj);
202: if (handlersByType != null) {
203: Iterator<String> it = handlersByType.keySet().iterator();
204: if (it.hasNext()) {
205: String eventType = null;
206: Map<String, Object> compAttrs = propertySheet
207: .getAttributes();
208: while (it.hasNext()) {
209: // Assign instance handlers to attribute for retrieval later
210: // (Retrieval must be explicit, see LayoutElementBase)
211: eventType = it.next();
212: compAttrs.put(eventType, handlersByType
213: .get(eventType));
214: }
215: }
216: }
217: }
218:
219: /**
220: * <p> This is the option that must be supplied when using this factory
221: * in order to specify which PropertySheetAdaptor instance should be used.
222: * The value should be a fully qualified class name of a valid
223: * PropertySheetAdaptor instance. The PropertySheetAdaptor instance must have a
224: * <code>public static PropertySheetAdaptor getInstance(FacesContext,
225: * LayoutComponent, UIComponent)</code> method in order to get access
226: * to an instance of the PropertySheetAdaptor instance.</p>
227: */
228: public static final String PROPERTY_SHEET_ADAPTOR_CLASS = "propertySheetAdaptorClass";
229: }
|