KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > perseus > fos > lib > FosTxContext


1 /**
2  * Copyright (C) 2000
3  */

4
5 package org.objectweb.perseus.fos.lib;
6
7 import org.objectweb.perseus.fos.api.FosAccess;
8 import org.objectweb.perseus.fos.api.FosException;
9 import org.objectweb.perseus.fos.api.FosLoggerFactory;
10 import org.objectweb.perseus.fos.api.FosStructure;
11 import org.objectweb.perseus.fos.api.FosTransaction;
12 import org.objectweb.util.monolog.api.BasicLevel;
13 import org.objectweb.util.monolog.api.Logger;
14
15 import java.io.File JavaDoc;
16 import java.io.ObjectInputStream JavaDoc;
17 import java.io.IOException JavaDoc;
18 import java.util.HashMap JavaDoc;
19 import java.util.Iterator JavaDoc;
20 import javax.transaction.xa.Xid JavaDoc;
21
22 /**
23  * @author S. Chassande-Barrioz, P. D?chamboux
24  */

25 public class FosTxContext implements FosTransaction {
26     /**
27      * The logger into which traces about FosTxContext are produced.
28      */

29     private Logger logger;
30     /**
31      * The FosManager associated with this FosTransaction.
32      */

33     private FosTxContextFactory txContextFactory;
34     /**
35      * The Xid associated with this transaction. It is null when executing in
36      * non XA-aware environment.
37      */

38     private Xid JavaDoc xid;
39     /**
40      * The termination status of the FOS transaction. It is true after either
41      * commit or rollback has been executed.
42      */

43     private boolean active;
44     /**
45      * Signals if prepared has been done.
46      */

47     private boolean prepared;
48     /**
49      * Signals if any Object File has been written within this transaction.
50      */

51     private boolean updated;
52     /**
53      * The list of Object File controlers involved in this transaction.
54      */

55     private HashMap JavaDoc fofList;
56     /**
57      *
58      */

59     private FosLogFile logFile;
60
61     /**
62      * Constructs a FosTxContext.
63      * @param el The logger to be used to produced TxContext-related traces.
64      * @param ftcf The factory that has requested the creation of this
65      * FosTxContext.
66      */

67     FosTxContext(Logger el, FosTxContextFactory ftcf) throws FosException {
68         logger = el;
69         txContextFactory = ftcf;
70         xid = null;
71         active = false;
72         prepared = false;
73         updated = false;
74         fofList = null;
75         logFile = null;
76         if (FosLoggerFactory.DEBUG)
77             logger.log(BasicLevel.DEBUG, "Constructs a new FosTxContext.");
78     }
79
80     /**
81      * Delivers the Object File associated with the given id within the given
82      * directory of DbDir.
83      */

84     private synchronized FosObjectFile getOf(String JavaDoc ofn) {
85         FosObjectFile fof = (FosObjectFile) fofList.get(ofn);
86         if (fof == null) {
87             fof = new FosObjectFile(ofn);
88             fofList.put(ofn, fof);
89         }
90         return fof;
91     }
92
93     /**
94      * Specifies if this FOS transaction is active and has been prepared.
95      */

96     boolean isPrepared() {
97         if (FosLoggerFactory.DEBUG)
98             logger.log(BasicLevel.DEBUG, "FOS Transaction "
99                 + (prepared ? "prepared." : "not prepared."));
100         return prepared;
101     }
102
103     /**
104      * Returns the DTP id associated with this FOS transaction.
105      */

106     Xid JavaDoc getXid() {
107         if (FosLoggerFactory.DEBUG)
108             logger.log(BasicLevel.DEBUG, "FOS Transaction DTP id: " + xid);
109         return xid;
110     }
111
112     /**
113      * Recreates the context for managing the recovery at cold restart.
114      * @return The Xid if it is a DTP transaction for which no local decision
115      * can be made wrt to its completion.
116      */

117     Xid JavaDoc recover(String JavaDoc txid) throws FosException {
118         if (FosLoggerFactory.DEBUG)
119             logger.log(BasicLevel.DEBUG, "Recovers transaction: " + txid);
120         logFile = new FosLogFile(txid);
121         try {
122             logFile.recover();
123             xid = logFile.getXid();
124             prepared = logFile.isPrepared();
125             Iterator JavaDoc it = logFile.iterateModifiedOf();
126             FosObjectFile fof;
127             String JavaDoc ofn;
128             while (it.hasNext()) {
129                 ofn = (String JavaDoc) it.next();
130                 if (FosLoggerFactory.DEBUG)
131                     logger.log(BasicLevel.DEBUG, "Recovers ObjectFile: " + ofn);
132                 fof = new FosObjectFile(ofn);
133                 fof.recover();
134                 if (!prepared)
135                     fof.rollback();
136                 else if (xid == null)
137                     fof.commit();
138             }
139             if (prepared && (xid != null)) {
140                 if (FosLoggerFactory.DEBUG)
141                     logger.log(BasicLevel.DEBUG, "DTP - cannot do local decision: " + xid);
142                 return xid;
143             }
144             logFile.completed();
145             return null;
146         } catch (Exception JavaDoc e) {
147             throw new FosException("Cannot recover transaction [nested exception].", e);
148         }
149     }
150
151     // IMPLEMENTATION OF METHODS FROM THE FosTransaction INTERFACE
152

153     /**
154      * Begins a FOS transaction with no DTP context.
155      */

156     public void begin() throws FosException {
157         begin(null);
158     }
159
160     /**
161      * Begins a FOS transaction with a DTP context.
162      * @param xid The DTP identifier associated with this FOS transaction. It
163      * is null if non XA runtime environment.
164      */

165     public void begin(Xid JavaDoc xid) throws FosException {
166         if (FosLoggerFactory.DEBUG)
167             logger.log(BasicLevel.DEBUG, "Begins a FOS transaction - XID: " + xid);
168         txContextFactory.setActiveTX(true);
169         this.xid = xid;
170         active = true;
171         prepared = false;
172         updated = false;
173         fofList = new HashMap JavaDoc();
174         if (xid != null) {
175             try {
176                 logFile = new FosLogFile(txContextFactory.getTxId());
177                 logFile.writeXid(xid);
178             } catch (Exception JavaDoc e) {
179                 throw new FosException("Cannot begin transaction [nested exception].", e);
180             }
181         } else
182             logFile = null;
183     }
184
185     /**
186      * Specifies if this FOS transaction is active or not. true means that
187      * it has begun but it has not been committed or rollbacked yet.
188      */

189     public boolean isActive() {
190         if (FosLoggerFactory.DEBUG)
191             logger.log(BasicLevel.DEBUG, "FOS Transaction "
192                 + (active ? "active." : "inactive."));
193         return active;
194     }
195
196     /**
197      * Prepares a FOS transaction to commit.
198      * @return true if all objects used by this transaction was just read.
199      */

200     public boolean prepare() throws FosException {
201         if (FosLoggerFactory.DEBUG)
202             logger.log(BasicLevel.DEBUG, "Prepares a FOS transaction - XID: " + xid);
203         prepared = true;
204         if (!updated) {
205             if (FosLoggerFactory.DEBUG)
206                 logger.log(BasicLevel.DEBUG, "Read-Only transaction!");
207             return true;
208         }
209         try {
210             if (logFile == null) {
211                 logFile = new FosLogFile(txContextFactory.getTxId());
212                 logFile.writeXid(null);
213             }
214             Iterator JavaDoc it = fofList.values().iterator();
215             while (it.hasNext())
216                 logFile.writeObjectFile(((FosObjectFile) it.next()).isModified());
217             logFile.writeEnd();
218             return false;
219         } catch (Exception JavaDoc e) {
220             throw new FosException("Cannot prepare transaction [nested exception].", e);
221         }
222     }
223
224     /**
225      * Commits a FOS transaction.
226      */

227     public void commit() throws FosException {
228         if (FosLoggerFactory.DEBUG)
229             logger.log(BasicLevel.DEBUG, "Commits a FOS transaction - XID: " + xid);
230         if (!active)
231             throw new FosException("Cannot commit inactive transaction.");
232         if (!prepared)
233             prepare();
234         txContextFactory.setActiveTX(false);
235         try {
236             if (!updated) {
237                 if (FosLoggerFactory.DEBUG)
238                     logger.log(BasicLevel.DEBUG, "Read-Only transaction!");
239             } else {
240                 logFile.completed();
241                 Iterator JavaDoc it = fofList.values().iterator();
242                 while (it.hasNext())
243                     ((FosObjectFile) it.next()).commit();
244             }
245             xid = null;
246             active = false;
247             prepared = false;
248             updated = false;
249             fofList = null;
250             logFile = null;
251         } catch (Exception JavaDoc e) {
252             throw new FosException("Cannot commit transaction [nested exception].", e);
253         }
254     }
255
256     /**
257      * Roolbacks a FOS transaction.
258      */

259     public void rollback() throws FosException {
260         if (FosLoggerFactory.DEBUG)
261             logger.log(BasicLevel.DEBUG, "Rollbacks a FOS transaction - XID: " + xid);
262         if (!active)
263             throw new FosException("Cannot rollback inactive transaction.");
264         txContextFactory.setActiveTX(false);
265         try {
266             if (!updated) {
267                 if (FosLoggerFactory.DEBUG)
268                     logger.log(BasicLevel.DEBUG, "Read-Only transaction!");
269             } else {
270                 if (logFile != null)
271                     logFile.completed();
272                 Iterator JavaDoc it = fofList.values().iterator();
273                 while (it.hasNext())
274                     ((FosObjectFile) it.next()).rollback();
275             }
276             xid = null;
277             active = false;
278             prepared = false;
279             updated = false;
280             fofList = null;
281             logFile = null;
282         } catch (Exception JavaDoc e) {
283             throw new FosException("Cannot rollback transaction [nested exception].", e);
284         }
285     }
286
287     // IMPLEMENTATION OF METHODS FROM THE FosAccess INTERFACE
288

289     /**
290      * Tests if the file associated to a persistent object exists. This file is
291      * specified by the directory under which it is stored under dbDir, and
292      * its name (or id) within this directory.
293      * @param dirof The directory under dbDir where the file should be located.
294      * @param id The name of the file to test (corresponding to the object
295      * identifier).
296      * @return true if the object file exists, else false.
297      */

298     public boolean exist(String JavaDoc dirof, String JavaDoc id) throws FosException {
299         if (FosLoggerFactory.DEBUG)
300             logger.log(BasicLevel.DEBUG, "EXIST operation: dirof=\"" + dirof
301                 + "\", id=\"" + id + "\"");
302         if (prepared || !active)
303             throw new FosException("FOS transaction context not ready to perform operations.");
304         FosObjectFile fof = getOf(txContextFactory.getDbDir() + File.separator
305             + dirof + File.separator + id);
306         if (FosLoggerFactory.DEBUG)
307             logger.log(BasicLevel.DEBUG, "Object " + (fof.exist() ? "exists" : "does not exist"));
308         return fof.exist();
309     }
310
311     /**
312      * Tests if a directory that stores persistent objects exists.
313      * @param dirof The directory under dbDir to test the existence.
314      * @return true if the directory exists, else false.
315      */

316     public boolean existDir(String JavaDoc dirof) throws FosException {
317         return (new File JavaDoc(txContextFactory.getDbDir() + File.separator + dirof)).exists();
318     }
319
320     /**
321      * Reads the content of a persistent object from a file. This file is
322      * specified by the directory under which it is stored under dbDir, and
323      * its name (or id) within this directory. The object that actually reads
324      * the file is also given by the user.
325      * @param dirof The directory under dbDir where the read file is located.
326      * @param id The name of the file to read (corresponding to the object
327      * identifier).
328      * @param fs The user object for actually reading the file.
329      */

330     public void read(String JavaDoc dirof, String JavaDoc id, FosStructure fs, Object JavaDoc ctxt)
331         throws FosException {
332         read(dirof, id, fs, this, ctxt);
333     }
334
335     public void read(String JavaDoc dirof, String JavaDoc id, FosStructure fs,
336                      FosAccess conn, Object JavaDoc ctxt) throws FosException {
337         if (FosLoggerFactory.DEBUG)
338             logger.log(BasicLevel.DEBUG, "READ operation: dirof=\"" + dirof
339                 + "\", id=\"" + id + "\", FosStructure=" + fs);
340         if (prepared || !active)
341             throw new FosException("FOS transaction context not ready to perform operations.");
342         if ((dirof == null) || (id == null) || (fs == null))
343             throw new FosException("Wrong parameters.");
344         FosObjectFile fof = getOf(txContextFactory.getDbDir() + File.separator
345             + dirof + File.separator + id);
346         if (!fof.exist()) {
347             throw new FosException("Cannot read: Data Object does not exist.");
348         }
349         ObjectInputStream JavaDoc ois = null;
350         try {
351             ois = fof.openReader();
352             fs.readFile(ois, conn, ctxt);
353             ois.close();
354             ois = null;
355         } catch (Exception JavaDoc e) {
356             if (ois != null) {
357                 try {
358                     ois.close();
359                 } catch (IOException JavaDoc e2) {
360                 }
361             }
362             throw new FosException("I/O problem [nested exception].", e);
363         }
364     }
365
366     /**
367      * Deletes the file associated with a persistent object. This file is
368      * specified by the directory under which it is stored under dbDir, and
369      * its name (or id) within this directory.
370      * @param dirof The directory under dbDir where the deleted file is
371      * located.
372      * @param id The name of the file to delete (corresponding to the object
373      * identifier).
374      */

375     public void delete(String JavaDoc dirof, String JavaDoc id) throws FosException {
376         if (FosLoggerFactory.DEBUG)
377             logger.log(BasicLevel.DEBUG, "REMOVE operation: dirof=\"" + dirof
378                 + "\", id=\"" + id + "\"");
379         if (prepared || !active)
380             throw new FosException("FOS transaction context not ready to perform operations.");
381         if ((dirof == null) || (id == null))
382             throw new FosException("Wrong parameters.");
383         FosObjectFile fof = getOf(txContextFactory.getDbDir() + File.separator
384             + dirof + File.separator + id);
385         try {
386             if (!fof.exist())
387                 throw new FosException("Cannot remove: Data Object does not exist.");
388             if (FosLoggerFactory.DEBUG)
389                 logger.log(BasicLevel.DEBUG, "Really removes!!");
390             fof.delete();
391             updated = true;
392         } catch (Exception JavaDoc e) {
393             throw new FosException("I/O problem [nested exception].", e);
394         }
395     }
396
397     /**
398      * Deletes a directory that stores persistent objects along with all object
399      * files stored under it.
400      * @param dirof The directory under dbDir to be deleted.
401      */

402     public void deleteDir(String JavaDoc dirof) throws FosException {
403         String JavaDoc dirpath = txContextFactory.getDbDir() + File.separator + dirof;
404         synchronized(txContextFactory) {
405             if (txContextFactory.getNbActiveTX() != 0)
406                 throw new FosException("Cannot perform deleteDir: some TX are still active");
407             if (! existDir(dirof))
408                 throw new FosException("Cannot perform deleteDir: directory does not exist");
409             try {
410                 txContextFactory.deleteDirContent(new File JavaDoc(dirpath));
411             } catch (Exception JavaDoc e) {
412                 throw new FosException("Fails performing deleteDir", e);
413             }
414         }
415     }
416
417     /**
418      * Gets an iterator in order to iterate over the names of the data
419      * object files stored into that sub-directory.
420      * @param dirof The sub-directory from which to scan the data
421      * object file names.
422      * @return The iterator in order to iterate over these names.
423      */

424     public Iterator JavaDoc scan(String JavaDoc dirof) throws FosException {
425         if (FosLoggerFactory.DEBUG)
426             logger.log(BasicLevel.DEBUG, "SCANEXTENSION operation: dirof=\""
427                 + dirof + "\"");
428         if (prepared || !active)
429             throw new FosException("FOS transaction context not ready to perform operations.");
430         if (dirof == null)
431             throw new FosException("Wrong parameters.");
432         return new FosExtension(txContextFactory.getDbDir() + File.separator
433             + dirof);
434     }
435
436     /**
437      * Writes the content of a persistent object to a file. This file is
438      * specified by the directory under which it is stored under dbDir, and
439      * its name (or id) within this directory. The object that actually writes
440      * the file is also given by the user.
441      * @param dirof The directory under dbDir where the written file is
442      * located.
443      * @param id The name of the file to write (corresponding to the object
444      * identifier).
445      * @param fs The user object for actually writing the file.
446      */

447     public void write(String JavaDoc dirof, String JavaDoc id, FosStructure fs, Object JavaDoc ctxt)
448         throws FosException {
449         write(dirof, id, fs, this, ctxt);
450     }
451
452     public void write(String JavaDoc dirof, String JavaDoc id, FosStructure fs,
453                       FosAccess conn, Object JavaDoc ctxt) throws FosException {
454         if (FosLoggerFactory.DEBUG)
455             logger.log(BasicLevel.DEBUG, "WRITE operation: dirof=\"" + dirof
456                 + "\", id=\"" + id + "\", FosStructure=" + fs);
457         if (prepared || !active)
458             throw new FosException("FOS transaction context not ready to perform operations.");
459         if ((dirof == null) || (id == null) || (fs == null))
460             throw new FosException("Wrong parameters.");
461         File JavaDoc od = new File JavaDoc(txContextFactory.getDbDir() + File.separator + dirof);
462         if (!od.exists()) {
463             if (FosLoggerFactory.DEBUG)
464                 logger.log(BasicLevel.DEBUG, "Create ObjectFile DIR: " + od.getPath());
465             od.mkdirs();
466         }
467         FosObjectFile fof = getOf(txContextFactory.getDbDir() + File.separator
468             + dirof + File.separator + id);
469         if (FosLoggerFactory.DEBUG)
470             logger.log(BasicLevel.DEBUG, "FosObjectFile: " + fof);
471         try {
472             fs.writeFile(fof.openWriter(), conn, ctxt);
473             fof.closeWriter();
474             updated = true;
475         } catch (Exception JavaDoc e) {
476             throw new FosException("I/O problem [nested exception].", e);
477         }
478     }
479 }
480
Popular Tags