KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > perseus > persistence > lib > TransactionalPersistenceManagerImpl


1 /**
2  * Copyright (C) 2001-2002
3  * - France Telecom R&D
4  * - Laboratoire Logiciels, Systemes, Reseaux - UMR 5526, CNRS-INPG-UJF
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  *
20  * Release: 1.0
21  *
22  * Authors:
23  *
24  */

25
26 package org.objectweb.perseus.persistence.lib;
27
28 import org.objectweb.fractal.api.control.BindingController;
29 import org.objectweb.perseus.cache.api.CacheEntry;
30 import org.objectweb.perseus.cache.api.CacheException;
31 import org.objectweb.perseus.cache.api.CacheFullException;
32 import org.objectweb.perseus.cache.api.CacheManager;
33 import org.objectweb.perseus.cache.api.FixableCacheEntry;
34 import org.objectweb.perseus.cache.api.UnbindManager;
35 import org.objectweb.perseus.concurrency.api.ConcurrencyException;
36 import org.objectweb.perseus.concurrency.api.ConcurrencyManager;
37 import org.objectweb.perseus.concurrency.api.RolledBackConcurrencyException;
38 import org.objectweb.perseus.persistence.api.MemoryInstanceManager;
39 import org.objectweb.perseus.persistence.api.PersistenceException;
40 import org.objectweb.perseus.persistence.api.RolledBackPersistenceException;
41 import org.objectweb.perseus.persistence.api.State;
42 import org.objectweb.perseus.persistence.api.StateFilter;
43 import org.objectweb.perseus.persistence.api.StateManager;
44 import org.objectweb.perseus.persistence.api.StorageManager;
45 import org.objectweb.perseus.persistence.api.TransactionalPersistenceManager;
46 import org.objectweb.perseus.persistence.api.TransactionalWorkingSet;
47 import org.objectweb.perseus.persistence.api.WorkingSet;
48 import org.objectweb.perseus.persistence.api.WorkingSetLifeCycle;
49 import org.objectweb.perseus.persistence.api.WorkingSetManager;
50 import org.objectweb.perseus.persistence.api.VirtualState;
51 import org.objectweb.perseus.persistence.api.PersistentObjectLifeCycleExcpetion;
52 import org.objectweb.perseus.persistence.api.NoDSIPersistenceException;
53 import org.objectweb.perseus.persistence.concurrency.NoDSIConcurrencyException;
54 import org.objectweb.util.monolog.api.BasicLevel;
55 import org.objectweb.util.monolog.api.Logger;
56
57 import java.util.Iterator JavaDoc;
58 import java.util.Set JavaDoc;
59 import java.util.ArrayList JavaDoc;
60
61 /**
62  * This class is an implementation of the TransactionalPersistenceManager
63  * interface. It manages the persistency, the concurrency and the caching of
64  * persistent objects. To do this it uses several other components:
65  * - a cache manager,
66  * - a concurrency manager,
67  * - a storage manager,
68  * - a state manager,
69  * - a memory instance manager,
70  * - a working set manager.
71  * This implementation is compliant to fractal by implementing the
72  * BindingController interface permitting the management of bindings between
73  * components.
74  *
75  * @author S.Chassande-Barrioz, P.Dechamboux, O.Lobry, Y. Bersihand
76  */

