View Javadoc

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 }