View Javadoc
1   package de.fhdw.wtf.persistence.facade;
2   
3   import java.math.BigDecimal;
4   import java.math.BigInteger;
5   import java.sql.CallableStatement;
6   import java.sql.ResultSet;
7   import java.sql.SQLException;
8   import java.sql.Timestamp;
9   import java.util.ArrayList;
10  import java.util.Collection;
11  import java.util.Date;
12  import java.util.HashSet;
13  
14  import oracle.jdbc.OracleCallableStatement;
15  import oracle.jdbc.OracleTypes;
16  import de.fhdw.wtf.persistence.exception.BaseTypeNotFoundException;
17  import de.fhdw.wtf.persistence.exception.DuplicateEntryException;
18  import de.fhdw.wtf.persistence.exception.InvalidLinkException;
19  import de.fhdw.wtf.persistence.exception.NoValidTransactionException;
20  import de.fhdw.wtf.persistence.exception.NotInScopeException;
21  import de.fhdw.wtf.persistence.exception.NotInstantiatableException;
22  import de.fhdw.wtf.persistence.exception.ObjectNotFoundException;
23  import de.fhdw.wtf.persistence.exception.OtherSQLException;
24  import de.fhdw.wtf.persistence.exception.PersistenceException;
25  import de.fhdw.wtf.persistence.exception.ToManyObjectsException;
26  import de.fhdw.wtf.persistence.meta.AdhocTransaction;
27  import de.fhdw.wtf.persistence.meta.Association;
28  import de.fhdw.wtf.persistence.meta.IntegerValue;
29  import de.fhdw.wtf.persistence.meta.Link;
30  import de.fhdw.wtf.persistence.meta.MapAssociation;
31  import de.fhdw.wtf.persistence.meta.MapLink;
32  import de.fhdw.wtf.persistence.meta.Object;
33  import de.fhdw.wtf.persistence.meta.StringValue;
34  import de.fhdw.wtf.persistence.meta.Transaction;
35  import de.fhdw.wtf.persistence.meta.UnidirectionalAssociation;
36  import de.fhdw.wtf.persistence.meta.UnidirectionalLink;
37  import de.fhdw.wtf.persistence.meta.UserObject;
38  import de.fhdw.wtf.persistence.meta.UserType;
39  import de.fhdw.wtf.persistence.utils.DBConnectionIntegerHandler;
40  import de.fhdw.wtf.persistence.utils.DBConnectionObjectHandler;
41  import de.fhdw.wtf.persistence.utils.DBConnectionStringHandler;
42  import de.fhdw.wtf.persistence.utils.DBConnectionUserObjectHandler;
43  import de.fhdw.wtf.persistence.utils.IntegerConstants;
44  import de.fhdw.wtf.persistence.utils.StringConstants;
45  import de.fhdw.wtf.persistence.utils.Tuple;
46  
47  /**
48   * A class to represent the implementation of the Object Facade Interface for the Oracle Database.
49   * 
50   */
51  public class OracleObjectFacadeImplementation implements ObjectFacade {
52  	
53  	private static final String CALL_SUFFIX = " end;";
54  	
55  	private static final String STORED_PROCEDURE_PREFIX = "begin ";
56  	
57  	private static final String STORED_FUNCTION_PREFIX = "begin ? := ";
58  	
59  	/**
60  	 * The Oracle Database Manager which is needed to call stored procedures in the database.
61  	 */
62  	private final OracleDatabaseManager database;
63  	
64  	/**
65  	 * The Type Manager, which has the Information about all model items.
66  	 */
67  	private final TypeManager typeManager;
68  	
69  	/**
70  	 * Constructor for a new Oracle Object Facade Implementation class.
71  	 * 
72  	 * @param database
73  	 *            An Oracle Database Manager, which is needed to access the Database.
74  	 * @param typeManager
75  	 *            A type Manager needed to determine type information.
76  	 */
77  	public OracleObjectFacadeImplementation(final OracleDatabaseManager database, final TypeManager typeManager) {
78  		super();
79  		this.database = database;
80  		this.typeManager = typeManager;
81  		IntegerValue.setObjectFacade(this);
82  		StringValue.setObjectFacade(this);
83  	}
84  	
85  	@Override
86  	public Collection<UserObject> find(final Association association, final String string, final Date date)
87  			throws PersistenceException {
88  		try (final CallableStatement call =
89  				this.database.getConnection().prepareCall(
90  						STORED_FUNCTION_PREFIX + this.database.getSchemaName() + ".objectfacade.findString(?,?,?);"
91  								+ CALL_SUFFIX)) {
92  			call.registerOutParameter(1, OracleTypes.CURSOR);
93  			call.setLong(IntegerConstants.TWO, association.getId());
94  			call.setString(IntegerConstants.THREE, string);
95  			call.setTimestamp(IntegerConstants.FOUR, new Timestamp(date.getTime()));
96  			call.execute();
97  			
98  			try (final ResultSet resultSet = ((OracleCallableStatement) call).getCursor(1)) {
99  				final Collection<UserObject> result = new HashSet<>();
100 				while (resultSet.next()) {
101 					result.add(UserObject.init(
102 							resultSet.getLong(1),
103 							this.typeManager.getTypeForId(resultSet.getLong(2))));
104 				}
105 				return result;
106 			}
107 		} catch (final SQLException e) {
108 			throw new OtherSQLException(e);
109 		}
110 	}
111 	
112 	@Override
113 	public Collection<UserObject> find(final Association association, final BigInteger integer, final Date date)
114 			throws PersistenceException {
115 		try (final CallableStatement call =
116 				this.database.getConnection().prepareCall(
117 						STORED_FUNCTION_PREFIX + this.database.getSchemaName() + ".objectfacade.findInteger(?,?,?);"
118 								+ CALL_SUFFIX)) {
119 			call.registerOutParameter(1, OracleTypes.CURSOR);
120 			call.setLong(2, association.getId());
121 			final BigDecimal wrapper = new BigDecimal(integer);
122 			call.setBigDecimal(IntegerConstants.THREE, wrapper);
123 			call.setTimestamp(IntegerConstants.FOUR, new Timestamp(date.getTime()));
124 			call.execute();
125 			
126 			try (final ResultSet resultSet = ((OracleCallableStatement) call).getCursor(1)) {
127 				final Collection<UserObject> result = new HashSet<>();
128 				while (resultSet.next()) {
129 					result.add(UserObject.init(
130 							resultSet.getLong(1),
131 							this.typeManager.getTypeForId(resultSet.getLong(2))));
132 				}
133 				return result;
134 			}
135 		} catch (final SQLException e) {
136 			throw new OtherSQLException(e);
137 		}
138 	}
139 	
140 	@Override
141 	public Collection<Tuple<UnidirectionalLink, Object>> get(final UserObject owner,
142 			final UnidirectionalAssociation association,
143 			final Date date) throws PersistenceException {
144 		try (final CallableStatement call =
145 				this.database.getConnection().prepareCall(
146 						STORED_FUNCTION_PREFIX + this.database.getSchemaName() + ".objectfacade.get(?,?,?);"
147 								+ CALL_SUFFIX)) {
148 			call.registerOutParameter(1, OracleTypes.CURSOR);
149 			call.setLong(2, owner.getId());
150 			call.setLong(IntegerConstants.THREE, association.getId());
151 			call.setTimestamp(IntegerConstants.FOUR, new Timestamp(date.getTime()));
152 			call.execute();
153 			
154 			try (final ResultSet resultSet = ((OracleCallableStatement) call).getCursor(1)) {
155 				final Collection<Tuple<UnidirectionalLink, Object>> result = new ArrayList<>();
156 				while (resultSet.next()) {
157 					final Object target =
158 							Object.checkForBaseTypes(
159 									resultSet.getLong(3),
160 									this.typeManager.getTypeForId(resultSet.getLong(4)));
161 					result.add(new Tuple<>(new UnidirectionalLink(resultSet.getLong(1), owner, target, this.typeManager
162 							.getUnidirectionalAssociationForId(resultSet.getLong(2))), target));
163 				}
164 				return result;
165 			}
166 		} catch (final SQLException e) {
167 			throw new OtherSQLException(e);
168 		}
169 	}
170 	
171 	private Collection<Object> getWithKeyHelper(final UserObject owner,
172 			final MapAssociation association,
173 			final DBConnectionObjectHandler keyHandler,
174 			final Date date) throws PersistenceException {
175 		try (final CallableStatement call =
176 				this.database.getConnection().prepareCall(
177 						STORED_FUNCTION_PREFIX + this.database.getSchemaName() + StringConstants.OBJECTFACADEGETMAP
178 								+ keyHandler.getObjectTypeString() + StringConstants.FOURQUESTIONMARKS + CALL_SUFFIX)) {
179 			call.registerOutParameter(1, OracleTypes.CURSOR);
180 			call.setLong(2, owner.getId());
181 			call.setLong(IntegerConstants.THREE, association.getId());
182 			keyHandler.handleCall(call, IntegerConstants.FOUR);
183 			call.setTimestamp(IntegerConstants.FIVE, new Timestamp(date.getTime()));
184 			call.execute();
185 			
186 			try (final ResultSet resultSet = ((OracleCallableStatement) call).getCursor(1)) {
187 				final Collection<Object> result = new ArrayList<>();
188 				while (resultSet.next()) {
189 					if (!result.isEmpty()) {
190 						throw new ToManyObjectsException();
191 					}
192 					final Object target =
193 							Object.checkForBaseTypes(
194 									resultSet.getLong(1),
195 									this.typeManager.getTypeForId(resultSet.getLong(2)));
196 					result.add(target);
197 				}
198 				if (result.isEmpty()) {
199 					throw new ObjectNotFoundException();
200 				}
201 				return result;
202 			}
203 		} catch (final SQLException e) {
204 			throw new OtherSQLException(e);
205 		}
206 	}
207 	
208 	@Override
209 	public Collection<Object> get(final UserObject owner,
210 			final MapAssociation association,
211 			final String key,
212 			final Date date) throws PersistenceException {
213 		return this.getWithKeyHelper(owner, association, new DBConnectionStringHandler(key), date);
214 	}
215 	
216 	@Override
217 	public Collection<Object> get(final UserObject owner,
218 			final MapAssociation association,
219 			final BigInteger key,
220 			final Date date) throws PersistenceException {
221 		return this.getWithKeyHelper(owner, association, new DBConnectionIntegerHandler(key), date);
222 	}
223 	
224 	@Override
225 	public Collection<Object> get(final UserObject owner,
226 			final MapAssociation association,
227 			final UserObject key,
228 			final Date date) throws PersistenceException {
229 		return this.getWithKeyHelper(owner, association, new DBConnectionUserObjectHandler(key), date);
230 	}
231 	
232 	@Override
233 	public Collection<Tuple<UnidirectionalLink, UserObject>> inverseGet(final UserObject target,
234 			final UnidirectionalAssociation association,
235 			final Date date) throws PersistenceException {
236 		try (final CallableStatement call =
237 				this.database.getConnection().prepareCall(
238 						STORED_FUNCTION_PREFIX + this.database.getSchemaName() + ".objectfacade.inverseGet(?,?,?);"
239 								+ CALL_SUFFIX)) {
240 			call.registerOutParameter(1, OracleTypes.CURSOR);
241 			call.setLong(2, target.getId());
242 			call.setLong(IntegerConstants.THREE, association.getId());
243 			call.setTimestamp(IntegerConstants.FOUR, new Timestamp(date.getTime()));
244 			call.execute();
245 			
246 			try (final ResultSet resultSet = ((OracleCallableStatement) call).getCursor(1)) {
247 				final Collection<Tuple<UnidirectionalLink, UserObject>> result = new ArrayList<>();
248 				while (resultSet.next()) {
249 					final UserObject owner =
250 							UserObject.init(resultSet.getLong(3), this.typeManager.getTypeForId(resultSet.getLong(4)));
251 					result.add(new Tuple<>(new UnidirectionalLink(resultSet.getLong(1), owner, target, this.typeManager
252 							.getUnidirectionalAssociationForId(resultSet.getLong(2))), owner));
253 				}
254 				return result;
255 			}
256 		} catch (final SQLException e) {
257 			throw new OtherSQLException(e);
258 		}
259 	}
260 	
261 	private Collection<Tuple<UserObject, Object>> inverseGetWithKeyHelper(final DBConnectionObjectHandler targetHandler,
262 			final MapAssociation association,
263 			final Date date) throws PersistenceException {
264 		try (final CallableStatement call =
265 				this.database.getConnection().prepareCall(
266 						STORED_FUNCTION_PREFIX + this.database.getSchemaName()
267 								+ StringConstants.OBJECTFACADEINVERSEGETMAP + targetHandler.getObjectTypeString()
268 								+ "(?,?,?);" + CALL_SUFFIX)) {
269 			call.registerOutParameter(1, OracleTypes.CURSOR);
270 			targetHandler.handleCall(call, 2);
271 			call.setLong(IntegerConstants.THREE, association.getId());
272 			call.setTimestamp(IntegerConstants.FOUR, new Timestamp(date.getTime()));
273 			call.execute();
274 			
275 			try (final ResultSet resultSet = ((OracleCallableStatement) call).getCursor(1)) {
276 				final Collection<Tuple<UserObject, Object>> owners = new ArrayList<>();
277 				while (resultSet.next()) {
278 					owners.add(new Tuple<>(UserObject.init(
279 							resultSet.getLong(1),
280 							this.typeManager.getTypeForId(resultSet.getLong(2))), Object.checkForBaseTypes(
281 							resultSet.getLong(IntegerConstants.THREE),
282 							this.typeManager.getTypeForId(resultSet.getLong(IntegerConstants.FOUR)))));
283 				}
284 				return owners;
285 			}
286 		} catch (final SQLException e) {
287 			throw new OtherSQLException(e);
288 		}
289 	}
290 	
291 	@Override
292 	public Collection<Tuple<UserObject, Object>> inverseGet(final UserObject target,
293 			final MapAssociation association,
294 			final Date date) throws PersistenceException {
295 		return this.inverseGetWithKeyHelper(new DBConnectionUserObjectHandler(target), association, date);
296 	}
297 	
298 	@Override
299 	public Collection<Tuple<UserObject, Object>> inverseGet(final String target,
300 			final MapAssociation association,
301 			final Date date) throws PersistenceException {
302 		return this.inverseGetWithKeyHelper(new DBConnectionStringHandler(target), association, date);
303 	}
304 	
305 	@Override
306 	public Collection<Tuple<UserObject, Object>> inverseGet(final BigInteger target,
307 			final MapAssociation association,
308 			final Date date) throws PersistenceException {
309 		return this.inverseGetWithKeyHelper(new DBConnectionIntegerHandler(target), association, date);
310 	}
311 	
312 	@Override
313 	public Collection<UserObject> find(final Association association, final String string, final Transaction transaction)
314 			throws PersistenceException {
315 		this.checkTransaction(transaction);
316 		try (final CallableStatement call =
317 				this.database.getConnection().prepareCall(
318 						STORED_FUNCTION_PREFIX + this.database.getSchemaName()
319 								+ ".objectfacade.findStringTransaction(?,?,?);" + CALL_SUFFIX)) {
320 			call.registerOutParameter(1, OracleTypes.CURSOR);
321 			call.setLong(2, association.getId());
322 			call.setString(IntegerConstants.THREE, string);
323 			call.setLong(IntegerConstants.FOUR, transaction.getId());
324 			call.execute();
325 			
326 			try (final ResultSet resultSet = ((OracleCallableStatement) call).getCursor(1)) {
327 				final Collection<UserObject> result = new HashSet<>();
328 				while (resultSet.next()) {
329 					result.add(UserObject.init(
330 							resultSet.getLong(1),
331 							this.typeManager.getTypeForId(resultSet.getLong(2))));
332 				}
333 				return result;
334 			}
335 		} catch (final SQLException e) {
336 			throw new OtherSQLException(e);
337 		}
338 	}
339 	
340 	/**
341 	 * This method checks if a given transaction is really an open transaction and throws an exception if not.
342 	 * 
343 	 * @param transaction
344 	 *            An Transaction.
345 	 * @throws PersistenceException
346 	 *             This Exception occurs if there are any communicating issues.
347 	 * @throws NoValidTransactionException
348 	 *             This Exception is the Transaction is not an open transaction.
349 	 */
350 	private void checkTransaction(final Transaction transaction) throws PersistenceException,
351 			NoValidTransactionException {
352 		if (!this.isOpenTransaction(transaction)) {
353 			throw new NoValidTransactionException();
354 		}
355 	}
356 	
357 	@Override
358 	public Collection<UserObject> find(final Association association,
359 			final BigInteger integer,
360 			final Transaction transaction) throws PersistenceException {
361 		this.checkTransaction(transaction);
362 		try (final CallableStatement call =
363 				this.database.getConnection().prepareCall(
364 						STORED_FUNCTION_PREFIX + this.database.getSchemaName()
365 								+ ".objectfacade.findIntegerTransaction(?,?,?);" + CALL_SUFFIX)) {
366 			call.registerOutParameter(1, OracleTypes.CURSOR);
367 			call.setLong(2, association.getId());
368 			final BigDecimal wrapper = new BigDecimal(integer);
369 			call.setBigDecimal(IntegerConstants.THREE, wrapper);
370 			call.setLong(IntegerConstants.FOUR, transaction.getId());
371 			call.execute();
372 			
373 			try (final ResultSet resultSet = ((OracleCallableStatement) call).getCursor(1)) {
374 				final Collection<UserObject> result = new HashSet<>();
375 				while (resultSet.next()) {
376 					result.add(UserObject.init(
377 							resultSet.getLong(1),
378 							this.typeManager.getTypeForId(resultSet.getLong(2))));
379 				}
380 				return result;
381 			}
382 		} catch (final SQLException e) {
383 			throw new OtherSQLException(e);
384 		}
385 	}
386 	
387 	@Override
388 	public Collection<Tuple<UnidirectionalLink, Object>> get(final UserObject owner,
389 			final UnidirectionalAssociation association,
390 			final Transaction transaction) throws PersistenceException {
391 		this.checkTransaction(transaction);
392 		try (final CallableStatement call =
393 				this.database.getConnection().prepareCall(
394 						STORED_FUNCTION_PREFIX + this.database.getSchemaName() + ".objectfacade.getTransaction(?,?,?);"
395 								+ CALL_SUFFIX)) {
396 			call.registerOutParameter(1, OracleTypes.CURSOR);
397 			call.setLong(2, owner.getId());
398 			call.setLong(IntegerConstants.THREE, association.getId());
399 			call.setLong(IntegerConstants.FOUR, transaction.getId());
400 			call.execute();
401 			
402 			try (final ResultSet resultSet = ((OracleCallableStatement) call).getCursor(1)) {
403 				final Collection<Tuple<UnidirectionalLink, Object>> result = new ArrayList<>();
404 				while (resultSet.next()) {
405 					final Object target =
406 							Object.checkForBaseTypes(
407 									resultSet.getLong(3),
408 									this.typeManager.getTypeForId(resultSet.getLong(4)));
409 					result.add(new Tuple<>(new UnidirectionalLink(resultSet.getLong(1), owner, target, this.typeManager
410 							.getUnidirectionalAssociationForId(resultSet.getLong(2))), target));
411 				}
412 				return result;
413 			}
414 		} catch (final SQLException e) {
415 			throw new OtherSQLException(e);
416 		}
417 	}
418 	
419 	private Collection<Tuple<MapLink, Object>> getWithKeyHelper(final UserObject owner,
420 			final MapAssociation a,
421 			final DBConnectionObjectHandler keyHandler,
422 			final Transaction transaction) throws PersistenceException {
423 		this.checkTransaction(transaction);
424 		try (final CallableStatement call =
425 				this.database.getConnection().prepareCall(
426 						STORED_FUNCTION_PREFIX + this.database.getSchemaName() + ".objectfacade.getMap"
427 								+ keyHandler.getObjectTypeString() + "Transaction(?,?,?,?);" + CALL_SUFFIX)) {
428 			call.registerOutParameter(1, OracleTypes.CURSOR);
429 			call.setLong(2, owner.getId());
430 			call.setLong(IntegerConstants.THREE, a.getId());
431 			keyHandler.handleCall(call, IntegerConstants.FOUR);
432 			call.setLong(IntegerConstants.FIVE, transaction.getId());
433 			call.execute();
434 			
435 			try (final ResultSet resultSet = ((OracleCallableStatement) call).getCursor(1)) {
436 				final Collection<Tuple<MapLink, Object>> result = new ArrayList<>();
437 				while (resultSet.next()) {
438 					if (!result.isEmpty()) {
439 						throw new ToManyObjectsException();
440 					}
441 					final Object target =
442 							Object.checkForBaseTypes(
443 									resultSet.getLong(1),
444 									this.typeManager.getTypeForId(resultSet.getLong(2)));
445 					final MapLink link =
446 							new MapLink(resultSet.getLong(IntegerConstants.FIVE), owner, target,
447 									keyHandler.getObject(), a);
448 					result.add(new Tuple<>(link, target));
449 				}
450 				if (result.isEmpty()) {
451 					throw new ObjectNotFoundException();
452 				}
453 				return result;
454 			}
455 		} catch (final SQLException e) {
456 			throw new OtherSQLException(e);
457 		}
458 	}
459 	
460 	@Override
461 	public Collection<Tuple<MapLink, Object>> get(final UserObject owner,
462 			final MapAssociation association,
463 			final String key,
464 			final Transaction transaction) throws PersistenceException {
465 		return this.getWithKeyHelper(owner, association, new DBConnectionStringHandler(key), transaction);
466 	}
467 	
468 	@Override
469 	public Collection<Tuple<MapLink, Object>> get(final UserObject owner,
470 			final MapAssociation association,
471 			final BigInteger key,
472 			final Transaction transaction) throws PersistenceException {
473 		return this.getWithKeyHelper(owner, association, new DBConnectionIntegerHandler(key), transaction);
474 	}
475 	
476 	@Override
477 	public Collection<Tuple<MapLink, Object>> get(final UserObject owner,
478 			final MapAssociation association,
479 			final UserObject key,
480 			final Transaction transaction) throws PersistenceException {
481 		return this.getWithKeyHelper(owner, association, new DBConnectionUserObjectHandler(key), transaction);
482 	}
483 	
484 	@Override
485 	public Collection<Tuple<UnidirectionalLink, UserObject>> inverseGet(final UserObject target,
486 			final UnidirectionalAssociation association,
487 			final Transaction transaction) throws PersistenceException {
488 		this.checkTransaction(transaction);
489 		try (final CallableStatement call =
490 				this.database.getConnection().prepareCall(
491 						STORED_FUNCTION_PREFIX + this.database.getSchemaName()
492 								+ ".objectfacade.inverseGetTransaction(?,?,?);" + CALL_SUFFIX)) {
493 			call.registerOutParameter(1, OracleTypes.CURSOR);
494 			call.setLong(2, target.getId());
495 			call.setLong(IntegerConstants.THREE, association.getId());
496 			call.setLong(IntegerConstants.FOUR, transaction.getId());
497 			call.execute();
498 			
499 			try (final ResultSet resultSet = ((OracleCallableStatement) call).getCursor(1)) {
500 				final Collection<Tuple<UnidirectionalLink, UserObject>> result = new ArrayList<>();
501 				while (resultSet.next()) {
502 					final UserObject owner =
503 							UserObject.init(resultSet.getLong(3), this.typeManager.getTypeForId(resultSet.getLong(4)));
504 					result.add(new Tuple<>(new UnidirectionalLink(resultSet.getLong(1), owner, target, this.typeManager
505 							.getUnidirectionalAssociationForId(resultSet.getLong(2))), owner));
506 				}
507 				return result;
508 			}
509 		} catch (final SQLException e) {
510 			throw new OtherSQLException(e);
511 		}
512 	}
513 	
514 	private Collection<Tuple<UserObject, Object>> inverseGetWithKeyHelper(final DBConnectionObjectHandler targetHandler,
515 			final MapAssociation association,
516 			final Transaction transaction) throws PersistenceException {
517 		this.checkTransaction(transaction);
518 		try (final CallableStatement call =
519 				this.database.getConnection().prepareCall(
520 						STORED_FUNCTION_PREFIX + this.database.getSchemaName() + ".objectfacade.inverseGetMap"
521 								+ targetHandler.getObjectTypeString() + "Transaction(?,?,?);" + CALL_SUFFIX)) {
522 			call.registerOutParameter(1, OracleTypes.CURSOR);
523 			targetHandler.handleCall(call, 2);
524 			call.setLong(IntegerConstants.THREE, association.getId());
525 			call.setLong(IntegerConstants.FOUR, transaction.getId());
526 			call.execute();
527 			
528 			try (final ResultSet resultSet = ((OracleCallableStatement) call).getCursor(1)) {
529 				final Collection<Tuple<UserObject, Object>> owners = new ArrayList<>();
530 				while (resultSet.next()) {
531 					owners.add(new Tuple<>(UserObject.init(
532 							resultSet.getLong(1),
533 							this.typeManager.getTypeForId(resultSet.getLong(2))), Object.checkForBaseTypes(
534 							resultSet.getLong(IntegerConstants.THREE),
535 							this.typeManager.getTypeForId(resultSet.getLong(IntegerConstants.FOUR)))));
536 				}
537 				return owners;
538 			}
539 		} catch (final SQLException e) {
540 			throw new OtherSQLException(e);
541 		}
542 	}
543 	
544 	@Override
545 	public Collection<Tuple<UserObject, Object>> inverseGet(final UserObject target,
546 			final MapAssociation association,
547 			final Transaction transaction) throws PersistenceException {
548 		return this.inverseGetWithKeyHelper(new DBConnectionUserObjectHandler(target), association, transaction);
549 	}
550 	
551 	@Override
552 	public Collection<Tuple<UserObject, Object>> inverseGet(final String target,
553 			final MapAssociation association,
554 			final Transaction transaction) throws PersistenceException {
555 		return this.inverseGetWithKeyHelper(new DBConnectionStringHandler(target), association, transaction);
556 	}
557 	
558 	@Override
559 	public Collection<Tuple<UserObject, Object>> inverseGet(final BigInteger target,
560 			final MapAssociation association,
561 			final Transaction transaction) throws PersistenceException {
562 		return this.inverseGetWithKeyHelper(new DBConnectionIntegerHandler(target), association, transaction);
563 	}
564 	
565 	@Override
566 	public boolean isInConflict(final Transaction transaction1, final Transaction transaction2)
567 			throws PersistenceException {
568 		this.checkTransaction(transaction1);
569 		this.checkTransaction(transaction2);
570 		try (final CallableStatement call =
571 				this.database.getConnection().prepareCall(
572 						STORED_FUNCTION_PREFIX + this.database.getSchemaName()
573 								+ ".objectfacade.getConflictingTransactions(?);" + CALL_SUFFIX)) {
574 			call.registerOutParameter(1, OracleTypes.CURSOR);
575 			call.setLong(2, transaction1.getId());
576 			call.execute();
577 			
578 			try (final ResultSet resultSet = ((OracleCallableStatement) call).getCursor(1)) {
579 				while (resultSet.next()) {
580 					if (transaction2.getId() == resultSet.getLong(1)) {
581 						return true;
582 					}
583 				}
584 				return false;
585 			}
586 		} catch (final SQLException e) {
587 			throw new OtherSQLException(e);
588 		}
589 	}
590 	
591 	@Override
592 	public boolean isOpenTransaction(final Transaction transaction) throws PersistenceException {
593 		try (final CallableStatement call =
594 				this.database.getConnection().prepareCall(
595 						STORED_FUNCTION_PREFIX + this.database.getSchemaName() + ".objectfacade.isTransactionOpen(?);"
596 								+ CALL_SUFFIX)) {
597 			call.registerOutParameter(1, OracleTypes.NUMBER);
598 			call.setLong(2, transaction.getId());
599 			call.execute();
600 			return call.getInt(1) == 1 ? true : false;
601 		} catch (final SQLException e) {
602 			throw new OtherSQLException(e);
603 		}
604 	}
605 	
606 	@Override
607 	public UserObject create(final UserType type, final Transaction transaction) throws PersistenceException {
608 		this.checkTransaction(transaction);
609 		try (final CallableStatement call =
610 				this.database.getConnection().prepareCall(
611 						STORED_FUNCTION_PREFIX + this.database.getSchemaName() + ".objectfacade.createUserObject(?,?);"
612 								+ CALL_SUFFIX)) {
613 			call.registerOutParameter(1, OracleTypes.NUMBER);
614 			call.setLong(2, type.getId());
615 			call.setLong(IntegerConstants.THREE, transaction.getId());
616 			call.execute();
617 			return UserObject.init(call.getLong(1), type);
618 		} catch (final SQLException e) {
619 			if (e.getErrorCode() == NotInstantiatableException.ERRORCODE) {
620 				throw new NotInstantiatableException(e);
621 			}
622 			e.printStackTrace();
623 			throw new OtherSQLException(e);
624 		}
625 	}
626 	
627 	@Override
628 	public void delete(final UserObject object, final Transaction transaction) throws PersistenceException {
629 		this.checkTransaction(transaction);
630 		try (final CallableStatement call =
631 				this.database.getConnection().prepareCall(
632 						STORED_PROCEDURE_PREFIX + this.database.getSchemaName()
633 								+ ".objectfacade.deleteUserObject(?,?);" + CALL_SUFFIX)) {
634 			call.setLong(1, object.getId());
635 			call.setLong(2, transaction.getId());
636 			call.execute();
637 		} catch (final SQLException e) {
638 			if (e.getErrorCode() == InvalidLinkException.ERRORCODE) {
639 				throw new InvalidLinkException(e);
640 			}
641 			throw new OtherSQLException(e);
642 		}
643 	}
644 	
645 	private UnidirectionalLink setHelper(final UserObject owner,
646 			final UnidirectionalAssociation association,
647 			final DBConnectionObjectHandler targetHandler,
648 			final Transaction transaction) throws PersistenceException {
649 		this.checkTransaction(transaction);
650 		try (final CallableStatement call =
651 				this.database.getConnection().prepareCall(
652 						STORED_FUNCTION_PREFIX + this.database.getSchemaName() + ".objectfacade.set"
653 								+ targetHandler.getObjectTypeString() + "(?,?,?,?);" + CALL_SUFFIX)) {
654 			call.registerOutParameter(1, OracleTypes.NUMBER);
655 			call.setLong(2, owner.getId());
656 			call.setLong(IntegerConstants.THREE, association.getId());
657 			targetHandler.handleCall(call, IntegerConstants.FOUR);
658 			call.setLong(IntegerConstants.FIVE, transaction.getId());
659 			call.execute();
660 			return new UnidirectionalLink(call.getLong(1), owner, targetHandler.getObject(), association);
661 		} catch (final SQLException e) {
662 			if (e.getErrorCode() == InvalidLinkException.ERRORCODE) {
663 				throw new InvalidLinkException(e);
664 			}
665 			if (e.getErrorCode() == NotInScopeException.ERRORCODE) {
666 				throw new NotInScopeException(e);
667 			}
668 			throw new OtherSQLException(e);
669 		}
670 	}
671 	
672 	@Override
673 	public UnidirectionalLink set(final UserObject owner,
674 			final UnidirectionalAssociation association,
675 			final UserObject target,
676 			final Transaction transaction) throws PersistenceException {
677 		return this.setHelper(owner, association, new DBConnectionUserObjectHandler(target), transaction);
678 	}
679 	
680 	@Override
681 	public UnidirectionalLink set(final UserObject owner,
682 			final UnidirectionalAssociation association,
683 			final BigInteger target,
684 			final Transaction transaction) throws PersistenceException {
685 		return this.setHelper(owner, association, new DBConnectionIntegerHandler(target), transaction);
686 	}
687 	
688 	@Override
689 	public UnidirectionalLink set(final UserObject owner,
690 			final UnidirectionalAssociation association,
691 			final String target,
692 			final Transaction transaction) throws PersistenceException {
693 		return this.setHelper(owner, association, new DBConnectionStringHandler(target), transaction);
694 	}
695 	
696 	private MapLink putHelper(final UserObject owner,
697 			final MapAssociation association,
698 			final DBConnectionObjectHandler targetHandler,
699 			final DBConnectionObjectHandler keyHandler,
700 			final Transaction transaction) throws PersistenceException {
701 		try (final CallableStatement call =
702 				this.database.getConnection().prepareCall(
703 						STORED_FUNCTION_PREFIX + this.database.getSchemaName() + ".objectfacade.put"
704 								+ targetHandler.getObjectTypeString() + keyHandler.getObjectTypeString()
705 								+ "(?,?,?,?,?);" + CALL_SUFFIX)) {
706 			call.registerOutParameter(1, OracleTypes.NUMBER);
707 			call.setLong(2, owner.getId());
708 			call.setLong(IntegerConstants.THREE, association.getId());
709 			targetHandler.handleCall(call, IntegerConstants.FOUR);
710 			keyHandler.handleCall(call, IntegerConstants.FIVE);
711 			call.setLong(IntegerConstants.SIX, transaction.getId());
712 			call.execute();
713 			return new MapLink(call.getLong(1), owner, targetHandler.getObject(), keyHandler.getObject(), association);
714 		} catch (final SQLException e) {
715 			if (e.getErrorCode() == InvalidLinkException.ERRORCODE) {
716 				throw new InvalidLinkException(e);
717 			}
718 			if (e.getErrorCode() == NotInScopeException.ERRORCODE) {
719 				throw new NotInScopeException(e);
720 			}
721 			if (e.getErrorCode() == DuplicateEntryException.ERRORCODE) {
722 				throw new DuplicateEntryException(e);
723 			}
724 			throw new OtherSQLException(e);
725 		}
726 	}
727 	
728 	@Override
729 	public MapLink put(final UserObject owner,
730 			final MapAssociation association,
731 			final UserObject target,
732 			final String key,
733 			final Transaction transaction) throws PersistenceException {
734 		return this.putHelper(
735 				owner,
736 				association,
737 				new DBConnectionUserObjectHandler(target),
738 				new DBConnectionStringHandler(key),
739 				transaction);
740 	}
741 	
742 	@Override
743 	public MapLink put(final UserObject owner,
744 			final MapAssociation association,
745 			final BigInteger target,
746 			final String key,
747 			final Transaction transaction) throws PersistenceException {
748 		return this.putHelper(
749 				owner,
750 				association,
751 				new DBConnectionIntegerHandler(target),
752 				new DBConnectionStringHandler(key),
753 				transaction);
754 	}
755 	
756 	@Override
757 	public MapLink put(final UserObject owner,
758 			final MapAssociation association,
759 			final String target,
760 			final String key,
761 			final Transaction transaction) throws PersistenceException {
762 		return this.putHelper(owner, association, new DBConnectionStringHandler(target), new DBConnectionStringHandler(
763 				key), transaction);
764 	}
765 	
766 	@Override
767 	public MapLink put(final UserObject owner,
768 			final MapAssociation association,
769 			final UserObject target,
770 			final BigInteger key,
771 			final Transaction transaction) throws PersistenceException {
772 		return this.putHelper(
773 				owner,
774 				association,
775 				new DBConnectionUserObjectHandler(target),
776 				new DBConnectionIntegerHandler(key),
777 				transaction);
778 	}
779 	
780 	@Override
781 	public MapLink put(final UserObject owner,
782 			final MapAssociation association,
783 			final BigInteger target,
784 			final BigInteger key,
785 			final Transaction transaction) throws PersistenceException {
786 		return this.putHelper(
787 				owner,
788 				association,
789 				new DBConnectionIntegerHandler(target),
790 				new DBConnectionIntegerHandler(key),
791 				transaction);
792 	}
793 	
794 	@Override
795 	public MapLink put(final UserObject owner,
796 			final MapAssociation association,
797 			final String target,
798 			final BigInteger key,
799 			final Transaction transaction) throws PersistenceException {
800 		return this.putHelper(
801 				owner,
802 				association,
803 				new DBConnectionStringHandler(target),
804 				new DBConnectionIntegerHandler(key),
805 				transaction);
806 	}
807 	
808 	@Override
809 	public MapLink put(final UserObject owner,
810 			final MapAssociation association,
811 			final UserObject target,
812 			final UserObject key,
813 			final Transaction transaction) throws PersistenceException {
814 		return this.putHelper(
815 				owner,
816 				association,
817 				new DBConnectionUserObjectHandler(target),
818 				new DBConnectionUserObjectHandler(key),
819 				transaction);
820 	}
821 	
822 	@Override
823 	public MapLink put(final UserObject owner,
824 			final MapAssociation association,
825 			final BigInteger target,
826 			final UserObject key,
827 			final Transaction transaction) throws PersistenceException {
828 		return this.putHelper(
829 				owner,
830 				association,
831 				new DBConnectionIntegerHandler(target),
832 				new DBConnectionUserObjectHandler(key),
833 				transaction);
834 	}
835 	
836 	@Override
837 	public MapLink put(final UserObject owner,
838 			final MapAssociation association,
839 			final String target,
840 			final UserObject key,
841 			final Transaction transaction) throws PersistenceException {
842 		return this.putHelper(
843 				owner,
844 				association,
845 				new DBConnectionStringHandler(target),
846 				new DBConnectionUserObjectHandler(key),
847 				transaction);
848 	}
849 	
850 	@Override
851 	public void unset(final Link link, final Transaction transaction) throws PersistenceException {
852 		this.checkTransaction(transaction);
853 		try (final CallableStatement call =
854 				this.database.getConnection().prepareCall(
855 						STORED_PROCEDURE_PREFIX + this.database.getSchemaName() + ".objectfacade.unset(?,?);"
856 								+ CALL_SUFFIX)) {
857 			call.setLong(1, link.getId());
858 			call.setLong(2, transaction.getId());
859 			call.execute();
860 		} catch (final SQLException e) {
861 			throw new OtherSQLException(e);
862 		}
863 	}
864 	
865 	@Override
866 	public void commit(final Transaction transaction) throws PersistenceException {
867 		this.checkTransaction(transaction);
868 		try (final CallableStatement call =
869 				this.database.getConnection().prepareCall(
870 						STORED_PROCEDURE_PREFIX + this.database.getSchemaName() + ".objectfacade.commitTransaction(?);"
871 								+ CALL_SUFFIX)) {
872 			call.setLong(1, transaction.getId());
873 			call.execute();
874 		} catch (final SQLException e) {
875 			throw new OtherSQLException(e);
876 		}
877 	}
878 	
879 	@Override
880 	public void rollback(final Transaction transaction) throws PersistenceException {
881 		this.checkTransaction(transaction);
882 		try (final CallableStatement call =
883 				this.database.getConnection().prepareCall(
884 						STORED_PROCEDURE_PREFIX + this.database.getSchemaName()
885 								+ ".objectfacade.rollbackTransaction(?);" + CALL_SUFFIX)) {
886 			call.setLong(1, transaction.getId());
887 			call.execute();
888 		} catch (final SQLException e) {
889 			throw new OtherSQLException(e);
890 		}
891 	}
892 	
893 	@Override
894 	public void savePoint(final Transaction transaction) throws PersistenceException {
895 		this.checkTransaction(transaction);
896 		try (final CallableStatement call =
897 				this.database.getConnection().prepareCall(
898 						STORED_PROCEDURE_PREFIX + this.database.getSchemaName() + ".objectfacade.makeSavePoint(?);"
899 								+ CALL_SUFFIX)) {
900 			call.setLong(1, transaction.getId());
901 			call.execute();
902 		} catch (final SQLException e) {
903 			throw new OtherSQLException(e);
904 		}
905 	}
906 	
907 	@Override
908 	public void rollbackToSavePoint(final Transaction transaction) throws PersistenceException {
909 		this.checkTransaction(transaction);
910 		try (final CallableStatement call =
911 				this.database.getConnection().prepareCall(
912 						STORED_PROCEDURE_PREFIX + this.database.getSchemaName()
913 								+ ".objectfacade.rollbackToSavePoint(?);" + CALL_SUFFIX)) {
914 			call.setLong(1, transaction.getId());
915 			call.execute();
916 		} catch (final SQLException e) {
917 			throw new OtherSQLException(e);
918 		}
919 	}
920 	
921 	@Override
922 	public BigInteger getIntForId(final long id) throws PersistenceException {
923 		try (final CallableStatement call =
924 				this.database.getConnection().prepareCall(
925 						STORED_FUNCTION_PREFIX + this.database.getSchemaName() + ".objectfacade.getInteger(?);"
926 								+ CALL_SUFFIX)) {
927 			call.registerOutParameter(1, OracleTypes.NUMBER);
928 			call.setLong(2, id);
929 			call.execute();
930 			return BigInteger.valueOf(call.getLong(1));
931 		} catch (final SQLException e) {
932 			if (e.getErrorCode() == BaseTypeNotFoundException.ERRORCODE) {
933 				throw new BaseTypeNotFoundException();
934 			}
935 			throw new OtherSQLException(e);
936 		}
937 	}
938 	
939 	@Override
940 	public String getStringForId(final long id) throws PersistenceException {
941 		try (final CallableStatement call =
942 				this.database.getConnection().prepareCall(
943 						STORED_FUNCTION_PREFIX + this.database.getSchemaName() + ".objectfacade.getString(?);"
944 								+ CALL_SUFFIX)) {
945 			call.registerOutParameter(1, OracleTypes.VARCHAR);
946 			call.setLong(2, id);
947 			call.execute();
948 			return call.getString(1);
949 		} catch (final SQLException e) {
950 			if (e.getErrorCode() == BaseTypeNotFoundException.ERRORCODE) {
951 				throw new BaseTypeNotFoundException();
952 			}
953 			throw new OtherSQLException(e);
954 		}
955 	}
956 	
957 	@Override
958 	public long getIdForString(final String string) throws PersistenceException {
959 		try (final CallableStatement call =
960 				this.database.getConnection().prepareCall(
961 						STORED_FUNCTION_PREFIX + this.database.getSchemaName() + ".objectfacade.getStringObject(?);"
962 								+ CALL_SUFFIX)) {
963 			call.registerOutParameter(1, OracleTypes.NUMBER);
964 			call.setString(2, string);
965 			call.execute();
966 			return call.getLong(1);
967 		} catch (final SQLException e) {
968 			throw new OtherSQLException(e);
969 		}
970 	}
971 	
972 	@Override
973 	public long getIdForInteger(final BigInteger integer) throws PersistenceException {
974 		try (final CallableStatement call =
975 				this.database.getConnection().prepareCall(
976 						STORED_FUNCTION_PREFIX + this.database.getSchemaName() + ".objectfacade.getIntegerObject(?);"
977 								+ CALL_SUFFIX)) {
978 			call.registerOutParameter(1, OracleTypes.NUMBER);
979 			final BigDecimal wrapper = new BigDecimal(integer);
980 			call.setBigDecimal(2, wrapper);
981 			call.execute();
982 			return call.getLong(1);
983 		} catch (final SQLException e) {
984 			throw new OtherSQLException(e);
985 		}
986 	}
987 	
988 	@Override
989 	public Transaction provideAdhocTransaction() throws PersistenceException {
990 		try (final CallableStatement call =
991 				this.database.getConnection().prepareCall(
992 						STORED_FUNCTION_PREFIX + this.database.getSchemaName()
993 								+ ".objectfacade.provideAdhocTransaction;" + CALL_SUFFIX)) {
994 			call.registerOutParameter(1, OracleTypes.NUMBER);
995 			call.execute();
996 			return new AdhocTransaction(call.getLong(1));
997 		} catch (final SQLException e) {
998 			throw new OtherSQLException(e);
999 		}
1000 	}
1001 	
1002 	@Override
1003 	public TypeManager getTypeManager() {
1004 		return this.typeManager;
1005 	}
1006 	
1007 	@Override
1008 	public void clear() throws PersistenceException {
1009 		try (final CallableStatement call =
1010 				this.database.getConnection().prepareCall(
1011 						STORED_PROCEDURE_PREFIX + this.database.getSchemaName() + ".objectfacade.clear;" + CALL_SUFFIX)) {
1012 			call.execute();
1013 		} catch (final SQLException e) {
1014 			e.printStackTrace();
1015 			throw new OtherSQLException(e);
1016 		}
1017 	}
1018 	
1019 	@Override
1020 	public Collection<UserObject> findAllObjects(final UserType type, final Transaction transaction)
1021 			throws PersistenceException {
1022 		final Collection<UserObject> result = new HashSet<>();
1023 		try (final CallableStatement call =
1024 				this.database.getConnection().prepareCall(
1025 						STORED_FUNCTION_PREFIX + this.database.getSchemaName()
1026 								+ ".objectfacade.findUserObjectByType(?,?);" + CALL_SUFFIX)) {
1027 			call.registerOutParameter(1, OracleTypes.CURSOR);
1028 			call.setLong(2, type.getId());
1029 			call.setLong(IntegerConstants.THREE, transaction.getId());
1030 			call.execute();
1031 			try (final ResultSet resultSet = ((OracleCallableStatement) call).getCursor(1)) {
1032 				while (resultSet.next()) {
1033 					result.add(UserObject.init(
1034 							resultSet.getLong(1),
1035 							this.typeManager.getTypeForId(resultSet.getLong(2))));
1036 				}
1037 			}
1038 		} catch (final SQLException e) {
1039 			throw new OtherSQLException(e);
1040 		}
1041 		return result;
1042 	}
1043 	
1044 	@Override
1045 	public UserObject checkUserObjectOut(final long id, final Transaction transaction) throws PersistenceException {
1046 		try (final CallableStatement call =
1047 				this.database.getConnection().prepareCall(
1048 						STORED_FUNCTION_PREFIX + this.database.getSchemaName()
1049 								+ ".objectfacade.checkUserObjectOut(?,?);" + CALL_SUFFIX)) {
1050 			call.registerOutParameter(1, OracleTypes.CURSOR);
1051 			call.setLong(2, id);
1052 			call.setLong(IntegerConstants.THREE, transaction.getId());
1053 			call.execute();
1054 			try (final ResultSet resultSet = ((OracleCallableStatement) call).getCursor(1)) {
1055 				if (resultSet.next()) {
1056 					return UserObject.init(resultSet.getLong(1), this.typeManager.getTypeForId(resultSet.getLong(2)));
1057 				} else {
1058 					throw new ObjectNotFoundException();
1059 				}
1060 			}
1061 		} catch (final SQLException e) {
1062 			throw new OtherSQLException(e);
1063 		}
1064 	}
1065 }