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.orchestra.dynaForm.jsf.component;
20
21 import org.apache.myfaces.orchestra.dynaForm.metadata.MetaFieldWritable;
22
23 import javax.faces.component.UIComponent;
24 import javax.faces.component.UIComponentBase;
25 import javax.faces.context.FacesContext;
26 import javax.faces.el.ValueBinding;
27
28 /**
29 * Overrule the way DynaForm presents a specific persistent attribute.
30 * <p>
31 * The DynaForm uses a pluggable Extractor to analyse a particular class and determine what
32 * persistent properties it has, and how to render them. By default the dynaform will
33 * create a JSF component for each one of the detected persistent properties, using the
34 * detected metadata.
35 * <p>
36 * Any number of instances of this component can be added as children to a DynaForm component
37 * to override the settings auto-detected by the Extractor. Each instance overrides the properties
38 * of a single persistent field. The attribute "for" on this component should specify the name
39 * of the property to be overridden on the persistent object associated with the DynaForm.
40 * <p>
41 * This component can also have a single child component, in which case that is used as the
42 * component for rendering this dynamic field.
43 */
44 public class DynaConfig extends UIComponentBase
45 {
46 public static final String COMPONENT_TYPE = "org.apache.myfaces.orchestra.dynaForm.DynaConfig";
47 public static final String COMPONENT_FAMILY = "org.apache.myfaces.orchestra.dynaForm.DynaForm";
48
49 private String forProperty;
50 private Integer displaySize;
51 private Boolean displayOnly;
52 private Boolean readOnly;
53 private Boolean disabled;
54 private Object componentHandler;
55
56 @Override
57 public String getFamily()
58 {
59 return COMPONENT_FAMILY;
60 }
61
62 /**
63 * @see #setDisplaySize(Integer)
64 */
65 public Integer getDisplaySize()
66 {
67 if (displaySize != null)
68 {
69 return displaySize;
70 }
71 ValueBinding vb = getValueBinding("displaySize");
72 return vb != null ? (Integer) vb.getValue(getFacesContext()) : null;
73 }
74
75 /**
76 * a hint for the size the ui should use when rendering the field
77 */
78 public void setDisplaySize(Integer displaySize)
79 {
80 this.displaySize = displaySize;
81 }
82
83 /**
84 * @see #setDisplayOnly(Boolean)
85 */
86 public Boolean getDisplayOnly()
87 {
88 if (displayOnly != null)
89 {
90 return displayOnly;
91 }
92 ValueBinding vb = getValueBinding("displayOnly");
93 return vb != null ? (Boolean) vb.getValue(getFacesContext()) : null;
94 }
95
96 /**
97 * set the field to display only
98 */
99 public void setDisplayOnly(Boolean displayOnly)
100 {
101 this.displayOnly = displayOnly;
102 }
103
104 /**
105 * @see #setReadOnly(Boolean)
106 */
107 public Boolean getReadOnly()
108 {
109 if (readOnly != null)
110 {
111 return readOnly;
112 }
113 ValueBinding vb = getValueBinding("readOnly");
114 return vb != null ? (Boolean) vb.getValue(getFacesContext()) : null;
115 }
116
117 /**
118 * configure this field as readOnly - noneditable input field
119 */
120 public void setReadOnly(Boolean readOnly)
121 {
122 this.readOnly = readOnly;
123 }
124
125 /**
126 * @see #setDisabled(Boolean)
127 */
128 public Boolean getDisabled()
129 {
130 if (disabled != null)
131 {
132 return disabled;
133 }
134 ValueBinding vb = getValueBinding("disabled");
135 return vb != null ? (Boolean) vb.getValue(getFacesContext()) : null;
136 }
137
138 /**
139 * configure this field as disabled - like readOnly but grayed too
140 */
141 public void setDisabled(Boolean disabled)
142 {
143 this.disabled = disabled;
144 }
145
146 /**
147 * Specifies the "controller bean" used to render this specific field.
148 * <p>
149 * This may return:
150 * <ul>
151 * <li>Null when there is no special component-handler..</li>
152 * <li>A String which is the name of a managed-bean that implements DynaFormComponentHandler</li>
153 * <li>A DynaFormComponentHandler object</li>
154 * </ul>
155 * <p>
156 * The configureMetaData method of this class just copies this setting into a MetaField object
157 * which is later used when building the components necessary to manage this field.
158 * <p>
159 * When the value is null, dynaform will create a default component to manage this field,
160 * depending on its type.
161 * <p>
162 * In the other cases, the DynaFormComponentHandler object is responsible for creating the
163 * necessary UI components to manage this field.
164 * <p>
165 * Normally, the JSP/Facelets framework will set this property to a String when the user
166 * provides a non-EL-expression, and will put a ValueBinding object into this component's
167 * value-binding map when the user provides an EL expression. As the value-binding could
168 * return a DynaFormComponentHandler or a String, this property type must be Object.
169 */
170 public Object getComponentHandler()
171 {
172 if (componentHandler != null)
173 {
174 return componentHandler;
175 }
176 ValueBinding vb = getValueBinding("componentHandler");
177 return vb != null ? vb.getValue(getFacesContext()) : null;
178 }
179
180 /**
181 * Specifies the "controller bean" used to render this specific field.
182 * <p>
183 * This should be the name of a managed bean which implements DynaFormComponentHandler,
184 * or an actual DynaFormComponentHandler instance.
185 */
186 public void setComponentHandler(Object value)
187 {
188 this.componentHandler = value;
189 }
190
191 /**
192 * @see #setFor(String)
193 */
194 public String getFor()
195 {
196 if (forProperty != null)
197 {
198 return forProperty;
199 }
200 ValueBinding vb = getValueBinding("for");
201 return vb != null ? (String) vb.getValue(getFacesContext()) : null;
202 }
203
204 /**
205 * the name of the property this configuration is for
206 */
207 public void setFor(String forProperty)
208 {
209 this.forProperty = forProperty;
210 }
211
212 @Override
213 public void restoreState(FacesContext context, Object stateArray)
214 {
215 Object[] states = (Object[]) stateArray;
216 super.restoreState(context, states[0]);
217 displaySize = (Integer) states[1];
218 forProperty = (String) states[2];
219 displayOnly = (Boolean) states[3];
220 readOnly = (Boolean) states[4];
221 disabled = (Boolean) states[5];
222 componentHandler = (String) states[6];
223 }
224
225 @Override
226 public Object saveState(FacesContext context)
227 {
228 return new Object[]
229 {
230 super.saveState(context),
231 displaySize,
232 forProperty,
233 displayOnly,
234 readOnly,
235 disabled,
236 componentHandler
237 };
238 }
239
240 /**
241 * Update the specified field with the settings the user has configured from this JSF component.
242 * <p>
243 * This method is called <i>after</i> the user-specified extractor implementation is called. This
244 * means that any settings the user has defined in the JSF can override those auto-detected via
245 * the earlier extractor. However here we must only override earlier settings if they really
246 * have been set in the JSF config.
247 */
248 public void configureMetaData(MetaFieldWritable field)
249 {
250 Integer displaySize = getDisplaySize();
251 if (displaySize != null)
252 {
253 field.setDisplaySize(displaySize.intValue());
254 }
255
256 Boolean displayOnly = getDisplayOnly();
257 if (displayOnly != null)
258 {
259 field.setDisplayOnly(displayOnly.booleanValue());
260 }
261
262 // readOnly is a synonym for displayOnly
263 Boolean readOnly = getReadOnly();
264 if (readOnly != null)
265 {
266 field.setDisplayOnly(readOnly.booleanValue());
267 }
268
269 Boolean disabled = getDisabled();
270 if (disabled != null)
271 {
272 // Note: the disabled property is deprecated
273 field.setDisabled(disabled.booleanValue());
274 }
275
276 Object ch = getComponentHandler();
277 if (ch != null)
278 {
279 field.setComponentHandler(ch);
280 }
281
282 if (getChildCount() > 0)
283 {
284 field.setWantedComponent((UIComponent) getChildren().get(0));
285 }
286 }
287 }