KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > oracle > toplink > essentials > internal > sessions > DatabaseSessionImpl


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.sessions;
23
24 import java.sql.Connection JavaDoc;
25 import java.sql.SQLException JavaDoc;
26
27 import java.util.*;
28 import oracle.toplink.essentials.exceptions.*;
29 import oracle.toplink.essentials.internal.helper.DBPlatformHelper;
30 import oracle.toplink.essentials.sessions.Login;
31 import oracle.toplink.essentials.internal.sequencing.Sequencing;
32 import oracle.toplink.essentials.internal.sequencing.SequencingCallback;
33 import oracle.toplink.essentials.internal.sequencing.SequencingHome;
34 import oracle.toplink.essentials.internal.sequencing.SequencingFactory;
35 import oracle.toplink.essentials.sequencing.SequencingControl;
36 import oracle.toplink.essentials.logging.SessionLog;
37 import oracle.toplink.essentials.sessions.DatasourceLogin;
38 import oracle.toplink.essentials.sessions.SessionProfiler;
39 import oracle.toplink.essentials.platform.server.ServerPlatform;
40 import oracle.toplink.essentials.platform.server.NoServerPlatform;
41
42 import oracle.toplink.essentials.descriptors.ClassDescriptor;
43
44 /**
45  * Implementation of oracle.toplink.essentials.sessions.DatabaseSession
46  * The public interface should be used by public API, the implementation should be used internally.
47  * @see oracle.toplink.essentials.sessions.DatabaseSession
48  *
49  * <p>
50  * <b>Purpose</b>: Define the implementation for a single user/single connection TopLink session.
51  * <p>
52  * <b>Description</b>: The session is the primary interface into TopLink,
53  * the application should do all of its reading and writing of objects through the session.
54  * The session also manages transactions and units of work. The database session is intended
55  * for usage in two-tier client-server applications. Although it could be used in a server
56  * situation, it is limitted to only having a single database connection and only allows
57  * a single open database transaction.
58  * <p>
59  * <b>Responsibilities</b>:
60  * <ul>
61  * <li> Connecting/disconnecting.
62  * <li> Reading and writing objects.
63  * <li> Transaction and unit of work support.
64  * <li> Identity maps and caching.
65  * </ul>
66  */

