1 package de.fhdw.wtf.persistence.facade;
2
3 import java.sql.CallableStatement;
4 import java.sql.ResultSet;
5 import java.sql.SQLException;
6 import java.util.Collection;
7 import java.util.Iterator;
8 import java.util.List;
9 import java.util.Vector;
10
11 import oracle.jdbc.OracleCallableStatement;
12 import oracle.jdbc.OracleTypes;
13 import oracle.sql.ARRAY;
14 import oracle.sql.ArrayDescriptor;
15 import de.fhdw.wtf.persistence.exception.ClassFacadeUninitializedException;
16 import de.fhdw.wtf.persistence.exception.InitializingDatabaseContractViolationException;
17 import de.fhdw.wtf.persistence.exception.OtherSQLException;
18 import de.fhdw.wtf.persistence.exception.PersistenceException;
19 import de.fhdw.wtf.persistence.exception.SpecializationCycleDetected;
20 import de.fhdw.wtf.persistence.meta.Association;
21 import de.fhdw.wtf.persistence.meta.IntegerType;
22 import de.fhdw.wtf.persistence.meta.MapAssociation;
23 import de.fhdw.wtf.persistence.meta.StringType;
24 import de.fhdw.wtf.persistence.meta.Type;
25 import de.fhdw.wtf.persistence.meta.UnidirectionalAssociation;
26 import de.fhdw.wtf.persistence.meta.UserType;
27 import de.fhdw.wtf.persistence.utils.IntegerConstants;
28
29
30
31
32
33 public class OracleClassFacadeImplementation implements ClassFacade {
34
35
36
37
38
39 private boolean initialized;
40
41
42
43
44 private TypeManagerImplementation typeManager;
45
46
47
48
49 private final OracleDatabaseManager database;
50
51
52
53
54
55
56
57 public OracleClassFacadeImplementation(final OracleDatabaseManager database) {
58 this.database = database;
59 this.initialized = false;
60 this.typeManager = TypeManagerImplementation.getInstance();
61 }
62
63 @Override
64 public UserType createUserType(final String name, final boolean abs, final boolean transaction)
65 throws PersistenceException {
66 final UserType result = new UserType(IDManager.instance().pullNextUnusedTypeID(name), name, abs, transaction);
67 try (final CallableStatement call =
68 this.database.getConnection().prepareCall(
69 "begin " + this.database.getSchemaName() + ".classfacade.createUserType(?,?,?,?); end;")) {
70 call.setLong(1, result.getId());
71 call.setString(2, result.getName());
72 call.setInt(IntegerConstants.THREE, result.isAbs() ? 1 : 0);
73 call.setInt(IntegerConstants.FOUR, result.isTrans() ? 1 : 0);
74 call.execute();
75 } catch (final SQLException e) {
76 throw new OtherSQLException(e);
77 }
78 this.typeManager.saveType(result);
79 return result;
80 }
81
82 @Override
83 public UnidirectionalAssociation createUnidirectionalAssociation(final String name,
84 final boolean essential,
85 final boolean unique,
86 final UserType owner,
87 final Type target) throws PersistenceException {
88 final UnidirectionalAssociation result =
89 new UnidirectionalAssociation(IDManager.instance().pullNextUnusedAssociationID(name), name, owner,
90 target, essential, unique);
91 try (final CallableStatement call =
92 this.database.getConnection().prepareCall(
93 "begin " + this.database.getSchemaName()
94 + ".classfacade.createUnidirAssociation(?,?,?,?,?,?); end;")) {
95 call.setLong(1, result.getId());
96 call.setString(2, result.getName());
97 call.setLong(IntegerConstants.THREE, result.getOwner().getId());
98 call.setLong(IntegerConstants.FOUR, result.getTarget().getId());
99 call.setInt(IntegerConstants.FIVE, result.isEssential() ? 1 : 0);
100 call.setInt(IntegerConstants.SIX, result.isUnique() ? 1 : 0);
101 call.execute();
102 } catch (final SQLException e) {
103 throw new OtherSQLException(e);
104 }
105 this.typeManager.saveAssociation(result);
106 return result;
107 }
108
109 @Override
110 public MapAssociation createMapAssociation(final String name,
111 final boolean essential,
112 final UserType owner,
113 final Type target,
114 final Type keyType) throws PersistenceException {
115 final MapAssociation result =
116 new MapAssociation(IDManager.instance().pullNextUnusedAssociationID(name), name, owner, target,
117 keyType, essential);
118 try (final CallableStatement call =
119 this.database.getConnection().prepareCall(
120 "begin " + this.database.getSchemaName()
121 + ".classfacade.createMapAssociation(?,?,?,?,?,?,?); end;")) {
122 call.setLong(1, result.getId());
123 call.setString(2, result.getName());
124 call.setLong(IntegerConstants.THREE, result.getOwner().getId());
125 call.setLong(IntegerConstants.FOUR, result.getTarget().getId());
126 call.setInt(IntegerConstants.FIVE, result.isEssential() ? 1 : 0);
127 call.setInt(IntegerConstants.SIX, 1);
128 call.setLong(IntegerConstants.SEVEN, result.getKeyType().getId());
129 call.execute();
130 } catch (final SQLException e) {
131 throw new OtherSQLException(e);
132 }
133 this.typeManager.saveAssociation(result);
134 return result;
135 }
136
137 @Override
138 public void createSpecializationBetween(final UserType ancestor, final Type descendant) throws PersistenceException {
139 try (final CallableStatement call =
140 this.database.getConnection().prepareCall(
141 "begin " + this.database.getSchemaName() + ".classfacade.createSpecialization(?,?); end;")) {
142 call.setLong(1, ancestor.getId());
143 call.setLong(2, descendant.getId());
144 call.execute();
145 } catch (final SQLException e) {
146 throw new OtherSQLException(e);
147 }
148 }
149
150 @Override
151 public void initialize() throws PersistenceException {
152 try (final CallableStatement call =
153 this.database.getConnection().prepareCall(
154 "begin " + this.database.getSchemaName() + ".classfacade.initialize; end;")) {
155 call.execute();
156 } catch (final SQLException e) {
157 throw new OtherSQLException(e);
158 }
159
160 try (final CallableStatement call =
161 this.database.getConnection().prepareCall(
162 "begin ? :=" + this.database.getSchemaName() + ".classfacade.getMaxIdFromType; end;")) {
163 call.registerOutParameter(1, OracleTypes.NUMBER);
164 call.execute();
165 if (IDManager.getMaxBaseTypeID() != call.getLong(1)) {
166 throw new InitializingDatabaseContractViolationException();
167 }
168 } catch (final SQLException e) {
169 throw new OtherSQLException(e);
170 }
171
172 try (final CallableStatement call =
173 this.database.getConnection().prepareCall(
174 "begin ? :=" + this.database.getSchemaName() + ".classfacade.getMaxIdFromAssociation; end;")) {
175 call.registerOutParameter(1, OracleTypes.NUMBER);
176 call.execute();
177 if (IDManager.getMaxAssociationContractID() != call.getLong(1)) {
178 throw new InitializingDatabaseContractViolationException();
179 }
180 } catch (final SQLException e) {
181 throw new OtherSQLException(e);
182 }
183
184 this.initializeBaseTypes();
185 this.finalizeSpecialization();
186 this.initialized = true;
187 }
188
189 @Override
190 public boolean isSuperClassTo(final Type ancestor, final Type descendant) throws PersistenceException {
191 try (final CallableStatement call =
192 this.database.getConnection().prepareCall(
193 "begin ?:=" + this.database.getSchemaName() + ".classfacade.isSuperclassTo(?,?); end;")) {
194 call.registerOutParameter(1, OracleTypes.NUMBER);
195 call.setLong(2, ancestor.getId());
196 call.setLong(IntegerConstants.THREE, descendant.getId());
197 call.execute();
198 return call.getInt(1) == 1 ? true : false;
199 } catch (final SQLException e) {
200 e.printStackTrace();
201 throw new OtherSQLException(e);
202 }
203 }
204
205 @Override
206 public void clear() throws PersistenceException {
207 try (final CallableStatement call =
208 this.database.getConnection().prepareCall(
209 "begin " + this.database.getSchemaName() + ".classfacade.clearAll; end;")) {
210 call.execute();
211 } catch (final SQLException e) {
212 throw new OtherSQLException(e);
213 }
214 }
215
216 @Override
217 public void finalizeSpecialization() throws PersistenceException {
218 try (final CallableStatement call =
219 this.database.getConnection().prepareCall(
220 "begin " + this.database.getSchemaName() + ".classfacade.finalizeSpecialization; end;")) {
221 call.execute();
222 } catch (final SQLException e) {
223 if (e.getErrorCode() == SpecializationCycleDetected.ERRORCODE) {
224 throw new SpecializationCycleDetected(e);
225 }
226 e.printStackTrace();
227 throw new OtherSQLException(e);
228 }
229 }
230
231 @Override
232 public void renameType(final Long typeId, final String newName) throws PersistenceException {
233 try (final CallableStatement call =
234 this.database.getConnection().prepareCall(
235 "begin " + this.database.getSchemaName() + ".classfacade.renameType(?,?); end;")) {
236 call.setLong(1, typeId);
237 call.setString(2, newName);
238 call.execute();
239 } catch (final SQLException e) {
240 e.printStackTrace();
241 throw new OtherSQLException(e);
242 }
243 }
244
245 @Override
246 public void renameAssociation(final Long associationId, final String newName) throws PersistenceException {
247 try (final CallableStatement call =
248 this.database.getConnection().prepareCall(
249 "begin " + this.database.getSchemaName() + ".classfacade.renameAssociation(?,?); end;")) {
250 call.setLong(1, associationId);
251 call.setString(2, newName);
252 call.execute();
253 } catch (final SQLException e) {
254 e.printStackTrace();
255 throw new OtherSQLException(e);
256 }
257 }
258
259 @Override
260 public void deleteAssociation(final Long assoId) throws PersistenceException {
261 this.typeManager.deleteAssociation(assoId);
262 try (final CallableStatement call =
263 this.database.getConnection().prepareCall(
264 "begin " + this.database.getSchemaName() + ".classfacade.deleteAssociation(?); end;")) {
265 call.setLong(1, assoId);
266 call.execute();
267 } catch (final SQLException e) {
268 e.printStackTrace();
269 throw new OtherSQLException(e);
270 }
271 }
272
273 @Override
274 public void updateLinksToNewAssociation(final Long assoId, final Collection<Long> newAssociationIds)
275 throws PersistenceException {
276 try (final CallableStatement call =
277 this.database.getConnection().prepareCall(
278 "begin " + this.database.getSchemaName() + ".classfacade.pushDownLinks(?,?); end;")) {
279 call.setLong(1, assoId);
280 final ArrayDescriptor des =
281 ArrayDescriptor.createDescriptor(
282 this.database.getSchemaName().toUpperCase() + ".ARRAY_INT",
283 this.database.getConnection());
284 final Long[] newAssos = newAssociationIds.toArray(new Long[newAssociationIds.size()]);
285 final ARRAY arrayNewAssociation = new ARRAY(des, this.database.getConnection(), newAssos);
286 call.setArray(2, arrayNewAssociation);
287 call.execute();
288 } catch (final SQLException e) {
289 e.printStackTrace();
290 throw new OtherSQLException(e);
291 }
292 }
293
294 @Override
295 public void deleteUserType(final Long typeId) throws PersistenceException {
296 this.typeManager.deleteType(typeId);
297 try (final CallableStatement call =
298 this.database.getConnection().prepareCall(
299 "begin " + this.database.getSchemaName() + ".classfacade.deleteUserTypeAndSpec(?); end;")) {
300 call.setLong(1, typeId);
301 call.execute();
302 } catch (final SQLException e) {
303 e.printStackTrace();
304 throw new OtherSQLException(e);
305 }
306 }
307
308 @Override
309 public void moveLinksAndCreateObjects(final List<Long> oldAssoIds,
310 final Association newAsso,
311 final UserType newType,
312 final List<Long> newAssoIds) throws PersistenceException {
313 try (final CallableStatement call =
314 this.database.getConnection().prepareCall(
315 "begin " + this.database.getSchemaName()
316 + ".classfacade.moveLinksAndCreateObjects(?,?,?,?); end;")) {
317
318 final ArrayDescriptor des =
319 ArrayDescriptor.createDescriptor(
320 this.database.getSchemaName().toUpperCase() + ".ARRAY_INT",
321 this.database.getConnection());
322 final Long[] oldAssosA = oldAssoIds.toArray(new Long[oldAssoIds.size()]);
323 final Long[] newAssosA = newAssoIds.toArray(new Long[newAssoIds.size()]);
324 final ARRAY arrayNewAssociations = new ARRAY(des, this.database.getConnection(), newAssosA);
325 final ARRAY arrayOldAssociations = new ARRAY(des, this.database.getConnection(), oldAssosA);
326
327 call.setArray(1, arrayOldAssociations);
328 call.setLong(2, newAsso.getId());
329 call.setLong(IntegerConstants.THREE, newType.getId());
330 call.setArray(IntegerConstants.FOUR, arrayNewAssociations);
331 call.execute();
332 } catch (final SQLException e) {
333 e.printStackTrace();
334 throw new OtherSQLException(e);
335 }
336 }
337
338 @Override
339 public TypeManager getTypeManager() throws ClassFacadeUninitializedException {
340 if (!this.hasBeenInitialized()) {
341 throw new ClassFacadeUninitializedException();
342 }
343 return this.typeManager;
344 }
345
346 private void initializeBaseTypes() {
347 this.typeManager.saveType(StringType.getInstance());
348 this.typeManager.saveType(IntegerType.getInstance());
349 }
350
351
352
353
354
355
356
357
358
359 private boolean checkIfStringIsCorrect(final Collection<Type> types) {
360 final Iterator<Type> i = types.iterator();
361 while (i.hasNext()) {
362 final Type current = i.next();
363 if (current.getId() == 1 && current.getName().equals(StringType.STRING_NAME)) {
364 i.remove();
365 return true;
366 }
367 }
368 return false;
369 }
370
371
372
373
374
375
376
377
378
379 private boolean checkIfIntegerIsCorrect(final Collection<Type> types) {
380 final Iterator<Type> i = types.iterator();
381 while (i.hasNext()) {
382 final Type current = i.next();
383 if (current.getId() == 2 && current.getName().equals(IntegerType.INTEGER_NAME)) {
384 i.remove();
385 return true;
386 }
387 }
388 return false;
389 }
390
391 @Override
392 public boolean hasBeenInitialized() {
393 return this.initialized;
394 }
395
396 @Override
397 public void initializeForRuntime() throws PersistenceException {
398 this.typeManager = TypeManagerImplementation.getInstance();
399 final Collection<Type> types = new Vector<>();
400 try (final CallableStatement call =
401 this.database.getConnection().prepareCall(
402 "begin ?:= " + this.database.getSchemaName() + ".classfacade.getAllTypes; end;")) {
403 call.registerOutParameter(1, OracleTypes.CURSOR);
404 call.execute();
405
406 try (final ResultSet result = ((OracleCallableStatement) call).getCursor(1)) {
407 while (result.next()) {
408 types.add(new UserType(result.getLong(1), result.getString(2), result
409 .getInt(IntegerConstants.THREE) == 1 ? true : false,
410 result.getInt(IntegerConstants.FOUR) == 1 ? true : false));
411 }
412 }
413 } catch (final SQLException e) {
414 throw new OtherSQLException(e);
415 }
416
417 if (!this.checkIfStringIsCorrect(types)) {
418 throw new InitializingDatabaseContractViolationException();
419 }
420 if (!this.checkIfIntegerIsCorrect(types)) {
421 throw new InitializingDatabaseContractViolationException();
422 }
423 this.initializeBaseTypes();
424 for (final Type t : types) {
425 this.typeManager.saveType(t);
426 }
427
428 try (final CallableStatement call =
429 this.database.getConnection().prepareCall(
430 "begin ?:= " + this.database.getSchemaName() + ".classfacade.getAllUnidirAssociations; end;")) {
431 call.registerOutParameter(1, OracleTypes.CURSOR);
432 call.execute();
433
434 final Collection<UnidirectionalAssociation> unidirectionalAssociations = new Vector<>();
435 try (final ResultSet result = ((OracleCallableStatement) call).getCursor(1)) {
436 while (result.next()) {
437 unidirectionalAssociations.add(new UnidirectionalAssociation(result.getLong(1),
438 result.getString(2), (UserType) this.typeManager.getTypeForId(result
439 .getLong(IntegerConstants.THREE)), this.typeManager.getTypeForId(result
440 .getLong(IntegerConstants.FOUR)), result.getInt(IntegerConstants.FIVE) == 1 ? true
441 : false, result.getInt(IntegerConstants.SIX) == 1 ? true : false));
442 }
443 }
444 final Iterator<UnidirectionalAssociation> i = unidirectionalAssociations.iterator();
445 while (i.hasNext()) {
446 final UnidirectionalAssociation current = i.next();
447 this.typeManager.saveAssociation(current);
448 }
449 } catch (final SQLException e) {
450 throw new OtherSQLException(e);
451 }
452
453 try (final CallableStatement call =
454 this.database.getConnection().prepareCall(
455 "begin ?:= " + this.database.getSchemaName() + ".classfacade.getAllMapAssociations; end;")) {
456 call.registerOutParameter(1, OracleTypes.CURSOR);
457 call.execute();
458
459 final Collection<MapAssociation> mapAssociations = new Vector<>();
460 try (final ResultSet result = ((OracleCallableStatement) call).getCursor(1)) {
461 while (result.next()) {
462 mapAssociations.add(new MapAssociation(result.getLong(1), result.getString(2),
463 (UserType) this.typeManager.getTypeForId(result.getLong(IntegerConstants.THREE)),
464 this.typeManager.getTypeForId(result.getLong(IntegerConstants.FOUR)), this.typeManager
465 .getTypeForId(result.getLong(IntegerConstants.FIVE)), result
466 .getInt(IntegerConstants.SIX) == 1 ? true : false));
467 }
468 }
469 final Iterator<MapAssociation> i = mapAssociations.iterator();
470 while (i.hasNext()) {
471 final MapAssociation current = i.next();
472 this.typeManager.saveAssociation(current);
473 }
474 } catch (final SQLException e) {
475 throw new OtherSQLException(e);
476 }
477
478 this.initialized = true;
479
480 }
481
482 }