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              Integer uniqueIdCounter = (Integer) getStateHelper().get(PropertyKeys.uniqueIdCounter);
81              uniqueIdCounter = (uniqueIdCounter == null) ? 0 : uniqueIdCounter;
82              getStateHelper().put(PropertyKeys.uniqueIdCounter, (uniqueIdCounter+1));
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         pushComponentToEL(context.getFacesContext(), this);
140         boolean isCachedFacesContext = isCachedFacesContext();
141         try
142         {
143             if (!isCachedFacesContext)
144             {
145                 setCachedFacesContext(context.getFacesContext());
146             }
147 
148             if (!isVisitable(context))
149             {
150                 return false;
151             }
152 
153             VisitResult res = context.invokeVisitCallback(this, callback);
154             switch (res)
155             {
156                 //we are done nothing has to be processed anymore
157                 case COMPLETE:
158                     return true;
159 
160                 case REJECT:
161                     return false;
162 
163                 //accept
164                 default:
165                     // Take advantage of the fact this is a NamingContainer
166                     // and we can know if there are ids to visit inside it
167                     Collection<String> subtreeIdsToVisit = context.getSubtreeIdsToVisit(this);
168 
169                     if (subtreeIdsToVisit != null && !subtreeIdsToVisit.isEmpty())
170                     {
171                         if (getFacetCount() > 0)
172                         {
173                             for (UIComponent facet : getFacets().values())
174                             {
175                                 if (facet.visitTree(context, callback))
176                                 {
177                                     return true;
178                                 }
179                             }
180                         }
181                         for (int i = 0, childCount = getChildCount(); i < childCount; i++)
182                         {
183                             UIComponent child = getChildren().get(i);
184                             if (child.visitTree(context, callback))
185                             {
186                                 return true;
187                             }
188                         }
189                     }
190                     return false;
191             }
192         }
193         finally
194         {
195             //all components must call popComponentFromEl after visiting is finished
196             popComponentFromEL(context.getFacesContext());
197             if (!isCachedFacesContext)
198             {
199                 setCachedFacesContext(null);
200             }
201         }
202     }
203 
204     enum PropertyKeys
205     {
206         uniqueIdCounter
207     }
208 }