1 19 20 package org.apache.cayenne.access; 21 22 import java.io.Serializable ; 23 import java.util.Collection ; 24 import java.util.Iterator ; 25 import java.util.LinkedList ; 26 import java.util.List ; 27 import java.util.ListIterator ; 28 29 import org.apache.cayenne.CayenneRuntimeException; 30 import org.apache.cayenne.PersistenceState; 31 import org.apache.cayenne.Persistent; 32 import org.apache.cayenne.ValueHolder; 33 import org.apache.cayenne.query.RelationshipQuery; 34 35 42 public class ToManyList implements List , Serializable , ValueHolder { 43 44 private Persistent source; 45 private String relationship; 46 47 List objectList; 49 50 LinkedList addedToUnresolved; 52 LinkedList removedFromUnresolved; 53 54 59 public ToManyList(Persistent source, String relationship) { 60 if (source == null) { 61 throw new NullPointerException ("'source' can't be null."); 62 } 63 64 if (relationship == null) { 65 throw new NullPointerException ("'relationship' can't be null."); 66 } 67 68 this.source = source; 69 this.relationship = relationship; 70 71 if (isTransientSource()) { 73 objectList = new LinkedList (); 74 } 75 } 76 77 80 public Persistent getRelationshipOwner() { 81 return source; 82 } 83 84 89 public String getRelationship() { 90 return relationship; 91 } 92 93 public void setObjectList(List objectList) { 94 this.objectList = objectList; 95 } 96 97 public Object getValue() throws CayenneRuntimeException { 98 return resolvedObjectList(); 99 } 100 101 public void invalidate() { 102 this.objectList = null; 103 } 104 105 public boolean isFault() { 106 return objectList == null; 107 } 108 109 public Object getValueDirectly() throws CayenneRuntimeException { 110 return objectList; 111 } 112 113 public Object setValueDirectly(Object value) throws CayenneRuntimeException { 114 if (value == null || value instanceof List ) { 115 Object old = this.objectList; 116 setObjectList((List ) value); 117 return old; 118 } 119 else { 120 throw new CayenneRuntimeException("Value must be a list, got: " 121 + value.getClass().getName()); 122 } 123 } 124 125 public Object setValue(Object value) throws CayenneRuntimeException { 126 resolvedObjectList(); 127 return setValueDirectly(objectList); 128 } 129 130 public boolean add(Object o) { 134 return (isFault()) ? addLocal(o) : objectList.add(o); 135 } 136 137 public void add(int index, Object element) { 138 resolvedObjectList().add(index, element); 139 } 140 141 public boolean addAll(Collection c) { 142 return resolvedObjectList().addAll(c); 143 } 144 145 public boolean addAll(int index, Collection c) { 146 return resolvedObjectList().addAll(index, c); 147 } 148 149 public void clear() { 150 resolvedObjectList().clear(); 151 } 152 153 public boolean contains(Object o) { 154 return resolvedObjectList().contains(o); 155 } 156 157 public boolean containsAll(Collection c) { 158 return resolvedObjectList().containsAll(c); 159 } 160 161 public boolean equals(Object o) { 162 if (o == null) { 163 return false; 164 } 165 166 if (!(o instanceof ToManyList)) { 167 return false; 168 } 169 170 return resolvedObjectList().equals(((ToManyList) o).resolvedObjectList()); 171 } 172 173 public int hashCode() { 174 return 15 + resolvedObjectList().hashCode(); 175 } 176 177 public Object get(int index) { 178 return resolvedObjectList().get(index); 179 } 180 181 public int indexOf(Object o) { 182 return resolvedObjectList().indexOf(o); 183 } 184 185 public boolean isEmpty() { 186 return resolvedObjectList().isEmpty(); 187 } 188 189 public Iterator iterator() { 190 return resolvedObjectList().iterator(); 191 } 192 193 public int lastIndexOf(Object o) { 194 return resolvedObjectList().lastIndexOf(o); 195 } 196 197 public ListIterator listIterator() { 198 return resolvedObjectList().listIterator(); 199 } 200 201 public ListIterator listIterator(int index) { 202 return resolvedObjectList().listIterator(index); 203 } 204 205 public Object remove(int index) { 206 return resolvedObjectList().remove(index); 207 } 208 209 public boolean remove(Object o) { 210 return (isFault()) ? removeLocal(o) : objectList.remove(o); 211 } 212 213 public boolean removeAll(Collection c) { 214 return resolvedObjectList().removeAll(c); 215 } 216 217 public boolean retainAll(Collection c) { 218 return resolvedObjectList().retainAll(c); 219 } 220 221 public Object set(int index, Object element) { 222 return resolvedObjectList().set(index, element); 223 } 224 225 public int size() { 226 return resolvedObjectList().size(); 227 } 228 229 public List subList(int fromIndex, int toIndex) { 230 return resolvedObjectList().subList(fromIndex, toIndex); 231 } 232 233 public Object [] toArray() { 234 return resolvedObjectList().toArray(); 235 } 236 237 public Object [] toArray(Object [] a) { 238 return resolvedObjectList().toArray(a); 239 } 240 241 246 boolean isTransientSource() { 247 int state = source.getPersistenceState(); 248 return state == PersistenceState.NEW || state == PersistenceState.TRANSIENT; 249 } 250 251 boolean isUncommittedSource() { 252 int state = source.getPersistenceState(); 253 return state == PersistenceState.MODIFIED || state == PersistenceState.DELETED; 254 } 255 256 259 List resolvedObjectList() { 260 if (isFault()) { 261 262 synchronized (this) { 263 266 if (isFault()) { 267 List localList; 268 269 if (isTransientSource()) { 270 localList = new LinkedList (); 271 } 272 else { 273 localList = source.getObjectContext().performQuery( 274 new RelationshipQuery( 275 source.getObjectId(), 276 relationship, 277 false)); 278 } 279 280 mergeLocalChanges(localList); 281 this.objectList = localList; 282 } 283 } 284 } 285 286 return objectList; 287 } 288 289 void clearLocalChanges() { 290 addedToUnresolved = null; 291 removedFromUnresolved = null; 292 } 293 294 void mergeLocalChanges(List fetchedList) { 295 296 if (isUncommittedSource()) { 300 301 if (removedFromUnresolved != null) { 302 fetchedList.removeAll(removedFromUnresolved); 303 } 304 305 if (addedToUnresolved != null && !addedToUnresolved.isEmpty()) { 308 Iterator it = addedToUnresolved.iterator(); 309 while (it.hasNext()) { 310 Object next = it.next(); 311 312 if (next instanceof Persistent) { 313 Persistent dataObject = (Persistent) next; 314 if (dataObject.getPersistenceState() == PersistenceState.TRANSIENT) { 315 continue; 316 } 317 } 318 319 if (!fetchedList.contains(next)) { 320 fetchedList.add(next); 321 } 322 } 323 } 324 } 325 326 clearLocalChanges(); 328 } 329 330 boolean addLocal(Object object) { 331 332 if (removedFromUnresolved != null) { 333 removedFromUnresolved.remove(object); 334 } 335 336 if (addedToUnresolved == null) { 337 addedToUnresolved = new LinkedList (); 338 } 339 340 addedToUnresolved.addLast(object); 341 342 return true; 345 } 346 347 boolean removeLocal(Object object) { 348 if (addedToUnresolved != null) { 349 addedToUnresolved.remove(object); 350 } 351 352 if (removedFromUnresolved == null) { 353 removedFromUnresolved = new LinkedList (); 354 } 355 356 boolean shouldAddToRemovedFromUnresolvedList = true; 359 if (object instanceof Persistent) { 360 Persistent dataObject = (Persistent) object; 361 if ((dataObject.getPersistenceState() == PersistenceState.TRANSIENT) 362 || (dataObject.getPersistenceState() == PersistenceState.NEW)) { 363 shouldAddToRemovedFromUnresolvedList = false; 364 } 365 } 366 367 if (shouldAddToRemovedFromUnresolvedList) { 368 removedFromUnresolved.addLast(object); 369 } 370 371 return true; 374 } 375 376 public String toString() { 377 return getClass().getName() + "@" + System.identityHashCode(this); 378 } 379 } 380 | Popular Tags |