KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > speedo > workingset > lib > SpeedoTransaction


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

18 package org.objectweb.speedo.workingset.lib;
19
20 import java.util.ArrayList JavaDoc;
21 import java.util.Iterator JavaDoc;
22
23 import javax.jdo.JDOException;
24 import javax.jdo.JDOFatalException;
25 import javax.jdo.JDOFatalInternalException;
26 import javax.jdo.JDOUserException;
27 import javax.jdo.PersistenceManager;
28 import javax.naming.InitialContext JavaDoc;
29 import javax.transaction.Status JavaDoc;
30 import javax.transaction.Synchronization JavaDoc;
31 import javax.transaction.TransactionManager JavaDoc;
32
33 import org.objectweb.fractal.api.Component;
34 import org.objectweb.fractal.api.control.LifeCycleController;
35 import org.objectweb.jorm.api.PMapper;
36 import org.objectweb.medor.eval.prefetch.api.PrefetchCache;
37 import org.objectweb.perseus.persistence.api.ConnectionHolder;
38 import org.objectweb.perseus.persistence.api.PersistenceException;
39 import org.objectweb.perseus.persistence.api.State;
40 import org.objectweb.perseus.persistence.api.TransactionalPersistenceManager;
41 import org.objectweb.perseus.persistence.api.TransactionalWorkingSet;
42 import org.objectweb.perseus.persistence.api.VirtualState;
43 import org.objectweb.perseus.persistence.api.WorkingSet;
44 import org.objectweb.perseus.persistence.api.WorkingSetLifeCycle;
45 import org.objectweb.perseus.persistence.lib.BasicWorkingSet;
46 import org.objectweb.speedo.api.ExceptionHelper;
47 import org.objectweb.speedo.api.SpeedoProperties;
48 import org.objectweb.speedo.api.TransactionListener;
49 import org.objectweb.speedo.mim.api.SpeedoAccessor;
50 import org.objectweb.speedo.pm.api.ProxyManager;
51 import org.objectweb.speedo.workingset.api.Transaction;
52 import org.objectweb.util.monolog.api.BasicLevel;
53
54 /**
55  * Is a working set assocaited to a ProxyManager. The working set can be
56  * transactional or not. It contains the list of reached instances.
57  *
58  * @see javax.jdo.Transaction
59  * @see org.objectweb.speedo.workingset.api.Transaction
60  * @see org.objectweb.perseus.persistence.api.WorkingSet
61  * @see org.objectweb.perseus.persistence.lib.BasicWorkingSet
62  *
63  * @author S.Chassande-Barrioz
64  */

