KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > oracle > toplink > essentials > internal > sequencing > SequencingManager


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the "License"). You may not use this file except
5  * in compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * glassfish/bootstrap/legal/CDDLv1.0.txt or
9  * https://glassfish.dev.java.net/public/CDDLv1.0.html.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * HEADER in each file and include the License file at
15  * glassfish/bootstrap/legal/CDDLv1.0.txt. If applicable,
16  * add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your
18  * own identifying information: Portions Copyright [yyyy]
19  * [name of copyright owner]
20  */

21 // Copyright (c) 1998, 2006, Oracle. All rights reserved.
22
package oracle.toplink.essentials.internal.sequencing;
23
24 import java.util.*;
25 import oracle.toplink.essentials.sequencing.*;
26 import oracle.toplink.essentials.sessions.Login;
27 import oracle.toplink.essentials.threetier.*;
28 import oracle.toplink.essentials.internal.databaseaccess.*;
29 import oracle.toplink.essentials.internal.helper.ConcurrencyManager;
30 import oracle.toplink.essentials.exceptions.DatabaseException;
31 import oracle.toplink.essentials.exceptions.ConcurrencyException;
32 import oracle.toplink.essentials.exceptions.ValidationException;
33 import oracle.toplink.essentials.logging.SessionLog;
34 import oracle.toplink.essentials.internal.sessions.DatabaseSessionImpl;
35 import oracle.toplink.essentials.internal.sessions.AbstractSession;
36 import oracle.toplink.essentials.descriptors.ClassDescriptor;
37
38 /**
39  * SequencingManager is private to TopLink.
40  * It provides most of sequencing functionality.
41  * It's accessed by DatabaseSession through getSequencingHome() method.
42  *
43  * Here's the lifecycle of SequencingManager.
44  * InitialState: SequencingManager doesn't exist.
45  * Action: SequencingManager created -> Not connected State.
46  * State: Not connected.
47  * isConnected() returns false;
48  * getSequencingControl() could be used;
49  * getSequencing() == getSequencingServer() == getSequencingCallback() == null;
50  * Action: onConnect is called -> Connected State.
51  * State: Connected.
52  * isConnected() returns true;
53  * getSequencingControl() could be used;
54  * getSequencing() could be used;
55  * in case ownwerSession is a ServerSession getSequencingServer() could be used;
56  * Action: onDisconnect is called -> Not connected State.
57  *
58  * Here's a sketch of SequencingManager architecture.
59  * The main 4 objects comprising SessionManager are:
60  * valueGenarationPolicy;
61  * preallocationHandler;
62  * connectionHandler;
63  * state;
64  *
65  * That's how they evolve during lifetime of SequencingManager object:
66  * Not connected State:
67  * preallocationHandler doesn't have any preallocated sequencing values.
68  * connectionHandler == null;
69  * state == null;
70  *
71  * Connected State:
72  * preallocationHandler may contain preallocated sequencing values.
73  * valueGenarationPolicy != null;
74  * state != null;
75  *
76  * The most important method of the class is onConnect():
77  * that's where, using values of the attributes'(accessible through SequencingControl):
78  * shouldUseSeparateConnection;
79  * login;
80  * minPoolSize;
81  * maxPoolSize;
82  * as well as boolean flags returned by valueGenerationPolicy methods:
83  * shouldAcquireValueAfterInsert();
84  * shouldUsePreallocation();
85  * shouldUseSeparateConnection();
86  * shouldUseTransaction();
87  * one of implementors of inner interface State is created.
88  *
89  * Once in Connected State, neither changes to attributes, nor to returns of valueGenerationPolicy's
90  * four should... methods can change the state object.
91  * To change the state object, onDisconnect(), than onConnect() should be called.
92  * There is no need to do it directly: each of the following methods
93  * available through SequencingControl does that:
94  * setValueGenerationPolicy;
95  * setShouldUseNativeSequencing;
96  * setShouldUseTableSequencing;
97  * resetSequencing;
98  */

