PageRenderTime 37ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/hibernate-core/src/main/java/org/hibernate/collection/internal/PersistentIdentifierBag.java

https://github.com/CodingFabian/hibernate-core
Java | 430 lines | 336 code | 58 blank | 36 comment | 39 complexity | a301ff0fb2fc1ecc6b4f99833c3b01cf MD5 | raw file
  1. /*
  2. * Hibernate, Relational Persistence for Idiomatic Java
  3. *
  4. * Copyright (c) 2008-2011, Red Hat Inc. or third-party contributors as
  5. * indicated by the @author tags or express copyright attribution
  6. * statements applied by the authors. All third-party contributions are
  7. * distributed under license by Red Hat Inc.
  8. *
  9. * This copyrighted material is made available to anyone wishing to use, modify,
  10. * copy, or redistribute it subject to the terms and conditions of the GNU
  11. * Lesser General Public License, as published by the Free Software Foundation.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  15. * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
  16. * for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public License
  19. * along with this distribution; if not, write to:
  20. * Free Software Foundation, Inc.
  21. * 51 Franklin Street, Fifth Floor
  22. * Boston, MA 02110-1301 USA
  23. */
  24. package org.hibernate.collection.internal;
  25. import java.io.Serializable;
  26. import java.sql.ResultSet;
  27. import java.sql.SQLException;
  28. import java.util.ArrayList;
  29. import java.util.Collection;
  30. import java.util.HashMap;
  31. import java.util.Iterator;
  32. import java.util.List;
  33. import java.util.ListIterator;
  34. import java.util.Map;
  35. import org.hibernate.EntityMode;
  36. import org.hibernate.HibernateException;
  37. import org.hibernate.engine.spi.SessionImplementor;
  38. import org.hibernate.loader.CollectionAliases;
  39. import org.hibernate.persister.collection.CollectionPersister;
  40. import org.hibernate.type.Type;
  41. /**
  42. * An <tt>IdentifierBag</tt> implements "bag" semantics more efficiently than
  43. * a regular <tt>Bag</tt> by adding a synthetic identifier column to the
  44. * table. This identifier is unique for all rows in the table, allowing very
  45. * efficient updates and deletes. The value of the identifier is never exposed
  46. * to the application.<br>
  47. * <br>
  48. * <tt>IdentifierBag</tt>s may not be used for a many-to-one association.
  49. * Furthermore, there is no reason to use <tt>inverse="true"</tt>.
  50. *
  51. * @author Gavin King
  52. */
  53. public class PersistentIdentifierBag extends AbstractPersistentCollection implements List {
  54. protected List values; //element
  55. protected Map identifiers; //index -> id
  56. public PersistentIdentifierBag(SessionImplementor session) {
  57. super(session);
  58. }
  59. public PersistentIdentifierBag() {} //needed for SOAP libraries, etc
  60. public PersistentIdentifierBag(SessionImplementor session, Collection coll) {
  61. super(session);
  62. if (coll instanceof List) {
  63. values = (List) coll;
  64. }
  65. else {
  66. values = new ArrayList();
  67. Iterator iter = coll.iterator();
  68. while ( iter.hasNext() ) {
  69. values.add( iter.next() );
  70. }
  71. }
  72. setInitialized();
  73. setDirectlyAccessible(true);
  74. identifiers = new HashMap();
  75. }
  76. public void initializeFromCache(CollectionPersister persister, Serializable disassembled, Object owner)
  77. throws HibernateException {
  78. Serializable[] array = (Serializable[]) disassembled;
  79. int size = array.length;
  80. beforeInitialize( persister, size );
  81. for ( int i = 0; i < size; i+=2 ) {
  82. identifiers.put(
  83. new Integer(i/2),
  84. persister.getIdentifierType().assemble( array[i], getSession(), owner )
  85. );
  86. values.add( persister.getElementType().assemble( array[i+1], getSession(), owner ) );
  87. }
  88. }
  89. public Object getIdentifier(Object entry, int i) {
  90. return identifiers.get( new Integer(i) );
  91. }
  92. public boolean isWrapper(Object collection) {
  93. return values==collection;
  94. }
  95. public boolean add(Object o) {
  96. write();
  97. values.add(o);
  98. return true;
  99. }
  100. public void clear() {
  101. initialize( true );
  102. if ( ! values.isEmpty() || ! identifiers.isEmpty() ) {
  103. values.clear();
  104. identifiers.clear();
  105. dirty();
  106. }
  107. }
  108. public boolean contains(Object o) {
  109. read();
  110. return values.contains(o);
  111. }
  112. public boolean containsAll(Collection c) {
  113. read();
  114. return values.containsAll(c);
  115. }
  116. public boolean isEmpty() {
  117. return readSize() ? getCachedSize()==0 : values.isEmpty();
  118. }
  119. public Iterator iterator() {
  120. read();
  121. return new IteratorProxy( values.iterator() );
  122. }
  123. public boolean remove(Object o) {
  124. initialize( true );
  125. int index = values.indexOf(o);
  126. if (index>=0) {
  127. beforeRemove(index);
  128. values.remove(index);
  129. dirty();
  130. return true;
  131. }
  132. else {
  133. return false;
  134. }
  135. }
  136. public boolean removeAll(Collection c) {
  137. if ( c.size() > 0 ) {
  138. boolean result = false;
  139. Iterator iter = c.iterator();
  140. while ( iter.hasNext() ) {
  141. if ( remove( iter.next() ) ) result=true;
  142. }
  143. return result;
  144. }
  145. else {
  146. return false;
  147. }
  148. }
  149. public boolean retainAll(Collection c) {
  150. initialize( true );
  151. if ( values.retainAll( c ) ) {
  152. dirty();
  153. return true;
  154. }
  155. else {
  156. return false;
  157. }
  158. }
  159. public int size() {
  160. return readSize() ? getCachedSize() : values.size();
  161. }
  162. public Object[] toArray() {
  163. read();
  164. return values.toArray();
  165. }
  166. public Object[] toArray(Object[] a) {
  167. read();
  168. return values.toArray(a);
  169. }
  170. public void beforeInitialize(CollectionPersister persister, int anticipatedSize) {
  171. identifiers = anticipatedSize <= 0 ? new HashMap() : new HashMap( anticipatedSize + 1 + (int)( anticipatedSize * .75f ), .75f );
  172. values = anticipatedSize <= 0 ? new ArrayList() : new ArrayList( anticipatedSize );
  173. }
  174. public Serializable disassemble(CollectionPersister persister)
  175. throws HibernateException {
  176. Serializable[] result = new Serializable[ values.size() * 2 ];
  177. int i=0;
  178. for (int j=0; j< values.size(); j++) {
  179. Object value = values.get(j);
  180. result[i++] = persister.getIdentifierType().disassemble( identifiers.get( new Integer(j) ), getSession(), null );
  181. result[i++] = persister.getElementType().disassemble( value, getSession(), null );
  182. }
  183. return result;
  184. }
  185. public boolean empty() {
  186. return values.isEmpty();
  187. }
  188. public Iterator entries(CollectionPersister persister) {
  189. return values.iterator();
  190. }
  191. public boolean entryExists(Object entry, int i) {
  192. return entry!=null;
  193. }
  194. public boolean equalsSnapshot(CollectionPersister persister) throws HibernateException {
  195. Type elementType = persister.getElementType();
  196. Map snap = (Map) getSnapshot();
  197. if ( snap.size()!= values.size() ) return false;
  198. for ( int i=0; i<values.size(); i++ ) {
  199. Object value = values.get(i);
  200. Object id = identifiers.get( new Integer(i) );
  201. if (id==null) return false;
  202. Object old = snap.get(id);
  203. if ( elementType.isDirty( old, value, getSession() ) ) return false;
  204. }
  205. return true;
  206. }
  207. public boolean isSnapshotEmpty(Serializable snapshot) {
  208. return ( (Map) snapshot ).isEmpty();
  209. }
  210. public Iterator getDeletes(CollectionPersister persister, boolean indexIsFormula) throws HibernateException {
  211. Map snap = (Map) getSnapshot();
  212. List deletes = new ArrayList( snap.keySet() );
  213. for ( int i=0; i<values.size(); i++ ) {
  214. if ( values.get(i)!=null ) deletes.remove( identifiers.get( new Integer(i) ) );
  215. }
  216. return deletes.iterator();
  217. }
  218. public Object getIndex(Object entry, int i, CollectionPersister persister) {
  219. throw new UnsupportedOperationException("Bags don't have indexes");
  220. }
  221. public Object getElement(Object entry) {
  222. return entry;
  223. }
  224. public Object getSnapshotElement(Object entry, int i) {
  225. Map snap = (Map) getSnapshot();
  226. Object id = identifiers.get( new Integer(i) );
  227. return snap.get(id);
  228. }
  229. public boolean needsInserting(Object entry, int i, Type elemType)
  230. throws HibernateException {
  231. Map snap = (Map) getSnapshot();
  232. Object id = identifiers.get( new Integer(i) );
  233. return entry!=null && ( id==null || snap.get(id)==null );
  234. }
  235. public boolean needsUpdating(Object entry, int i, Type elemType) throws HibernateException {
  236. if (entry==null) return false;
  237. Map snap = (Map) getSnapshot();
  238. Object id = identifiers.get( new Integer(i) );
  239. if (id==null) return false;
  240. Object old = snap.get(id);
  241. return old!=null && elemType.isDirty( old, entry, getSession() );
  242. }
  243. public Object readFrom(
  244. ResultSet rs,
  245. CollectionPersister persister,
  246. CollectionAliases descriptor,
  247. Object owner)
  248. throws HibernateException, SQLException {
  249. Object element = persister.readElement( rs, owner, descriptor.getSuffixedElementAliases(), getSession() );
  250. Object old = identifiers.put(
  251. new Integer( values.size() ),
  252. persister.readIdentifier( rs, descriptor.getSuffixedIdentifierAlias(), getSession() )
  253. );
  254. if ( old==null ) values.add(element); //maintain correct duplication if loaded in a cartesian product
  255. return element;
  256. }
  257. public Serializable getSnapshot(CollectionPersister persister) throws HibernateException {
  258. HashMap map = new HashMap( values.size() );
  259. Iterator iter = values.iterator();
  260. int i=0;
  261. while ( iter.hasNext() ) {
  262. Object value = iter.next();
  263. map.put(
  264. identifiers.get( new Integer(i++) ),
  265. persister.getElementType().deepCopy(value, persister.getFactory())
  266. );
  267. }
  268. return map;
  269. }
  270. public Collection getOrphans(Serializable snapshot, String entityName) throws HibernateException {
  271. Map sn = (Map) snapshot;
  272. return getOrphans( sn.values(), values, entityName, getSession() );
  273. }
  274. public void preInsert(CollectionPersister persister) throws HibernateException {
  275. Iterator iter = values.iterator();
  276. int i=0;
  277. while ( iter.hasNext() ) {
  278. Object entry = iter.next();
  279. Integer loc = new Integer(i++);
  280. if ( !identifiers.containsKey(loc) ) { //TODO: native ids
  281. Serializable id = persister.getIdentifierGenerator().generate( getSession(), entry );
  282. identifiers.put(loc, id);
  283. }
  284. }
  285. }
  286. public void add(int index, Object element) {
  287. write();
  288. beforeAdd(index);
  289. values.add(index, element);
  290. }
  291. public boolean addAll(int index, Collection c) {
  292. if ( c.size() > 0 ) {
  293. Iterator iter = c.iterator();
  294. while ( iter.hasNext() ) {
  295. add( index++, iter.next() );
  296. }
  297. return true;
  298. }
  299. else {
  300. return false;
  301. }
  302. }
  303. public Object get(int index) {
  304. read();
  305. return values.get(index);
  306. }
  307. public int indexOf(Object o) {
  308. read();
  309. return values.indexOf(o);
  310. }
  311. public int lastIndexOf(Object o) {
  312. read();
  313. return values.lastIndexOf(o);
  314. }
  315. public ListIterator listIterator() {
  316. read();
  317. return new ListIteratorProxy( values.listIterator() );
  318. }
  319. public ListIterator listIterator(int index) {
  320. read();
  321. return new ListIteratorProxy( values.listIterator(index) );
  322. }
  323. private void beforeRemove(int index) {
  324. Object removedId = identifiers.get( new Integer(index) );
  325. int last = values.size()-1;
  326. for ( int i=index; i<last; i++ ) {
  327. Object id = identifiers.get( new Integer(i+1) );
  328. if ( id==null ) {
  329. identifiers.remove( new Integer(i) );
  330. }
  331. else {
  332. identifiers.put( new Integer(i), id );
  333. }
  334. }
  335. identifiers.put( new Integer(last), removedId );
  336. }
  337. private void beforeAdd(int index) {
  338. for ( int i=index; i<values.size(); i++ ) {
  339. identifiers.put( new Integer(i+1), identifiers.get( new Integer(i) ) );
  340. }
  341. identifiers.remove( new Integer(index) );
  342. }
  343. public Object remove(int index) {
  344. write();
  345. beforeRemove(index);
  346. return values.remove(index);
  347. }
  348. public Object set(int index, Object element) {
  349. write();
  350. return values.set(index, element);
  351. }
  352. public List subList(int fromIndex, int toIndex) {
  353. read();
  354. return new ListProxy( values.subList(fromIndex, toIndex) );
  355. }
  356. public boolean addAll(Collection c) {
  357. if ( c.size()> 0 ) {
  358. write();
  359. return values.addAll(c);
  360. }
  361. else {
  362. return false;
  363. }
  364. }
  365. public void afterRowInsert(
  366. CollectionPersister persister,
  367. Object entry,
  368. int i)
  369. throws HibernateException {
  370. //TODO: if we are using identity columns, fetch the identifier
  371. }
  372. }