1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 * 4 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. 5 * 6 * The contents of this file are subject to the terms of either the GNU 7 * General Public License Version 2 only ("GPL") or the Common Development 8 * and Distribution License("CDDL") (collectively, the "License"). You 9 * may not use this file except in compliance with the License. You can obtain 10 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html 11 * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific 12 * language governing permissions and limitations under the License. 13 * 14 * When distributing the software, include this License Header Notice in each 15 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt. 16 * Sun designates this particular file as subject to the "Classpath" exception 17 * as provided by Sun in the GPL Version 2 section of the License file that 18 * accompanied this code. If applicable, add the following below the License 19 * Header, with the fields enclosed by brackets [] replaced by your own 20 * identifying information: "Portions Copyrighted [year] 21 * [name of copyright owner]" 22 * 23 * Contributor(s): 24 * 25 * If you wish your version of this file to be governed by only the CDDL or 26 * only the GPL Version 2, indicate your decision by adding "[Contributor] 27 * elects to include this software in this distribution under the [CDDL or GPL 28 * Version 2] license." If you don't indicate a single choice of license, a 29 * recipient has the option to distribute your version of this file under 30 * either the CDDL, the GPL Version 2 or to extend the choice of license to 31 * its licensees as provided above. However, if you add GPL Version 2 code 32 * and therefore, elected the GPL Version 2 license, then the option applies 33 * only if the new code is made subject to such option by the copyright 34 * holder. 35 */ 36 37 38 package javax.faces.component; 39 40 import javax.faces.context.FacesContext; 41 import static javax.faces.component.UIComponentBase.saveAttachedState; 42 import static javax.faces.component.UIComponentBase.restoreAttachedState; 43 import javax.el.ValueExpression; 44 import java.util; 45 import java.io.Serializable; 46 47 /**A base implementation for 48 * maps which implement the PartialStateHolder interface. 49 * 50 * This can be used as a base-class for all 51 * state-holder implementations in components, 52 * converters and validators and other implementations 53 * of the StateHolder interface. 54 */ 55 @SuppressWarnings({"unchecked"}) 56 class ComponentStateHelper implements StateHelper { 57 58 private UIComponent component; 59 private boolean isTransient; 60 private Map<Serializable, Object> deltaMap; 61 private Map<Serializable, Object> defaultMap; 62 63 // ------------------------------------------------------------ Constructors 64 65 66 public ComponentStateHelper(UIComponent component) { 67 68 this.component = component; 69 this.deltaMap = new HashMap<Serializable,Object>(); 70 this.defaultMap = new HashMap<Serializable,Object>(); 71 72 } 73 74 75 // ------------------------------------------------ Methods from StateHelper 76 77 78 /** 79 * Put the object in the main-map 80 * and/or the delta-map, if necessary. 81 * 82 * @param key 83 * @param value 84 * @return the original value in the delta-map, if not present, the old value in the main map 85 */ 86 public Object put(Serializable key, Object value) { 87 88 if(component.initialStateMarked() || value instanceof PartialStateHolder) { 89 Object retVal = deltaMap.put(key, value); 90 91 if(retVal==null) { 92 return defaultMap.put(key,value); 93 } 94 else { 95 defaultMap.put(key,value); 96 return retVal; 97 } 98 } 99 else { 100 return defaultMap.put(key,value); 101 } 102 } 103 104 105 /** 106 * We need to remove from both 107 * maps, if we do remove an existing key. 108 * 109 * @param key 110 * @return the removed object in the delta-map. if not present, the removed object from the main map 111 */ 112 public Object remove(Serializable key) { 113 if(component.initialStateMarked()) { 114 Object retVal = deltaMap.remove(key); 115 116 if(retVal==null) { 117 return defaultMap.remove(key); 118 } 119 else { 120 defaultMap.remove(key); 121 return retVal; 122 } 123 } 124 else { 125 return defaultMap.remove(key); 126 } 127 } 128 129 130 /** 131 * @see StateHelper#put(java.io.Serializable, String, Object) 132 */ 133 public Object put(Serializable key, String mapKey, Object value) { 134 135 Object ret = null; 136 if (component.initialStateMarked()) { 137 Map<String,Object> dMap = (Map<String,Object>) deltaMap.get(key); 138 if (dMap == null) { 139 dMap = new HashMap<String,Object>(5); 140 deltaMap.put(key, dMap); 141 } 142 ret = dMap.put(mapKey, value); 143 144 } 145 Map<String,Object> map = (Map<String,Object>) get(key); 146 if (map == null) { 147 map = new HashMap<String,Object>(8); 148 defaultMap.put(key, map); 149 } 150 if (ret == null) { 151 return map.put(mapKey, value); 152 } else { 153 map.put(mapKey, value); 154 return ret; 155 } 156 157 } 158 159 160 /** 161 * Get the object from the main-map. 162 * As everything is written through 163 * from the delta-map to the main-map, this 164 * should be enough. 165 * 166 * @param key 167 * @return 168 */ 169 public Object get(Serializable key) { 170 return defaultMap.get(key); 171 } 172 173 174 /** 175 * @see StateHelper#eval(java.io.Serializable) 176 */ 177 public Object eval(Serializable key) { 178 return eval(key, null); 179 } 180 181 182 /** 183 * @see StateHelper#eval(java.io.Serializable, Object) 184 */ 185 public Object eval(Serializable key, Object defaultValue) { 186 Object retVal = get(key); 187 if (retVal == null) { 188 ValueExpression ve = component.getValueExpression(key.toString()); 189 if (ve != null) { 190 retVal = ve.getValue(component.getFacesContext().getELContext()); 191 } 192 193 } 194 195 return ((retVal != null) ? retVal : defaultValue); 196 } 197 198 199 /** 200 * @see StateHelper#add(java.io.Serializable, Object) 201 */ 202 public void add(Serializable key, Object value) { 203 204 if (component.initialStateMarked()) { 205 List<Object> deltaList = (List<Object>) deltaMap.get(key); 206 if (deltaList == null) { 207 deltaList = new ArrayList<Object>(4); 208 deltaMap.put(key, deltaList); 209 } 210 deltaList.add(value); 211 } 212 List<Object> items = (List<Object>) get(key); 213 if (items == null) { 214 items = new ArrayList<Object>(4); 215 defaultMap.put(key, items); 216 } 217 items.add(value); 218 219 } 220 221 222 /** 223 * @see StateHelper#remove(java.io.Serializable, Object) 224 */ 225 public Object remove(Serializable key, Object valueOrKey) { 226 Object source = get(key); 227 if (source instanceof Collection) { 228 return removeFromList(key, valueOrKey); 229 } else if (source instanceof Map) { 230 return removeFromMap(key, valueOrKey.toString()); 231 } 232 return null; 233 } 234 235 236 // ------------------------------------------------ Methods from StateHolder 237 238 239 /** 240 * One and only implementation of 241 * save-state - makes all other implementations 242 * unnecessary. 243 * 244 * @param context 245 * @return the saved state 246 */ 247 public Object saveState(FacesContext context) { 248 if (context == null) { 249 throw new NullPointerException(); 250 } 251 if(component.initialStateMarked()) { 252 return saveMap(context, deltaMap); 253 } 254 else { 255 return saveMap(context, defaultMap); 256 } 257 } 258 259 260 261 /** 262 * One and only implementation of 263 * restore state. Makes all other implementations 264 * unnecessary. 265 * 266 * @param context FacesContext 267 * @param state the state to be restored. 268 */ 269 public void restoreState(FacesContext context, Object state) { 270 271 if (context == null) { 272 throw new NullPointerException(); 273 } 274 if (state == null) { 275 return; 276 } 277 Object[] savedState = (Object[]) state; 278 if (savedState[savedState.length - 1] != null) { 279 component.initialState = (Boolean) savedState[savedState.length - 1]; 280 } 281 int length = (savedState.length-1)/2; 282 for (int i = 0; i < length; i++) { 283 Object value = savedState[i * 2 + 1]; 284 if (Void.TYPE.equals(value)) { 285 value = null; 286 } 287 Serializable serializable = (Serializable) savedState[i * 2]; 288 if (value != null) { 289 if (value instanceof Collection) { 290 value = restoreAttachedState(context, value); 291 } else if (value instanceof StateHolderSaver) { 292 value = ((StateHolderSaver) value).restore(context); 293 } else { 294 value = (value instanceof Serializable 295 ? value 296 : restoreAttachedState(context, value)); 297 } 298 } 299 if (value instanceof Map) { 300 for (Map.Entry<String, Object> entry : ((Map<String, Object>) value) 301 .entrySet()) { 302 this.put(serializable, entry.getKey(), entry.getValue()); 303 } 304 } else if (value instanceof List) { 305 List<Object> list = (List) get(serializable); 306 for (Object o : ((List<Object>) value)) { 307 if (list == null || !list.contains(o)) { 308 this.add(serializable, o); 309 } 310 } 311 } else { 312 put(serializable, value); 313 } 314 } 315 } 316 317 318 /** 319 * @see javax.faces.component.StateHolder#isTransient() 320 */ 321 public boolean isTransient() { 322 return isTransient; 323 } 324 325 326 /** 327 * @see StateHolder#setTransient(boolean) 328 */ 329 public void setTransient(boolean newTransientValue) { 330 isTransient = newTransientValue; 331 } 332 333 334 // --------------------------------------------------------- Private Methods 335 336 337 private Object saveMap(FacesContext context, Map<Serializable, Object> map) { 338 339 if (map.isEmpty()) { 340 if (!component.initialStateMarked()) { 341 // only need to propagate the component's delta status when 342 // delta tracking has been disabled. We're assuming that 343 // the VDL will reset the status when the view is reconstructed, 344 // so no need to save the state if the saved state is the default. 345 return new Object[] { component.initialStateMarked() }; 346 } 347 return null; 348 } 349 350 Object[] savedState = new Object[map.size() * 2 + 1]; 351 352 int i=0; 353 354 for(Map.Entry<Serializable, Object> entry : map.entrySet()) { 355 Object value = entry.getValue(); 356 if (value == null) { 357 value = Void.TYPE; 358 } 359 savedState[i * 2] = entry.getKey(); 360 if (value instanceof Collection 361 || value instanceof StateHolder 362 || !(value instanceof Serializable)) { 363 value = saveAttachedState(context,value); 364 } 365 savedState[i * 2 + 1] = value; 366 i++; 367 } 368 if (!component.initialStateMarked()) { 369 savedState[savedState.length - 1] = component.initialStateMarked(); 370 } 371 return savedState; 372 373 } 374 375 376 private Object removeFromList(Serializable key, Object value) { 377 Object ret = null; 378 if (component.initialStateMarked() || value instanceof PartialStateHolder) { 379 Collection<Object> deltaList = (Collection<Object>) deltaMap.get(key); 380 if (deltaList != null) { 381 ret = deltaList.remove(value); 382 if (deltaList.isEmpty()) { 383 deltaMap.remove(key); 384 } 385 } 386 } 387 Collection<Object> list = (Collection<Object>) get(key); 388 if (list != null) { 389 if (ret == null) { 390 ret = list.remove(value); 391 } else { 392 list.remove(value); 393 } 394 if (list.isEmpty()) { 395 defaultMap.remove(key); 396 } 397 } 398 return ret; 399 } 400 401 402 private Object removeFromMap(Serializable key, String mapKey) { 403 Object ret = null; 404 if (component.initialStateMarked()) { 405 Map<String,Object> dMap = (Map<String,Object>) deltaMap.get(key); 406 if (dMap != null) { 407 ret = dMap.remove(mapKey); 408 if (dMap.isEmpty()) { 409 deltaMap.remove(key); 410 } 411 } 412 } 413 Map<String,Object> map = (Map<String,Object>) get(key); 414 if (map != null) { 415 if (ret == null) { 416 ret = map.remove(mapKey); 417 } else { 418 map.remove(mapKey); 419 420 } 421 if (map.isEmpty()) { 422 defaultMap.remove(key); 423 } 424 } 425 if (ret != null && !component.initialStateMarked()) { 426 deltaMap.remove(key); 427 } 428 return ret; 429 } 430 431 }