Source Code Cross Referenced for FileStructureDependenciesUpdater.java in  » IDE » Schmortopf » Schmortopf » FileStructure » 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 » Schmortopf » Schmortopf.FileStructure 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        package Schmortopf.FileStructure;
002:
003:        /**                         
004:         *  This is a permanent running updater thread, which
005:         *  updates the file dependencies required for compiling.
006:         *         
007:         *  An instance of this class is held and managed by
008:         *  the FileStructureDescriptionManager.
009:         *
010:         *  Note: This thread scales its cpu consumption automatically.
011:         *        Because the update entries are heavy ( fsd plus parsertree )
012:         *        it must hurry up the more entries there are.   
013:         *        If there are many entries ( more than 10 ), it will consume
014:         *        almost ALL cpu power.
015:         *        However, in normal operation, when there are 1,2 or 3 entries,  
016:         *        it will be almost on standby and call sleep(5) in its scanners.
017:         *                 
018:         *        If there are more than 10 entries, this thread will become
019:         *        very busy and process the queue, until its below this threshold
020:         *        value. ( Memory increases fast along with the queue size )
021:         *
022:         *  Note: The thread uses wait/notify mechanism. Normally it waits for
023:         *        the calculated time. But if many entries are appended to its queue,
024:         *        it will get notified and come alive fast for not letting 
025:         *        grow the queue too much.
026:         *
027:         *  The thread works on the dependencyUpdaterQueue, which is filled
028:         *  when files are edited by the user, or moved,copied or removed.
029:         *  It's triggered by FSD updates.
030:         *
031:         */
032:
033:        import java.util.Vector;
034:        import javax.swing.tree.DefaultMutableTreeNode;
035:
036:        import Shared.Logging.Log;
037:
038:        //
039:        // Using the ThreadEngine in this object is NOT allowed.
040:        // Reason: There are tasks in the ThreadEngine waiting
041:        // for this thread to become idle.
042:        //
043:        // So if this thread performs tasks in the ThreadEngine,
044:        // this will create a deadlock for sure, because the
045:        // ThreadEngine "threadqueue" processes its entries
046:        // one after the other.
047:        //
048:
049:        import Schmortopf.FileStructure.Descriptions.FileStructureDescription;
050:        import Schmortopf.FileComponents.Model.TokenTreeUserObject;
051:
052:        public class FileStructureDependenciesUpdater extends Thread {
053:
054:            private static final int ForegroundMode = 0;
055:            private static final int BackgroundMode = 1;
056:
057:            private int threadMode = BackgroundMode;
058:
059:            private boolean doTerminate = false;
060:
061:            private FileStructureDescriptionManager fsdManager;
062:            private FileStructureDependenciesScanner dependenciesScanner;
063:
064:            // Contains DependencyUpdaterQueueEntry objects of files, which need an update of their
065:            // filedependencies information.
066:            private final Vector dependencyUpdaterQueue = new Vector();
067:
068:            // If there are more than BusyThreshold entries in the queue,
069:            // this thread processes the queue, until there are less than
070:            // this amount of entries. (memory reasons)                                            
071:            private final static int BusyThreshold = 10;
072:
073:            // Some processes disable this updater for a short time for getting
074:            // faster updates for the user.
075:            // For example, if a new document is set, the method in the EditorPanel
076:            // will disable the updater for letting the editor and filecomponent tree
077:            // tasks be processed immediately. After theses tasks are finished,
078:            // it will enable this updater again.
079:            // While the updater is finished, added files will just remain in the
080:            // dependencyUpdaterQueue and processed after it is enabled again.
081:            // No data is lost while it is disabled.
082:            // Note: If a notify() call is made, the updater will be enabled in any case.
083:            private boolean updaterIsEnabled = true;
084:
085:            // This flag is set, if time is expensive - Usually before
086:            // compiling starts, or before the document is changed.
087:            // The thread then shouldnt sleep, but process all pending entries.
088:            // This flag will be cleared as soon as the queue is empty.
089:            private boolean doProcessAllPendingEntries = false;
090:
091:            public FileStructureDependenciesUpdater(
092:                    final FileStructureDescriptionManager fsdManager) {
093:                this .fsdManager = fsdManager;
094:                this .dependenciesScanner = new FileStructureDependenciesScanner(
095:                        this .fsdManager);
096:                this .setName("FileStructureDependenciesUpdater [permanent]");
097:            } // Constructor
098:
099:            /**
100:             *  The thread loop: synchronized cause of the wait() call.
101:             */
102:            public synchronized void run() {
103:                while (!this .doTerminate) {
104:                    // Calculate the delay as function of the number of (heavy) entries.
105:                    long delay = this .calculateDelayTime();
106:
107:                    // If there has been a request call for processing all entries
108:                    // without pause, test and clear that flag now, if the queue has
109:                    // become empty:
110:                    if (this .doProcessAllPendingEntries) {
111:                        if (this .dependencyUpdaterQueue.size() == 0) {
112:                            this .doProcessAllPendingEntries = false; // job has been done
113:                        }
114:                    }
115:
116:                    // Note that the thread can be notified and wake up, when we get
117:                    // more than BusyThreshold entries into the queue.
118:                    // The notify call is in the appendEntryToQueue() method.
119:                    // If the updater is not enabled, we continue waiting and don't
120:                    // process the queue entries.
121:                    if (!this .doProcessAllPendingEntries) {
122:                        while (true) {
123:                            try {
124:                                this .wait(delay);
125:                            } catch (Exception anyEx1235) {
126:                            }
127:                            // Leave the loop, if its enabled, stay here otherwise.
128:                            if ((this .updaterIsEnabled) || (this .doTerminate))
129:                                break;
130:                        }
131:                    }
132:
133:                    //Log.Info("FSDDependencyUpdater> process entry");
134:
135:                    if (this .dependencyUpdaterQueue.size() <= BusyThreshold) {
136:                        // Flag true: Allow the scanner to call sleep(2) from time to time
137:                        // for being better in the background.
138:                        this .processFirstEntryInQueue(true);
139:                    } else {
140:                        // If we have more than BusyThreshold entries, process until we are below this
141:                        // number ( memory increases fast along with the queue size )
142:                        while (this .dependencyUpdaterQueue.size() > BusyThreshold) {
143:                            // Flag false: Don't allow the scanner to call sleep(2).
144:                            // It should run without interruption by other threads (of same or lower
145:                            // priority )
146:                            this .processFirstEntryInQueue(false);
147:                        } // while
148:                    }
149:
150:                } // while
151:            } // run
152:
153:            private void processFirstEntryInQueue(final boolean allowWaitStates) {
154:                // Try to get the next fsd for update from the queue:
155:
156:                // A little side note:      
157:                // We do NOT synchronize [ =lock ] the dependencyUpdaterQueue during the
158:                // whole processing time of this method.
159:                // The only complication, which we get for this speed advantage is, that
160:                // at the end, we can't just remove the first element, but have to
161:                // test before we remove, if it's still containing the same reference.
162:                // If not, there's nothing to do.
163:
164:                DependencyUpdaterQueueEntry entryForUpdate = null;
165:                synchronized (this .dependencyUpdaterQueue) {
166:                    if (this .dependencyUpdaterQueue.size() > 0) {
167:                        entryForUpdate = (DependencyUpdaterQueueEntry) this .dependencyUpdaterQueue
168:                                .elementAt(0);
169:                    }
170:                } // sync
171:                if (entryForUpdate != null) {
172:
173:                    // If it's old and it's member attributes have been released already,
174:                    // there is nothing to do - it's outdated anyway:
175:                    if (entryForUpdate.fsd.fullyQualifiedClassNameBuffer
176:                            .length() > 0) {
177:
178:                        //ystem.out.println("FSDU> FileStructureDependenciesUpdater starts.");
179:
180:                        // Invalidate it, until the scanner has finished its work:
181:                        entryForUpdate.fsd.referencedProjectFilesAreValid = false;
182:                        // Set the save flag immediately:
183:                        this .fsdManager.setDataHasChanged();
184:
185:                        // Go update this one:
186:                        // If the parser itself has found errors, we can't scan the
187:                        // parser tree, but have to compile it always:
188:                        if (entryForUpdate.fsd.parserOutput.success) {
189:                            // Scan for dependencies. This will set the fsd's referencedProjectFiles Vector
190:                            // and associated referencedProjectFiles attributes.
191:                            // Note, that fsd.belongsToProject must be set at this time.
192:                            this .dependenciesScanner.scanReferencedObjects(
193:                                    entryForUpdate.fsd,
194:                                    entryForUpdate.compilationRootNode,
195:                                    entryForUpdate.fsd.pathNameBuffer
196:                                            .toString(), this .fsdManager,
197:                                    allowWaitStates);
198:                        } else {
199:                            // We have errors on parser level:
200:                            // Set it invalid, so it's reupdated before the next compiler run:
201:                            entryForUpdate.fsd.referencedProjectFilesAreValid = false;
202:                            entryForUpdate.fsd.hasToBeCompiledAlways = true;
203:                        }
204:                        // Set the save flag again:
205:                        this .fsdManager.setDataHasChanged();
206:
207:                        //ystem.out.println("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
208:                        //ystem.out.println("++++ FSDDependenciesUpdater: Entry processed for " +
209:                        //                   entryForUpdate.fsd.fullyQualifiedClassNameBuffer.toString() );
210:                        //ystem.out.println("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
211:
212:                    } // if fsd still valid
213:                    /*
214:                    else
215:                     {
216:                       ystem.out.println("---------------------------------------------------------");
217:                       ystem.out.println("---- FSDDependenciesUpdater: Outdated entry has been skipped.");
218:                       ystem.out.println("---------------------------------------------------------");
219:                     }
220:                     */
221:
222:                    //
223:                    // The queue has been processed, so REMOVE the processed element.
224:                    //
225:                    // IMPORTANT: Before the compiler is launched, this updater is notified,
226:                    //            and the ThreadEngine task, which starts the compiler will
227:                    //            wait, until the dependencyUpdaterQueue is empty. Therefore
228:                    //            it is important, that we remove the first entry ONLY after
229:                    //            it has been fully processed and the dependency fsd information
230:                    //            has been updated.
231:                    //
232:                    // See the comments above about non-synchronization (over the whole method)
233:                    // of the queue. -> Result is:
234:                    // We only remove the first queue entry, if it still contains the
235:                    // same reference, otherwise we do nothing:
236:                    synchronized (this .dependencyUpdaterQueue) {
237:                        if (this .dependencyUpdaterQueue.size() > 0) {
238:                            // Reference check:
239:                            if (this .dependencyUpdaterQueue.elementAt(0) == entryForUpdate) {
240:                                this .dependencyUpdaterQueue.removeElementAt(0);
241:                            }
242:                        }
243:                    } // sync
244:                    // GC assistance:
245:                    entryForUpdate.fsd = null;
246:                    this .freeTreeMemoryFor(entryForUpdate.compilationRootNode);
247:                    entryForUpdate.compilationRootNode = null;
248:
249:                    //ystem.out.println("FSDU> FileStructureDependenciesUpdater has ended. " +
250:                    //                   this.dependencyUpdaterQueue.size() +
251:                    //                   " entries in queue.");
252:
253:                }
254:            } // startUpdate
255:
256:            /**
257:             *   Calculate the delay as function of the number of (heavy) entries.
258:             */
259:            private long calculateDelayTime() {
260:                // delay is in milliseconds.
261:                final long numberOfEntries = this .dependencyUpdaterQueue.size();
262:
263:                final long delay = 3000 / (1 + numberOfEntries
264:                        * numberOfEntries);
265:                // 24.8.04 Changed, original line has been:    
266:                // final long delay = 6000 / ( 1 + numberOfEntries*numberOfEntries );
267:
268:                return delay;
269:            }
270:
271:            public void terminate_Thread() {
272:                this .doTerminate = true;
273:            }
274:
275:            /**
276:             *  Enables/disables the processing of the updater queue.
277:             *
278:             *  Used by f.ex. the editorpanel to let other tasks, which are
279:             *  important for the user, be processed faster, before it's
280:             *  enabled again.
281:             */
282:            public void enableUpdater(final boolean doEnable) {
283:                this .updaterIsEnabled = doEnable;
284:            }
285:
286:            /**
287:             *  This is used by the compiler thread for wake up this
288:             *  thread, if there still are fsd's with dependency data,
289:             *  which is not up to date.
290:             *  This shortens the wait time.
291:             */
292:            public synchronized void requestForProcessingAllPendingEntries() {
293:                //ystem.out.println("DependenciesUpdater.requestForProcessingAllPendingEntries():  " + this.dependencyUpdaterQueue.size() + "  entries.");
294:                // Set the associated flag:
295:                this .doProcessAllPendingEntries = true;
296:                this .updaterIsEnabled = true; // in any case, see comments where
297:                // updaterIsEnabled is declared.
298:                this .notify();
299:                // We have set the flag doProcessAllPendingEntries and notified the updater thread,
300:                // so from now, the updater will run through, until all queue entries have been processed.
301:            }
302:
303:            /**
304:             *  Also called by the compiler thread: This one has to
305:             *  wait, until all entries here have been processed.
306:             */
307:            public int getNumberOfPendingQueueEntries() {
308:                return this .dependencyUpdaterQueue.size();
309:            }
310:
311:            /**
312:             *  Called when the postprocessor has created or updated an FSD.
313:             *  Synchronized cause of the possible notify() call.
314:             */
315:            public synchronized void appendEntryToQueue(
316:                    final DependencyUpdaterQueueEntry entry) {
317:                // Security: Break, if its not a project fsd:
318:                if (!entry.fsd.belongsToProject) {
319:                    return;
320:                }
321:                synchronized (this .dependencyUpdaterQueue) {
322:                    // The passed entry is the most uptodate entry.
323:                    // Therefore we append this always.
324:                    // But if we see other entries (except the first one) for the same fsd, we remove them.
325:                    // Why do we exclude the first one and possibly add the same entry twice,
326:                    // if it equals the first one ? --> BECAUSE the first one possibly is
327:                    // beeing processed when the append call comes in. In this case we really
328:                    // have TWO subsequent dependency update tasks for the same entry.
329:                    // This is VERY important.
330:                    // We keep the first entry in the queue, until it has been processed,                         
331:                    // because we then can see simply from the size of the queue, if there
332:                    // are updates pending or being processed.
333:                    String qualifiedClassNameBuffer = entry.fsd.fullyQualifiedClassNameBuffer
334:                            .toString();
335:                    int i = 1; // Skip the first one, see explanation above.
336:                    while (i < this .dependencyUpdaterQueue.size()) {
337:                        final DependencyUpdaterQueueEntry queueEntry = (DependencyUpdaterQueueEntry) this .dependencyUpdaterQueue
338:                                .elementAt(i);
339:                        final StringBuffer queueEntryQualifiedClassNameBuffer = queueEntry.fsd.fullyQualifiedClassNameBuffer;
340:                        if (qualifiedClassNameBuffer
341:                                .equals(queueEntryQualifiedClassNameBuffer
342:                                        .toString())) {
343:                            queueEntry.fsd = null; // gc assistance
344:                            queueEntry.compilationRootNode = null; // gc assistance
345:                            this .dependencyUpdaterQueue.removeElementAt(i);
346:                        } else {
347:                            i++;
348:                        }
349:                    } // while
350:                    this .dependencyUpdaterQueue.addElement(entry);
351:                }
352:                // If we have more than BusyThreshold entries in the queue,
353:                // wake up the thread (!) :
354:                if (this .dependencyUpdaterQueue.size() > BusyThreshold) {
355:                    this .notify();
356:                }
357:            } // appendEntryToQueue
358:
359:            /**
360:             *  Called, when a file has been removed, so that it's not
361:             *  scanned after it has ben removed already (if there is
362:             *  an entry in here at all)
363:             */
364:            public void removeFileForDependencyUpdate(
365:                    final String fullyQualifiedClassIdentifier) {
366:                synchronized (this .dependencyUpdaterQueue) {
367:                    int i = 0;
368:                    while (i < this .dependencyUpdaterQueue.size()) {
369:                        final DependencyUpdaterQueueEntry queueEntry = (DependencyUpdaterQueueEntry) this .dependencyUpdaterQueue
370:                                .elementAt(i);
371:                        final StringBuffer queueFSDIdentifierBuffer = queueEntry.fsd.fullyQualifiedClassNameBuffer;
372:                        if (fullyQualifiedClassIdentifier
373:                                .equals(queueFSDIdentifierBuffer.toString())) {
374:                            queueEntry.fsd = null;
375:                            this 
376:                                    .freeTreeMemoryFor(queueEntry.compilationRootNode);
377:                            queueEntry.compilationRootNode = null;
378:                            this .dependencyUpdaterQueue.removeElementAt(i);
379:                        } else {
380:                            i++;
381:                        }
382:                    }
383:                }
384:            } // removeFileForDependencyUpdate
385:
386:            public void setForegroundMode() {
387:                this .threadMode = ForegroundMode;
388:            }
389:
390:            public void setBackgroundMode() {
391:                this .threadMode = BackgroundMode;
392:            }
393:
394:            /**
395:             *  Adds string to the passed vector, which exclusively must contain string entries,
396:             *  if this string is not already found in the vector.
397:             */
398:            private void addUniqueStringToStringVector(final String string,
399:                    final Vector vector) {
400:                boolean isAlreadyExisting = false;
401:                for (int i = 0; i < vector.size(); i++) {
402:                    final String s = (String) vector.elementAt(i);
403:                    if (s.equals(string)) {
404:                        isAlreadyExisting = true;
405:                        break;
406:                    }
407:                }
408:                if (!isAlreadyExisting) {
409:                    vector.addElement(string);
410:                }
411:            } // addUniqueStringToStringVector
412:
413:            /**
414:             *  Recursive GC assistance
415:             */
416:            private void freeTreeMemoryFor(final DefaultMutableTreeNode node) {
417:                if (node != null) {
418:                    if (node.getAllowsChildren()) {
419:                        for (int i = 0; i < node.getChildCount(); i++) {
420:                            DefaultMutableTreeNode this Child = (DefaultMutableTreeNode) node
421:                                    .getChildAt(i);
422:                            this .freeTreeMemoryFor(this Child);
423:                        }
424:                        node.removeAllChildren(); // only removes level one children
425:                        node.removeFromParent();
426:                        node.setUserObject(null);
427:                    } else {
428:                        final Object userObject = node.getUserObject();
429:                        if (userObject != null) {
430:                            if (userObject instanceof  TokenTreeUserObject) {
431:                                ((TokenTreeUserObject) userObject).freeMemory();
432:                            }
433:                            node.removeFromParent();
434:                            node.setUserObject(null);
435:                        }
436:                    }
437:                }
438:            } // freeTreeMemoryFor
439:
440:        } // FileStructureDependenciesUpdater
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.