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