67 public class DatabaseSessionImpl extends AbstractSession implements oracle.toplink.essentials.sessions.DatabaseSession {
68
69     /**
70      * INTERNAL:
71      * sequencingHome for this session.
72      */

73     private SequencingHome sequencingHome;
74
75     /**
76      * Used to store the server platform that handles server-specific functionality for Oc4j, WLS, etc.
77      */

78     private ServerPlatform serverPlatform;
79
80     /**
81      * INTERNAL:
82      * connectedTime indicates the exact time this session was logged in.
83      */

84     private long connectedTime;
85
86     /**
87      * INTERNAL
88      * Indicate if this session is logged in.
89      */

90
91     //Bug#3440544 Used to stop the attempt to login more than once.
92
protected boolean isLoggedIn;
93
94     /**
95      * INTERNAL:
96      * Set the SequencingHome object used by the session.
97      */

98     protected void setSequencingHome(SequencingHome sequencingHome) {
99         this.sequencingHome = sequencingHome;
100     }
101
102     /**
103      * INTERNAL:
104      * Return SequencingHome which used to obtain all sequence-related
105      * interfaces for DatabaseSession
106      */

107     protected SequencingHome getSequencingHome() {
108         if (sequencingHome == null) {
109             setSequencingHome(SequencingFactory.createSequencingHome(this));
110         }
111         return sequencingHome;
112     }
113
114     /**
115      * PUBLIC:
116      * Return SequencingControl which used for sequencing setup and
117      * customization including management of sequencing preallocation.
118      */

119     public SequencingControl getSequencingControl() {
120         return getSequencingHome().getSequencingControl();
121     }
122
123     /**
124      * INTERNAL:
125      * Return the Sequencing object used by the session.
126      */

127     public Sequencing getSequencing() {
128         return getSequencingHome().getSequencing();
129     }
130
131     /**
132      * INTERNAL:
133      * Creates sequencing object
134      */

135     public void initializeSequencing() {
136         getSequencingHome().onDisconnect();
137         getSequencingHome().onConnect();
138     }
139
140     /**
141      * INTERNAL:
142      * Called after transaction is completed (committed or rolled back)
143      */

144     public void afterTransaction(boolean committed, boolean isExternalTransaction) {
145         SequencingCallback callback = getSequencingHome().getSequencingCallback();
146         if (callback != null) {
147             callback.afterTransaction(getAccessor(), committed);
148         }
149     }
150
151     /**
152      * INTERNAL:
153      * Create and return a new default database session.
154      * Used for EJB SessionManager to instantiate a database session
155      */

156     public DatabaseSessionImpl() {
157         super();
158         this.setServerPlatform(new NoServerPlatform(this));
159     }
160
161     /**
162      * PUBLIC:
163      * Create and return a new session.
164      * By giving the login information on creation this allows the session to initialize itself
165      * to the platform given in the login. This constructor does not return a connected session.
166      * To connect the session to the database login() must be sent to it. The login(userName, password)
167      * method may also be used to connect the session, this allows for the user name and password
168      * to be given at login but for the other database information to be provided when the session is created.
169      */

170     public DatabaseSessionImpl(Login login) {
171         this(new oracle.toplink.essentials.sessions.Project(login));
172     }
173
174     /**
175      * PUBLIC:
176      * Create and return a new session.
177      * This constructor does not return a connected session.
178      * To connect the session to the database login() must be sent to it. The login(userName, password)
179      * method may also be used to connect the session, this allows for the user name and password
180      * to be given at login but for the other database information to be provided when the session is created.
181      */

182     public DatabaseSessionImpl(oracle.toplink.essentials.sessions.Project project) {
183         super(project);
184         this.setServerPlatform(new NoServerPlatform(this));
185     }
186
187     /**
188      * PUBLIC:
189      * Add the descriptor to the session.
190      * All persistent classes must have a descriptor registered for them with the session.
191      * It is best to add the descriptors before login, if added after login the order in which
192      * descriptors are added is dependant on inheritice and references unless the addDescriptors
193      * method is used.
194      *
195      * @see #addDescriptors(Vector)
196      * @see #addDescriptors(oracle.toplink.essentials.sessions.Project)
197      */

198     public void addDescriptor(ClassDescriptor descriptor) {
199         // Reset cached data, as may be invalid later on.
200
this.lastDescriptorAccessed = null;
201
202         getProject().addDescriptor(descriptor, this);
203     }
204
205     /**
206      * PUBLIC:
207      * Add the descriptors to the session.
208      * All persistent classes must have a descriptor registered for them with the session.
209      * This method allows for a batch of descriptors to be added at once so that TopLink
210      * can resolve the dependancies between the descriptors and perform initialization optimially.
211      */

212     public void addDescriptors(Vector descriptors) {
213         // Reset cached data, as may be invalid later on.
214
this.lastDescriptorAccessed = null;
215
216         getProject().addDescriptors(descriptors, this);
217     }
218
219     /**
220      * PUBLIC:
221      * Add the descriptors to the session from the Project.
222      * This can be used to combine the descriptors from multiple projects into a single session.
223      * This can be called after the session has been connected as long as there are no external dependencies.
224      */

225     public void addDescriptors(oracle.toplink.essentials.sessions.Project project) {
226         // Reset cached data, as may be invalid later on.
227
this.lastDescriptorAccessed = null;
228
229         getProject().addDescriptors(project, this);
230     }
231
232     /**
233      * INTERNAL:
234      * Connect the session only.
235      */

236     public void connect() throws DatabaseException {
237         connect(false);
238     }
239
240     /**
241      * INTERNAL:
242      * Connect the session only.
243      */

244     public void connect(boolean updatePlatform) throws DatabaseException {
245         getAccessor().connect(getDatasourceLogin(), this);
246     }
247
248     /**
249      * INTERNAL:
250      * Disconnect the accessor only.
251      */

252     public void disconnect() throws DatabaseException {
253         getSequencingHome().onDisconnect();
254         getAccessor().disconnect(this);
255     }
256
257     /**
258      * PUBLIC:
259      * Answer the server platform to handle server specific behaviour for WLS, Oc4j, etc.
260      *
261      * If the user wants a different external transaction controller class or
262      * to provide some different behaviour than the provided ServerPlatform(s), we recommend
263      * subclassing oracle.toplink.essentials.platform.server.ServerPlatformBase (or a subclass),
264      * and overriding:
265      *
266      * ServerPlatformBase.getExternalTransactionControllerClass()
267      * ServerPlatformBase.registerMBean()
268      * ServerPlatformBase.unregisterMBean()
269      *
270      * for the desired behaviour.
271      *
272      * @see oracle.toplink.essentials.platform.server.ServerPlatformBase
273      */

274     public ServerPlatform getServerPlatform() {
275         return serverPlatform;
276     }
277
278     /**
279      * PUBLIC:
280      * Set the server platform to handle server specific behaviour for WLS, Oc4j, etc
281      *
282      * This is not permitted after the session is logged in.
283      *
284      * If the user wants a different external transaction controller class or
285      * to provide some different behaviour than the provided ServerPlatform(s), we recommend
286      * subclassing oracle.toplink.essentials.platform.server.ServerPlatformBase (or a subclass),
287      * and overriding:
288      *
289      * ServerPlatformBase.getExternalTransactionControllerClass()
290      * ServerPlatformBase.registerMBean()
291      * ServerPlatformBase.unregisterMBean()
292      *
293      * for the desired behaviour.
294      *
295      * @see oracle.toplink.essentials.platform.server.ServerPlatformBase
296      */

297     public void setServerPlatform(ServerPlatform newServerPlatform) {
298         if (this.isConnected()) {
299             throw ValidationException.serverPlatformIsReadOnlyAfterLogin(newServerPlatform.getClass().getName());
300         }
301         this.serverPlatform = newServerPlatform;
302     }
303
304     /**
305      * INTERNAL:
306      * Logout in case still connected.
307      */

308     protected void finalize() throws DatabaseException {
309         if (isConnected()) {
310             logout();
311         }
312     }
313
314     /**
315      * PUBLIC:
316      * Return all registered descriptors.
317      */

318     public Map getDescriptors() {
319         return getProject().getDescriptors();
320     }
321
322     /**
323      * INTERNAL:
324      * A descriptor may have been added after the session is logged in.
325      * In this case the descriptor must be allowed to initialize any dependancies on this session.
326      * Normally the descriptors are added before login, then initialized on login.
327      */

328     public void initializeDescriptorIfSessionAlive(ClassDescriptor descriptor) {
329         if (isConnected() && (descriptor.requiresInitialization())) {
330             try {
331                 try {
332                     descriptor.preInitialize(this);
333                     descriptor.initialize(this);
334                     descriptor.postInitialize(this);
335                     getCommitManager().initializeCommitOrder();
336                 } catch (RuntimeException JavaDoc exception) {
337                     getIntegrityChecker().handleError(exception);
338                 }
339
340                 if (getIntegrityChecker().hasErrors()) {
341                     //CR#4011
342
handleException(new IntegrityException(getIntegrityChecker()));
343                 }
344             } finally {
345                 clearIntegrityChecker();
346             }
347         }
348     }
349
350     /**
351      * INTERNAL:
352      * Allow each descriptor to initialize any dependancies on this session.
353      * This is done in two passes to allow the inheritence to be resolved first.
354      * Normally the descriptors are added before login, then initialized on login.
355      */

356     public void initializeDescriptors() {
357         // Assume all descriptors are CMP, if any are not their init will set this to false.
358
getProject().setIsPureCMP2Project(true);
359         // Must clone to avoid modification of the hashtable while enumerating.
360
initializeDescriptors((Map)((HashMap)getDescriptors()).clone());
361     }
362
363     /**
364      * INTERNAL:
365      * Allow each descriptor to initialize any dependancies on this session.
366      * This is done in two passes to allow the inheritence to be resolved first.
367      * Normally the descriptors are added before login, then initialized on login.
368      * The descriptors session must be used, not the broker.
369      */

370     public void initializeDescriptors(Map descriptors) {
371         initializeSequencing();
372         try {
373             // First initialize basic properties (things that do not depend on anything else)
374
Iterator iterator = descriptors.values().iterator();
375             while (iterator.hasNext()) {
376                 ClassDescriptor descriptor = (ClassDescriptor)iterator.next();
377                 try {
378                     AbstractSession session = getSessionForClass(descriptor.getJavaClass());
379                     if (descriptor.requiresInitialization()) {
380                         descriptor.preInitialize(session);
381                     }
382
383                     //check if inheritance is involved in aggregate relationship, and let the parent know the child descriptor
384
if (descriptor.isAggregateDescriptor() && descriptor.isChildDescriptor()) {
385                         descriptor.initializeAggregateInheritancePolicy(session);
386                     }
387                 } catch (RuntimeException JavaDoc exception) {
388                     getIntegrityChecker().handleError(exception);
389                 }
390             }
391
392             // Second basic initialize mappings
393
iterator = descriptors.values().iterator();
394             while (iterator.hasNext()) {
395                 ClassDescriptor descriptor = (ClassDescriptor)iterator.next();
396                 try {
397                     AbstractSession session = getSessionForClass(descriptor.getJavaClass());
398                     if (descriptor.requiresInitialization()) {
399                         descriptor.initialize(session);
400                     }
401                 } catch (RuntimeException JavaDoc exception) {
402                     getIntegrityChecker().handleError(exception);
403                 }
404             }
405
406             // Third initialize child dependencies
407
iterator = descriptors.values().iterator();
408             while (iterator.hasNext()) {
409                 ClassDescriptor descriptor = (ClassDescriptor)iterator.next();
410                 try {
411                     AbstractSession session = getSessionForClass(descriptor.getJavaClass());
412                     if (descriptor.requiresInitialization()) {
413                         descriptor.postInitialize(session);
414                     }
415                 } catch (RuntimeException JavaDoc exception) {
416                     getIntegrityChecker().handleError(exception);
417                 }
418             }
419
420             try {
421                 getCommitManager().initializeCommitOrder();
422             } catch (RuntimeException JavaDoc exception) {
423                 getIntegrityChecker().handleError(exception);
424             }
425
426             if (getIntegrityChecker().hasErrors()) {
427                 //CR#4011
428
handleSevere(new IntegrityException(getIntegrityChecker()));
429             }
430         } finally {
431             clearIntegrityChecker();
432         }
433     }
434
435     /**
436      * INTERNAL:
437      * Allow each descriptor to initialize any dependancies on this session.
438      * This is done in two passes to allow the inheritence to be resolved first.
439      * Normally the descriptors are added before login, then initialized on login.
440      * The descriptors session must be used, not the broker.
441      */

442     public void initializeDescriptors(Vector descriptors) {
443         initializeSequencing();
444         try {
445             // First initialize basic properties (things that do not depend on anything else)
446
for (Enumeration descriptorEnum = descriptors.elements();
447                      descriptorEnum.hasMoreElements();) {
448                 try {
449                     ClassDescriptor descriptor = (ClassDescriptor)descriptorEnum.nextElement();
450                     AbstractSession session = getSessionForClass(descriptor.getJavaClass());
451                     if (descriptor.requiresInitialization()) {
452                         descriptor.preInitialize(session);
453                     }
454
455                     //check if inheritance is involved in aggregate relationship, and let the parent know the child descriptor
456
if (descriptor.isAggregateDescriptor() && descriptor.isChildDescriptor()) {
457                         descriptor.initializeAggregateInheritancePolicy(session);
458                     }
459                 } catch (RuntimeException JavaDoc exception) {
460                     getIntegrityChecker().handleError(exception);
461                 }
462             }
463
464             // Second basic initialize mappings
465
for (Enumeration descriptorEnum = descriptors.elements();
466                      descriptorEnum.hasMoreElements();) {
467                 try {
468                     ClassDescriptor descriptor = (ClassDescriptor)descriptorEnum.nextElement();
469                     AbstractSession session = getSessionForClass(descriptor.getJavaClass());
470                     if (descriptor.requiresInitialization()) {
471                         descriptor.initialize(session);
472                     }
473                 } catch (RuntimeException JavaDoc exception) {
474                     getIntegrityChecker().handleError(exception);
475                 }
476             }
477
478             // Third initialize child dependencies
479
for (Enumeration descriptorEnum = descriptors.elements();
480                      descriptorEnum.hasMoreElements();) {
481                 try {
482                     ClassDescriptor descriptor = (ClassDescriptor)descriptorEnum.nextElement();
483                     AbstractSession session = getSessionForClass(descriptor.getJavaClass());
484                     if (descriptor.requiresInitialization()) {
485                         descriptor.postInitialize(session);
486                     }
487                 } catch (RuntimeException JavaDoc exception) {
488                     getIntegrityChecker().handleError(exception);
489                 }
490             }
491
492             try {
493                 getCommitManager().initializeCommitOrder();
494             } catch (RuntimeException JavaDoc exception) {
495                 getIntegrityChecker().handleError(exception);
496             }
497
498             if (getIntegrityChecker().hasErrors()) {
499                 //CR#4011
500
handleException(new IntegrityException(getIntegrityChecker()));
501             }
502         } finally {
503             clearIntegrityChecker();
504         }
505     }
506
507     /**
508      * INTERNAL:
509      * Return if this session is a database session.
510      */

511     public boolean isDatabaseSession() {
512         return true;
513     }
514
515     /**
516      * INTERNAL:
517      * Return the login for the read connection. Used by the platform autodetect feature
518      */

519     protected Login getReadLogin(){
520         return getDatasourceLogin();
521     }
522
523     /**
524      * PUBLIC:
525      * Connect to the database using the predefined login.
526      * Durring connection attempt to auto detect the required database platform.
527      * This method can be used in systems where for ease of use developers have
528      * TopLink autodetect the platform.
529      * To be safe, however, the platform should be configured directly.
530      * The login must have been assigned when or after creating the session.
531      *
532      */

533     public void loginAndDetectDatasource() throws DatabaseException {
534         preConnectDatasource();
535         Connection JavaDoc conn = null;
536         try{
537             conn = (Connection JavaDoc)getReadLogin().connectToDatasource(null);
538             getLogin().setPlatformClassName(DBPlatformHelper.getDBPlatform(conn.getMetaData().getDatabaseProductName(), getSessionLog()));
539         }catch (SQLException JavaDoc ex){
540             DatabaseException dbEx = DatabaseException.errorRetrieveDbMetadataThroughJDBCConnection();
541             // Typically exception would occur if user did not provide correct connection
542
// parameters. The root cause of exception should be propogated up
543
dbEx.initCause(ex);
544             throw dbEx;
545         }finally{
546             if (conn != null){
547                 try{
548                     conn.close();
549                 }catch (SQLException JavaDoc ex){
550                     DatabaseException dbEx = DatabaseException.errorRetrieveDbMetadataThroughJDBCConnection();
551                     // Typically exception would occur if user did not provide correct connection
552
// parameters. The root cause of exception should be propogated up
553
dbEx.initCause(ex);
554                     throw dbEx;
555                 }
556             }
557         }
558         connect(true);
559         postConnectDatasource();
560     }
561
562     /**
563      * PUBLIC:
564      * Connect to the database using the predefined login.
565      * The login must have been assigned when or after creating the session.
566      *
567      * @see #login(Login)
568      */

569     public void login() throws DatabaseException {
570         preConnectDatasource();
571         connect(false);
572         postConnectDatasource();
573     }
574
575     /**
576      * PUBLIC:
577      * Connect to the database using the given user name and password.
578      * The additional login information must have been preset in the session's login attribute.
579      * This is the login that should be used if each user has their own id,
580      * but all users share the same database configuration.
581      */

582     public void login(String JavaDoc userName, String JavaDoc password) throws DatabaseException {
583         getDatasourceLogin().setUserName(userName);
584         getDatasourceLogin().setPassword(password);
585         login();
586     }
587
588     /**
589      * PUBLIC:
590      * Connect to the database using the given login.
591      * The login may also the preset and the login() protocol called.
592      * This is the login should only be used if each user has their own database configuration.
593      */

594     public void login(Login login) throws DatabaseException {
595         setLogin(login);
596         login();
597     }
598
599     /**
600      * PUBLIC:
601      * Disconnect from the database.
602      *
603      * @exception TopLinkException if a transaction is active, you must rollback any active transaction before logout.
604      * @exception DatabaseException the database will also raise an error if their is an active transaction,
605      * or a general error occurs.
606      */

607     public void logout() throws DatabaseException {
608         // Reset cached data, as may be invalid later on.
609
this.lastDescriptorAccessed = null;
610
611         if (isInTransaction()) {
612             throw DatabaseException.logoutWhileTransactionInProgress();
613         }
614         if (getAccessor() == null) {
615             return;
616         }
617
618         disconnect();
619         getIdentityMapAccessor().initializeIdentityMaps();
620         isLoggedIn = false;
621         log(SessionLog.INFO, null, "logout_successful", this.getName());
622        
623         //unregister the MBean
624
getServerPlatform().unregisterMBean();
625     }
626
627     /**
628      * PUBLIC:
629      * Initialize the time that this session got connected. This can help determine how long a session has been
630      * connected.
631      */

632     public void initializeConnectedTime() {
633         connectedTime = System.currentTimeMillis();
634     }
635
636     /**
637      * PUBLIC:
638      * Answer the time that this session got connected. This can help determine how long a session has been
639      * connected.
640      */

641     public long getConnectedTime() {
642         return connectedTime;
643     }
644
645     /**
646      * INTERNAL:
647      * This method includes all of the code that is issued before the datasource
648      * is connected to.
649      */

650     protected void preConnectDatasource(){
651         //Bug#3440544 Check if logged in already to stop the attempt to login more than once
652
if (isLoggedIn) {
653             throw ValidationException.alreadyLoggedIn(this.getName());
654         }
655         this.platform = null;
656         if (isInProfile()) {
657             getProfiler().initialize();
658         }
659         updateProfile(SessionProfiler.LoginTime, new Date(System.currentTimeMillis()));
660
661         // Login and initialize
662
getEventManager().preLogin(this);
663         //setup the external transaction controller
664
getServerPlatform().initializeExternalTransactionController();
665         log(SessionLog.INFO, null, "topLink_version", DatasourceLogin.getVersion());
666         if (getServerPlatform().getServerNameAndVersion() != null) {
667             log(SessionLog.INFO, null, "application_server_name_and_version", getServerPlatform().getServerNameAndVersion());
668         }
669     }
670
671     /**
672      * INTERNAL:
673      * This method includes all of the code that is issued after the datasource
674      * is connected to.
675      */

676     protected void postConnectDatasource(){
677         initializeDescriptors();
678         //added to process ejbQL query strings
679
processEJBQLQueries();
680         log(SessionLog.INFO, null, "login_successful", this.getName());
681         getEventManager().postLogin(this);
682
683         initializeConnectedTime();
684         this.isLoggedIn = true;
685         this.platform = null;
686         
687         //register the MBean
688
getServerPlatform().registerMBean();
689     }
690
691     /**
692      * PUBLIC:
693      * Write all of the objects and all of their privately owned parts in the database.
694      * The objects will be commited through a single transaction.
695      *
696      * @exception DatabaseException if an error occurs on the database,
697      * these include constraint violations, security violations and general database erros.
698      * @exception OptimisticLockException if the object's descriptor is using optimistic locking and
699      * the object has been updated or deleted by another user since it was last read.
700      */

701     public void writeAllObjects(Collection domainObjects) throws DatabaseException, OptimisticLockException {
702         for (Iterator objectsEnum = domainObjects.iterator(); objectsEnum.hasNext();) {
703             writeObject(objectsEnum.next());
704         }
705     }
706
707     /**
708      * PUBLIC:
709      * Write all of the objects and all of their privately owned parts in the database.
710      * The objects will be commited through a single transaction.
711      *
712      * @exception DatabaseException if an error occurs on the database,
713      * these include constraint violations, security violations and general database erros.
714      * @exception OptimisticLockException if the object's descriptor is using optimistic locking and
715      * the object has been updated or deleted by another user since it was last read.
716      */

717     public void writeAllObjects(Vector domainObjects) throws DatabaseException, OptimisticLockException {
718         for (Enumeration objectsEnum = domainObjects.elements(); objectsEnum.hasMoreElements();) {
719             writeObject(objectsEnum.nextElement());
720         }
721     }
722 }
723
Popular Tags