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 java.util.Collection;
22  import java.util.Map;
23  
24  import javax.faces.component.visit.VisitCallback;
25  import javax.faces.component.visit.VisitContext;
26  import javax.faces.component.visit.VisitResult;
27  import javax.faces.context.ExternalContext;
28  import javax.faces.context.FacesContext;
29  
30  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFComponent;
31  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFJspProperty;
32  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFProperty;
33  
34  /**
35   * Base class for components that provide a new "namespace" for the ids of their
36   * child components.
37   * <p>
38   * See the javadocs for interface NamingContainer for further details.
39   * </p>
40   */
41  @JSFComponent(
42          name="f:subview",
43          bodyContent="JSP",
44          tagClass="org.apache.myfaces.taglib.core.SubviewTag")
45  @JSFJspProperty(name="id",required=true)
46  public class UINamingContainer extends UIComponentBase implements NamingContainer, UniqueIdVendor
47  {
48      public static final String COMPONENT_TYPE = "javax.faces.NamingContainer";
49      public static final String COMPONENT_FAMILY = "javax.faces.NamingContainer";
50      public static final String SEPARATOR_CHAR_PARAM_NAME = "javax.faces.SEPARATOR_CHAR";
51  
52      /**
53       * Construct an instance of the UINamingContainer.
54       */
55      public UINamingContainer()
56      {
57          setRendererType(null);
58      }
59  
60      @Override
61      public String getFamily()
62      {
63          return COMPONENT_FAMILY;
64      }
65  
66      /**
67       * 
68       * {@inheritDoc}
69       * 
70       * @since 2.0
71       */
72      public String createUniqueId(FacesContext context, String seed)
73      {
74          StringBuilder bld = _getSharedStringBuilder(context);
75  
76          // Generate an identifier for a component. The identifier will be prefixed with UNIQUE_ID_PREFIX,
77          // and will be unique within this UIViewRoot.
78          if(seed==null)
79          {
80              Long uniqueIdCounter = (Long) getStateHelper().get(PropertyKeys.uniqueIdCounter);
81              uniqueIdCounter = (uniqueIdCounter == null) ? 0 : uniqueIdCounter;
82              getStateHelper().put(PropertyKeys.uniqueIdCounter, (uniqueIdCounter+1L));
83              return bld.append(UIViewRoot.UNIQUE_ID_PREFIX).append(uniqueIdCounter).toString();    
84          }
85          // Optionally, a unique seed value can be supplied by component creators
86          // which should be included in the generated unique id.
87          else
88          {
89              return bld.append(UIViewRoot.UNIQUE_ID_PREFIX).append(seed).toString();
90          }
91      }
92      
93      /**
94       * 
95       * @param context
96       * @return
97       * 
98       * @since 2.0
99       */
100     @SuppressWarnings("deprecation")
101     public static char getSeparatorChar(FacesContext context)
102     {
103         Map<Object, Object> attributes = context.getAttributes();
104         Character separatorChar = (Character) attributes.get(SEPARATOR_CHAR_PARAM_NAME);
105         if (separatorChar == null)
106         { // not cached yet for this request
107             ExternalContext eContext = context.getExternalContext();
108             
109             // The implementation must determine if there is a <context-param> with the value given by the 
110             // value of the symbolic constant SEPARATOR_CHAR_PARAM_NAME
111             String param = eContext.getInitParameter(SEPARATOR_CHAR_PARAM_NAME);
112             if (param == null || param.length() == 0)
113             {
114                 // Otherwise, the value of the symbolic constant NamingContainer.SEPARATOR_CHAR must be returned.
115                 separatorChar = NamingContainer.SEPARATOR_CHAR;
116             }
117             else
118             {
119                 // If there is a value for this param, the first character of the value must be returned from 
120                 // this method
121                 separatorChar = param.charAt(0);
122             }
123             // Cache it under standard name
124             attributes.put(SEPARATOR_CHAR_PARAM_NAME, separatorChar);
125         }
126         return separatorChar.charValue();
127     }
128     
129     @JSFProperty(deferredValueType="java.lang.Boolean")
130     @Override
131     public boolean isRendered()
132     {
133         return super.isRendered();
134     }
135     
136     @Override
137     public boolean visitTree(VisitContext context, VisitCallback callback)
138     {
139         boolean isCachedFacesContext = isCachedFacesContext();
140         try
141         {
142             if (!isCachedFacesContext)
143             {
144                 setCachedFacesContext(context.getFacesContext());
145             }
146             
147             if (!isVisitable(context))
148             {
149                 return false;
150             }
151     
152             pushComponentToEL(context.getFacesContext(), this);
153             try
154             {
155                 VisitResult res = context.invokeVisitCallback(this, callback);
156                 switch (res)
157                 {
158                     //we are done nothing has to be processed anymore
159                     case COMPLETE:
160                         return true;
161 
162                     case REJECT:
163                         return false;
164 
165                     //accept
166                     default:
167                         // Take advantage of the fact this is a NamingContainer
168                         // and we can know if there are ids to visit inside it
169                         Collection<String> subtreeIdsToVisit = context.getSubtreeIdsToVisit(this);
170 
171                         if (subtreeIdsToVisit != null && !subtreeIdsToVisit.isEmpty())
172                         {
173                             if (getFacetCount() > 0)
174                             {
175                                 for (UIComponent facet : getFacets().values())
176                                 {
177                                     if (facet.visitTree(context, callback))
178                                     {
179                                         return true;
180                                     }
181                                 }
182                             }
183                             for (int i = 0, childCount = getChildCount(); i < childCount; i++)
184                             {
185                                 UIComponent child = getChildren().get(i);
186                                 if (child.visitTree(context, callback))
187                                 {
188                                     return true;
189                                 }
190                             }
191                         }
192                         return false;
193                 }
194             }
195             finally
196             {
197                 //all components must call popComponentFromEl after visiting is finished
198                 popComponentFromEL(context.getFacesContext());
199             }
200         }
201         finally
202         {
203             if (!isCachedFacesContext)
204             {
205                 setCachedFacesContext(null);
206             }
207         }
208     }
209 
210     enum PropertyKeys
211     {
212         uniqueIdCounter
213     }
214 }