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 javax.faces.component;
20  
21  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFComponent;
22  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFProperty;
23  
24  import javax.faces.FacesException;
25  import javax.faces.component.visit.VisitCallback;
26  import javax.faces.component.visit.VisitContext;
27  import javax.faces.component.visit.VisitResult;
28  import javax.faces.context.FacesContext;
29  import javax.faces.event.PostValidateEvent;
30  import javax.faces.event.PreValidateEvent;
31  import javax.faces.view.Location;
32  
33  import java.util.Collection;
34  
35  /**
36   * see Javadoc of <a href="http://java.sun.com/javaee/javaserverfaces/1.2/docs/api/index.html">JSF Specification</a>
37   * 
38   * @author Manfred Geiler (latest modification by $Author: lu4242 $)
39   * @version $Revision: 1306709 $ $Date: 2012-03-28 23:26:51 -0500 (Wed, 28 Mar 2012) $
40   */
41  @JSFComponent(type = "javax.faces.Form", family = "javax.faces.Form")
42  public class UIForm extends UIComponentBase implements NamingContainer, UniqueIdVendor
43  {
44      // private static final Log log = LogFactory.getLog(UIForm.class);
45  
46      //private boolean _submitted;
47  
48      /**
49       * 
50       * {@inheritDoc}
51       * 
52       * @since 2.0
53       */
54      public String createUniqueId(FacesContext context, String seed)
55      {
56          StringBuilder bld = null;
57          
58          if (!isPrependId())
59          {
60              bld = new StringBuilder();
61              UniqueIdVendor parentUniqueIdVendor = _ComponentUtils.findParentUniqueIdVendor(this);
62              if (parentUniqueIdVendor == null)
63              {
64                  UIViewRoot viewRoot = context.getViewRoot();
65                  if (viewRoot != null)
66                  {
67                      bld.append(viewRoot.createUniqueId());
68                      bld.append('_');
69                  }
70                  else
71                  {
72                      // The RI throws a NPE
73                      String location = getComponentLocation(this);
74                      throw new FacesException("Cannot create clientId. No id is assigned for component"
75                              + " to create an id and UIViewRoot is not defined: "
76                              + getPathToComponent(this)
77                              + (location != null ? " created from: " + location : ""));
78                  }
79              }
80              else
81              {
82                  bld.append(parentUniqueIdVendor.createUniqueId(context, null));
83                  bld.append('_');
84              }
85          }
86          else
87          {
88              bld = _getSharedStringBuilder(context);
89          }
90  
91          // Generate an identifier for a component. The identifier will be prefixed with
92          // UNIQUE_ID_PREFIX, and will be unique within this UIViewRoot.
93          if(seed==null)
94          {
95              Long uniqueIdCounter = (Long) getStateHelper().get(PropertyKeys.uniqueIdCounter);
96              uniqueIdCounter = (uniqueIdCounter == null) ? 0 : uniqueIdCounter;
97              getStateHelper().put(PropertyKeys.uniqueIdCounter, (uniqueIdCounter+1L));
98              return bld.append(UIViewRoot.UNIQUE_ID_PREFIX).append(uniqueIdCounter).toString();    
99          }
100         // Optionally, a unique seed value can be supplied by component creators
101         // which should be included in the generated unique id.
102         else
103         {
104             return bld.append(UIViewRoot.UNIQUE_ID_PREFIX).append(seed).toString();
105         }
106     }
107     
108     public boolean isSubmitted()
109     {
110         //return _submitted;
111         return (Boolean) getTransientStateHelper().getTransient(PropertyKeys.submitted, false);
112     }
113 
114     public void setSubmitted(boolean submitted)
115     {
116         getTransientStateHelper().putTransient(PropertyKeys.submitted, submitted);
117         //_submitted = submitted;
118     }
119 
120     @Override
121     public void processDecodes(FacesContext context)
122     {
123         if (context == null)
124         {
125             throw new NullPointerException("context");
126         }
127         try
128         {
129             setCachedFacesContext(context);
130             try
131             {
132                 pushComponentToEL(context, this);
133                 
134                 decode(context);
135                 
136                 if (!isSubmitted())
137                 {
138                     return;
139                 }
140 
141                 int facetCount = getFacetCount();
142                 if (facetCount > 0)
143                 {
144                     for (UIComponent facet : getFacets().values())
145                     {
146                         facet.processDecodes(context);
147                     }
148                 }
149                 
150                 for (int i = 0, childCount = getChildCount(); i < childCount; i++)
151                 {
152                     UIComponent child = getChildren().get(i);
153                     child.processDecodes(context);
154                 }
155                 
156             }
157             finally
158             {
159                 popComponentFromEL(context);
160             }
161         }
162         finally
163         {
164             setCachedFacesContext(null);
165         }
166     }
167 
168     @Override
169     public void processValidators(FacesContext context)
170     {
171         if (context == null)
172         {
173             throw new NullPointerException("context");
174         }
175         
176         try
177         {
178             setCachedFacesContext(context);
179             try
180             {
181                 pushComponentToEL(context, this);
182                 // SF issue #1050022: a form used within a datatable will loose it's submitted state
183                 // as UIForm is no EditableValueHolder and therefore it's state is not saved/restored by UIData
184                 // to restore the submitted state we call decode here again
185                 if (!isSubmitted())
186                 {
187                     decode(context);
188                 }
189                 if (!isSubmitted())
190                 {
191                     return;
192                 }
193 
194                 //Pre validation event dispatch for component
195                 context.getApplication().publishEvent(context,  PreValidateEvent.class, getClass(), this);
196                 
197                 int facetCount = getFacetCount();
198                 if (facetCount > 0)
199                 {
200                     for (UIComponent facet : getFacets().values())
201                     {
202                         facet.processValidators(context);
203                     }
204                 }
205                 
206                 for (int i = 0, childCount = getChildCount(); i < childCount; i++)
207                 {
208                     UIComponent child = getChildren().get(i);
209                     child.processValidators(context);
210                 }
211                 
212             }
213             finally
214             {
215                 context.getApplication().publishEvent(context,  PostValidateEvent.class, getClass(), this);
216                 popComponentFromEL(context);
217             }
218         }
219         finally
220         {
221             setCachedFacesContext(null);
222         }
223     }
224 
225     @Override
226     public void processUpdates(FacesContext context)
227     {
228         if (context == null)
229         {
230             throw new NullPointerException("context");
231         }
232         
233         try
234         {
235             setCachedFacesContext(context);
236             try
237             {
238                 pushComponentToEL(context, this);
239                 // SF issue #1050022: a form used within a datatable will loose it's submitted state
240                 // as UIForm is no EditableValueHolder and therefore it's state is not saved/restored by UIData
241                 // to restore the submitted state we call decode here again
242                 if (!isSubmitted())
243                 {
244                     decode(context);
245                 }
246                 if (!isSubmitted())
247                 {
248                     return;
249                 }
250                 
251                 int facetCount = getFacetCount();
252                 if (facetCount > 0)
253                 {
254                     for (UIComponent facet : getFacets().values())
255                     {
256                         facet.processUpdates(context);
257                     }
258                 }
259                 
260                 for (int i = 0, childCount = getChildCount(); i < childCount; i++)
261                 {
262                     UIComponent child = getChildren().get(i);
263                     child.processUpdates(context);
264                 }
265 
266             }
267             finally
268             {
269                 popComponentFromEL(context);
270             }
271         }
272         finally
273         {
274             setCachedFacesContext(null);
275         }
276     }
277 
278     enum PropertyKeys
279     {
280          prependId,
281          uniqueIdCounter,
282          submitted,
283     }
284     
285     @Override
286     public Object saveState(FacesContext context)
287     {
288         // The saveState() method of UIForm must call setSubmitted(false) before calling super.saveState() as an 
289         // extra precaution to ensure the submitted state is not persisted across requests.
290         //setSubmitted(false);
291 
292         return super.saveState(context);
293     }
294     
295     @Override
296     public boolean visitTree(VisitContext context, VisitCallback callback)
297     {
298         if (!isPrependId())
299         {
300             // Since the container client id will not be added to child clientId,
301             // It is not possible to take advantage of NamingContainer interface
302             // and prevent visit child nodes. Just do it as default.
303             return super.visitTree(context, callback);
304         }
305         else
306         {
307             boolean isCachedFacesContext = isCachedFacesContext();
308             try
309             {
310                 if (!isCachedFacesContext)
311                 {
312                     setCachedFacesContext(context.getFacesContext());
313                 }
314                 
315                 if (!isVisitable(context))
316                 {
317                     return false;
318                 }
319         
320                 pushComponentToEL(context.getFacesContext(), this);
321                 try
322                 {
323                     VisitResult res = context.invokeVisitCallback(this, callback);
324                     switch (res)
325                     {
326                     //we are done nothing has to be processed anymore
327                     case COMPLETE:
328                         return true;
329         
330                     case REJECT:
331                         return false;
332         
333                     //accept
334                     default:
335                         // Take advantage of the fact this is a NamingContainer
336                         // and we can know if there are ids to visit inside it 
337                         Collection<String> subtreeIdsToVisit = context.getSubtreeIdsToVisit(this);
338                         
339                         if (subtreeIdsToVisit != null && !subtreeIdsToVisit.isEmpty())
340                         {
341                             if (getFacetCount() > 0)
342                             {
343                                 for (UIComponent facet : getFacets().values())
344                                 {
345                                     if (facet.visitTree(context, callback))
346                                     {
347                                         return true;
348                                     }
349                                 }
350                             }
351                             for (int i = 0, childCount = getChildCount(); i < childCount; i++)
352                             {
353                                 UIComponent child = getChildren().get(i);
354                                 if (child.visitTree(context, callback))
355                                 {
356                                     return true;
357                                 }
358                             }
359                         }
360                         return false;
361                     }
362                 }
363                 finally
364                 {
365                     //all components must call popComponentFromEl after visiting is finished
366                     popComponentFromEL(context.getFacesContext());
367                 }
368             }
369             finally
370             {
371                 if (!isCachedFacesContext)
372                 {
373                     setCachedFacesContext(null);
374                 }
375             }
376         }
377     }
378 
379     // ------------------ GENERATED CODE BEGIN (do not modify!) --------------------
380 
381     public static final String COMPONENT_TYPE = "javax.faces.Form";
382     public static final String COMPONENT_FAMILY = "javax.faces.Form";
383     private static final String DEFAULT_RENDERER_TYPE = "javax.faces.Form";
384 
385     public UIForm()
386     {
387         setRendererType(DEFAULT_RENDERER_TYPE);
388     }
389 
390     @Override
391     public String getFamily()
392     {
393         return COMPONENT_FAMILY;
394     }
395 
396     private String getComponentLocation(UIComponent component)
397     {
398         Location location = (Location) component.getAttributes()
399                 .get(UIComponent.VIEW_LOCATION_KEY);
400         if (location != null)
401         {
402             return location.toString();
403         }
404         return null;
405     }
406     
407     private String getPathToComponent(UIComponent component)
408     {
409         StringBuffer buf = new StringBuffer();
410 
411         if (component == null)
412         {
413             buf.append("{Component-Path : ");
414             buf.append("[null]}");
415             return buf.toString();
416         }
417 
418         getPathToComponent(component, buf);
419 
420         buf.insert(0, "{Component-Path : ");
421         buf.append("}");
422 
423         return buf.toString();
424     }
425     
426     private void getPathToComponent(UIComponent component, StringBuffer buf)
427     {
428         if (component == null)
429         {
430             return;
431         }
432 
433         StringBuffer intBuf = new StringBuffer();
434 
435         intBuf.append("[Class: ");
436         intBuf.append(component.getClass().getName());
437         if (component instanceof UIViewRoot)
438         {
439             intBuf.append(",ViewId: ");
440             intBuf.append(((UIViewRoot) component).getViewId());
441         }
442         else
443         {
444             intBuf.append(",Id: ");
445             intBuf.append(component.getId());
446         }
447         intBuf.append("]");
448 
449         buf.insert(0, intBuf.toString());
450 
451         getPathToComponent(component.getParent(), buf);
452     }
453 
454     // ------------------ GENERATED CODE END ---------------------------------------
455 
456     @Override
457     public String getContainerClientId(FacesContext ctx)
458     {
459         if (isPrependId())
460         {
461             return super.getContainerClientId(ctx);
462         }
463         UIComponent parentNamingContainer = _ComponentUtils.findParentNamingContainer(this, false);
464         if (parentNamingContainer != null)
465         {
466             return parentNamingContainer.getContainerClientId(ctx);
467         }
468         return null;
469     }
470 
471     @JSFProperty(defaultValue = "true")
472     public boolean isPrependId()
473     {
474         return (Boolean) getStateHelper().eval(PropertyKeys.prependId, true);
475     }
476 
477     public void setPrependId(boolean prependId)
478     {
479         getStateHelper().put(PropertyKeys.prependId, prependId ); 
480     }
481 
482 }