1 /* 2 * $Id: UINamingContainer.java,v 1.19 2007/04/27 22:00:05 ofung Exp $ 3 */ 4 5 /* 6 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 7 * 8 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. 9 * 10 * The contents of this file are subject to the terms of either the GNU 11 * General Public License Version 2 only ("GPL") or the Common Development 12 * and Distribution License("CDDL") (collectively, the "License"). You 13 * may not use this file except in compliance with the License. You can obtain 14 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html 15 * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific 16 * language governing permissions and limitations under the License. 17 * 18 * When distributing the software, include this License Header Notice in each 19 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt. 20 * Sun designates this particular file as subject to the "Classpath" exception 21 * as provided by Sun in the GPL Version 2 section of the License file that 22 * accompanied this code. If applicable, add the following below the License 23 * Header, with the fields enclosed by brackets [] replaced by your own 24 * identifying information: "Portions Copyrighted [year] 25 * [name of copyright owner]" 26 * 27 * Contributor(s): 28 * 29 * If you wish your version of this file to be governed by only the CDDL or 30 * only the GPL Version 2, indicate your decision by adding "[Contributor] 31 * elects to include this software in this distribution under the [CDDL or GPL 32 * Version 2] license." If you don't indicate a single choice of license, a 33 * recipient has the option to distribute your version of this file under 34 * either the CDDL, the GPL Version 2 or to extend the choice of license to 35 * its licensees as provided above. However, if you add GPL Version 2 code 36 * and therefore, elected the GPL Version 2 license, then the option applies 37 * only if the new code is made subject to such option by the copyright 38 * holder. 39 */ 40 41 package javax.faces.component; 42 43 import java.util.Collection; 44 45 import javax.faces.component.visit.VisitCallback; 46 import javax.faces.component.visit.VisitContext; 47 import javax.faces.component.visit.VisitResult; 48 import javax.faces.context.FacesContext; 49 50 51 /** 52 * <p><strong class="changed_modified_2_0">UINamingContainer</strong> is a 53 * convenience base class for components that wish to implement {@link 54 * NamingContainer} functionality.</p> 55 */ 56 57 public class UINamingContainer extends UIComponentBase 58 implements NamingContainer, UniqueIdVendor, StateHolder { 59 60 61 // ------------------------------------------------------ Manifest Constants 62 63 64 /** 65 * <p>The standard component type for this component.</p> 66 */ 67 public static final String COMPONENT_TYPE = "javax.faces.NamingContainer"; 68 69 70 /** 71 * <p>The standard component family for this component.</p> 72 */ 73 public static final String COMPONENT_FAMILY = "javax.faces.NamingContainer"; 74 75 /** 76 * <p class="changed_added_2_0">The context-param that allows the separator 77 * char for clientId strings to be set on a per-web application basis.</p> 78 * 79 * @since 2.0 80 */ 81 public static final String SEPARATOR_CHAR_PARAM_NAME = 82 "javax.faces.SEPARATOR_CHAR"; 83 84 85 enum PropertyKeys { 86 lastId 87 } 88 89 90 // ------------------------------------------------------------ Constructors 91 92 93 /** 94 * <p>Create a new {@link UINamingContainer} instance with default property 95 * values.</p> 96 */ 97 public UINamingContainer() { 98 99 super(); 100 setRendererType(null); 101 102 } 103 104 105 // -------------------------------------------------------------- Properties 106 107 108 public String getFamily() { 109 110 return (COMPONENT_FAMILY); 111 112 } 113 114 /** 115 * <p class="changed_added_2_0">Return the character used to separate 116 * segments of a clientId. The implementation must determine if there is a 117 * <<code>context-param</code>> with the value given by the value of 118 * the symbolic constant {@link #SEPARATOR_CHAR_PARAM_NAME}. If there is a 119 * value for this param, the first character of the value must be returned 120 * from this method. Otherwise, the value of the symbolic constant {@link 121 * NamingContainer#SEPARATOR_CHAR} must be returned.</p> 122 * 123 * @param context the {@link FacesContext} for the current request 124 * @since 2.0 125 */ 126 public static char getSeparatorChar(FacesContext context) { 127 128 129 Character separatorChar = 130 (Character) context.getAttributes().get(SEPARATOR_CHAR_PARAM_NAME); 131 if (separatorChar == null) { 132 String initParam = context.getExternalContext().getInitParameter(SEPARATOR_CHAR_PARAM_NAME); 133 separatorChar = NamingContainer.SEPARATOR_CHAR; 134 if (initParam != null) { 135 initParam = initParam.trim(); 136 if (initParam.length() != 0) { 137 separatorChar = initParam.charAt(0); 138 } 139 } 140 context.getAttributes().put(SEPARATOR_CHAR_PARAM_NAME, separatorChar); 141 } 142 return separatorChar; 143 144 } 145 146 /** 147 * @see UIComponent#visitTree 148 */ 149 @Override 150 public boolean visitTree(VisitContext context, 151 VisitCallback callback) { 152 153 // NamingContainers can optimize partial tree visits by taking advantage 154 // of the fact that it is possible to detect whether any ids to visit 155 // exist underneath the NamingContainer. If no such ids exist, there 156 // is no need to visit the subtree under the NamingContainer. 157 Collection<String> idsToVisit = context.getSubtreeIdsToVisit(this); 158 assert(idsToVisit != null); 159 160 // If we have ids to visit, let the superclass implementation 161 // handle the visit 162 if (!idsToVisit.isEmpty()) { 163 return super.visitTree(context, callback); 164 } 165 166 // If we have no child ids to visit, just visit ourselves, if 167 // we are visitable. 168 if (isVisitable(context)) { 169 FacesContext facesContext = context.getFacesContext(); 170 pushComponentToEL(facesContext, null); 171 172 try { 173 VisitResult result = context.invokeVisitCallback(this, callback); 174 return (result == VisitResult.COMPLETE); 175 } 176 finally { 177 popComponentFromEL(facesContext); 178 } 179 } 180 181 // Done visiting this subtree. Return false to allow 182 // visit to continue. 183 return false; 184 } 185 186 public String createUniqueId(FacesContext context, String seed) { 187 Integer i = (Integer) getStateHelper().get(PropertyKeys.lastId); 188 int lastId = ((i != null) ? i : 0); 189 getStateHelper().put(PropertyKeys.lastId, ++lastId); 190 return UIViewRoot.UNIQUE_ID_PREFIX + (seed == null ? lastId : seed); 191 } 192 193 } 194