/poleposition-0.20/openaccess-4.0.0beta4/engine/src/com/versant/core/jdo/sco/SCOList.java

http://jdbcperf.googlecode.com/ · Java · 632 lines · 544 code · 57 blank · 31 comment · 138 complexity · d6ac7ea03ed9d06f4894cd1f109c4339 MD5 · raw file

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