1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 * 4 * Copyright 1997-2009 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 package javax.faces.component; 38 39 import javax.faces.context.FacesContext; 40 import java.util.List; 41 import java.util.ArrayList; 42 import java.lang.reflect.Array; 43 44 /** 45 * <p> 46 * Utility class to enable partial state saving of Lists of attached objects 47 * such as <code>FacesListener</code>s or <code>Validator</code>s. 48 * </p> 49 */ 50 @SuppressWarnings({"unchecked"}) 51 class AttachedObjectListHolder<T> implements PartialStateHolder { 52 53 private boolean initialState; 54 private List<T> attachedObjects = new ArrayList<T>(2); 55 56 57 // ------------------------------------- Methods from PartialStateHolder 58 59 60 public void markInitialState() { 61 62 if (!attachedObjects.isEmpty()) { 63 for (T t : attachedObjects) { 64 if (t instanceof PartialStateHolder) { 65 ((PartialStateHolder) t).markInitialState(); 66 } 67 } 68 } 69 initialState = true; 70 71 } 72 73 74 public boolean initialStateMarked() { 75 76 return initialState; 77 78 } 79 80 81 public void clearInitialState() { 82 83 if (!attachedObjects.isEmpty()) { 84 for (T t : attachedObjects) { 85 if (t instanceof PartialStateHolder) { 86 ((PartialStateHolder) t).clearInitialState(); 87 } 88 } 89 } 90 initialState = false; 91 92 } 93 94 95 // -------------------------------------------- Methods from StateHolder 96 97 98 public Object saveState(FacesContext context) { 99 100 if (context == null) { 101 throw new NullPointerException(); 102 } 103 if (attachedObjects == null) { 104 return null; 105 } 106 if (initialState) { 107 Object[] attachedObjects = new Object[this.attachedObjects.size()]; 108 boolean stateWritten = false; 109 for (int i = 0, len = attachedObjects.length; i < len; i++) { 110 T attachedObject = this.attachedObjects.get(i); 111 if (attachedObject instanceof StateHolder) { 112 StateHolder sh = (StateHolder) attachedObject; 113 if (!sh.isTransient()) { 114 attachedObjects[i] = sh.saveState(context); 115 } 116 if (attachedObjects[i] != null) { 117 stateWritten = true; 118 } 119 } 120 } 121 return ((stateWritten) ? attachedObjects : null); 122 } else { 123 124 Object[] attachedObjects = new Object[this.attachedObjects.size()]; 125 for (int i = 0, len = attachedObjects.length; i < len; i++) { 126 attachedObjects[i] = UIComponentBase.saveAttachedState(context, this.attachedObjects.get(i)); 127 } 128 return (attachedObjects); 129 } 130 131 } 132 133 134 public void restoreState(FacesContext context, Object state) { 135 136 if (context == null) { 137 throw new NullPointerException(); 138 } 139 if (state == null) { 140 return; 141 } 142 143 Object[] attachedObjects = (Object[]) state; 144 if (attachedObjects.length > 0 && attachedObjects[0] instanceof StateHolderSaver) { 145 // overwrite the existing attachedObjects with those included 146 // in the full state. 147 if (this.attachedObjects != null) { 148 this.attachedObjects.clear(); 149 } else { 150 this.attachedObjects = new ArrayList<T>(2); 151 } 152 for (int i = 0, len = attachedObjects.length; i < len; i++) { 153 T restored = (T) ((StateHolderSaver) attachedObjects[i]).restore(context); 154 if (restored != null) { 155 this.attachedObjects.add(restored); 156 } 157 } 158 } else { 159 // assume 1:1 relation between existing attachedObjects and state 160 for (int i = 0, len = attachedObjects.length; i < len; i++) { 161 T l = this.attachedObjects.get(i); 162 if (l instanceof StateHolder) { 163 ((StateHolder) l).restoreState(context, attachedObjects[i]); 164 } 165 } 166 } 167 168 } 169 170 171 public boolean isTransient() { 172 173 return false; 174 175 } 176 177 178 public void setTransient(boolean newTransientValue) { 179 180 // no-op 181 182 } 183 184 185 // ------------------------------------------------------ Public Methods 186 187 188 void add(T attachedObject) { 189 190 clearInitialState(); 191 attachedObjects.add(attachedObject); 192 193 } 194 195 void remove(T attachedObject) { 196 197 clearInitialState(); 198 attachedObjects.remove(attachedObject); 199 200 } 201 202 T[] asArray(Class<T> type) { 203 204 return new ArrayList<T>(attachedObjects).toArray((T[])Array.newInstance(type, attachedObjects.size())); 205 206 } 207 208 }