1 2 12 package com.versant.core.jdo.sco; 13 14 import com.versant.core.jdo.VersantPersistenceManagerImp; 15 import com.versant.core.jdo.VersantStateManager; 16 17 import javax.jdo.spi.PersistenceCapable; 18 import java.io.Serializable ; 19 import java.util.AbstractList ; 20 import java.util.Collection ; 21 import java.util.Iterator ; 22 23 import com.versant.core.common.*; 24 import com.versant.core.metadata.FieldMetaData; 25 26 31 public final class SCOList extends AbstractList 32 implements VersantManagedSCOCollection, Serializable , 33 VersantAdvancedSCO { 34 35 private static final long serialVersionUID = 8683452581122892189L; 37 38 private transient Object [] data; 39 private int size; 40 41 private transient PersistenceCapable owner; 42 private final transient int managed; 43 private final transient int inverseFieldNo; 44 private final transient VersantFieldMetaData fmd; 45 private transient VersantStateManager stateManager; 46 private transient Object [] originalData; 47 private transient boolean beenReset; 48 49 public SCOList(PersistenceCapable owner, VersantStateManager stateManager, 50 VersantFieldMetaData fmd, Object [] originalData) { 51 this.owner = owner; 52 if (fmd.isManaged()) { 53 if (fmd.isMaster()) { 54 managed = MANAGED_ONE_TO_MANY; 55 } else if (fmd.isManyToMany()) { 56 managed = MANAGED_MANY_TO_MANY; 57 } else { 58 managed = MANAGED_NONE; 59 } 60 } else { 61 managed = MANAGED_NONE; 62 } 63 this.inverseFieldNo = fmd.getInverseFieldNo(); 64 this.stateManager = stateManager; 65 this.fmd = fmd; 66 this.originalData = originalData; 67 int n = originalData == null ? 0 : originalData.length; 68 if (n == 0) { 69 data = new Object [10]; 70 } else { 71 data = new Object [n]; 72 if (owner.jdoIsNew()) { 73 size = n; 74 switch (managed) { 75 case MANAGED_ONE_TO_MANY: 76 for (int i = 0; i < n; i++) { 77 Object o = originalData[i]; 78 if (Debug.DEBUG) { 79 checkNull(o); 80 } 81 SCOInverseUtil.addMasterOnDetail(o, owner, 82 inverseFieldNo); 83 data[i] = o; 84 } 85 break; 86 case MANAGED_MANY_TO_MANY: 87 for (int i = 0; i < n; i++) { 88 Object o = originalData[i]; 89 if (Debug.DEBUG) { 90 checkNull(o); 91 } 92 SCOInverseUtil.addToOtherSideOfManyToMany(o, 93 inverseFieldNo, owner); 94 data[i] = o; 95 } 96 break; 97 default: 98 for (int i = 0; i < n; i++) { 99 Object o = originalData[i]; 100 if (Debug.DEBUG) { 101 checkNull(o); 102 } 103 data[i] = o; 104 } 105 } 106 ; 107 } else { 108 int i; 109 for (i = 0; i < n; i++) { 110 Object o = originalData[i]; 111 if (Debug.DEBUG) { 112 checkNull(o); 113 } 114 data[i] = o; 115 } 116 size = i; 117 } 118 } 119 } 120 121 public Object get(int index) { 122 checkIndex(index); 123 return data[index]; 124 } 125 126 public int size() { 127 return size; 128 } 129 130 private RuntimeException createNPE() { 131 return BindingSupportImpl.getInstance().nullElement( 132 "Null element not allowed: " + fmd.getQName()); 133 } 134 135 public boolean add(Object o) { 136 if (Debug.DEBUG) { 137 checkNull(o); 138 } 139 140 if (size == data.length) expand(); 141 data[size++] = o; 142 makeDirty(); 143 switch (managed) { 144 case MANAGED_ONE_TO_MANY: 145 SCOInverseUtil.addMasterOnDetail(o, owner, inverseFieldNo); 146 break; 147 case MANAGED_MANY_TO_MANY: 148 SCOInverseUtil.addToOtherSideOfManyToMany(o, inverseFieldNo, 149 owner); 150 break; 151 } 152 return true; 153 } 154 155 private void checkNull(Object o) { 156 if (!((FieldMetaData)fmd).ordered && o == null) { 157 throw createNPE(); 158 } 159 } 160 161 private void expand() { 162 modCount++; 163 Object [] a = new Object [(size * 3) / 2 + 1]; 164 System.arraycopy(data, 0, a, 0, size); 165 data = a; 166 } 167 168 private void ensureCapacity(int minSize) { 169 modCount++; 170 int n = (size * 3) / 2 + 1; 171 if (n < minSize) n = minSize; 172 Object [] a = new Object [n]; 173 System.arraycopy(data, 0, a, 0, size); 174 data = a; 175 } 176 177 public void add(int index, Object element) { 178 if (Debug.DEBUG) { 179 checkNull(element); 180 } 181 if (index > size || index < 0) { 182 throw BindingSupportImpl.getInstance().indexOutOfBounds( 183 "Index: " + index + ", Size: " + size); 184 } 185 if (size == data.length) expand(); 186 if (index < size) { 187 System.arraycopy(data, index, data, index + 1, size - index); 188 } 189 data[index] = element; 190 size++; 191 makeDirty(); 192 switch (managed) { 193 case MANAGED_ONE_TO_MANY: 194 SCOInverseUtil.addMasterOnDetail(element, owner, 195 inverseFieldNo); 196 break; 197 case MANAGED_MANY_TO_MANY: 198 SCOInverseUtil.addToOtherSideOfManyToMany(element, 199 inverseFieldNo, owner); 200 break; 201 } 202 } 203 204 private void checkIndex(int index) { 205 if (index >= size || index < 0) { 206 throw BindingSupportImpl.getInstance().indexOutOfBounds( 207 "Index: " + index + ", Size: " + size); 208 } 209 } 210 211 public Object set(int index, Object element) { 212 if (Debug.DEBUG) { 213 checkNull(element); 214 } 215 checkIndex(index); 216 Object result = data[index]; 217 data[index] = element; 218 makeDirty(); 219 switch (managed) { 220 case MANAGED_ONE_TO_MANY: 221 if (result != null) { 222 SCOInverseUtil.removeMasterOnDetail(result, owner, 223 inverseFieldNo); 224 } 225 SCOInverseUtil.addMasterOnDetail(element, owner, 226 inverseFieldNo); 227 break; 228 case MANAGED_MANY_TO_MANY: 229 if (result != null) { 230 SCOInverseUtil.removeFromOtherSideOfManyToMany(result, 231 inverseFieldNo, owner); 232 } 233 SCOInverseUtil.addToOtherSideOfManyToMany(element, 234 inverseFieldNo, owner); 235 break; 236 } 237 return result; 238 } 239 240 public Object remove(int index) { 241 checkIndex(index); 242 modCount++; 243 makeDirty(); 244 return removeImp(index); 245 } 246 247 private Object removeImp(int index) { 248 Object result = data[index]; 249 int n = size - index - 1; 250 if (n > 0) System.arraycopy(data, index + 1, data, index, n); 251 data[--size] = null; 252 if (result == null) return null; switch (managed) { 254 case MANAGED_ONE_TO_MANY: 255 SCOInverseUtil.removeMasterOnDetail(result, owner, 256 inverseFieldNo); 257 break; 258 case MANAGED_MANY_TO_MANY: 259 SCOInverseUtil.removeFromOtherSideOfManyToMany(result, 260 inverseFieldNo, owner); 261 break; 262 } 263 return result; 264 } 265 266 public int indexOf(Object o) { 267 if (o == null) { 268 for (int i = 0; i < size; i++) { 269 if (data[i] == o) return i; 270 } 271 } else { 272 for (int i = 0; i < size; i++) { 273 if (o.equals(data[i])) return i; 274 } 275 } 276 return -1; 277 } 278 279 public int lastIndexOf(Object o) { 280 if (o == null) { 281 for (int i = size - 1; i >= 0; i--) { 282 if (data[i] == o) return i; 283 } 284 } else { 285 for (int i = size - 1; i >= 0; i--) { 286 if (o.equals(data[i])) return i; 287 } 288 } 289 return -1; 290 } 291 292 public void clear() { 293 modCount++; 294 switch (managed) { 295 case MANAGED_ONE_TO_MANY: 296 for (int i = 0; i < size; i++) { 297 SCOInverseUtil.removeMasterOnDetail(data[i], owner, 298 inverseFieldNo); 299 data[i] = null; 300 } 301 break; 302 case MANAGED_MANY_TO_MANY: 303 for (int i = 0; i < size; i++) { 304 SCOInverseUtil.removeFromOtherSideOfManyToMany(data[i], 305 inverseFieldNo, owner); 306 data[i] = null; 307 } 308 break; 309 default: 310 for (int i = 0; i < size; i++) data[i] = null; 311 } 312 size = 0; 313 makeDirty(); 314 } 315 316 public boolean addAll(int index, Collection c) { 317 if (index > size || index < 0) { 318 throw BindingSupportImpl.getInstance().indexOutOfBounds( 319 "Index: " + index + ", Size: " + size); 320 } 321 int numNew = c.size(); 322 if (numNew == 0) return false; 323 int newSize = size + numNew; 324 if (newSize > data.length) ensureCapacity(newSize); 325 326 int n = size - index; 327 if (n > 0) System.arraycopy(data, index, data, index + numNew, n); 328 329 Iterator e = c.iterator(); 330 switch (managed) { 331 case MANAGED_ONE_TO_MANY: 332 for (int i = 0; i < numNew; i++) { 333 Object o = e.next(); 334 if (Debug.DEBUG) { 335 checkNull(o); 336 } 337 SCOInverseUtil.addMasterOnDetail(o, owner, inverseFieldNo); 338 data[index++] = o; 339 } 340 break; 341 case MANAGED_MANY_TO_MANY: 342 for (int i = 0; i < numNew; i++) { 343 Object o = e.next(); 344 if (Debug.DEBUG) { 345 checkNull(o); 346 } 347 SCOInverseUtil.addToOtherSideOfManyToMany(o, 348 inverseFieldNo, owner); 349 data[index++] = o; 350 } 351 break; 352 default: 353 for (int i = 0; i < numNew; i++) { 354 Object o = e.next(); 355 if (Debug.DEBUG) { 356 checkNull(o); 357 } 358 data[index++] = o; 359 } 360 } 361 362 size += numNew; 363 makeDirty(); 364 return true; 365 } 366 367 public boolean addAll(Collection c) { 368 int numNew = c.size(); 369 if (numNew == 0) return false; 370 int newSize = size + numNew; 371 if (newSize > data.length) ensureCapacity(newSize); 372 373 Iterator e = c.iterator(); 374 switch (managed) { 375 case MANAGED_ONE_TO_MANY: 376 for (int i = 0; i < numNew; i++) { 377 Object o = e.next(); 378 if (Debug.DEBUG) { 379 checkNull(o); 380 } 381 SCOInverseUtil.addMasterOnDetail(o, owner, inverseFieldNo); 382 data[size++] = o; 383 } 384 break; 385 case MANAGED_MANY_TO_MANY: 386 for (int i = 0; i < numNew; i++) { 387 Object o = e.next(); 388 if (Debug.DEBUG) { 389 checkNull(o); 390 } 391 SCOInverseUtil.addToOtherSideOfManyToMany(o, 392 inverseFieldNo, owner); 393 data[size++] = o; 394 } 395 break; 396 default: 397 for (int i = 0; i < numNew; i++) { 398 Object o = e.next(); 399 if (Debug.DEBUG) { 400 checkNull(o); 401 } 402 data[size++] = o; 403 } 404 } 405 406 makeDirty(); 407 return true; 408 } 409 410 protected void removeRange(int fromIndex, int toIndex) { 411 modCount++; 412 413 switch (managed) { 414 case MANAGED_ONE_TO_MANY: 415 for (int i = fromIndex; i < toIndex; i++) { 416 SCOInverseUtil.removeMasterOnDetail(data[i], owner, 417 inverseFieldNo); 418 } 419 break; 420 case MANAGED_MANY_TO_MANY: 421 for (int i = fromIndex; i < toIndex; i++) { 422 SCOInverseUtil.removeFromOtherSideOfManyToMany(data[i], 423 inverseFieldNo, owner); 424 } 425 break; 426 } 427 428 int numMoved = size - toIndex; 429 if (numMoved > 0) { 430 System.arraycopy(data, toIndex, data, fromIndex, 431 numMoved); 432 } 433 434 int newSize = size - (toIndex - fromIndex); 435 while (size != newSize) data[--size] = null; 436 437 makeDirty(); 438 } 439 440 public boolean isEmpty() { 441 return size == 0; 442 } 443 444 public boolean contains(Object o) { 445 if (o == null) { 446 for (int i = 0; i < size; i++) { 447 if (data[i] == o) return true; 448 } 449 } else { 450 for (int i = 0; i < size; i++) { 451 if (o.equals(data[i])) return true; 452 } 453 } 454 return false; 455 } 456 457 public Object [] toArray() { 458 Object [] a = new Object [size]; 459 System.arraycopy(data, 0, a, 0, size); 460 return a; 461 } 462 463 public Object [] toArray(Object a[]) { 464 if (a.length < size) { 465 a = (Object [])java.lang.reflect.Array.newInstance( 466 a.getClass().getComponentType(), size); 467 } 468 System.arraycopy(data, 0, a, 0, size); 469 if (a.length > size) a[size] = null; 470 return a; 471 } 472 473 public boolean remove(Object o) { 474 int i = indexOf(o); 475 if (i >= 0) { 476 remove(i); 477 return true; 478 } 479 return false; 480 } 481 482 public Object clone() { 483 try { 484 SCOList v = (SCOList)super.clone(); 485 v.data = new Object [size]; 486 System.arraycopy(data, 0, v.data, 0, size); 487 v.modCount = 0; 488 return v; 489 } catch (CloneNotSupportedException e) { 490 throw new InternalError (); 492 } 493 } 494 495 498 private synchronized void writeObject(java.io.ObjectOutputStream s) 499 throws java.io.IOException { 500 s.defaultWriteObject(); 501 s.writeInt(data.length); 502 for (int i = 0; i < size; i++) s.writeObject(data[i]); 503 } 504 505 508 private synchronized void readObject(java.io.ObjectInputStream s) 509 throws java.io.IOException , ClassNotFoundException { 510 s.defaultReadObject(); 511 int arrayLength = s.readInt(); 512 data = new Object [arrayLength]; 513 for (int i = 0; i < size; i++) data[i] = s.readObject(); 514 } 515 516 public CollectionDiff getCollectionDiff(PersistenceContext pm) { 517 if (fmd.isOrdered()) { 518 return CollectionDiffUtil.getOrderedCollectionDiff(fmd, pm, 519 data, size, 520 (owner.jdoIsNew() && !beenReset) ? null : originalData); 521 } else { 522 return CollectionDiffUtil.getUnorderedCollectionDiff(fmd, pm, 523 data, size, 524 (owner.jdoIsNew() && !beenReset) ? null : originalData); 525 } 526 } 527 528 public Object getOwner() { 529 return owner; 530 } 531 532 public void makeTransient() { 533 owner = null; 534 stateManager = null; 535 } 536 537 public void makeDirty() { 538 if (stateManager != null) { 539 stateManager.makeDirty(owner, fmd.getManagedFieldNo()); 540 } 541 } 542 543 public void reset() { 544 beenReset = true; 545 originalData = toArray(); 546 } 547 548 public void manyToManyAdd(Object o) { 549 if (size == data.length) expand(); 550 data[size++] = o; 551 makeDirty(); 552 } 553 554 public void manyToManyRemove(Object o) { 555 int i = indexOf(o); 556 if (i < 0) return; 557 modCount++; 558 int n = size - i - 1; 559 if (n > 0) System.arraycopy(data, i + 1, data, i, n); 560 data[--size] = null; 561 makeDirty(); 562 } 563 564 public boolean containsAll(Collection c) { 565 for (Iterator i = c.iterator(); i.hasNext();) { 566 if (indexOf(i.next()) < 0) return false; 567 } 568 return true; 569 } 570 571 public boolean removeAll(Collection c) { 572 int mc = modCount; 573 for (Iterator i = c.iterator(); i.hasNext();) { 574 int index = indexOf(i.next()); 575 if (index >= 0) { 576 removeImp(index); 577 modCount++; 578 } 579 } 580 if (mc != modCount) { 581 makeDirty(); 582 return true; 583 } else { 584 return false; 585 } 586 } 587 588 public boolean retainAll(Collection c) { 589 int mc = modCount; 590 for (int i = 0; i < size;) { 591 if (c.contains(data[i])) { 592 i++; 593 } else { 594 removeImp(i); 595 modCount++; 596 } 597 } 598 if (mc != modCount) { 599 makeDirty(); 600 return true; 601 } else { 602 return false; 603 } 604 } 605 606 609 public boolean isOrdered() { 610 return fmd.isOrdered(); 611 } 612 613 618 public CollectionData fillCollectionData(CollectionData collectionData) { 619 int size = size(); 620 collectionData.valueCount = size; 621 Object [] newData; 622 Object [] values = collectionData.values; 623 if (values == null || values.length < size) { 624 newData = new Object [size]; 625 } else { 626 newData = values; 627 } 628 System.arraycopy(data, 0, newData, 0, size); 629 collectionData.values = newData; 630 return collectionData; 631 } 632 } 633 | Popular Tags |