Source Code Cross Referenced for LockFile.java in  » Database-DBMS » hsql » org » hsqldb » persist » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Database DBMS » hsql » org.hsqldb.persist 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /* Copyright (c) 2001-2005, The HSQL Development Group
002:         * All rights reserved.
003:         *
004:         * Redistribution and use in source and binary forms, with or without
005:         * modification, are permitted provided that the following conditions are met:
006:         *
007:         * Redistributions of source code must retain the above copyright notice, this
008:         * list of conditions and the following disclaimer.
009:         *
010:         * Redistributions in binary form must reproduce the above copyright notice,
011:         * this list of conditions and the following disclaimer in the documentation
012:         * and/or other materials provided with the distribution.
013:         *
014:         * Neither the name of the HSQL Development Group nor the names of its
015:         * contributors may be used to endorse or promote products derived from this
016:         * software without specific prior written permission.
017:         *
018:         * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019:         * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020:         * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021:         * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
022:         * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
023:         * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
024:         * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
025:         * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
026:         * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
027:         * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
028:         * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029:         */
030:
031:        package org.hsqldb.persist;
032:
033:        import java.io.DataInputStream;
034:        import java.io.File;
035:        import java.io.FileInputStream;
036:        import java.io.RandomAccessFile;
037:
038:        import org.hsqldb.DatabaseManager;
039:        import org.hsqldb.HsqlDateTime;
040:        import org.hsqldb.HsqlException;
041:        import org.hsqldb.Trace;
042:        import org.hsqldb.lib.FileUtil;
043:        import org.hsqldb.lib.HsqlTimer;
044:        import org.hsqldb.lib.java.JavaSystem;
045:
046:        /**
047:         * The base HSQLDB cooperative file locking implementation and factory. <p>
048:         *
049:         * <hr>
050:         *
051:         * Here is the way this class operates: <p>
052:         *
053:         * <ol>
054:         * <li>A file with a well-known path relative to each database instance
055:         *     is used to implement cooperative locking of database files across
056:         *     process boundaries (database instances running in different JVM
057:         *     host processes) and class loader contexts (databases whose classes
058:         *     have been loaded by distinct class loaders such that their open
059:         *     database repositories are distinct and are inaccessible across
060:         *     the class loader context boundaries).<p>
061:         *
062:         * <li>A background thread periodically writes a timestamp to this object's
063:         *     lock file at {@link #HEARTBEAT_INTERVAL} millisecond intervals,
064:         *     acting as a heartbeat to indicate that a lock is still held.<p>
065:         *
066:         * <li>The generic lock attempt rules are: <p>
067:         *    <ul>
068:         *    <li>If a lock condition is already held by this object, do nothing and
069:         *        signify that the lock attempt was successful, else...<p>
070:         *
071:         *    <li>If no lock file exists, go ahead and create one, silently issue the
072:         *        {@link java.io.File#deleteOnExit File.deleteOnExit()} directive via
073:         *        refelective method invocation (in order to stay JDK 1.1 compliant),
074:         *        schedule a periodic heartbeat task and signify that the lock attempt
075:         *        was successful, else...<p>
076:         *
077:         *    <li>The lock file must already exist, so try to read its heartbeat
078:         *        timestamp. If the read fails, assume that a lock condition is held by
079:         *        another process or a database in an inaccessible class loader context
080:         *        and signify that the attempt failed, else if the read value
081:         *        is less than <code>HEARTBEAT_INTERVAL</code> milliseconds into the
082:         *        past or futuer, assume that a lock condition is held by another
083:         *        process or a database in an inaccessible class loader context and
084:         *        signify that the lock attempt failed, else assume that the file is
085:         *        not in use, schedule a periodic heartbeat task and signify that the
086:         *        lock attempt was successful.<p>
087:         *
088:         *    </ul>
089:         * <li>The generic release attempt rules are:<p>
090:         *    <ul>
091:         *    <li>If a lock condition is not currently held, do nothing and signify
092:         *        that the release attempt was successful, else...<p>
093:         *
094:         *    <li>A lock condition is currently held, so try to release it.  By
095:         *        default, releasing the lock condition consists of closing and
096:         *        nullifying any objects that have a file descriptor open on the
097:         *        lock file. If the release is successful, cancel the periodic
098:         *        heartbeat task and signify that the release succeeded, else signify
099:         *        that the release attempt failed.<p>
100:         *    </ul>
101:         * </ol> <p>
102:         *
103:         * In addition to the generic lock and release rules, the protected methods
104:         * {@link #lockImpl() lockImpl()} and {@link #releaseImpl() releaseImpl()}
105:         * are called during lock and release attempts, respectively.  This allows
106:         * transparent, JDK 1.1 compliant integration of extended strategies for
107:         * locking and releasing, based on subclassing and reflective construction
108:         * of such specializations in the factory method
109:         * {@link #newLockFile newLockFile()}, determined by information gathered
110:         * at run-time. <p>
111:         *
112:         * In particular, if it is available at runtime, then newLockFile() retrieves
113:         * instances of {@link org.hsqldb.NIOLockFile  NIOLockFile} to capitalize,
114:         * when possible, on the existence of the {@link java.nio.channels.FileLock
115:         * FileLock} class. If the <code>NIOLockFile</code> class does not exist at
116:         * run-time or the java.nio classes it uses are not supported under the
117:         * run-time JVM, then newLockFile() produces vanilla LockFile instances,
118:         * meaning that only purely cooperative locking takes place, as opposed to
119:         * possibly O/S-enforced file locking which, at least in theory, is made
120:         * available through the {@link java.nio.channels} package). However, it
121:         * must be noted that even if a JVM implementation provides the full
122:         * java.nio.channels package, it is not absolutely required to guarantee
123:         * that the underlying platform (the current operating system) provides
124:         * true process-wide file locking. <p>
125:         *
126:         * <b>Note:</b> <p>
127:         *
128:         * The <code>NIOLockFile</code> descendent exists because it has been determined
129:         * though experimenatation that <code>java.nio.channels.FileLock</code>
130:         * does not always exhibit the correct/desired behaviour under reflective
131:         * method invocation. That is, it has been discovered that under some operating
132:         * system/JVM combinations, after calling <code>FileLock.release()</code>
133:         * via a reflective method invocation, the lock is not released properly,
134:         * deletion of the lock file is not possible even from the owning object
135:         * (this) and it is impossible for other <code>LockFile</code> instances
136:         * or any other objects or processes to successfully obtain a lock
137:         * condition on the lock file, despite the fact that the <code>FileLock</code>
138:         * object reports that its lock is invalid (was released successfully).
139:         * Frustratingly, this condition appears to persist until full exit of the
140:         * JVM process in which the <code>FileLock.tryLock()</code> method was
141:         * reflectively invoked. <p>
142:         *
143:         * To solve this, the original <code>LockFile</code> class was split in two and
144:         * instead of reflective method invocation, reflection-based class
145:         * instantiation is now performed at the level of the <code>newLockFile()</code>
146:         * factory method. Similarly, the HSQLDB ANT build script detects the presence
147:         * or abscence of JDK 1.4 features such as java.nio and only attempts to build
148:         * and deploy <code>NIOLockFile</code> to the hsqldb.jar if such features are
149:         * reported present. </p>
150:         *
151:         * @author boucherb@users
152:         * @version 1.7.2
153:         * @since 1.7.2
154:         */
155:        public class LockFile {
156:
157:            /** Canonical reference to this object's lock file. */
158:            protected File f;
159:
160:            /** Cached value of the lock file's canonical path. */
161:            private String cpath = null;
162:
163:            /**
164:             * A RandomAccessFile constructed from this object's reference, f, to its
165:             * lock file. <p>
166:             *
167:             * This RandomAccessFile is used to periodically write out the heartbeat
168:             * timestamp to this object's lock file.
169:             */
170:            protected RandomAccessFile raf;
171:
172:            /**
173:             * The period, in milliseconds, at which heartbeat timestamps are written
174:             * to this object's lock file.
175:             */
176:            public static final long HEARTBEAT_INTERVAL = 10000;
177:
178:            /**
179:             * A magic value to place at the beginning of the lock file to
180:             * differentiate it from other files. The value is "HSQLLOCK".getBytes().
181:             */
182:            public static final byte[] MAGIC = "HSQLLOCK".getBytes();
183:
184:            /** Indicates whether this object has a lock condition on its lock file. */
185:            protected boolean locked;
186:
187:            /**
188:             * The timed scheduler with which to register this object's
189:             * heartbeat task.
190:             */
191:            protected static final HsqlTimer timer = DatabaseManager.getTimer();
192:
193:            /**
194:             * An opaque reference to this object's heatbeat task.
195:             */
196:            private Object timerTask;
197:
198:            /**
199:             * Attempts to read the hearbeat timestamp from this object's lock file
200:             * and compare it with the current time. <p>
201:             *
202:             * An exception is thrown if it must be presumned that another process has
203:             * locked the file, using the following rules: <p>
204:             *
205:             * <ol>
206:             * <li>If the file does not exist, this method returns immediately.
207:             *
208:             * <li>If an exception is raised reading the file, then an exeption is
209:             *     thrown.
210:             *
211:             * <li>If the read is successful and the timestamp read in is less than
212:             *     <code>HEARTBEAT_INTERVAL</code> milliseconds into the past or
213:             *     future, then an exception is thrown.
214:             *
215:             * <li>If no exception is thrown in 2.) or 3.), this method simply returns.
216:             * </ol>
217:             * @throws Exception if it must be presumed that another process
218:             *        or isolated class loader context currently has a
219:             *        lock condition on this object's lock file
220:             */
221:            private void checkHeartbeat() throws Exception {
222:
223:                long lastHeartbeat;
224:                String mn;
225:                String path;
226:
227:                mn = "checkHeartbeat(): ";
228:                path = "lock file [" + cpath + "]";
229:
230:                trace(mn + "entered.");
231:
232:                if (!f.exists()) {
233:                    trace(mn + path + " does not exist. Check OK.");
234:
235:                    return;
236:                }
237:
238:                if (f.length() != 16) {
239:                    trace(mn + path + " length != 16; Check OK.");
240:
241:                    return;
242:                }
243:
244:                try {
245:                    lastHeartbeat = System.currentTimeMillis()
246:                            - readHeartbeat();
247:                } catch (Exception e) {
248:
249:                    // e.printStackTrace();
250:                    throw new Exception(Trace.getMessage(
251:                            Trace.LockFile_checkHeartbeat, true, new Object[] {
252:                                    e.toString(), cpath }));
253:                }
254:
255:                trace(mn + path + " last heartbeat " + lastHeartbeat
256:                        + " ms ago.");
257:
258:                if (Math.abs(lastHeartbeat) < HEARTBEAT_INTERVAL) {
259:                    throw new Exception(Trace.getMessage(
260:                            Trace.LockFile_checkHeartbeat2, true, new Object[] {
261:                                    mn, path }));
262:                }
263:            }
264:
265:            /**
266:             * Closes this object's {@link #raf RandomAccessFile}.
267:             *
268:             * @throws Exception if an IOException occurs
269:             */
270:            private void closeRAF() throws Exception {
271:
272:                String mn;
273:
274:                mn = "closeRAF(): ";
275:
276:                trace(mn + "entered.");
277:
278:                if (raf == null) {
279:                    trace(mn + "raf was null upon entry. Exiting immediately.");
280:                } else {
281:                    trace(mn + "closing " + raf);
282:                    raf.close();
283:                    trace(mn + raf + " closed successfully. Setting raf null");
284:
285:                    raf = null;
286:                }
287:            }
288:
289:            /**
290:             * Initializes this object with the specified <code>File</code>
291:             * object. <p>
292:             *
293:             * The file argument is a reference to this object's lock file. <p>
294:             *
295:             * This action has the effect of attempting to release any existing
296:             * lock condition and reinitializing all lock-related member attributes
297:             * @param file a reference to the file this object is to use as its
298:             *      lock file
299:             */
300:            private void setFile(File file) throws Exception {
301:
302:                if (isLocked()) {
303:                    try {
304:                        tryRelease();
305:                    } catch (Exception e) {
306:                        trace(e);
307:                    }
308:                }
309:
310:                f = FileUtil.canonicalFile(file);
311:                cpath = f.getPath();
312:                raf = null;
313:                locked = false;
314:            }
315:
316:            /**
317:             * Provides any specialized locking actions for the
318:             * {@link #tryLock() tryLock()} method. <p>
319:             *
320:             * Descendents are free to provide additional functionality here,
321:             * using the following rules:
322:             *
323:             * <pre>
324:             * PRE:
325:             *
326:             * This method is only called if tryLock() thinks it needs to get a lock
327:             * condition, so it can be assumed the locked == false upon entry, raf is
328:             * a non-null instance that can be used to get a FileChannel if desired,
329:             * and the lock file is, at the very least, readable.  Further, this
330:             * object's heatbeat task is definitely cancelled and/or has not yet been
331:             * scheduled, so whatever timestamp is recorded in the lock file, if it
332:             * exists, is what was written by a previous locker, if any.  A timestamp
333:             * value in a preexisting file is only considered valid if the file is
334:             * of the correct length and its first eight bytes are
335:             * the value {@link #MAGIC MAGIC}.
336:             *
337:             * POST:
338:             *
339:             * This method must return false if any additional locking work fails,
340:             * else true.
341:             * </pre>
342:             *
343:             * The default implementation of this method reflectively (for JDK1.1
344:             * compliance) invokes f.deleteOnExit() in a silent manner and always
345:             * returns true. <p>
346:             *
347:             * @throws Exception if a situation is encountered that absolutely
348:             *        prevents the status of the lock condtion
349:             *        to be determined. (e.g. an IO exception
350:             *        occurs here)
351:             * @return <code>true</code> if no extended locking
352:             *        actions are taken or the actions succeed,
353:             *        else <code>false</code>.
354:             */
355:            protected boolean lockImpl() throws Exception {
356:
357:                String mn;
358:
359:                mn = "lockImpl(): ";
360:
361:                trace(mn + "entered.");
362:                FileUtil.deleteOnExit(f);
363:
364:                return true;
365:            }
366:
367:            /**
368:             * Opens this object's {@link #raf RandomAccessFile}. <p>
369:             *
370:             * @throws Exception if an IOException occurs
371:             */
372:            private void openRAF() throws Exception {
373:
374:                trace("openRAF(): entered.");
375:
376:                raf = new RandomAccessFile(f, "rw");
377:
378:                trace("openRAF(): got new 'rw' mode " + raf);
379:            }
380:
381:            /**
382:             * Retrieves the last written hearbeat timestamp from
383:             * this object's lock file.  If this object's lock file
384:             * does not exist, <code>Long.MIN_VALUE</code> (the earliest
385:             * time representable as a long in Java) is retrieved. <p>
386:             *
387:             * @throws Exception if an error occurs while reading the hearbeat
388:             *      timestamp from this object's lock file.
389:             * @return the hearbeat timestamp from this object's lock file,
390:             *      as a <code>long</code> value or, if this object's lock
391:             *      file does not exist, Long.MIN_VALUE, the earliest time
392:             *      representable as a long in Java,
393:             */
394:            private long readHeartbeat() throws Exception {
395:
396:                DataInputStream dis;
397:                long heartbeat;
398:
399:                heartbeat = Long.MIN_VALUE;
400:
401:                String mn = "readHeartbeat(): ";
402:                String path = "lock file [" + cpath + "]";
403:
404:                trace(mn + "entered.");
405:
406:                if (!f.exists()) {
407:                    trace(mn + path + " does not exist. Return  '" + heartbeat
408:                            + "'");
409:
410:                    return heartbeat;
411:                }
412:
413:                dis = new DataInputStream(new FileInputStream(f));
414:
415:                trace(mn + " got new " + dis);
416:
417:                for (int i = 0; i < MAGIC.length; i++) {
418:                    if (MAGIC[i] != dis.readByte()) {
419:                        trace(mn + path + " is not lock file. Return '"
420:                                + heartbeat + "'");
421:
422:                        return heartbeat;
423:                    }
424:                }
425:
426:                heartbeat = dis.readLong();
427:
428:                trace(mn + " read:  ["
429:                        + HsqlDateTime.getTimestampString(heartbeat) + "]");
430:                dis.close();
431:                trace(mn + " closed " + dis);
432:
433:                return heartbeat;
434:            }
435:
436:            /**
437:             * Provides any specialized release actions for the tryRelease()
438:             * method. <p>
439:             *
440:             * @return true if there are no specialized release
441:             *        actions performed or they succeed,
442:             *        else false
443:             * @throws Exception if a situation is encountered that absolutely
444:             *        prevents the status of the lock condtion
445:             *        to be determined. (e.g. an IO exception
446:             *        occurs here).
447:             */
448:            protected boolean releaseImpl() throws Exception {
449:
450:                trace("releaseImpl(): no action: returning true");
451:
452:                return true;
453:            }
454:
455:            /** Schedules the lock heartbeat task. */
456:            private void startHeartbeat() {
457:
458:                Runnable r;
459:
460:                trace("startHeartbeat(): entered.");
461:
462:                if (timerTask == null || HsqlTimer.isCancelled(timerTask)) {
463:                    r = new HeartbeatRunner();
464:
465:                    // now, periodic at HEARTBEAT_INTERVAL, running this, fixed rate
466:                    timerTask = timer.schedulePeriodicallyAfter(0,
467:                            HEARTBEAT_INTERVAL, r, true);
468:
469:                    trace("startHeartbeat(): heartbeat task scheduled.");
470:                }
471:
472:                trace("startHeartbeat(): exited.");
473:            }
474:
475:            /** Cancels the lock heartbeat task. */
476:            private void stopHeartbeat() {
477:
478:                String mn = "stopHeartbeat(): ";
479:
480:                trace(mn + "entered");
481:
482:                if (timerTask != null && !HsqlTimer.isCancelled(timerTask)) {
483:                    HsqlTimer.cancel(timerTask);
484:
485:                    timerTask = null;
486:                }
487:
488:                trace(mn + "exited");
489:            }
490:
491:            /**
492:             * Writes a magic value to this object's lock file that distiguishes
493:             * it as an HSQLDB lock file.
494:             *
495:             * @throws Exception if the magic value cannot be written to
496:             *      the lock file
497:             */
498:            private void writeMagic() throws Exception {
499:
500:                String mn = "writeMagic(): ";
501:                String path = "lock file [" + cpath + "]";
502:
503:                trace(mn + "entered.");
504:                trace(mn + "raf.seek(0)");
505:                raf.seek(0);
506:                trace(mn + "raf.write(byte[])");
507:                raf.write(MAGIC);
508:                trace(mn + "wrote [\"HSQLLOCK\".getBytes()] to " + path);
509:            }
510:
511:            /**
512:             * Writes the current hearbeat timestamp value to this
513:             * object's lock file. <p>
514:             *
515:             * @throws Exception if the current heartbeat timestamp value
516:             *      cannot be written
517:             */
518:            private void writeHeartbeat() throws Exception {
519:
520:                long time;
521:                String mn = "writeHeartbeat(): ";
522:                String path = "lock file [" + cpath + "]";
523:
524:                trace(mn + "entered.");
525:
526:                time = System.currentTimeMillis();
527:
528:                trace(mn + "raf.seek(" + MAGIC.length + ")");
529:                raf.seek(MAGIC.length);
530:                trace(mn + "raf.writeLong(" + time + ")");
531:                raf.writeLong(time);
532:                trace(mn + "wrote [" + time + "] to " + path);
533:            }
534:
535:            /**
536:             * Retrieves a <code>LockFile</code> instance, initialized with a
537:             * <code>File</code> object whose path is the one specified by
538:             * the <code>path</code> argument. <p>
539:             *
540:             * @return a <code>LockFile</code> instance initialized with a
541:             *        <code>File</code> object whose path is the one specified
542:             *        by the <code>path</code> argument.
543:             * @param path the path of the <code>File</code> object with
544:             *        which the retrieved <code>LockFile</code>
545:             *        object is to be initialized
546:             */
547:            public static LockFile newLockFile(String path) throws Exception {
548:
549:                File f;
550:                LockFile lf;
551:                Class c;
552:
553:                c = null;
554:
555:                try {
556:                    Class.forName("java.nio.channels.FileLock");
557:
558:                    c = Class.forName("org.hsqldb.persist.NIOLockFile");
559:                    lf = (LockFile) c.newInstance();
560:                } catch (Exception e) {
561:                    lf = new LockFile();
562:                }
563:
564:                f = new File(path);
565:
566:                FileUtil.makeParentDirectories(f);
567:                lf.setFile(f);
568:
569:                return lf;
570:            }
571:
572:            public static LockFile newLockFileLock(String path)
573:                    throws HsqlException {
574:
575:                LockFile lf = null;
576:
577:                try {
578:                    lf = LockFile.newLockFile(path + ".lck");
579:                } catch (Exception e) {
580:                    throw Trace.error(Trace.FILE_IO_ERROR, e.toString());
581:                }
582:
583:                boolean locked = false;
584:                String msg = "";
585:
586:                try {
587:                    locked = lf.tryLock();
588:                } catch (Exception e) {
589:
590:                    // e.printStackTrace();
591:                    msg = e.toString();
592:                }
593:
594:                if (!locked) {
595:                    throw Trace.error(Trace.DATABASE_ALREADY_IN_USE, lf + ": "
596:                            + msg);
597:                }
598:
599:                return lf;
600:            }
601:
602:            /**
603:             * Tests whether some other object is "equal to" this one.
604:             *
605:             * An object is considered equal to a <code>LockFile</code> object iff it
606:             * is not null, it is an instance of <code>LockFile</code> and either it's
607:             * the identical instance or it has the same lock file.  More  formally,
608:             * is is considered equal iff it is not null, it is an instance of
609:             * <code>LockFile</code>, and the expression: <p>
610:             *
611:             * <pre>
612:             * this == other ||
613:             * this.f == null ? other.f == null : this.f.equals(other.f);
614:             * </pre>
615:             *
616:             * yeilds true. <p>
617:             *
618:             * @param obj the reference object with which to compare.
619:             * @return <code>true</code> if this object is equal to
620:             *        the <code>obj</code> argument;
621:             *        <code>false</code> otherwise.
622:             * @see #hashCode
623:             */
624:            public boolean equals(Object obj) {
625:
626:                // do faster tests first
627:                if (this  == obj) {
628:                    return true;
629:                } else if (obj instanceof  LockFile) {
630:                    LockFile that = (LockFile) obj;
631:
632:                    return (f == null) ? that.f == null : f.equals(that.f);
633:                } else {
634:                    return false;
635:                }
636:            }
637:
638:            /**
639:             * Retrieves, as a String, the canonical path of this object's lock file.
640:             *
641:             * @return the canonical path of this object's lock file.
642:             */
643:            public String getCanonicalPath() {
644:                return cpath;
645:            }
646:
647:            /**
648:             * Retrieves the hash code value for this object.
649:             *
650:             * The value is zero if the <code>File</code> object attribute
651:             * <code>f</code> is <code>null</code>, else it is the <code>hashCode</code>
652:             * of <code>f</code>. That is, two <code>LockFile</code>
653:             * objects have the same <code>hashCode</code> value if they have the
654:             * same lock file. <p>
655:             *
656:             * @return a hash code value for this object.
657:             * @see #equals(java.lang.Object)
658:             */
659:            public int hashCode() {
660:                return f == null ? 0 : f.hashCode();
661:            }
662:
663:            /**
664:             * Retrieves whether this object has successfully obtained and is
665:             * still currently holding (has not yet released) a cooperative
666:             * lock condition on its lock file. <p>
667:             *
668:             * <b>Note:</b>  Due to the retrictions placed on the JVM by
669:             * platform-independence, it is very possible to successfully
670:             * obtain and hold a cooperative lock on a lock file and yet for
671:             * the lock to become invalid while held. <p>
672:             *
673:             * For instance, under JVMs with no <code>java.nio</code> package or
674:             * operating systems that cannot live up to the contracts set forth for
675:             * {@link java.nio.channels.FileLock FileLock}, it is quite possible
676:             * for another process or even an uncooperative bit of code running
677:             * in the same JVM to delete or overwrite the lock file while
678:             * this object holds a lock on it. <p>
679:             *
680:             * Because of this, the isValid() method is provided in the public
681:             * interface in order to allow clients to detect such situations. <p>
682:             *
683:             * @return true iff this object has successfully obtained
684:             *        and is currently holding (has not yet released)
685:             *        a lock on its lock file
686:             * @see #isValid
687:             */
688:            public boolean isLocked() {
689:                return locked;
690:            }
691:
692:            /**
693:             * Retrieves whether there is potentially already a cooperative lock,
694:             * operating system lock or some other situation preventing
695:             * a cooperative lock condition from being aquired, relative to the
696:             * specified path.
697:             *
698:             * @param path the path to test
699:             */
700:            public static boolean isLocked(String path) {
701:
702:                FileInputStream fis = null;
703:
704:                try {
705:                    LockFile lf = LockFile.newLockFile(path);
706:
707:                    lf.checkHeartbeat();
708:
709:                    if (lf.f.exists() && lf.f.isFile()) {
710:                        fis = new FileInputStream(lf.f);
711:
712:                        fis.read();
713:                    }
714:
715:                    return false;
716:                } catch (Exception e) {
717:                } finally {
718:                    if (fis != null) {
719:                        try {
720:                            fis.close();
721:                        } catch (java.io.IOException e) {
722:                        }
723:                    }
724:                }
725:
726:                return true;
727:            }
728:
729:            /**
730:             * Retrieves whether this object holds a valid lock on its lock file. <p>
731:             *
732:             * More formally, this method retrieves true iff: <p>
733:             *
734:             * <pre>
735:             * isLocked() &&
736:             * f != null &&
737:             * f.exists() &&
738:             * raf != null
739:             * </pre>
740:             *
741:             * @return true iff this object holds a valid lock on its
742:             *        lock file.
743:             */
744:            public boolean isValid() {
745:                return isLocked() && f != null && f.exists() && raf != null;
746:            }
747:
748:            /**
749:             * For internal use only. <p>
750:             *
751:             * This Runnable class provides the implementation for the timed task
752:             * that periodically writes out a heartbeat timestamp to the lock file.<p>
753:             */
754:            protected class HeartbeatRunner implements  Runnable {
755:
756:                public void run() {
757:
758:                    try {
759:                        trace("HeartbeatRunner.run(): writeHeartbeat()");
760:                        writeHeartbeat();
761:                    } catch (Throwable t) {
762:                        trace("HeartbeatRunner.run(): caught Throwable: " + t);
763:                    }
764:                }
765:            }
766:
767:            /**
768:             * Retrieves a String representation of this object. <p>
769:             *
770:             * The String is of the form: <p>
771:             *
772:             * <pre>
773:             * super.toString() +
774:             * "[file=" + getAbsolutePath() +
775:             * ", exists=" + f.exists() +
776:             * ", locked=" + isLocked() +
777:             * ", valid=" + isValid() +
778:             * ", " + toStringImpl() +
779:             * "]";
780:             * </pre>
781:             * @return a String representation of this object.
782:             * @see #toStringImpl
783:             */
784:            public String toString() {
785:
786:                return super .toString() + "[file =" + cpath + ", exists="
787:                        + f.exists() + ", locked=" + isLocked() + ", valid="
788:                        + isValid() + ", " + toStringImpl() + "]";
789:            }
790:
791:            /**
792:             * Retrieves an implementation-specific tail value for the
793:             * toString() method. <p>
794:             *
795:             * The default implementation returns the empty string.
796:             * @return an implementation-specific tail value for the toString() method
797:             * @see #toString
798:             */
799:            protected String toStringImpl() {
800:                return "";
801:            }
802:
803:            /**
804:             * Attempts, if not already held, to obtain a cooperative lock condition
805:             * on this object's lock file. <p>
806:             *
807:             * @throws Exception if an error occurs that absolutely prevents the lock
808:             *        status of the lock condition from being determined
809:             *        (e.g. an unhandled file I/O error).
810:             * @return <code>true</code> if this object already holds a lock or
811:             *        the lock was obtained successfully, else
812:             *        <code>false</code>
813:             */
814:            public boolean tryLock() throws Exception {
815:
816:                String mn = "tryLock(): ";
817:
818:                trace(mn + "entered.");
819:
820:                if (locked) {
821:                    trace(mn
822:                            + " lock already held. Returning true immediately.");
823:
824:                    return true;
825:                }
826:
827:                checkHeartbeat();
828:
829:                // Alternatively, we could give ourselves a second try,
830:                // raising our chances of success in the rare case that the
831:                // last locker terminiated abruptly just less than
832:                // HEARTBEAT_INTERVAL ago.
833:                //
834:                //        try {
835:                //            checkHeartbeat();
836:                //        } catch (Exception e) {
837:                //            try {
838:                //                Thread.sleep(HEARTBEAT_INTERVAL);
839:                //            } catch (Exception e2) {}
840:                //            checkHeartbeat();
841:                //        }
842:                openRAF();
843:
844:                locked = lockImpl();
845:
846:                if (locked) {
847:                    writeMagic();
848:                    startHeartbeat();
849:
850:                    try {
851:
852:                        // attempt to ensure that tryRelease() gets called if/when
853:                        // the VM shuts down, just in case this object has not yet
854:                        // been garbage-collected or explicitly released.
855:                        JavaSystem.runFinalizers();
856:                        trace(mn
857:                                + "success for System.runFinalizersOnExit(true)");
858:                    } catch (Exception e) {
859:                        trace(mn + e.toString());
860:                    }
861:                } else {
862:                    try {
863:                        releaseImpl();
864:                        closeRAF();
865:                    } catch (Exception e) {
866:                        trace(mn + e.toString());
867:                    }
868:                }
869:
870:                trace(mn + "ran to completion.  Returning " + locked);
871:
872:                return locked;
873:            }
874:
875:            /**
876:             * Attempts to release any cooperative lock condition this object
877:             * may have on its lock file. <p>
878:             *
879:             * @throws Exception if an error occurs that absolutely prevents
880:             *       the status of the lock condition from
881:             *       being determined (e.g. an unhandled file
882:             *       I/O exception).
883:             * @return <code>true</code> if this object does not hold a
884:             *        lock or the lock is released successfully,
885:             *        else <code>false</code>.
886:             */
887:            public boolean tryRelease() throws Exception {
888:
889:                String mn = "tryRelease(): ";
890:                String path;
891:
892:                trace(mn + "entered.");
893:
894:                boolean released = !locked;
895:
896:                if (released) {
897:                    trace(mn + "No lock held. Returning true immediately");
898:
899:                    return true;
900:                }
901:
902:                try {
903:                    released = releaseImpl();
904:                } catch (Exception e) {
905:                    trace(mn + e);
906:                }
907:
908:                if (!released) {
909:                    trace(mn
910:                            + "releaseImpl() failed. Returning false immediately.");
911:
912:                    return false;
913:                }
914:
915:                trace(mn + "releaseImpl() succeeded.");
916:                stopHeartbeat();
917:                closeRAF();
918:
919:                // without a small delay, the following delete may occasionally fail
920:                // and return false on some systems, when really it should succeed
921:                // and return true.
922:                trace(mn + "Starting Thread.sleep(100).");
923:
924:                try {
925:                    Thread.sleep(100);
926:                } catch (Exception e) {
927:                    trace(mn + e.toString());
928:                }
929:
930:                trace(mn + "Finished Thread.sleep(100).");
931:
932:                path = "[" + cpath + "]";
933:
934:                if (f.exists()) {
935:                    trace(mn + path + " exists.");
936:
937:                    released = f.delete();
938:
939:                    trace(mn + path + (released ? "" : "not") + " deleted.");
940:
941:                    if (f.exists()) {
942:                        trace(mn + " WARNING!: " + path + "still exists.");
943:                    }
944:                }
945:
946:                locked = !released;
947:
948:                trace(mn + "ran to completion.  Returning " + released);
949:
950:                return released;
951:            }
952:
953:            /**
954:             * Prints tracing information and the value of the specified object
955:             *
956:             * @param o the value to print
957:             */
958:            protected void trace(Object o) {
959:
960:                if (Trace.TRACE) {
961:                    Trace.printSystemOut("[" + super .toString() + "]: " + o);
962:                }
963:            }
964:
965:            /**
966:             * Attempts to release any lock condition this object may have on its
967:             * lock file. <p>
968:             *
969:             * @throws Throwable if this object encounters an unhandled exception
970:             *        trying to release the lock condition,
971:             *        if any, that it has on its lock file.
972:             */
973:            protected void finalize() throws Throwable {
974:                trace("finalize(): calling tryRelease()");
975:                tryRelease();
976:            }
977:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.