65 public class SpeedoTransaction
66         extends BasicWorkingSet
67         implements Transaction, LifeCycleController {
68
69     public final static String JavaDoc PROXY_MANAGER_BINDING = "proxy-manager";
70     public final static String JavaDoc MAPPER_BINDING = "mapper";
71     public final static String JavaDoc TRANSACTIONAL_PERSISTENCE_MANAGER_BINDING
72             = "transactional-persistence-manager";
73     public final static String JavaDoc COMPONENT_BINDING = "component";
74     public static TransactionListener txListener = null;
75
76     /**
77      * Is the linked Proxy manager.
78      */

79     private ProxyManager pm = null;
80
81     /**
82      * is the mapper permitting to reach the prefetch cache and to invalidate
83      * prefetched buffer at working set closing time.
84      */

85     private PMapper mapper = null;
86
87     /**
88      * Is used to delegates working set/transaction demercation
89      */

90     private TransactionalPersistenceManager tpm = null;
91
92     /**
93      * the reference to this component in Speedo
94      */

95     private Transaction thisT;
96
97     private boolean nontransactionalRead;
98     private boolean nontransactionalWrite;
99
100     /**
101      * Indicates if the transaction is optimistic.
102      */

103     private boolean optimistic;
104
105     /**
106      * The JDO user synchronization registered (can be null if none has been
107      * registered).
108      */

109     private Synchronization JavaDoc synchronization = null;
110
111     /**
112      * indicates if the transaction is managed by a J2EE environnement.
113      */

114     private boolean managedEnv = false;
115     
116     /**
117      * Indicates if the jdo transaction must be rolledback.
118      */

119     private boolean rollbackOnly = false;
120
121     /**
122      * It activates the working set. This is used to delimit the begining of
123      * the working set.
124      */

125     public void active() throws PersistenceException {
126         tpm.createWS(thisT);
127         try {
128             status = WorkingSetLifeCycle.getNextStatus(
129                     status, WorkingSetLifeCycle.ACTIVE_ACTION);
130         } catch (PersistenceException e) {
131             logger.log(BasicLevel.WARN, "Bad initial state of the working set:", e);
132             status = WorkingSet.CTX_ACTIVE;
133         }
134     }
135
136     /**
137      * Attaches an entry to the transaction.
138      * Plus version update.
139      * @param state the state which must be attached to the transaction
140      * @param mode the action that stared the binding: either read or write intention
141      */

142     public State bind(State state, Object JavaDoc oid, byte mode) {
143         State old = super.bind(state, oid, mode);
144         if(! (state instanceof VirtualState)){
145             SpeedoAccessor sa = (SpeedoAccessor) state;
146             if (mode == BasicWorkingSet.WRITE_INTENTION) {
147                 sa.changeVersion();
148             }
149         }
150         return old;
151     }
152
153     /**
154      * Invalidates the prefetch buffer associated to this working set.
155      *
156      * @throws PersistenceException
157      */

158     public void beforeWSPrepare() throws PersistenceException {
159         logger.log(BasicLevel.DEBUG, "Starting beforeWSPrepare");
160         Iterator JavaDoc it = oid2state.values().iterator();
161         ArrayList JavaDoc exceptions = null;
162         while(it.hasNext()) {
163             State state = (State) it.next();
164             if (state == VirtualState.instance) {
165                 continue;
166             }
167             try {
168                 ((SpeedoAccessor) state).prepareWrite();
169             } catch (Exception JavaDoc e) {
170                 if (exceptions == null) {
171                     exceptions = new ArrayList JavaDoc();
172                 }
173                 exceptions.add(e);
174                 int level = e instanceof JDOException ? BasicLevel.DEBUG : BasicLevel.ERROR ;
175                 if (logger.isLoggable(level)) {
176                     logger.log(level,
177                         "Error on SpeedoAccessor preparation for flushing: "
178                         + "\n\tstate.ce.identifier=" + state.getCacheEntry().getCeIdentifier()
179                         + "\n\tstate=" + state
180                         + "\n\texception: ", e);
181                 }
182             }
183         }
184         // close the prefetch buffers associated to the context
185
PrefetchCache pc = mapper.getPrefetchCache();
186         if (pc != null) {
187             pc.invalidatePrefetchBuffer(thisT);
188         }
189         logger.log(BasicLevel.DEBUG, "Ending beforeWSPrepare");
190         if (exceptions != null) {
191             Exception JavaDoc inner;
192             if (exceptions.size() == 1) {
193                 throw new PersistenceException((Exception JavaDoc) exceptions.get(0));
194             } else {
195                 throw new PersistenceException(new JDOUserException(
196                     "Impossible to prepare instances before flushing",
197                     (Exception JavaDoc[]) exceptions.toArray(new Exception JavaDoc[exceptions.size()])));
198             }
199         }
200     }
201
202     /**
203      * Signal to the persistent instances reached in the working set that the
204      * current working set is closed. Some actions on persistent instances at
205      * this time can be done, such as reference unswizlling
206      */

207     public void onWSEnd() {
208         logger.log(BasicLevel.DEBUG, "Starting onWSEnd");
209         ArrayList JavaDoc exceptions = null;
210         if (!oid2state.isEmpty()) {
211             Iterator JavaDoc it = oid2state.values().iterator();
212             while(it.hasNext()) {
213                 State state = (State) it.next();
214                 if (state == VirtualState.instance) {
215                     continue;
216                 }
217                 try {
218                     ((SpeedoAccessor) state).workingSetClosed();
219                 } catch (Exception JavaDoc e) {
220                     if (exceptions == null) {
221                         exceptions = new ArrayList JavaDoc();
222                     }
223                     exceptions.add(e);
224                     if (!(e instanceof JDOException)) {
225                         logger.log(BasicLevel.ERROR,
226                             "Error on workingSetClosed for the SpeedoAccessor: "
227                             + "\n\tstate.ce.identifier=" + state.getCacheEntry().getCeIdentifier()
228                             + "\n\tstate=" + state
229                             + "\n\texception: ", e);
230                     }
231                 }
232             }
233         }
234         logger.log(BasicLevel.DEBUG, "Ending onWSEnd");
235         if (exceptions != null) {
236             Exception JavaDoc inner;
237             if (exceptions.size() == 1) {
238                 throw new JDOException(
239                         "Error when signal the close of working set on state(s):",
240                         (Exception JavaDoc) exceptions.get(0));
241             } else {
242                 throw new JDOUserException(
243                     "Error when signal the close of working set on states:",
244                     (Exception JavaDoc[]) exceptions.toArray(new Exception JavaDoc[exceptions.size()]));
245             }
246         }
247     }
248
249     // IMPLEMENTATION OF THE Transaction INTERFACE //
250
//-----------------------------------------------------//
251

252     public void setConnectionHolder(ConnectionHolder ch) {
253         connectionHolder = ch;
254         connectionHolder.bindWorkingSet(thisT);
255     }
256
257     public JDOFatalException rollBackOnInternalError(Exception JavaDoc _e) {
258         Exception JavaDoc ie = ExceptionHelper.getNested(_e);
259         if (isActive()) {
260             if (managedEnv) {
261                 logger.log(BasicLevel.INFO, ".");
262                 String JavaDoc tmName = pm.getPersistenceManagerFactory().getProperties()
263                         .getProperty(SpeedoProperties.TM_NAME);
264                 if (tmName == null) {
265                     return new JDOFatalException("No transaction manager jndi name found in initialisation properties");
266                 }
267                 try {
268                     Object JavaDoc o = new InitialContext JavaDoc().lookup(tmName);
269                     if (o == null) {
270                         String JavaDoc msg = "The transaction must be marked as rollbackOnly: JNDI retrieves a null transaction manager for the name '" + tmName + "'.";
271                         logger.log(BasicLevel.ERROR, msg);
272                         return new JDOFatalException(msg);
273                     }
274                     if (!(o instanceof TransactionManager JavaDoc)) {
275                         String JavaDoc msg = "The transaction must be marked as rollbackOnly: JNDI retrieves an object which is not a javax.transaction.TransactionManager (JNDI name: " + tmName + "): " + o;
276                         logger.log(BasicLevel.ERROR, msg);
277                         return new JDOFatalException(msg);
278                     }
279                     javax.transaction.Transaction JavaDoc t = ((TransactionManager JavaDoc) o).getTransaction();
280                     if (t == null) {
281                         String JavaDoc msg = "Impossible to rollback an unexisting transaction (TM.getTransaction()=null)";
282                         logger.log(BasicLevel.ERROR, msg);
283                         return new JDOFatalException(msg);
284                     }
285                     t.setRollbackOnly();
286                 } catch (Exception JavaDoc e) {
287                     String JavaDoc msg = "The transaction must be marked as rollbackOnly: Error when lookup the transaction manager in JNDI with the name '"
288                             + tmName + "'";
289                     logger.log(BasicLevel.ERROR, msg, e);
290                     return new JDOFatalException(msg);
291                 }
292             } else {
293                 rollback();
294             }
295             return new JDOFatalException("The current transaction has been rolledback, please retry", ie);
296         } else {
297             return new JDOFatalException("The current working set occrurs an error, please retry", ie);
298         }
299     }
300
301     public boolean isManagedEnv() {
302         return managedEnv;
303     }
304
305     // IMPLEMENTATION OF THE LifeCycleController INTERFACE //
306
//-----------------------------------------------------//
307

308     public String JavaDoc getFcState() {
309         return null;
310     }
311
312     public void startFc() {
313         managedEnv = pm.getPersistenceManagerFactory().getProperties()
314             .getProperty(SpeedoProperties.MANAGED, "")
315             .equals("true");
316     }
317
318     public void stopFc() {
319     }
320
321     // IMPLEMENTATION OF THE UserBindingController INTERFACE //
322
//-------------------------------------------------------//
323

324     public String JavaDoc[] listFc() {
325         String JavaDoc[] names = super.listFc();
326         String JavaDoc[] itfs = new String JavaDoc[names.length + 3];
327         itfs[0] = PROXY_MANAGER_BINDING;
328         itfs[1] = TRANSACTIONAL_PERSISTENCE_MANAGER_BINDING;
329         itfs[2] = MAPPER_BINDING;
330         System.arraycopy(names, 0, itfs, 3, names.length);
331         return itfs;
332     }
333
334     public Object JavaDoc lookupFc(String JavaDoc c) {
335         if (PROXY_MANAGER_BINDING.equals(c))
336             return pm;
337         else if (TRANSACTIONAL_PERSISTENCE_MANAGER_BINDING.equals(c))
338             return tpm;
339         else if (MAPPER_BINDING.equals(c))
340             return mapper;
341         else
342             return super.lookupFc(c);
343     }
344
345     public void bindFc(String JavaDoc c, Object JavaDoc s) {
346         if (PROXY_MANAGER_BINDING.equals(c))
347             pm = (ProxyManager) s;
348         else if (TRANSACTIONAL_PERSISTENCE_MANAGER_BINDING.equals(c))
349             tpm = (TransactionalPersistenceManager) s;
350         else if (MAPPER_BINDING.equals(c))
351             mapper = (PMapper) s;
352         else if (COMPONENT_BINDING.equals(c)) {
353             try {
354                 thisT = (Transaction) ((Component) s).getFcInterface("transaction");
355             } catch (Exception JavaDoc e) {
356                 throw new JDOFatalInternalException(
357                         "Impossible to get self transaction",
358                         ExceptionHelper.getNested(e));
359             }
360         } else
361             super.bindFc(c, s);
362     }
363
364     public void unbindFc(String JavaDoc c) {
365         if (PROXY_MANAGER_BINDING.equals(c))
366             pm = null;
367         else if (TRANSACTIONAL_PERSISTENCE_MANAGER_BINDING.equals(c))
368             tpm = null;
369         else if (MAPPER_BINDING.equals(c))
370             mapper = null;
371         else
372             super.unbindFc(c);
373     }
374
375     public void setStatus(byte status) throws PersistenceException {
376         try {
377             switch(status) {
378             case TransactionalWorkingSet.CTX_PREPARED:
379                 beforeWSPrepare();
380                 break;
381             case TransactionalWorkingSet.CTX_COMMITTED:
382             case TransactionalWorkingSet.CTX_ABORTED:
383                 onWSEnd();
384                 break;
385             case TransactionalWorkingSet.CTX_CLOSED:
386                 if (oid2state.isEmpty()) {
387                     // close the prefetch buffers associated to the context
388
PrefetchCache pc = mapper.getPrefetchCache();
389                     if (pc != null) {
390                         pc.invalidatePrefetchBuffer(thisT);
391                     }
392                 }
393                 onWSEnd();
394                 break;
395             }
396         } finally {
397             super.setStatus(status);
398         }
399     }
400
401     // IMPLEMENTATION OF THE javax.jdo.Transactionn INTERFACE //
402
//--------------------------------------------------------//
403

404     public void begin() {
405         logger.log(BasicLevel.INFO, "Begin the transaction");
406         try {
407             rollbackOnly = false; //initialize the flag
408
tpm.begin(thisT);
409         } catch (PersistenceException e) {
410             Exception JavaDoc ie = ExceptionHelper.getNested(e);
411             logger.log(BasicLevel.ERROR,
412                     "Error during the begin of the transaction:", ie);
413             throw new JDOException("", ie);
414         }
415         if (txListener != null) {
416             txListener.transactionBegun(this);
417         }
418     }
419
420     public void commit() {
421         int size = oid2state.size();
422         logger.log(BasicLevel.INFO, "Commit the transaction, working set size: " + size);
423         if (synchronization != null) {
424             synchronization.beforeCompletion();
425         }
426         //register working set size for statistics
427
boolean validated = rollbackOnly;
428         try {
429             if (rollbackOnly) {
430                 tpm.rollback(thisT);
431             } else {
432                 tpm.commit(thisT);
433                 validated = true;
434             }
435         } catch (PersistenceException e) {
436             Exception JavaDoc ie = ExceptionHelper.getNested(e);
437             if (ie instanceof JDOException) {
438                 throw (JDOException) ie;
439             } else {
440                 ie = new JDOFatalException(
441                     "Transaction rolledback due to an exception at commit time: ", ie);
442                 logger.log(BasicLevel.INFO, ie.getMessage(), ie);
443                 throw (JDOFatalException) ie;
444             }
445         } finally {
446             if (synchronization != null)
447                 synchronization.afterCompletion((validated
448                         ? Status.STATUS_COMMITTED : Status.STATUS_ROLLEDBACK));
449             if (txListener != null) {
450                 if (validated) {
451                     txListener.transactionCommitted(this, size);
452                 } else {
453                     txListener.transactionAborted(this, size);
454                 }
455             }
456         }
457     }
458
459     public void rollback() {
460         logger.log(BasicLevel.INFO, "Roll back a transaction: ");
461         int size = oid2state.size();
462         try {
463             tpm.rollback(thisT);
464         } catch (PersistenceException e) {
465             Exception JavaDoc ie = ExceptionHelper.getNested(e);
466             logger.log(BasicLevel.ERROR,
467                     "Error during the rollback of the transaction:", ie);
468             throw new JDOException("", ie);
469         } finally {
470             if (txListener != null) {
471                 txListener.transactionAborted(this, size);
472             }
473             if (synchronization != null) {
474                 synchronization.afterCompletion(Status.STATUS_ROLLEDBACK);
475             }
476         }
477     }
478
479     public boolean isActive() {
480         switch(status){
481         case TransactionalWorkingSet.CTX_ACTIVE_TRANSACTIONAL:
482         case TransactionalWorkingSet.CTX_PREPARED:
483         case TransactionalWorkingSet.CTX_PREPARED_OK:
484         case TransactionalWorkingSet.CTX_PREPARED_FAIL:
485             return true;
486         case TransactionalWorkingSet.CTX_ACTIVE:
487         case TransactionalWorkingSet.CTX_COMMITTED:
488         case TransactionalWorkingSet.CTX_ABORTED:
489         case TransactionalWorkingSet.CTX_CLOSED:
490         default:
491             return false;
492         }
493     }
494
495     public void setNontransactionalRead(boolean b) {
496         nontransactionalRead = b;
497     }
498
499     public boolean getNontransactionalRead() {
500         return nontransactionalRead;
501     }
502
503     public void setNontransactionalWrite(boolean b) {
504         nontransactionalWrite = b;
505     }
506
507     public boolean getNontransactionalWrite() {
508         return nontransactionalWrite;
509     }
510
511     public void setRetainValues(boolean b) {
512         setWSRetainValues(b);
513     }
514
515     public boolean getRetainValues() {
516         return getWSRetainValues();
517     }
518
519     public void setRestoreValues(boolean b) {
520         setWSRestoreValues(b);
521     }
522
523     public boolean getRestoreValues() {
524         return getWSRestoreValues();
525     }
526
527     public void setOptimistic(boolean b) {
528         optimistic = b;
529     }
530
531     public boolean getOptimistic() {
532         return optimistic;
533     }
534
535     public void setSynchronization(Synchronization JavaDoc s) {
536         synchronization = s;
537     }
538
539     public Synchronization JavaDoc getSynchronization() {
540         return synchronization;
541     }
542
543     public PersistenceManager getPersistenceManager() {
544         return pm;
545     }
546     
547     public boolean getRollbackOnly() {
548         return rollbackOnly;
549     }
550
551     public void setRollbackOnly() {
552         rollbackOnly = true;
553     }
554 }
555
Popular Tags