99 class SequencingManager implements SequencingHome, SequencingServer, SequencingControl {
100     private DatabaseSessionImpl ownerSession;
101     private SequencingConnectionHandler connectionHandler;
102     private PreallocationHandler preallocationHandler;
103     private int whenShouldAcquireValueForAll;
104     private Vector connectedSequences;
105     boolean atLeastOneSequenceShouldUseTransaction;
106     boolean atLeastOneSequenceShouldUsePreallocation;
107
108     // state ids
109
private static final int NOPREALLOCATION = 0;
110     private static final int PREALLOCATION_NOTRANSACTION = 1;
111     private static final int PREALLOCATION_TRANSACTION_NOACCESSOR = 2;
112     private static final int PREALLOCATION_TRANSACTION_ACCESSOR = 3;
113     private static final int NUMBER_OF_STATES = 4;
114     private State[] states;
115     private Hashtable locks;
116     private SequencingCallback callback;
117     private SequencingServer server;
118     private Sequencing seq;
119     private boolean shouldUseSeparateConnection;
120     private Login login;
121     private int minPoolSize;
122     private int maxPoolSize;
123
124     public SequencingManager(DatabaseSessionImpl ownerSession) {
125         this.ownerSession = ownerSession;
126     }
127
128     protected DatabaseSessionImpl getOwnerSession() {
129         return ownerSession;
130     }
131
132     protected void createConnectionHandler() {
133         boolean isServerSession = getOwnerSession().isServerSession();
134
135         if (getLogin() == null) {
136             Login login;
137             if (isServerSession) {
138                 login = ((ServerSession)getOwnerSession()).getReadConnectionPool().getLogin();
139             } else {
140                 login = getOwnerSession().getDatasourceLogin();
141             }
142             setLogin((Login)login.clone());
143         }
144
145         if (getLogin() != null) {
146             if (getLogin().shouldUseExternalTransactionController()) {
147                 throw ValidationException.invalidSequencingLogin();
148             }
149         }
150
151         if (isServerSession) {
152             ConnectionPool pool = null;
153             if (getLogin().shouldUseExternalConnectionPooling()) {
154                 pool = new ExternalConnectionPool("sequencing", getLogin(), (ServerSession)getOwnerSession());
155             } else {
156                 if ((getMinPoolSize() == 0) && (getMaxPoolSize() == 0)) {
157                     setMinPoolSize(2);
158                     setMaxPoolSize(2);
159                 }
160                 pool = new ConnectionPool("sequencing", getLogin(), getMinPoolSize(), getMaxPoolSize(), (ServerSession)getOwnerSession());
161             }
162
163             setConnectionHandler(new ServerSessionConnectionHandler(pool));
164
165         } else {
166             setConnectionHandler(new DatabaseSessionConnectionHandler(getOwnerSession(), getLogin()));
167
168         }
169     }
170
171     public SequencingControl getSequencingControl() {
172         return this;
173     }
174
175     protected void setSequencing(Sequencing sequencing) {
176         this.seq = sequencing;
177     }
178
179     public Sequencing getSequencing() {
180         return seq;
181     }
182
183     protected void setSequencingServer(SequencingServer server) {
184         this.server = server;
185     }
186
187     public SequencingServer getSequencingServer() {
188         return server;
189     }
190
191     protected void setSequencingCallback(SequencingCallback callback) {
192         this.callback = callback;
193     }
194
195     public SequencingCallback getSequencingCallback() {
196         return callback;
197     }
198
199     public boolean shouldUseSeparateConnection() {
200         return shouldUseSeparateConnection;
201     }
202
203     public void setShouldUseSeparateConnection(boolean shouldUseSeparateConnection) {
204         this.shouldUseSeparateConnection = shouldUseSeparateConnection;
205     }
206
207     public boolean isConnectedUsingSeparateConnection() {
208         return isConnected() && (getConnectionHandler() != null);
209     }
210
211     public Login getLogin() {
212         return login;
213     }
214
215     public void setLogin(Login login) {
216         this.login = login;
217     }
218
219     public int getMinPoolSize() {
220         return minPoolSize;
221     }
222
223     public void setMinPoolSize(int size) {
224         this.minPoolSize = size;
225     }
226
227     public int getMaxPoolSize() {
228         return maxPoolSize;
229     }
230
231     public void setMaxPoolSize(int size) {
232         this.maxPoolSize = size;
233     }
234
235     public boolean isConnected() {
236         return states != null;
237     }
238
239     // SequencingSetup
240
protected SequencingConnectionHandler getConnectionHandler() {
241         return connectionHandler;
242     }
243
244     protected void setConnectionHandler(SequencingConnectionHandler handler) {
245         this.connectionHandler = handler;
246     }
247
248     public Object JavaDoc getNextValue(Class JavaDoc cls) {
249         return getNextValue(getOwnerSession(), cls);
250     }
251
252     public void initializePreallocated() {
253         if (getPreallocationHandler() != null) {
254             getPreallocationHandler().initializePreallocated();
255         }
256     }
257
258     public void initializePreallocated(String JavaDoc seqName) {
259         if (getPreallocationHandler() != null) {
260             getPreallocationHandler().initializePreallocated(seqName);
261         }
262     }
263
264     protected void setLocks(Hashtable locks) {
265         this.locks = locks;
266     }
267
268     protected Hashtable getLocks() {
269         return locks;
270     }
271
272     protected void acquireLock(String JavaDoc seqName) {
273         ConcurrencyManager manager;
274         synchronized (getLocks()) {
275             manager = (ConcurrencyManager)getLocks().get(seqName);
276             if (manager == null) {
277                 manager = new ConcurrencyManager();
278                 getLocks().put(seqName, manager);
279             }
280         }
281         manager.acquire();
282     }
283
284     protected void releaseLock(String JavaDoc seqName) {
285         ConcurrencyManager manager = (ConcurrencyManager)locks.get(seqName);
286         manager.release();
287     }
288
289     protected Sequence getSequence(Class JavaDoc cls) {
290         //** should check here that sequencing is used?
291
String JavaDoc seqName = getOwnerSession().getDescriptor(cls).getSequenceNumberName();
292         return getSequence(seqName);
293     }
294
295     protected void logDebugPreallocation(String JavaDoc seqName, Vector sequences) {
296         if (getOwnerSession().shouldLog(SessionLog.FINEST, SessionLog.SEQUENCING)) {
297             Object JavaDoc[] args = { seqName, new Integer JavaDoc(sequences.size()), sequences.firstElement(), sequences.lastElement() };
298             getOwnerSession().log(SessionLog.FINEST, SessionLog.SEQUENCING, "sequencing_preallocation", args);
299         }
300     }
301
302     protected void logDebugLocalPreallocation(AbstractSession writeSession, String JavaDoc seqName, Vector sequences, Accessor accessor) {
303         if (writeSession.shouldLog(SessionLog.FINEST, SessionLog.SEQUENCING)) {
304             Object JavaDoc[] args = { seqName, new Integer JavaDoc(sequences.size()), sequences.firstElement(), sequences.lastElement() };
305             writeSession.log(SessionLog.FINEST, SessionLog.SEQUENCING, "sequencing_localPreallocation", args, accessor);
306         }
307     }
308
309     static abstract class State {
310         abstract Object JavaDoc getNextValue(Sequence sequence, AbstractSession writeSession);
311
312         SequencingCallback getSequencingCallback() {
313             return null;
314         }
315
316         public String JavaDoc toString() {
317             String JavaDoc name = getClass().getName();
318             return name.substring(name.lastIndexOf('$') + 1);
319         }
320     }
321
322     // uses preallocation, uses Transaction, no separate connection.
323
class Preallocation_Transaction_NoAccessor_State extends State implements SequencingCallback {
324         protected Hashtable accessorToPreallocated = new Hashtable(20);
325
326         SequencingCallback getSequencingCallback() {
327             return this;
328         }
329
330         public void afterTransaction(Accessor accessor, boolean committed) {
331             Hashtable localSequences = (Hashtable)accessorToPreallocated.get(accessor);
332             if (localSequences != null) {
333                 if (committed) {
334                     for (Enumeration enumtr = localSequences.keys(); enumtr.hasMoreElements();) {
335                         String JavaDoc seqName = (String JavaDoc)enumtr.nextElement();
336                         Vector localSequenceForName = (Vector)localSequences.get(seqName);
337                         if (!localSequenceForName.isEmpty()) {
338                             acquireLock(seqName);
339                             getPreallocationHandler().setPreallocated(seqName, localSequenceForName);
340                             // clear all localSequencesForName
341
localSequenceForName.clear();
342                             releaseLock(seqName);
343                         }
344                     }
345                 }
346
347                 // remove localSequencing corresponding to the accessor from accessorToPreallocated
348
accessorToPreallocated.remove(accessor);
349
350                 if (committed) {
351                     getOwnerSession().log(SessionLog.FINEST, SessionLog.SEQUENCING, "sequencing_afterTransactionCommitted", null, accessor);
352                 } else {
353                     getOwnerSession().log(SessionLog.FINEST, SessionLog.SEQUENCING, "sequencing_afterTransactionRolledBack", null, accessor);
354                 }
355             }
356         }
357
358         public Object JavaDoc getNextValue(Sequence sequence, AbstractSession writeSession) {
359             Object JavaDoc sequenceValue;
360             String JavaDoc seqName = sequence.getName();
361             acquireLock(seqName);
362
363             // keepLocked indicates whether the sequence lock should be kept for the whole duration of this method.
364
// Of course the lock should be released in any case when the method returns or throws an exception.
365
boolean keepLocked = false;
366
367             Vector sequencesForName = (Vector)getPreallocationHandler().getPreallocated(seqName);
368             try {
369                 if (!sequencesForName.isEmpty()) {
370                     sequenceValue = sequencesForName.firstElement();
371                     sequencesForName.removeElementAt(0);
372                     return sequenceValue;
373                 } else {
374                     if (!getOwnerSession().getDatasourceLogin().shouldUseExternalTransactionController() && (sequence.getPreallocationSize() > 1) && !writeSession.isInTransaction()) {
375                         // To prevent several threads from sumultaneously allocating a separate bunch of
376
// sequencing numbers each. With keepLocked==true the first thread locks out others
377
// until it copies the obtained sequence numbers to the global storage.
378
// Note that this optimization possible only in non-jts case when there is no transaction,
379
// and makes sense only in case preallocation size > 1
380
writeSession.beginTransaction();//write accessor is set in begin
381
keepLocked = true;
382                     }
383                 }
384             } finally {
385                 if (!keepLocked) {
386                     releaseLock(seqName);
387                 }
388             }
389
390             Accessor accessor;
391             Vector localSequencesForName;
392             if (!keepLocked) {
393                 writeSession.beginTransaction();//write accessor is set in begin
394
}
395             try {
396                 accessor = writeSession.getAccessor();
397                 Hashtable localSequences = (Hashtable)accessorToPreallocated.get(accessor);
398                 if (localSequences == null) {
399                     localSequences = new Hashtable(20);
400                     accessorToPreallocated.put(accessor, localSequences);
401                 }
402                 localSequencesForName = (Vector)localSequences.get(seqName);
403                 if ((localSequencesForName == null) || localSequencesForName.isEmpty()) {
404                     localSequencesForName = sequence.getGeneratedVector(null, writeSession);
405                     localSequences.put(seqName, localSequencesForName);
406                     logDebugLocalPreallocation(writeSession, seqName, localSequencesForName, accessor);
407                 }
408             } catch (RuntimeException JavaDoc ex) {
409                 if (keepLocked) {
410                     releaseLock(seqName);
411                 }
412                 try {
413                     // make sure to rollback the transaction we've begun
414
writeSession.rollbackTransaction();
415                 } catch (Exception JavaDoc rollbackException) {
416                     // ignore rollback exception
417
}
418
419                 // don't eat the original exception
420
throw ex;
421             }
422
423             if (!keepLocked) {
424                 acquireLock(seqName);
425             }
426             try {
427                 try {
428                     // commitTransaction may copy preallocated sequence numbers
429
// from localSequences to preallocationHandler: that happens
430
// if it isn't a nested transaction, and afterTransaction method
431
// is called.
432
// In this case:
433
// 1. localSequences corresponding to the accessor
434
// has been removed from accessorToPreallocated;
435
// 2. All its members are empty (therefore localSequenceForName is empty).
436
writeSession.commitTransaction();
437                 } catch (DatabaseException ex) {
438                     try {
439                         // make sure to rollback the transaction we've begun
440
writeSession.rollbackTransaction();
441                     } catch (Exception JavaDoc rollbackException) {
442                         // ignore rollback exception
443
}
444
445                     // don't eat the original exception
446
throw ex;
447                 }
448
449                 if (!localSequencesForName.isEmpty()) {
450                     // localSeqencesForName is not empty, that means
451
// afterTransaction() has not been called.
452
sequenceValue = localSequencesForName.firstElement();
453                     localSequencesForName.removeElementAt(0);
454                     return sequenceValue;
455                 } else {
456                     // localSeqencesForName is empty, that means
457
// afterTransaction() has been called.
458
// Note the lock before writeSession.commitTransaction() call:
459
// it insures that no other thread could have used seq. values copied
460
// from localSequencesForName to sequencesForName - so it shouldn't be empty.
461
// The only possibility for sequencesForName to be empty is a case of several threads
462
// using the same accessor simultaneously: while sequenceForName is empty,
463
// thread 1 uses localSequencesForName, thread 2 therefore comes here empty sequencesForName.
464
// There should be no concurrent writing through the same DatabaseSession
465
// or ClientSession.
466
try {
467                         sequenceValue = sequencesForName.firstElement();
468                     } catch (java.util.NoSuchElementException JavaDoc ex) {
469                         throw ConcurrencyException.sequencingMultithreadThruConnection(String.valueOf(System.identityHashCode(accessor)));
470                     }
471                     sequencesForName.removeElementAt(0);
472                     return sequenceValue;
473                 }
474             } finally {
475                 releaseLock(seqName);
476             }
477         }
478     }
479
480     // Preallocation vs NoPreallocation; Transaction vs NoTransaction; Accessor vs NoAccessor
481
class Preallocation_Transaction_Accessor_State extends State {
482         public Object JavaDoc getNextValue(Sequence sequence, AbstractSession writeSession) {
483             Object JavaDoc sequenceValue = null;
484             String JavaDoc seqName = sequence.getName();
485             acquireLock(seqName);
486             try {
487                 Vector sequencesForName = (Vector)getPreallocationHandler().getPreallocated(seqName);
488                 if (sequencesForName.isEmpty()) {
489                     Accessor accessor = null;
490                     try {
491                         // note that accessor.getLogin().shouldUseExternalTransactionController()
492
// should be set to false
493
accessor = getConnectionHandler().acquireAccessor();
494                         accessor.beginTransaction(writeSession);
495                         Vector sequences = sequence.getGeneratedVector(accessor, writeSession);
496                         getPreallocationHandler().setPreallocated(seqName, sequences);
497                         accessor.commitTransaction(writeSession);
498                         logDebugPreallocation(seqName, sequences);
499                     } catch (RuntimeException JavaDoc ex) {
500                         sequencesForName.clear();
501                         try {
502                             // make sure to rollback the transaction we've begun
503
accessor.rollbackTransaction(writeSession);
504                         } catch (Exception JavaDoc rollbackException) {
505                             // ignore rollback exception
506
}
507
508                         // don't eat the original exception
509
throw ex;
510                     } finally {
511                         getConnectionHandler().releaseAccessor(accessor);
512                     }
513                 }
514                 sequenceValue = sequencesForName.firstElement();
515                 sequencesForName.removeElementAt(0);
516             } finally {
517                 releaseLock(seqName);
518             }
519             return sequenceValue;
520         }
521     }
522
523     // Preallocation vs NoPreallocation; Transaction vs NoTransaction; Accessor vs NoAccessor
524
class Preallocation_NoTransaction_State extends State {
525         public Object JavaDoc getNextValue(Sequence sequence, AbstractSession writeSession) {
526             Object JavaDoc sequenceValue;
527             String JavaDoc seqName = sequence.getName();
528             acquireLock(seqName);
529             try {
530                 Vector sequencesForName = (Vector)getPreallocationHandler().getPreallocated(seqName);
531                 if (sequencesForName.isEmpty()) {
532                     Vector sequences = sequence.getGeneratedVector(null, writeSession);
533                     getPreallocationHandler().setPreallocated(seqName, sequences);
534                     logDebugPreallocation(seqName, sequences);
535                 }
536                 sequenceValue = sequencesForName.firstElement();
537                 sequencesForName.removeElementAt(0);
538             } finally {
539                 releaseLock(seqName);
540             }
541             return sequenceValue;
542         }
543     }
544
545     // Preallocation vs NoPreallocation; Transaction vs NoTransaction; Accessor vs NoAccessor
546
class NoPreallocation_State extends State {
547         public Object JavaDoc getNextValue(Sequence sequence, AbstractSession writeSession) {
548             return sequence.getGeneratedValue(null, writeSession);
549         }
550     }
551
552     public void resetSequencing() {
553         if (isConnected()) {
554             onDisconnect();
555             onConnect();
556         }
557     }
558
559     public void onConnect() {
560         if (isConnected()) {
561             return;
562         }
563
564         if (!getOwnerSession().getProject().usesSequencing()) {
565             return;
566         }
567
568         getOwnerSession().getDatasourcePlatform().platformSpecificSequencingInitialization(getOwnerSession());
569
570         onConnectAllSequences();
571
572         boolean onExceptionDisconnectPreallocationHandler = false;
573         boolean onExceptionDisconnectConnectionHandler = false;
574
575         try {
576             if (!shouldUseSeparateConnection()) {
577                 setConnectionHandler(null);
578             } else if (atLeastOneSequenceShouldUseTransaction) {
579                 if (getConnectionHandler() == null) {
580                     createConnectionHandler();
581                 }
582                 if (getConnectionHandler() != null) {
583                     getConnectionHandler().onConnect();
584                     onExceptionDisconnectConnectionHandler = true;
585                 }
586             }
587
588             if (atLeastOneSequenceShouldUsePreallocation) {
589                 if (getPreallocationHandler() == null) {
590                     createPreallocationHandler();
591                 }
592                 getPreallocationHandler().onConnect();
593                 onExceptionDisconnectPreallocationHandler = true;
594             }
595
596             initializeStates();
597
598         } catch (RuntimeException JavaDoc ex) {
599             onDisconnectAllSequences();
600             if (getConnectionHandler() != null) {
601                 if (onExceptionDisconnectConnectionHandler) {
602                     getConnectionHandler().onDisconnect();
603                 }
604                 setConnectionHandler(null);
605             }
606             if (getPreallocationHandler() != null) {
607                 if (onExceptionDisconnectPreallocationHandler) {
608                     getPreallocationHandler().onDisconnect();
609                 }
610                 clearPreallocationHandler();
611             }
612             throw ex;
613         }
614         if (atLeastOneSequenceShouldUsePreallocation) {
615             setLocks(new Hashtable(20));
616         }
617         createSequencingCallback();
618         if (getOwnerSession().isServerSession()) {
619             setSequencingServer(this);
620         }
621         setSequencing(this);
622         logDebugSequencingConnected();
623     }
624
625     public void onDisconnect() {
626         if (!isConnected()) {
627             return;
628         }
629
630         setSequencing(null);
631         setSequencingServer(null);
632         setSequencingCallback(null);
633         setLocks(null);
634         clearStates();
635
636         if (getConnectionHandler() != null) {
637             getConnectionHandler().onDisconnect();
638             setConnectionHandler(null);
639         }
640         if (getPreallocationHandler() != null) {
641             getPreallocationHandler().onDisconnect();
642             clearPreallocationHandler();
643         }
644         onDisconnectAllSequences();
645         getOwnerSession().log(SessionLog.FINEST, SessionLog.SEQUENCING, "sequencing_disconnected");
646     }
647
648     protected PreallocationHandler getPreallocationHandler() {
649         return preallocationHandler;
650     }
651
652     protected void createPreallocationHandler() {
653         preallocationHandler = new PreallocationHandler();
654     }
655
656     protected void clearPreallocationHandler() {
657         preallocationHandler = null;
658     }
659
660     protected void onConnectAllSequences() {
661         connectedSequences = new Vector();
662         boolean shouldUseTransaction = false;
663         boolean shouldUsePreallocation = false;
664         boolean shouldAcquireValueAfterInsert = false;
665         Iterator descriptors = getOwnerSession().getDescriptors().values().iterator();
666         while (descriptors.hasNext()) {
667             ClassDescriptor descriptor = (ClassDescriptor)descriptors.next();
668             if (!descriptor.usesSequenceNumbers()) {
669                 continue;
670             }
671             String JavaDoc seqName = descriptor.getSequenceNumberName();
672             Sequence sequence = getSequence(seqName);
673             if (sequence == null) {
674                 sequence = new DefaultSequence(seqName);
675                 getOwnerSession().getDatasourcePlatform().addSequence(sequence);
676             }
677             if (connectedSequences.contains(sequence)) {
678                 continue;
679             }
680             try {
681                 if (sequence instanceof DefaultSequence && !connectedSequences.contains(getDefaultSequence())) {
682                     getDefaultSequence().onConnect(getOwnerSession().getDatasourcePlatform());
683                     connectedSequences.add(0, getDefaultSequence());
684                     shouldUseTransaction |= getDefaultSequence().shouldUseTransaction();
685                     shouldUsePreallocation |= getDefaultSequence().shouldUsePreallocation();
686                     shouldAcquireValueAfterInsert |= getDefaultSequence().shouldAcquireValueAfterInsert();
687                 }
688                 sequence.onConnect(getOwnerSession().getDatasourcePlatform());
689                 connectedSequences.addElement(sequence);
690                 shouldUseTransaction |= sequence.shouldUseTransaction();
691                 shouldUsePreallocation |= sequence.shouldUsePreallocation();
692                 shouldAcquireValueAfterInsert |= sequence.shouldAcquireValueAfterInsert();
693             } catch (RuntimeException JavaDoc ex) {
694                 // defaultSequence has to disconnect the last
695
for (int i = connectedSequences.size() - 1; i >= 0; i--) {
696                     try {
697                         Sequence sequenceToDisconnect = (Sequence)connectedSequences.elementAt(i);
698                         sequenceToDisconnect.onDisconnect(getOwnerSession().getDatasourcePlatform());
699                     } catch (RuntimeException JavaDoc ex2) {
700                         //ignore
701
}
702                 }
703                 connectedSequences = null;
704                 throw ex;
705             }
706         }
707
708         if (shouldAcquireValueAfterInsert && !shouldUsePreallocation) {
709             whenShouldAcquireValueForAll = AFTER_INSERT;
710         } else if (!shouldAcquireValueAfterInsert && shouldUsePreallocation) {
711             whenShouldAcquireValueForAll = BEFORE_INSERT;
712         }
713         atLeastOneSequenceShouldUseTransaction = shouldUseTransaction;
714         atLeastOneSequenceShouldUsePreallocation = shouldUsePreallocation;
715     }
716
717     protected void onDisconnectAllSequences() {
718         RuntimeException JavaDoc exception = null;
719
720         // defaultSequence has to disconnect the last
721
for (int i = connectedSequences.size() - 1; i >= 0; i--) {
722             try {
723                 Sequence sequenceToDisconnect = (Sequence)connectedSequences.elementAt(i);
724                 sequenceToDisconnect.onDisconnect(getOwnerSession().getDatasourcePlatform());
725             } catch (RuntimeException JavaDoc ex) {
726                 if (exception == null) {
727                     exception = ex;
728                 }
729             }
730         }
731         connectedSequences = null;
732         whenShouldAcquireValueForAll = UNDEFINED;
733         atLeastOneSequenceShouldUseTransaction = false;
734         atLeastOneSequenceShouldUsePreallocation = false;
735         if (exception != null) {
736             throw exception;
737         }
738     }
739
740     protected void initializeStates() {
741         states = new State[NUMBER_OF_STATES];
742
743         Iterator itConnectedSequences = connectedSequences.iterator();
744         while (itConnectedSequences.hasNext()) {
745             Sequence sequence = (Sequence)itConnectedSequences.next();
746             State state = getState(sequence.shouldUsePreallocation(), sequence.shouldUseTransaction());
747             if (state == null) {
748                 createState(sequence.shouldUsePreallocation(), sequence.shouldUseTransaction());
749             }
750         }
751     }
752
753     protected void clearStates() {
754         states = null;
755     }
756
757     protected int getStateId(boolean shouldUsePreallocation, boolean shouldUseTransaction) {
758         if (!shouldUsePreallocation) {
759             // Non-Oracle native sequencing uses this state
760
return NOPREALLOCATION;
761         } else if (!shouldUseTransaction) {
762             // Oracle native sequencing uses this state
763
return PREALLOCATION_NOTRANSACTION;
764         } else if (getConnectionHandler() == null) {
765             // TableSequence and UnaryTableSequence in case there is no separate connection(s) available use this state
766
return PREALLOCATION_TRANSACTION_NOACCESSOR;
767         } else/*if(getConnectionHandler()!=null)*/
768          {
769             // TableSequence and UnaryTableSequence in case there is separate connection(s) available use this state
770
return PREALLOCATION_TRANSACTION_ACCESSOR;
771         }
772     }
773
774     protected State getState(boolean shouldUsePreallocation, boolean shouldUseTransaction) {
775         return states[getStateId(shouldUsePreallocation, shouldUseTransaction)];
776     }
777
778     protected void createState(boolean shouldUsePreallocation, boolean shouldUseTransaction) {
779         if (!shouldUsePreallocation) {
780             // Non-Oracle native sequencing uses this state
781
states[NOPREALLOCATION] = new NoPreallocation_State();
782         } else if (!shouldUseTransaction) {
783             // Oracle native sequencing uses this state
784
states[PREALLOCATION_NOTRANSACTION] = new Preallocation_NoTransaction_State();
785         } else if (getConnectionHandler() == null) {
786             // TableSequence and UnaryTableSequence in case there is no separate connection(s) available use this state
787
states[PREALLOCATION_TRANSACTION_NOACCESSOR] = new Preallocation_Transaction_NoAccessor_State();
788         } else/*if(getConnectionHandler()!=null)*/
789          {
790             // TableSequence and UnaryTableSequence in case there is separate connection(s) available use this state
791
states[PREALLOCATION_TRANSACTION_ACCESSOR] = new Preallocation_Transaction_Accessor_State();
792         }
793     }
794
795     protected void createSequencingCallback() {
796         Vector callbackVector = new Vector();
797         for (int i = 0; i < NUMBER_OF_STATES; i++) {
798             if (states[i] != null) {
799                 SequencingCallback callback = states[i].getSequencingCallback();
800                 if (callback != null) {
801                     callbackVector.addElement(callback);
802                 }
803             }
804         }
805         if (callbackVector.isEmpty()) {
806             setSequencingCallback(null);
807         } else if (callbackVector.size() == 1) {
808             setSequencingCallback((SequencingCallback)callbackVector.firstElement());
809         } else {
810             setSequencingCallback(new SequencingCallbackContainer(callbackVector));
811         }
812     }
813
814     static class SequencingCallbackContainer implements SequencingCallback {
815         SequencingCallback[] callbackArray;
816
817         SequencingCallbackContainer(Vector callbackVector) {
818             callbackArray = new SequencingCallback[callbackVector.size()];
819             callbackVector.copyInto(callbackArray);
820         }
821
822         public void afterTransaction(Accessor accessor, boolean committed) {
823             for (int i = 0; i < callbackArray.length; i++) {
824                 callbackArray[i].afterTransaction(accessor, committed);
825             }
826         }
827     }
828
829     public Object JavaDoc getNextValue(AbstractSession writeSession, Class JavaDoc cls) {
830         Sequence sequence = getSequence(cls);
831         State state = getState(sequence.shouldUsePreallocation(), sequence.shouldUseTransaction());
832         return state.getNextValue(sequence, writeSession);
833     }
834
835     protected void logDebugSequencingConnected() {
836         Vector[] sequenceVectors = new Vector[NUMBER_OF_STATES];
837         Iterator itConnectedSequences = connectedSequences.iterator();
838         while (itConnectedSequences.hasNext()) {
839             Sequence sequence = (Sequence)itConnectedSequences.next();
840             int stateId = getStateId(sequence.shouldUsePreallocation(), sequence.shouldUseTransaction());
841             Vector v = sequenceVectors[stateId];
842             if (v == null) {
843                 v = new Vector();
844                 sequenceVectors[stateId] = v;
845             }
846             v.addElement(sequence);
847         }
848         for (int i = 0; i < NUMBER_OF_STATES; i++) {
849             Vector v = sequenceVectors[i];
850             if (v != null) {
851                 getOwnerSession().log(SessionLog.FINEST, SessionLog.SEQUENCING, "sequencing_connected", states[i]);
852                 for (int j = 1; j < v.size(); j++) {
853                     Sequence sequence = (Sequence)v.elementAt(j);
854                     Object JavaDoc[] args = { sequence.getName(), Integer.toString(sequence.getPreallocationSize()),
855                             Integer.toString(sequence.getInitialValue())};
856                     getOwnerSession().log(SessionLog.FINEST, SessionLog.SEQUENCING, "sequence_without_state", args);
857                 }
858             }
859         }
860     }
861
862     public int getPreallocationSize() {
863         return getDefaultSequence().getPreallocationSize();
864     }
865
866     public int getInitialValue() {
867         return getDefaultSequence().getInitialValue();
868     }
869     
870     public boolean shouldAcquireValueAfterInsert(Class JavaDoc cls) {
871         return getSequence(cls).shouldAcquireValueAfterInsert();
872     }
873
874     public boolean shouldOverrideExistingValue(Class JavaDoc cls, Object JavaDoc existingValue) {
875         return getSequence(cls).shouldOverrideExistingValue(existingValue);
876     }
877
878     public int whenShouldAcquireValueForAll() {
879         return whenShouldAcquireValueForAll;
880     }
881
882     protected Sequence getDefaultSequence() {
883         return getOwnerSession().getDatasourcePlatform().getDefaultSequence();
884     }
885
886     protected Sequence getSequence(String JavaDoc seqName) {
887         return getOwnerSession().getDatasourcePlatform().getSequence(seqName);
888     }
889 }
890
Popular Tags