Source Code Cross Referenced for DocumentCache.java in  » IDE » DrJava » edu » rice » cs » drjava » model » cache » 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 » IDE » DrJava » edu.rice.cs.drjava.model.cache 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*BEGIN_COPYRIGHT_BLOCK
002:         *
003:         * Copyright (c) 2001-2007, JavaPLT group at Rice University (javaplt@rice.edu)
004:         * All rights reserved.
005:         * 
006:         * Redistribution and use in source and binary forms, with or without
007:         * modification, are permitted provided that the following conditions are met:
008:         *    * Redistributions of source code must retain the above copyright
009:         *      notice, this list of conditions and the following disclaimer.
010:         *    * Redistributions in binary form must reproduce the above copyright
011:         *      notice, this list of conditions and the following disclaimer in the
012:         *      documentation and/or other materials provided with the distribution.
013:         *    * Neither the names of DrJava, the JavaPLT group, Rice University, nor the
014:         *      names of its contributors may be used to endorse or promote products
015:         *      derived from this software without specific prior written permission.
016:         * 
017:         * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
018:         * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
019:         * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
020:         * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
021:         * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
022:         * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
023:         * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
024:         * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
025:         * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
026:         * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
027:         * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
028:         *
029:         * This software is Open Source Initiative approved Open Source Software.
030:         * Open Source Initative Approved is a trademark of the Open Source Initiative.
031:         * 
032:         * This file is part of DrJava.  Download the current version of this project
033:         * from http://www.drjava.org/ or http://sourceforge.net/projects/drjava/
034:         * 
035:         * END_COPYRIGHT_BLOCK*/
036:
037:        package edu.rice.cs.drjava.model.cache;
038:
039:        import javax.swing.event.DocumentListener;
040:        import javax.swing.text.BadLocationException;
041:        import java.util.*;
042:        import java.io.IOException;
043:
044:        import edu.rice.cs.drjava.model.definitions.DefinitionsDocument;
045:        import edu.rice.cs.drjava.model.OpenDefinitionsDocument;
046:        import edu.rice.cs.drjava.model.FileMovedException;
047:
048:        import edu.rice.cs.util.Log;
049:        import edu.rice.cs.util.UnexpectedException;
050:        import edu.rice.cs.util.swing.Utilities;
051:        import edu.rice.cs.util.OrderedHashSet;
052:
053:        /** The document cache is a structure that maps OpenDefinitionsDocuments to DefinitionsDocuments (which contain
054:         *  the actual document text).  Since the latter can consume a lot of memory, the cache virtualizes some of them
055:         *  using DefinitionsDocument reconstructors (DDReconstructor).  It tries to limit the number of 
056:         *  DefinitionsDocuments loaded in memory at one time, but it must of course retain all modified 
057:         *  DefinitionsDocuments.
058:         *  <p>
059:         *  The cache creates a DocManager for each OpenDefinitionsDocument entered (registered) in the cache. The managers
060:         *  maintain the actual links to DefinitionsDocuments. Since the Managers themselves implement the DCacheAdapter 
061:         *  interface, the model goes directly to the manager to get the instance of the DefinitionsDocument.
062:         *  <p>
063:         *  When a document is accessed through the document manager by the model, the cache informs the manager, which 
064:         *  tells the active queue to add the manager to the end of the queue--if it isn't already in the queue.  If the
065:         *  active queue had already reached maximum size, it deletes the last document in the queue to keep the queue from
066:         *  growing larger than its maximum size.
067:         *  <p>
068:         *  The resident queue only contains documents that have not been modified since their last save (except in the process
069:         *  of responding to notification that a document has been modified).  When a document is modified for the first time, 
070:         *  it is immediately removed from the resident queue and marked as UNMANAGED by its document manager.  An
071:         *  UNMANAGED document remains in memory until it is saved or closed without being saved.  If such a document is
072:         *  saved, it is inserted again in the resident queue.
073:         *  <p>
074:         *  Since the cache and document managers can both be concurrently accessed from multiple threads, the methods in the
075:         *  DocumentCache and DocManager classes are synchronized.  Some operations require locks on both the cache and a
076:         *  document manager, but the code is written so that none of require these locks to be held simultaneously.
077:         */
078:
079:        public class DocumentCache {
080:
081:            /** Log file. */
082:            private static final Log _log = new Log("DocumentCache.txt", false);
083:
084:            private static final int INIT_CACHE_SIZE = 32;
085:
086:            /** @invariant _residentQueue.size() <= CACHE_SIZE */
087:            private int CACHE_SIZE;
088:
089:            private OrderedHashSet<DocManager> _residentQueue;
090:
091:            private Object _cacheLock = new Object();
092:
093:            /* General constructor.  Not currently used except when called by default constructor. */
094:            public DocumentCache(int size) {
095:                //    Utilities.showDebug("DocumentCache created with size = " + size);
096:                CACHE_SIZE = size;
097:                _residentQueue = new OrderedHashSet<DocManager>();
098:            }
099:
100:            /* Default constructor; uses default cache size. */
101:            public DocumentCache() {
102:                this (INIT_CACHE_SIZE);
103:            }
104:
105:            /** Returns a cache adapter corresponding to the owner of the given reconstructor.
106:             *  @param odd The open definitions document that is registering.  (Useful for debugging purposes.)
107:             *  @param rec A reconstructor from which to create the document that is to be managed in this cache
108:             *  @return an adapter that allows its owner to access its definitions document
109:             */
110:            public DCacheAdapter register(OpenDefinitionsDocument odd,
111:                    DDReconstructor rec) {
112:                DocManager mgr = new DocManager(rec, odd.isUntitled());
113:                notifyRegistrationListeners(odd, mgr); // runs synchronously; only used in tests
114:                //    System.err.println("register(" + odd + ", " + rec + ") called");
115:                return mgr;
116:            }
117:
118:            /** Changes the number of <b>unmodified</b> documents allowed in the cache at one time. <b> Note: modified documents 
119:             * are not managed in the cache except in transitional situations when a queue document becomes modified.  Only
120:             * used in tests.
121:             */
122:            public void setCacheSize(int size) {
123:                if (size <= 0)
124:                    throw new IllegalArgumentException(
125:                            "Cannot set the cache size to zero or less.");
126:                int diff;
127:                DocManager[] removed = null; // bogus initialization makes javac happy
128:                synchronized (_cacheLock) { // lock the cache so entries can be removed if necessary
129:                    CACHE_SIZE = size;
130:                    diff = _residentQueue.size() - CACHE_SIZE;
131:                    if (diff > 0) {
132:                        removed = new DocManager[diff];
133:                        for (int i = 0; i < diff; i++)
134:                            removed[i] = _residentQueue.remove(0);
135:                    }
136:                    if (diff > 0)
137:                        kickOut(removed);
138:                }
139:            }
140:
141:            /** Kicks out all documents in removed.  Assumes that _cacheLock is already held. */
142:            private void kickOut(DocManager[] removed) {
143:                for (DocManager dm : removed)
144:                    dm.kickOut();
145:            }
146:
147:            public int getCacheSize() {
148:                return CACHE_SIZE;
149:            }
150:
151:            public int getNumInCache() {
152:                return _residentQueue.size();
153:            }
154:
155:            public String toString() {
156:                return _residentQueue.toString();
157:            }
158:
159:            ///////////////////////////// DocManager //////////////////////////
160:
161:            private static final int IN_QUEUE = 0; // In the resident queue and hence subject to virtualization
162:            private static final int UNTITLED = 1; // An untitled document not in queue (may or may not be modified)
163:            private static final int NOT_IN_QUEUE = 2; // Virtualized and not in the QUEUE
164:            private static final int UNMANAGED = 3; // A modified, titled document not in the queue
165:
166:            /** Note: before extending this table, check that the extension does not conflict with isUnmangedOrUntitled() */
167:
168:            /** Manages the retrieval of a document for a corresponding open definitions document.  This manager only 
169:             *  maintains its document data if it contained in _residentQueue, which is maintained using a round-robin
170:             *  replacement scheme.
171:             */
172:            private class DocManager implements  DCacheAdapter {
173:
174:                private final DDReconstructor _rec;
175:                private volatile int _stat; // I know, this is not very OO
176:                private volatile DefinitionsDocument _doc;
177:
178:                /** Instantiates a manager for the documents that are produced by the given document reconstructor.
179:                 *  @param rec The reconstructor used to create the document
180:                 */
181:                public DocManager(DDReconstructor rec, boolean isUntitled) {
182:                    //      Utilities.showDebug("DocManager(" + rec + ", " + fn + ", " + isUntitled + ")");
183:                    _rec = rec;
184:                    if (isUntitled)
185:                        _stat = UNTITLED;
186:                    else
187:                        _stat = NOT_IN_QUEUE;
188:                    _doc = null;
189:                    //      System.err.println(this + " constructed");
190:                }
191:
192:                /** Adds DocumentListener to the reconstructor. */
193:                public void addDocumentListener(DocumentListener l) {
194:                    _rec.addDocumentListener(l);
195:                }
196:
197:                /** Makes this document; assumes that cacheLock is already held. */
198:                private DefinitionsDocument makeDocument() {
199:                    try { // _doc is not in memory
200:                        _doc = _rec.make();
201:                        assert _doc != null;
202:                    } catch (Exception e) {
203:                        throw new UnexpectedException(e);
204:                    }
205:                    //        Utilities.showDebug("Document " + _doc + " reconstructed; _stat = " + _stat);
206:                    //      System.err.println("Making document for " + this);
207:                    if (_stat == NOT_IN_QUEUE)
208:                        add(); // add this to queue 
209:                    return _doc;
210:                }
211:
212:                /** Gets the physical document (DD) for this manager.  If DD is not in memory, it loads it from its image in its
213:                 * DDReconstructor and returns it.  If the document has been modified in memory since it was last fetched, make 
214:                 * it "unmanaged", removing it from the queue.  It will remain in memory until saved.  If a document is not in 
215:                 * the queue, add it.
216:                 *  @return the physical document that is managed by this adapter
217:                 */
218:                public DefinitionsDocument getDocument() throws IOException,
219:                        FileMovedException {
220:                    //      Utilities.showDebug("getDocument called on " + this + " with _stat = " + _stat);
221:
222:                    //      The following double-check idiom is safe in Java 1.4 and later JVMs provided that _doc is volatile.
223:                    final DefinitionsDocument doc = _doc; // create a snapshot of _doc
224:                    if (doc != null)
225:                        return doc;
226:                    synchronized (_cacheLock) { // lock the cache so that this DocManager's state can be updated
227:                        if (_doc != null)
228:                            return _doc; // _doc may have changed since test outside of _cacheLock
229:                        return makeDocument();
230:                    }
231:                }
232:
233:                /** Gets the length of this document using (i) cached _doc or (ii) reconstructor (which may force the document
234:                 * to be loaded. */
235:                public int getLength() {
236:                    final DefinitionsDocument doc = _doc; // create a snapshot of _doc
237:                    if (doc != null)
238:                        return doc.getLength();
239:                    return _rec.getText().length(); // There is a technical race here; _doc could be set and modified before here
240:                }
241:
242:                /** Gets the text of this document using in order of preference (i) cached _doc; (ii) cached reconstructor _image; 
243:                 * and (iii) the document after forcing it to be loaded. */
244:                public String getText() {
245:                    final DefinitionsDocument doc = _doc; // create a snapshot of _doc
246:                    if (doc != null)
247:                        return doc.getText();
248:                    return _rec.getText(); // There is a technical race here; _doc could be set and modified before here
249:                }
250:
251:                /* Gets the specified substring of this document; throws an exception if the specification is ill-formed. */
252:                public String getText(int offset, int len) {
253:                    String text = getText();
254:                    //      _log.log("getText(" + offset + ", " + len + ") called on '" + text + "' which has " + text.length() + " chars");
255:                    return text.substring(offset, offset + len);
256:                }
257:
258:                /** Checks whether the document is resident (in the cache or modified). 
259:                 *  @return if the document is resident.
260:                 */
261:                public boolean isReady() {
262:                    return _doc != null;
263:                } // _doc is volatile so synchronization is unnecessary
264:
265:                /** Closes the corresponding document for this adapter.  Done when a document is closed by the navigator. */
266:                public void close() {
267:                    //      Utilities.showDebug("close() called on " + this);
268:                    synchronized (_cacheLock) {
269:                        _residentQueue.remove(this );
270:                        closingKickOut();
271:                    }
272:                }
273:
274:                public void documentModified() {
275:                    synchronized (_cacheLock) {
276:                        _residentQueue.remove(this ); // remove modified document from queue if present
277:                        _stat = UNMANAGED;
278:                    }
279:                }
280:
281:                public void documentReset() {
282:                    synchronized (_cacheLock) {
283:                        if (_stat == UNMANAGED)
284:                            add(); // add document to queue if it was formerly unmanaged
285:                    }
286:                }
287:
288:                /** Updates status of this document in the cache. */
289:                public void documentSaved() {
290:                    //      Utilities.showDebug("Document " + _doc + " has been saved");
291:                    //      System.err.println("Document " + _doc + " has been saved");
292:                    synchronized (_cacheLock) { // lock the document manager so that document manager fields can be updated
293:                        if (isUnmanagedOrUntitled()) {
294:                            add(); // add formerly unmanaged/untitled document to queue
295:                        }
296:                    }
297:                }
298:
299:                /** Adds this DocManager to the queue and sets status to IN_QUEUE.  Assumes _cacheLock is already held. */
300:                private void add() {
301:                    //      Utilities.showDebug("add " + this + " to the QUEUE\n" + "QUEUE = " + _residentQueue);
302:                    //      System.err.println("adding " + this + " to the QUEUE\n" + "QUEUE = " + _residentQueue);
303:                    if (!_residentQueue.contains(this )) {
304:                        _residentQueue.add(this );
305:                        _stat = IN_QUEUE;
306:                    }
307:                    if (_residentQueue.size() > CACHE_SIZE)
308:                        _residentQueue.get(0).remove();
309:                }
310:
311:                /** Removes this DocManager from the queue and sets status to NOT_IN_QUEUE.  Assumes _cacheLock is already held. */
312:                private void remove() {
313:                    boolean removed = _residentQueue.remove(this );
314:                    kickOut();
315:                }
316:
317:                /** All of the following private methods presume that _cacheLock is held */
318:                private boolean isUnmanagedOrUntitled() {
319:                    return (_stat & 0x1) != 0;
320:                } // tests if _stat is odd
321:
322:                /** Called by the cache when the document is removed from the active queue and subject to virtualization. 
323:                 * Assumes cacheLock is already held. 
324:                 */
325:                void kickOut() {
326:                    kickOut(false);
327:                }
328:
329:                /** Called by the cache when the document is being closed.   Note that _doc can be null in this case!
330:                 * Assumes cacheLock is already held. 
331:                 */
332:                void closingKickOut() {
333:                    kickOut(true);
334:                }
335:
336:                /** Performs the actual kickOut operation.  Assumes cacheLock is already held. */
337:                private void kickOut(boolean isClosing) {
338:                    //      Utilities.showDebug("kickOut(" + isClosing + ") called on " + this);
339:                    if (!isClosing) {
340:                        /* virtualize this document */
341:                        //        Utilities.showDebug("Virtualizing " + _doc);
342:                        _rec.saveDocInfo(_doc);
343:                    }
344:                    if (_doc != null) {
345:                        _doc.close();
346:                        _doc = null;
347:                    }
348:                    _stat = NOT_IN_QUEUE;
349:                }
350:
351:                public String toString() {
352:                    return "DocManager for " + _rec.toString() + "[stat = "
353:                            + _stat + "]";
354:                }
355:            }
356:
357:            ////////////////////////////////////////
358:
359:            /** This interface allows the unit tests to get a handle on what's going on since the work is spread
360:             *  between the ODD, the cache, and the Adapters.
361:             */
362:            public interface RegistrationListener {
363:                public void registered(OpenDefinitionsDocument odd,
364:                        DCacheAdapter man);
365:            }
366:
367:            private LinkedList<RegistrationListener> _regListeners = new LinkedList<RegistrationListener>();
368:
369:            public void addRegistrationListener(RegistrationListener list) {
370:                synchronized (_regListeners) {
371:                    _regListeners.add(list);
372:                }
373:            }
374:
375:            public void removeRegistrationListener(RegistrationListener list) {
376:                synchronized (_regListeners) {
377:                    _regListeners.remove(list);
378:                }
379:            }
380:
381:            public void clearRegistrationListeners() {
382:                _regListeners.clear();
383:            }
384:
385:            // Only used in DocumentCacheTest; must be synchronous for test to succeed.
386:            private void notifyRegistrationListeners(
387:                    final OpenDefinitionsDocument odd, final DocManager man) {
388:                synchronized (_regListeners) {
389:                    if (_regListeners.isEmpty())
390:                        return;
391:                    Utilities.invokeAndWait(new Runnable() {
392:                        public void run() {
393:                            for (RegistrationListener list : _regListeners) {
394:                                list.registered(odd, man);
395:                            }
396:                        }
397:                    });
398:                }
399:            }
400:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.