77 public class TransactionalPersistenceManagerImpl
78         implements TransactionalPersistenceManager, BindingController {
79
80     public final static String JavaDoc CACHE_MANAGER_BINDING = "cache-manager";
81     public final static String JavaDoc CONCURRENCY_MANAGER_BINDING = "concurrency-manager";
82     public final static String JavaDoc STORAGE_MANAGER_BINDING = "storage-manager";
83     public final static String JavaDoc STATE_MANAGER_BINDING = "state-manager";
84     public final static String JavaDoc MEMORY_INSTANCE_MANAGER_BINDING = "memory-instance-manager";
85     public final static String JavaDoc UNBIND_MANAGER_BINDING = "unbind-manager";
86     public final static String JavaDoc WORKINGSET_MANAGER_BINDING = "workingset-manager";
87
88     /**
89      * The cache of the persistent object.
90      */

91     protected CacheManager cache;
92
93     protected UnbindManager unbindManager;
94
95     /**
96      * The concurrency manager
97      */

98     protected ConcurrencyManager cm;
99
100     /**
101      * The storage manager in charge of the I/O to the data support, and the
102      * naming management.
103      */

104     protected StorageManager storage;
105
106     /**
107      * The manager of state of persistent object.
108      */

109     protected StateManager stateManager;
110
111     /**
112      * The manager of working set instance.
113      */

114     protected WorkingSetManager wsManager;
115
116     /**
117      * The factory of persistent objects
118      */

119     protected MemoryInstanceManager mim;
120
121     protected Logger logger = null;
122
123     /**
124      * @deprecated
125      * Attaches a state to a working Set.
126      *
127      * @param state is the state of the persistent object which must be attached
128      * to working set.
129      * @param ws is the working set to attach the state.
130      *
131      * @throws RolledBackPersistenceException if the entry has been evicted
132      * from the cache during the locking step (concurrency manager). It is
133      * possible that it has been removed by another thread ==> rollback the
134      * working set.
135      */

136     protected void bindCeInWS(State state, WorkingSet ws, byte mode)
137             throws PersistenceException {
138         Object JavaDoc oid = state.getCacheEntry().getCeIdentifier();
139         ws.bind(state, oid, mode);
140     }
141
142
143     /**
144      * finds or creates the CacheEntry matching to an identifier. If no cache
145      * antry matching the identifier is found in the cache, an new instance
146      * is created without state.
147      * @param ws if the WorkingSet requiring a CacheEntry.
148      * @param oid the identifier of the expected cache entry
149      * @return a cache entry instance (never null).
150      * @throws PersistenceException if it is not possible to instanciate a
151      * persistent object
152      * @throws RolledBackPersistenceException if the cache is full (case of the
153      * entry has not been found into the cache and a new entry is bound).
154      */

155     protected CacheEntry getCacheEntry(WorkingSet ws,
156                                        Object JavaDoc oid) throws PersistenceException {
157         CacheEntry ce = cache.lookup(oid);
158         if (logger != null && logger.isLoggable(BasicLevel.DEBUG)) {
159             logger.log(BasicLevel.DEBUG, "getCacheEntry( " + oid + ")");
160         }
161         if (ce != null) {
162             return ce;
163         }
164         // The element is not in the cache => create an entry in the cache
165
return createCacheEntry(ws, oid);
166     }
167     
168     /**
169      * creates a CacheEntry without state, corresponding to an identifier.
170      * @param ws if the WorkingSet requiring a CacheEntry.
171      * @param oid the identifier of the expected cache entry
172      * @return a cache entry instance (never null).
173      * @throws PersistenceException if it is not possible to instanciate a
174      * persistent object
175      * @throws RolledBackPersistenceException if the cache is full.
176      */

177     protected CacheEntry createCacheEntry(WorkingSet ws,
178                Object JavaDoc oid) throws PersistenceException {
179         if (logger != null && logger.isLoggable(BasicLevel.DEBUG)) {
180             logger.log(BasicLevel.DEBUG, "createCacheEntry( " + oid + ")");
181         }
182         Object JavaDoc obj = null;
183         // create memory instance if lookup failed
184
obj = mim.newInstance(oid, ws.getConnectionHolder());
185         CacheEntry ce;
186         // add memory instance to cache
187
try {
188             ce = cache.bind(oid, obj);
189             //Remove the reference in order to force the data loading
190
stateManager.setReferenceState(ce, null);
191         } catch (CacheFullException e) {
192             throw new RolledBackPersistenceException(e);
193         } catch (CacheException e) {
194             //That means the entry has been already bind to the cache. There
195
// are concurrent accesses.
196
ce = cache.lookup(oid);
197         }
198         return ce;
199     }
200     
201     /**
202      * Check if a cache entry is already referenced in the cache. If the entry
203      * has not been found, the entry is bound in the cache.
204      *
205      * @param ce is the cache entry to check
206      * @throws PersistenceException if the cache is full or if another cache
207      * entry has been found in the cache with the same identifier.
208      */

209     protected void checkCacheEntry(CacheEntry ce) throws PersistenceException {
210         Object JavaDoc oid = ce.getCeIdentifier();
211         if (logger != null && logger.isLoggable(BasicLevel.DEBUG)) {
212             logger.log(BasicLevel.DEBUG, "checkCacheEntry " + oid);
213         }
214         if (((FixableCacheEntry) ce).getCeFixCount() == 0) {
215             CacheEntry _ce = cache.lookup(oid);
216             if (_ce == null) {
217                 //the entry is not present in the cache
218
try {
219                     ce = cache.bind(oid, ce.getCeObject());
220                 } catch (CacheFullException e) {
221                     throw new RolledBackPersistenceException(e);
222                 } catch (CacheException e) {
223                     //That means the entry has been already bind to the cache. There
224
// are concurrent accesses.
225
ce = cache.lookup(oid);
226                 }
227             } else if (ce != _ce) {
228                 //the entry present in the cache is not the same than the parameter
229
throw new RolledBackPersistenceException(
230                         "Another persistent object is already present into the cache (identifier=" + oid + ")");
231             }
232         }
233     }
234
235     /**
236      * Prepares the end of a working set.
237      * @param ws is can be simple working set or a transaction
238      * @return true if the context CAN be committed, false if the context MUST be
239      * rolled back
240      * @throws PersistenceException
241      */

242     private boolean prepareWS(WorkingSet ws, boolean validate)
243             throws PersistenceException {
244         if (logger != null && logger.isLoggable(BasicLevel.DEBUG)) {
245             logger.log(BasicLevel.DEBUG, "prepareWS " + ws + " / " + validate);
246         }
247         boolean valid = validate;
248         PersistenceException pe = null;
249         try {
250             ws.setStatus(WorkingSetLifeCycle.getNextStatus(
251                     ws.getStatus(), WorkingSetLifeCycle.PREPARE_ACTION));
252         } catch (PersistenceException e) {
253             pe = e;
254             valid = false;
255         }
256         try {
257             // check if the context can be validate on concurrency manager
258
valid = cm.validate(ws) && valid;
259             if (pe != null) {
260                 throw pe;
261             }
262             if (valid) {
263                 //flush dirty objects into data support,
264
Set entries = ws.entries();
265                 for (Iterator JavaDoc it = entries.iterator(); it.hasNext();) {
266                     State state = (State) it.next();
267                     if (state == VirtualState.instance) {
268                         continue;
269                     }
270                     if (stateManager.isDirty(state)) {
271                         storage.write(ws.getConnectionHolder(),
272                                 state.getCacheEntry().getCeIdentifier(),
273                                 state);
274                     }
275                 }
276             }
277         } catch(Exception JavaDoc e) {
278             // If an exception occurs then the working set must be cancelled
279
valid = false;
280             throw (e instanceof PersistenceException
281                 ? (PersistenceException) e
282                 : new PersistenceException("An exception occurs during the "
283                     + "working preparation, it is marked as rolled back",e));
284         } finally {
285             //release the data support connection
286
ws.getConnectionHolder().releaseCHConnection();
287             if (valid) {
288                 ws.setStatus(WorkingSetLifeCycle.getNextStatus(
289                         ws.getStatus(), WorkingSetLifeCycle.PREPARE_OK_ACTION));
290             } else {
291                 ws.setStatus(WorkingSetLifeCycle.getNextStatus(
292                         ws.getStatus(), WorkingSetLifeCycle.PREPARE_FAIL_ACTION));
293             }
294         }
295         return valid;
296     }
297
298     /**
299      * commit a context.
300      * @param ws is can be simple working set or a transaction
301      * @param action is the action declenching the rollback
302      * @throws PersistenceException
303      */

304     private void commitWS(WorkingSet ws,
305                           byte action) throws PersistenceException {
306         if (logger != null && logger.isLoggable(BasicLevel.DEBUG)) {
307             logger.log(BasicLevel.DEBUG, "commitWS " + ws + " / " + action);
308         }
309         byte newStatus = WorkingSetLifeCycle.getNextStatus(
310                 ws.getStatus(), action);
311         try {
312             ws.getConnectionHolder().commitCH();
313         } catch (PersistenceException e) {
314             rollbackWS(ws, WorkingSetLifeCycle.ROLLBACK_ACTION);
315             throw new RolledBackPersistenceException(e);
316         }
317
318         try {
319             ArrayList JavaDoc unexportedOids = null;
320             for (Iterator JavaDoc it = ws.entries().iterator(); it.hasNext();) {
321                 State state = (State) it.next();
322                 if (state == VirtualState.instance) {
323                     continue;
324                 }
325                 if (stateManager.isUnexported(state)) {
326                     if (unexportedOids == null) {
327                         unexportedOids = new ArrayList JavaDoc();
328                     }
329                     //Register the entry to unexport
330
CacheEntry ce = state.getCacheEntry();
331                     unexportedOids.add(ce.getCeIdentifier());
332                     //Unbind the entry from the persistent layer
333
stateManager.makeUnbound(ce);
334                 }
335             }
336             if (unexportedOids != null) {
337                 // unbind removed entries from the cache
338
unbindManager.unbindAll(unexportedOids, true);
339             }
340         } catch (CacheException e) {
341             throw new PersistenceException(e);
342         } finally {
343             try {
344                 ws.getConnectionHolder().closeCHConnection();
345             } finally {
346                 cm.finalize(ws);
347                 ws.setStatus(newStatus);
348                 ws.clear();
349                 storage.endWS(ws);
350             }
351         }
352     }
353
354     /**
355      * cancel a context. The unfix action is out of date.
356      * @param ws is can be simple working set or a transaction
357      * @param action is the action declenching the rollback
358      * @throws PersistenceException
359      */

360     private void rollbackWS(WorkingSet ws,
361                             byte action) throws PersistenceException {
362         if (logger != null && logger.isLoggable(BasicLevel.DEBUG)) {
363             logger.log(BasicLevel.DEBUG, "rollbackWS " + ws + " / " + action);
364         }
365         byte newStatus = WorkingSetLifeCycle.getNextStatus(
366                 ws.getStatus(), action);
367         try {
368             try {
369                 ws.getConnectionHolder().rollbackCH();
370             } finally {
371                 ws.setStatus(newStatus);
372             }
373             ArrayList JavaDoc unexportedOids = null;
374             for (Iterator JavaDoc i = ws.entries().iterator(); i.hasNext();) {
375                 State state = (State) i.next();
376                 if (state == VirtualState.instance) {
377                     continue;
378                 }
379                 CacheEntry ce = state.getCacheEntry();
380                 if (stateManager.isExported(state)) {
381                     if (unexportedOids == null) {
382                         unexportedOids = new ArrayList JavaDoc();
383                     }
384                     unexportedOids.add(ce.getCeIdentifier());
385                     stateManager.makeUnbound(ce);
386                 }
387                 
388             }
389             if (unexportedOids != null) {
390                 // unbind removed entries from the cache
391
unbindManager.unbindAll(unexportedOids, true);
392             }
393         } catch (CacheException ce) {
394             throw new PersistenceException("Impossible to rollback - ", ce);
395         } finally {
396             try {
397                 ws.getConnectionHolder().closeCHConnection();
398             } finally {
399                 cm.abort(ws);
400                 ws.clear();
401                 ws.setStatus(newStatus);
402                 storage.endWS(ws);
403             }
404         }
405     }
406
407     private void assertOpenWorkingset(WorkingSet ws) throws PersistenceException {
408         if (ws.getStatus() == WorkingSet.CTX_CLOSED) {
409             throw new PersistenceException("Impossible to work with a closed WorkingSet");
410         }
411     }
412
413     //IMPLEMENTATION OF THE UserBindingControler INTERFACE //
414
//------------------------------------------------------//
415

416     public String JavaDoc[] listFc() {
417         return new String JavaDoc[]{
418             CACHE_MANAGER_BINDING,
419             CONCURRENCY_MANAGER_BINDING,
420             STATE_MANAGER_BINDING,
421             STORAGE_MANAGER_BINDING,
422             MEMORY_INSTANCE_MANAGER_BINDING,
423             UNBIND_MANAGER_BINDING,
424             WORKINGSET_MANAGER_BINDING,
425             STATE_MANAGER_BINDING
426         };
427     }
428
429     public Object JavaDoc lookupFc(String JavaDoc s) {
430         if (CACHE_MANAGER_BINDING.equals(s)) {
431             return cache;
432         } else if (CONCURRENCY_MANAGER_BINDING.equals(s)) {
433             return cm;
434         } else if (STATE_MANAGER_BINDING.equals(s)) {
435             return stateManager;
436         } else if (STORAGE_MANAGER_BINDING.equals(s)) {
437             return storage;
438         } else if (MEMORY_INSTANCE_MANAGER_BINDING.equals(s)) {
439             return mim;
440         } else if (UNBIND_MANAGER_BINDING.equals(s)) {
441             return unbindManager;
442         } else if (WORKINGSET_MANAGER_BINDING.equals(s)) {
443             return wsManager;
444         } else if (STATE_MANAGER_BINDING.equals(s)) {
445             return stateManager;
446         }
447         return null;
448     }
449
450     public void bindFc(String JavaDoc s, Object JavaDoc o) {
451         if ("logger".equals(s)) {
452             logger = (Logger) o;
453         } else if (CACHE_MANAGER_BINDING.equals(s)) {
454             cache = (CacheManager) o;
455         } else if (CONCURRENCY_MANAGER_BINDING.equals(s)) {
456             cm = (ConcurrencyManager) o;
457         } else if (STATE_MANAGER_BINDING.equals(s)) {
458             stateManager = (StateManager) o;
459         } else if (STORAGE_MANAGER_BINDING.equals(s)) {
460             storage = (StorageManager) o;
461         } else if (MEMORY_INSTANCE_MANAGER_BINDING.equals(s)) {
462             mim = (MemoryInstanceManager) o;
463         } else if (UNBIND_MANAGER_BINDING.equals(s)) {
464             unbindManager = (UnbindManager) o;
465         } else if (WORKINGSET_MANAGER_BINDING.equals(s)) {
466             wsManager = (WorkingSetManager) o;
467         } else if (STATE_MANAGER_BINDING.equals(s)) {
468             stateManager = (StateManager) o;
469         }
470     }
471
472     public void unbindFc(String JavaDoc s) {
473         if (CACHE_MANAGER_BINDING.equals(s)) {
474             cache = null;
475         } else if (CONCURRENCY_MANAGER_BINDING.equals(s)) {
476             cm = null;
477         } else if (STATE_MANAGER_BINDING.equals(s)) {
478             stateManager = null;
479         } else if (STORAGE_MANAGER_BINDING.equals(s)) {
480             storage = null;
481         } else if (MEMORY_INSTANCE_MANAGER_BINDING.equals(s)) {
482             mim = null;
483         } else if (UNBIND_MANAGER_BINDING.equals(s)) {
484             unbindManager = null;
485         } else if (WORKINGSET_MANAGER_BINDING.equals(s)) {
486             wsManager = null;
487         } else if (STATE_MANAGER_BINDING.equals(s)) {
488             stateManager = null;
489         }
490     }
491
492     // IMPLEMENTATION OF THE PersistenceManager INTERFACE //
493
//----------------------------------------------------//
494

495     public State export(WorkingSet ws, Object JavaDoc obj)
496             throws PersistenceException {
497         return export(ws, obj, null);
498     }
499
500     public State export(WorkingSet ws, Object JavaDoc obj, Object JavaDoc hints)
501             throws PersistenceException {
502         if (logger.isLoggable(BasicLevel.DEBUG))
503             logger.log(BasicLevel.DEBUG, "export ctx=" + ws
504                     + " / obj=" + obj.getClass().getName()
505                     + " / hints=" + hints);
506         assertOpenWorkingset(ws);
507         State state = null;
508         //export through storage manager
509
Object JavaDoc oid = null;
510         CacheEntry ce = null;
511         try {
512
513             if (hints == null) {
514                 oid = storage.export(ws.getConnectionHolder(), obj);
515             } else {
516                 oid = storage.export(ws.getConnectionHolder(), obj, hints);
517             }
518
519             //add to cache
520
ce = cache.bind(oid, obj);
521
522             //notify concurrency manager
523
state = writeIntention(ws, ce, null);
524             stateManager.makeExported(state);
525             return state;
526         } catch (PersistenceException e) {
527             if (ce != null) {
528                 stateManager.makeUnbound(ce);
529             }
530             throw e;
531         } catch (CacheFullException e) {
532             throw new RolledBackPersistenceException(e);
533         } catch (CacheException e) {
534             //if the object has been deleted in the same tx,
535
//then its id can be re-used
536
//virtual state???
537
try {
538                 state = ws.lookup(oid);
539                 if (state != null && stateManager.isUnexported(state)) {
540                     ce = cache.lookup(oid);
541                     if (ce != null) {
542                         // unbind removed entries from the cache
543
unbindManager.unbind(oid, true);
544                         //add to cache
545
ce = cache.bind(oid, obj);
546                         //bind the entry from the persistent layer
547
stateManager.makeBound(ce, oid);
548                         ws.bind(VirtualState.instance, oid, WorkingSet.WRITE_INTENTION);
549                         //notify concurrency manager
550
state = writeIntention(ws, ce, null);
551                         //do not make it exported but make it clean then dirty
552
stateManager.makeClean(state);
553                         stateManager.makeDirty(state);
554                         //stateManager.makeExported(state);
555
return state;
556                     }
557                 }
558             } catch (CacheException cacheE) {
559                 throw new PersistenceException(
560                         "Cannot put object into cache, oid=" + oid, cacheE);
561             }
562             throw new PersistenceException(
563                     "Cannot put object into cache, oid=" + oid, e);
564         }
565     }
566
567     public State unexport(WorkingSet ws, Object JavaDoc oid) throws PersistenceException {
568         return unexport(ws, getCacheEntry(ws, oid));
569     }
570
571     public State unexport(WorkingSet ws, CacheEntry ce)
572             throws PersistenceException {
573         assertOpenWorkingset(ws);
574         if (!stateManager.isBound(ce)) {
575             throw new PersistentObjectLifeCycleExcpetion(
576                     PersistentObjectLifeCycleExcpetion.UNEXPORT_NPO_MSG);
577         }
578         Object JavaDoc oid = ce.getCeIdentifier();
579         State state = null;
580         //notify concurrency manager
581
state = writeIntention(ws, ce, null);
582         //unexport through storage manager
583
storage.unexport(ws.getConnectionHolder(), oid, ce);
584         stateManager.makeUnexported(state);
585         return state;
586     }
587
588     public State readIntention(WorkingSet ws, Object JavaDoc oid, Object JavaDoc thinLock)
589             throws PersistenceException {
590         return readIntention(ws, getCacheEntry(ws, oid), thinLock);
591     }
592
593     public CacheEntry getObjectById(WorkingSet ws, Object JavaDoc oid)
594         throws PersistenceException {
595         if (logger.isLoggable(BasicLevel.DEBUG)) {
596             logger.log(BasicLevel.DEBUG, "getObjectById ctx=" + ws
597                     + " / oid=" + oid);
598         }
599         assertOpenWorkingset(ws);
600         //Check in the worling set if already associated
601
State s = ws.lookup(oid);
602         if (s != null && s != VirtualState.instance) {
603             return s.getCacheEntry();
604         }
605         return getCacheEntry(ws, oid);
606     }
607
608     /**
609      * This method records an access intention to a data object in read mode.
610      * @param ce is the cache entry
611      * @param ws is an identifier of the execution context. It can be a
612      * transaction handle.
613      * @exception PersistenceException
614      */

615     public State readIntention(WorkingSet ws, CacheEntry ce, Object JavaDoc thinLock) throws PersistenceException {
616         assertOpenWorkingset(ws);
617         if (!stateManager.isBound(ce)) {
618             throw new PersistentObjectLifeCycleExcpetion(
619                     PersistentObjectLifeCycleExcpetion.READ_NPO_MSG);
620         }
621         checkCacheEntry(ce);
622         State state;
623         // notify concurrency manager
624
try {
625             state = (State) cm.readIntention(ws, ce, thinLock);
626         } catch (RolledBackConcurrencyException e) {
627             throw new RolledBackPersistenceException(e);
628         } catch (NoDSIConcurrencyException e) {
629             try {
630                 unbindManager.unbind(ce.getCeIdentifier(), true);
631             } catch (CacheException e1) {
632                 logger.log(BasicLevel.ERROR,
633                         "Impossible to unbind from the cache an entry which " +
634                         "does not exist on the data support", e1);
635             }
636             throw new NoDSIPersistenceException(e);
637         } catch (ConcurrencyException e) {
638             throw new PersistenceException(e);
639         }
640         Object JavaDoc oid = state.getCacheEntry().getCeIdentifier();
641         ws.bind(state, oid, WorkingSet.READ_INTENTION);
642         return state;
643     }
644
645     public State writeIntention(WorkingSet ws, Object JavaDoc oid, Object JavaDoc thinLock)
646             throws PersistenceException {
647         return writeIntention(ws, getCacheEntry(ws, oid), thinLock);
648     }
649
650     public State writeIntention(WorkingSet ws, CacheEntry ce, Object JavaDoc thinLock)
651             throws PersistenceException {
652         assertOpenWorkingset(ws);
653         if (!stateManager.isBound(ce)) {
654             throw new PersistentObjectLifeCycleExcpetion(
655                     PersistentObjectLifeCycleExcpetion.WRITE_NPO_MSG);
656         }
657         checkCacheEntry(ce);
658         State state;
659         // notify concurrency manager
660
try {
661             state = (State) cm.writeIntention(ws, ce, thinLock);
662         } catch (RolledBackConcurrencyException e) {
663             throw new RolledBackPersistenceException(e);
664         } catch (NoDSIConcurrencyException e) {
665             try {
666                 unbindManager.unbind(ce.getCeIdentifier(), true);
667             } catch (CacheException e1) {
668                 logger.log(BasicLevel.ERROR,
669                         "Impossible to unbind from the cache an entry which " +
670                         "does not exist on the data support", e1);
671             }
672             throw new NoDSIPersistenceException(e);
673         } catch (ConcurrencyException e) {
674             throw new PersistenceException(e);
675         }
676         Object JavaDoc oid = state.getCacheEntry().getCeIdentifier();
677         ws.bind(state, oid, WorkingSet.WRITE_INTENTION);
678         stateManager.makeDirty(state);
679         return state;
680     }
681
682     /**
683      * This method can be used to mark the end of an access to a data object.
684      * @param ws is an identifier of the execution context. It can be a
685      * transaction handle.
686      * @param ce is the cache entry on which the access is finished.
687      * @exception PersistenceException
688      */

689     public void accessCompletion(WorkingSet ws, State ce) throws PersistenceException {
690         assertOpenWorkingset(ws);
691     }
692
693     /**
694      * This method permits to flush entries associated to a context.
695      * @param ws is an identifier of the execution context. It can be a
696      * transaction handle.
697      * @param statefilter is a filter of the state which must be flushed
698      * @throws PersistenceException if the context is not valid.
699      */

700     public void flush(WorkingSet ws, StateFilter statefilter)
701             throws PersistenceException {
702         assertOpenWorkingset(ws);
703         Iterator JavaDoc it = ws.entries().iterator();
704         while (it.hasNext()) {
705             State state = (State) it.next();
706             if (state == VirtualState.instance) {
707                 continue;
708             }
709             if (stateManager.isDirty(state)
710                     && (statefilter == null || statefilter.accept(state))) {
711                 storage.write(ws.getConnectionHolder(),
712                         state.getCacheEntry().getCeIdentifier(),
713                         state);
714                 //Mark the entry as flushed in order to avoid I/O at prepare time
715
stateManager.makeFlushed(state);
716             }
717         }
718     }
719
720     /**
721      * This method permits to flush entries associated to a context.
722      * @param ws is an identifier of the execution context. It can be a
723      * transaction handle.
724      * @param state is the state taht must be flushed
725      * @throws PersistenceException if the context is not valid.
726      */

727     public void flush(WorkingSet ws, State stateToFlush)
728             throws PersistenceException {
729         assertOpenWorkingset(ws);
730         Iterator JavaDoc it = ws.entries().iterator();
731         while (it.hasNext()) {
732             State state = (State) it.next();
733             if (state == VirtualState.instance) {
734                 continue;
735             }
736             if (stateManager.isDirty(state) && state == stateToFlush) {
737                 storage.write(ws.getConnectionHolder(),
738                         state.getCacheEntry().getCeIdentifier(),
739                         state);
740                 //Mark the entry as flushed in order to avoid I/O at prepare time
741
stateManager.makeFlushed(state);
742             }
743         }
744     }
745     /**
746      * The unfix action is out of date.
747      */

748     public boolean evict(WorkingSet ws, Object JavaDoc oid, boolean force) throws PersistenceException {
749         FixableCacheEntry ce = (FixableCacheEntry) cache.lookup(oid);
750         assertOpenWorkingset(ws);
751         if (ce == null) {
752             return true;
753         }
754         int fix = ce.getCeFixCount();
755         State state = ws.lookup(oid);
756         if (fix == 1 && state != null) {
757             //The entry is used only in the specified working set
758
if (stateManager.isDirty(state)) {
759                 //flush the dirty object and mark it as flushed
760
storage.write(ws.getConnectionHolder(), oid, state);
761                 stateManager.makeFlushed(state);
762             }
763             //remove the entry from the working set by replaceing the state
764
// by a virtual state.
765
ws.bind(VirtualState.instance, oid, WorkingSet.UNKNOWN_INTENTION);
766         }
767         if (fix > 0) {
768             if (force) {
769                 throw new PersistenceException("Impossible to evict an entry from the cache: There is another user than the given working set");
770             } else {
771                 return false;
772             }
773         }
774         //Remove the reference state
775
stateManager.setReferenceState(ce, null);
776         //Remove the local reference for the GC
777
ce = null;
778         //remove the entry from the cache
779
try {
780             return unbindManager.unbind(oid, false);
781         } catch (CacheException e) {
782             if (force) {
783                 throw new PersistenceException("Impossible to unbind the entry: ", e);
784             } else {
785                 return false;
786             }
787         }
788     }
789
790     public int evictAll(WorkingSet ws, boolean force) throws PersistenceException{
791         assertOpenWorkingset(ws);
792         try {
793             return unbindManager.unbindUnfixed(force).size();
794         } catch (CacheException e) {
795             throw new PersistenceException(e);
796         }
797     }
798
799     public void unbind(WorkingSet ws, Object JavaDoc oid) throws PersistenceException {
800         assertOpenWorkingset(ws);
801         unbind(ws, cache.lookup(oid));
802     }
803
804     public void unbind(WorkingSet ws, CacheEntry ce) throws PersistenceException {
805         assertOpenWorkingset(ws);
806         FixableCacheEntry fce = (FixableCacheEntry) ce;
807         
808         Object JavaDoc oid = ce.getCeIdentifier();
809         State state = ws.lookup(oid);
810         if (state == null) {
811             state = readIntention(ws, ce, null);
812         } else if (stateManager.isDirty(state)) {
813             //flush the dirty object and mark it as flushed
814
storage.write(ws.getConnectionHolder(), oid, state);
815             stateManager.makeFlushed(state);
816         }
817         // Remove the entry from the working set by replacing the real state
818
// by a virtual state. It is required to keep the oid into the
819
// working set in order to free the locking of the concurrency
820
// manager
821
ws.bind(VirtualState.instance, oid, WorkingSet.UNKNOWN_INTENTION);
822
823         //remove the entry from the cache
824
try {
825             while (fce.getCeFixCount() > 0) {
826                 cache.unfix(fce);
827             }
828             unbindManager.unbind(oid, true);
829         } catch (CacheException e) {
830                 throw new PersistenceException("Impossible to unbind the entry: ", e);
831         }
832
833         //Mark the cache entry as unbound from the Persistence system
834
stateManager.makeUnbound(ce);
835         //Use the current state as reference state
836
stateManager.setReferenceState(ce, state);
837     }
838
839     public void refresh(WorkingSet ws, Object JavaDoc oid) throws PersistenceException {
840         assertOpenWorkingset(ws);
841         CacheEntry ce = cache.lookup(oid);
842         if (ce != null) {
843             refresh(ws, ce);
844         }
845     }
846     public void refresh(WorkingSet ws, CacheEntry ce) throws PersistenceException {
847         if (logger != null && logger.isLoggable(BasicLevel.DEBUG)) {
848             logger.log(BasicLevel.DEBUG, "refresh " + ce.getCeIdentifier());
849         }
850         assertOpenWorkingset(ws);
851         // Remove the reference state in order to reload from the database
852
// on the next access
853
stateManager.setReferenceState(ce, null);
854         // Trash the current state associated to the working set
855
// (maybe not already attached)
856
ws.bind(VirtualState.instance,
857                 ce.getCeIdentifier(),
858                 WorkingSet.UNKNOWN_INTENTION);
859     }
860
861     /**
862      * creates a working set
863      * @param userObject can be an external user depending on the
864      * personnality.
865      * @return a new WorkingSet
866      * @throws PersistenceException
867      */

868     public WorkingSet createWS(Object JavaDoc userObject)
869             throws PersistenceException {
870         WorkingSet ws = wsManager.createWS(userObject);
871         storage.beginWS(ws);
872         return ws;
873     }
874
875     /**
876      * creates a working set
877      * @param userObject can be an external user depending on the
878      * personnality.
879      * @param workingSetType is a type of the working set.
880      * @return a new WorkingSet
881      * @throws PersistenceException
882      */

883     public WorkingSet createWS(Object JavaDoc userObject,
884                                Object JavaDoc workingSetType)
885             throws PersistenceException {
886         WorkingSet ws = wsManager.createWS(userObject, workingSetType);
887         storage.beginWS(ws);
888         return ws;
889     }
890
891     /**
892      * Closes and releases a context.
893      * @param context which must be closed
894      * @throws PersistenceException if the context is a transactional context
895      * which has not been commited or aborted.
896      */

897     public void close(WorkingSet context) throws PersistenceException {
898         if (!context.entries().isEmpty()) {
899             boolean prepared_ok = false;
900             PersistenceException pe = null;
901             try {
902                 prepared_ok = prepareWS(context, true);
903             } catch (PersistenceException e) {
904                 pe = e;
905             }
906             if (prepared_ok) {
907                 commitWS(context, WorkingSetLifeCycle.CLOSE_ACTION);
908             } else {
909                 rollbackWS(context, WorkingSetLifeCycle.CLOSE_ACTION);
910                 if (pe == null) {
911                     throw new RolledBackPersistenceException();
912                 } else {
913                     throw pe;
914                 }
915             }
916         } else {
917             context.getConnectionHolder().closeCHConnection();
918             context.setStatus(WorkingSetLifeCycle.getNextStatus(
919                     context.getStatus(), WorkingSetLifeCycle.CLOSE_ACTION));
920             storage.endWS(context);
921         }
922         wsManager.closeWS(context);
923     }
924
925     // IMPLEMENTATION OF THE TransactionalPersistenceManager INTERFACE //
926
//-----------------------------------------------------------------//
927

928     /**
929      * converts a context to a transaction
930      * @param tx becomes transactional
931      * @throws PersistenceException if the context is already transactional.
932      */

933     public void begin(TransactionalWorkingSet tx) throws PersistenceException {
934         assertOpenWorkingset(tx);
935         if (logger != null && logger.isLoggable(BasicLevel.DEBUG)) {
936             logger.log(BasicLevel.DEBUG, "begin " + tx);
937         }
938         // 1st step: flush objects in working set, outside transaction
939
if (tx.entries().size() > 0) {
940             logger.log(BasicLevel.DEBUG, "Flush modification before the transaction " + tx);
941             close(tx);
942         }
943         tx.getConnectionHolder().begin();
944
945         // 2nd step: change the transaction's status
946
tx.setStatus(WorkingSetLifeCycle.getNextStatus(
947                 tx.getStatus(), WorkingSetLifeCycle.BEGIN_TX_ACTION));
948     }
949
950     /**
951      * Prepare the transactinal context.
952      * @param tx the
953      * @return true if the transaction can be commit or false is the transaction
954      * must be rolled back.
955      * @throws PersistenceException if an error raised during the prepare
956      * operation, or if the context is not a transactional context.
957      */

958     public boolean prepare(TransactionalWorkingSet tx) throws PersistenceException {
959         assertOpenWorkingset(tx);
960         return prepareWS(tx, !tx.getWSRollBackOnly());
961     }
962
963     /**
964      * commits a transactional context. The call to the prepare method is
965      * required.
966      * @param tx
967      * @throws PersistenceException if an error raised during the commit
968      * operation, or if the context is not a transactional context.
969      */

970     public void commit(TransactionalWorkingSet tx) throws PersistenceException {
971         assertOpenWorkingset(tx);
972         if (tx.getStatus() == TransactionalWorkingSet.CTX_ACTIVE_TRANSACTIONAL) {
973             //One phase commit
974
boolean prepared_ok = false;
975             PersistenceException pe = null;
976             try {
977                 prepared_ok = prepareWS(tx, !tx.getWSRollBackOnly());
978             } catch (PersistenceException e) {
979                 pe = e;
980             }
981             if (prepared_ok) {
982                 commitWS(tx, WorkingSetLifeCycle.COMMIT_ACTION);
983             } else {
984                 rollbackWS(tx, WorkingSetLifeCycle.ROLLBACK_ACTION);
985                 if (pe == null) {
986                     throw new RolledBackPersistenceException();
987                 } else {
988                     throw pe;
989                 }
990             }
991         } else {
992             commitWS(tx, WorkingSetLifeCycle.COMMIT_ACTION);
993         }
994         storage.beginWS(tx);
995     }
996
997     /**
998      * rollbacks a transactional context. The call to the prepare method is
999      * required.
1000     * @param tx
1001     * @throws PersistenceException if an error raised during the rollback
1002     * operation, or if the context is not a transactional context.
1003     */

1004    public void rollback(TransactionalWorkingSet tx) throws PersistenceException {
1005        assertOpenWorkingset(tx);
1006        try {
1007            prepareWS(tx, false);
1008        } catch (PersistenceException e) {
1009            logger.log(BasicLevel.WARN, "An error occris during the rollback operation", e);
1010        }
1011        rollbackWS(tx, WorkingSetLifeCycle.ROLLBACK_ACTION);
1012        storage.beginWS(tx);
1013    }
1014}
1015
Popular Tags