Source Code Cross Referenced for ClassFilesManager.java in  » IDE » tIDE » tide » project » 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 » tIDE » tide.project 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        package tide.project;
002:
003:        import java.util.concurrent.*;
004:        import java.util.*;
005:        import java.io.*;
006:        import java.util.zip.*;
007:        import snow.utils.storage.FileUtils;
008:        import tide.utils.FileUtilities;
009:        import tide.editor.MainEditorFrame;
010:        import tide.sources.SourceFile;
011:
012:        /** Manages the classes files (from classpath and the generated ones).
013:         *   is associated to a project.
014:         *
015:         *   Include rt.jar (all java API classes)
016:         *   Should be used for classes locations instead of the libs tree (that also contain sources)
017:         *
018:         *   load classes such as java.awt.geom.Point2D.Double ! (enclosed public classes)
019:         *    ( java/awt/geom/Point2D$Double.class => java.awt.geom.Point2D$Double )
020:         *    no problem, replace file names "$" with ".".
021:         *
022:         * PROBLEM:  source file A may contain toplevel private classes named B => create b.class, not A$B !
023:         *   no way to find out what it is (?) from the simple file name !
024:         *
025:         * TODO: allow rescanning from a root (deleting root.* and rescan root)
026:         *
027:         * TODO: allow only update new class files (use the last op system time and create a quick get)
028:         *
029:         * Also keep old classes for completion classesCacheForCompletion. To avoid duplicate class exception when moving or refactoring from
030:         * inner class to standalone, the cache is emptyed on successful global build of branchs!
031:         *
032:         *  Oct: removed the toUppercase
033:         */
034:        public final class ClassFilesManager {
035:            // ext libs (key = java name with case)  (TAKES MUCH PLACE!)
036:            final private HashMap<String, ProjClass> classPathClasses = new HashMap<String, ProjClass>();
037:            //final private List<ProjClass> sortedClassPathClasses = new ArrayList<ProjClass>();
038:
039:            // generated
040:            final private HashMap<String, ProjClass> generatedClasses = new HashMap<String, ProjClass>();
041:
042:            // cached classes, copied to classesCacheForCompletion. Used for completion !
043:            final private HashMap<String, ProjClass> generatedClassesCache = new HashMap<String, ProjClass>();
044:
045:            // keep ref to be able to close them
046:            final List<ZipFile> openedZipFiles = new ArrayList<ZipFile>();
047:
048:            final File generatedClassesRoot;
049:            final File classesCacheForCompletion;
050:            final List<File> classPath;
051:
052:            /** Ensures that the analysis runs one at a time. Also useful to quit the compile thread, because this is not
053:             *   important to wait.
054:             */
055:            final private ExecutorService analysisExecutionService = Executors
056:                    .newFixedThreadPool(1);
057:
058:            public ClassFilesManager(List<File> classPath,
059:                    File generatedClassesRoot, File classesCacheForCompletion) {
060:                this .generatedClassesRoot = generatedClassesRoot;
061:                this .classesCacheForCompletion = classesCacheForCompletion;
062:                this .classPath = classPath;
063:
064:                long t0 = System.currentTimeMillis();
065:
066:                // enqueued
067:                Future fut = analyseGeneratedClasses();
068:
069:                // not enqueued, has nothing to do with the project classes (is rt.jar, ...).
070:                reanalyseClassPath();
071:
072:                // WAITS.  (the two above tasks may run in parallel !)
073:                try {
074:                    fut.get();
075:                } catch (Exception ign) {
076:                }
077:
078:                // always print it out, it is also a kind of benchmark
079:                long dt = System.currentTimeMillis() - t0;
080:                MainEditorFrame.debugOut("ClassFilesManager: "
081:                        + classPathClasses.size() + " classes in libs, "
082:                        + generatedClasses.size() + " in project. ("
083:                        + generatedClassesCache.size()
084:                        + " in cache), analysed in " + dt + " ms");
085:
086:                if (!classesCacheForCompletion.exists()) {
087:                    classesCacheForCompletion.mkdirs();
088:                }
089:
090:            }
091:
092:            public void remove(String javaName) {
093:                // todo: delete the classes, not just remove...
094:                //generatedClasses.get(javaName).
095:                generatedClasses.remove(javaName);
096:                generatedClassesCache.remove(javaName);
097:                //no: classPathClasses
098:            }
099:
100:            /** @param name for example "java.util.Vector"...
101:             *  Search order: generated classes, ext libs
102:             */
103:            public ProjClass getClassExact(final String name) {
104:                String nameN = name.replace('$', '.'); // inner classes
105:
106:                ProjClass pc = generatedClasses.get(nameN);
107:                if (pc != null)
108:                    return pc;
109:
110:                //System.out.println("getClassExact("+name+") not found in project: "+generatedClasses.keySet());
111:
112:                pc = generatedClassesCache.get(nameN);
113:                if (pc != null)
114:                    return pc;
115:
116:                //int pos = Collections.binarySearch(sortedClassPathClasses, nameN);
117:
118:                pc = classPathClasses.get(nameN);
119:                if (pc != null)
120:                    return pc;
121:
122:                /*MainEditorFrame.debugOut(""+name+" not found in cfm ("
123:                   +generatedClasses.size()+", "+generatedClassesCache.size()
124:                   +", "+classPathClasses.size()+"  classes)");
125:                 */
126:                return null;
127:            }
128:
129:            /* @param name for example "util.Vector"...
130:             *  search order: generated classes, ext libs
131:             *  BAD ! ONLY FOR HELP !
132:             *
133:            public ProjClass getClassEndingWith(String name)
134:            {
135:               for(ProjClass pc : generatedClasses)
136:               {
137:                  if(pc.getJavaName().endsWith(name)) return pc;
138:               }
139:
140:               for(ProjClass pc : classPathClasses)
141:               {
142:                  if(pc.getJavaName().endsWith(name)) return pc;
143:               }
144:
145:               return null;
146:            }*/
147:
148:            /** Must be called after each compilation... and at startup. Also on failure.
149:             *  Immediately returns, the result is an ENQUEUED task.
150:             */
151:            public Future analyseGeneratedClasses() {
152:                return analysisExecutionService.submit(new Runnable() {
153:                    public void run() {
154:                        long t0 = System.currentTimeMillis();
155:                        MainEditorFrame
156:                                .debugOut("\r\ncfm.analyseGeneratedClasses");
157:
158:                        generatedClasses.clear();
159:                        addAllClassesFromDir(generatedClasses,
160:                                generatedClassesRoot);
161:
162:                        generatedClassesCache.clear();
163:                        addAllClassesFromDir(generatedClassesCache,
164:                                classesCacheForCompletion);
165:
166:                        // 3 sec for 2 * 6'000 classes. OK.
167:                        MainEditorFrame.debugOut("cfm.analyse_end ("
168:                                + (System.currentTimeMillis() - t0) + " ms, "
169:                                + generatedClassesCache.size() + " cla)");
170:
171:                    }
172:                });
173:            }
174:
175:            /** Called for "XXX/classes" and "XXX/.tide/classesTemp".
176:             *  TODO: diff update, only reput if not already contained
177:             */
178:            private static void addAllClassesFromDir(
179:                    final Map<String, ProjClass> vc, final File root) {
180:                //MainEditorFrame.debugOut("CFM:add all classes from "+root);
181:                int baseNameLength = FileUtils.getCanonicalName(root).length();
182:                final List<File> cfs = new ArrayList<File>();
183:                FileUtils.getAllClassFilesRecurse(root, cfs, true);
184:                MainEditorFrame.debugOut("CFM: " + cfs.size()
185:                        + " classes added from " + root);
186:
187:                for (final File cf : cfs) {
188:                    String jn = FileUtils.getCanonicalName(cf).substring(
189:                            baseNameLength);
190:                    jn = createJavaNameFromClassFileName(jn);
191:                    //if(!vc.containsKey(jn)) ... (?)
192:                    vc.put(jn, new ProjClass(cf, jn));
193:                }
194:                cfs.clear();
195:            }
196:
197:            /** Add all classes from classpath (currently only zip and jars).
198:             *  Only called from constructor at new creation.
199:             */
200:            private void reanalyseClassPath() {
201:                //MainEditorFrame.debugOut("fcm.reanalyse");
202:                classPathClasses.clear();
203:                for (File cpf : classPath) {
204:                    if (!cpf.exists()) {
205:                        MainEditorFrame.instance.outputPanels.tideOutputPanel.doc
206:                                .appendErrorLine("Classpath file not found: "
207:                                        + cpf);
208:                        continue;
209:                    }
210:
211:                    if (cpf.isDirectory()) {
212:                        addAllClassesFromDir(classPathClasses, cpf);
213:                    } else {
214:                        String fn = cpf.getName().toLowerCase();
215:                        if (fn.endsWith(".zip") || fn.endsWith(".jar")) {
216:                            try {
217:                                addAllClassesFromArchive(classPathClasses, cpf);
218:                            } catch (Exception e) {
219:                                e.printStackTrace();
220:                            }
221:                        } else {
222:                            System.out
223:                                    .println("Unknown classpath item: " + cpf);
224:                        }
225:                    }
226:                }
227:            }
228:
229:            private static String createJavaNameFromClassFileName(
230:                    final String cn) {
231:                return cn.substring(0, cn.length() - 6).replace('/', '.')
232:                        .replace('$', '.');
233:            }
234:
235:            private void addAllClassesFromArchive(Map<String, ProjClass> vc,
236:                    File archive) throws Exception {
237:                try {
238:                    ZipFile zf = new ZipFile(archive);
239:                    Enumeration<? extends ZipEntry> entries = zf.entries();
240:                    while (entries.hasMoreElements()) {
241:                        ZipEntry ze = entries.nextElement();
242:                        String cn = ze.getName();
243:                        if (cn.toLowerCase().endsWith(".class")) {
244:                            String jn = createJavaNameFromClassFileName(cn);
245:                            vc.put(jn,
246:                            //.toUpperCase(Locale.ENGLISH),
247:                                    new ProjClass(ze, zf));
248:                        }
249:                    }
250:                } catch (Exception e) {
251:                    throw e;
252:                }
253:            }
254:
255:            /** Called before compiling or on project clear.
256:             *   HERE IS THE ONLY POINT WHERE CLASSES ARE DELETED !
257:             */
258:            public void deleteAllClassesOnDiskAndWait() {
259:                final Future fut = analysisExecutionService
260:                        .submit(new Runnable() {
261:                            public void run() {
262:                                long t0 = System.currentTimeMillis();
263:                                MainEditorFrame
264:                                        .debugOut("\r\ncfm.deleteAllClassesOnDisk");
265:
266:                                final ProjectSettings actualProject = MainEditorFrame.instance
267:                                        .getActualProject();
268:                                final int baseNameLength = FileUtils
269:                                        .getCanonicalName(
270:                                                actualProject.getClasses_Home())
271:                                        .length();
272:
273:                                final List<File> allClasses = new ArrayList<File>();
274:                                FileUtils.getAllClassFilesRecurse(actualProject
275:                                        .getClasses_Home(), allClasses, true);
276:
277:                                //FileUtilities.getAllFilesRecurse_withNameEndingWith(allClasses, actualProject.getClasses_Home(), ".class");
278:                                /*     MainEditorFrame.instance.outputPanels.tideOutputPanel.doc.appendLine(
279:                                         "Deleting all " + allClasses.size() + " generated classes");*/
280:                                long t1 = System.currentTimeMillis();
281:                                for (final File cf : allClasses) {
282:                                    String baseName = FileUtils
283:                                            .getCanonicalName(cf).substring(
284:                                                    baseNameLength);
285:                                    copyGeneratedClasseInCache(cf, baseName,
286:                                            true); // DELETE the source...
287:                                }
288:                                MainEditorFrame.debugOut("cfm: "
289:                                        + allClasses.size()
290:                                        + " classes moved to the cache ("
291:                                        + (System.currentTimeMillis() - t1)
292:                                        + " ms)");
293:
294:                                // remove empty directories
295:                                final List<File> allDirs = new ArrayList<File>();
296:                                t1 = System.currentTimeMillis();
297:                                FileUtilities
298:                                        .getAllDirectoriesRecurse_depthFirst(
299:                                                allDirs, actualProject
300:                                                        .getClasses_Home()); // depth first is important here
301:
302:                                for (final File d : allDirs) {
303:                                    if (!d.delete()) {
304:                                        System.out
305:                                                .println("CFM: Cannot delete dir: "
306:                                                        + d
307:                                                        + " ("
308:                                                        + d.listFiles().length
309:                                                        + " files)");
310:                                    }
311:                                }
312:                                MainEditorFrame.debugOut("deleted "
313:                                        + allDirs.size() + " classes dirs ("
314:                                        + (System.currentTimeMillis() - t1)
315:                                        + " ms)");
316:
317:                                MainEditorFrame
318:                                        .debugOut("cfm.deleteAllClassesOnDisk done ("
319:                                                + (System.currentTimeMillis() - t0)
320:                                                + " ms).");
321:                            }
322:                        });
323:
324:                try {
325:                    fut.get(); // WAIT.
326:                } catch (Exception ign) {
327:                }
328:            }
329:
330:            /** Puts the hits in dest.
331:             *   Collects the "*.class" files named name+".class" and starting with name+"$".
332:             */
333:            // problem: old private classes are not removed  (toplevel private class A defined in B.java !)
334:            private static void getClassesAndInnerClassesNamed(File dir,
335:                    String name, List<File> dest) {
336:                File[] files = dir.listFiles(FileUtils.classFileNameFilter); // limit to *.class in dir
337:                if (files == null)
338:                    return;
339:                for (File f : files) {
340:                    if (f.isDirectory())
341:                        continue;
342:
343:                    if (f.getName().equalsIgnoreCase(name + ".class"))
344:                        dest.add(f); // [March2008]: corrected
345:                    if (f.getName().startsWith(name + "$"))
346:                        dest.add(f);
347:                }
348:            }
349:
350:            /** if false, we have a kind of "contamination", keeping old removed classes (after renames, removes).
351:             *   caches classes are then only replaced when they size are different,
352:             *   this is inexact but ok for a cache used for completion purposes.
353:             *   Advantage: it's quicker.
354:             */
355:            private final static boolean deleteCachedClassesAfterRebuild = false;
356:
357:            /** Call this on successful build. This allows to reconstruct a valid cache, i.e.
358:             *  where no duplicate classes may occur. (when moving a class and partial recompile, for example !)
359:             * @param rootRebuild null when the whole project was compiled !
360:             *
361:             * Immediately returns, ENQUEUED.
362:             */
363:            public Future buildWasSuccessful(final SourceFile rootRebuild) {
364:                return analysisExecutionService.submit(new Runnable() {
365:                    public void run() {
366:
367:                        MainEditorFrame.debugOut("\r\nSuccessful build for "
368:                                + rootRebuild);
369:
370:                        final long t0 = System.currentTimeMillis();
371:
372:                        // 1) delete actual cache
373:                        final ProjectSettings actualProject = MainEditorFrame.instance
374:                                .getActualProject();
375:                        final File cacheSubRootToConsider;
376:                        final File classesRootToConsider;
377:
378:                        if (rootRebuild != null) {
379:                            String packageToConsider = rootRebuild
380:                                    .getPackageName().replace('.', '/');
381:                            cacheSubRootToConsider = new File(
382:                                    classesCacheForCompletion,
383:                                    packageToConsider);
384:                            classesRootToConsider = new File(actualProject
385:                                    .getClasses_Home(), packageToConsider);
386:                        } else {
387:                            cacheSubRootToConsider = classesCacheForCompletion;
388:                            classesRootToConsider = actualProject
389:                                    .getClasses_Home();
390:                        }
391:
392:                        if (deleteCachedClassesAfterRebuild) {
393:                            final List<File> cachedClassesToDelete = new ArrayList<File>();
394:                            if (rootRebuild != null) {
395:                                if (rootRebuild.isDirectory()) {
396:                                    // delete all the cached files in that directory
397:                                    //FileUtilities.getAllFilesRecurse_withNameEndingWith(cachedClassesToDelete, cacheSubRootToConsider, ".class");
398:                                    FileUtils.getAllClassFilesRecurse(
399:                                            cacheSubRootToConsider,
400:                                            cachedClassesToDelete, true);
401:                                } else {
402:                                    // problem: old private classes are not removed  (toplevel private class A defined in B.java !)
403:                                    getClassesAndInnerClassesNamed(
404:                                            cacheSubRootToConsider, rootRebuild
405:                                                    .getJavaPartName(),
406:                                            cachedClassesToDelete);
407:                                }
408:                            } else {
409:                                // recache all, cause the whole project was successful compiled
410:
411:                                //FileUtilities.getAllFilesRecurse_withNameEndingWith(cachedClassesToDelete, classesCacheForCompletion, ".class");
412:                                FileUtils.getAllClassFilesRecurse(
413:                                        classesCacheForCompletion,
414:                                        cachedClassesToDelete, true); // ignore "dots dirs"
415:                            }
416:
417:                            long t1 = System.currentTimeMillis();
418:
419:                            df: for (final File cf : cachedClassesToDelete) {
420:                                cf.delete();
421:                            }
422:                            MainEditorFrame
423:                                    .debugOut("deleting "
424:                                            + cachedClassesToDelete.size()
425:                                            + " cached classes in "
426:                                            + (System.currentTimeMillis() - t1)
427:                                            + " ms");
428:                            cachedClassesToDelete.clear();
429:
430:                            // remove empty directories
431:                            final List<File> allCachedDirs = new ArrayList<File>();
432:                            FileUtilities.getAllDirectoriesRecurse_depthFirst(
433:                                    allCachedDirs, cacheSubRootToConsider); // depth first is important here
434:                            //System.out.println("deleting "+allCachedDirs.size()+" cached classes dirs");
435:                            for (final File d : allCachedDirs) {
436:                                d.delete();
437:                                // not so important...
438:                            }
439:                            allCachedDirs.clear();
440:                        }
441:
442:                        // 2) copy all generated classes to the cache
443:                        long t1 = System.currentTimeMillis();
444:                        int baseNameLength = FileUtils.getCanonicalName(
445:                                actualProject.getClasses_Home()).length();
446:                        List<File> allClasses = new ArrayList<File>();
447:                        FileUtils.getAllClassFilesRecurse(
448:                                classesRootToConsider, allClasses, true);
449:                        for (final File cf : allClasses) {
450:                            String baseName = FileUtils.getCanonicalName(cf)
451:                                    .substring(baseNameLength);
452:                            copyGeneratedClasseInCache(cf, baseName, false); // DO NOT DELETE IT
453:                        }
454:                        MainEditorFrame.debugOut("copying " + allClasses.size()
455:                                + " classes to the cache ("
456:                                + (System.currentTimeMillis() - t1) + " ms)");
457:
458:                        MainEditorFrame
459:                                .debugOut("successful afterbuild done. (tot "
460:                                        + (System.currentTimeMillis() - t0)
461:                                        + " ms)");
462:                    }
463:                });
464:            }
465:
466:            /** Allows to "keep" the classes for completion purpose,
467:             *   called when deleting the classes.
468:             *   Copies only if the length is different (lazy, inexact but ok for our cache purpose).
469:             */
470:            private void copyGeneratedClasseInCache(final File classFile,
471:                    final String relativePathName, final boolean deleteSource) {
472:                final File dest = new File(this .classesCacheForCompletion,
473:                        relativePathName);
474:                final boolean replace;
475:                if (!dest.exists()) {
476:                    replace = true;
477:                } else {
478:                    //ALWAYS THE CASE... replace = (classFile.lastModified() != dest.lastModified());
479:                    // CAUTION: not robust, but it's ok because our cache is only
480:                    // for completion purposes...
481:                    replace = (classFile.length() != dest.length());
482:                }
483:
484:                if (replace) {
485:                    try {
486:
487:                        if (deleteSource) {
488:                            if (!classFile.renameTo(dest)) // quick..
489:                            {
490:                                FileUtils.copy(classFile, dest);
491:                                if (!classFile.delete()) {
492:                                    System.out.println("Cannot delete1 "
493:                                            + classFile);
494:                                }
495:                            }
496:                        } else {
497:                            // just copy
498:                            FileUtils.copy(classFile, dest);
499:                        }
500:                    } catch (Exception e) {
501:                        e.printStackTrace();
502:                    }
503:
504:                } else if (deleteSource) {
505:                    // just delete
506:                    if (!classFile.delete()) {
507:                        System.out.println("Cannot delete2 " + classFile);
508:                    }
509:                }
510:            }
511:
512:            /** Call when terminated. And on project refresh.
513:                Closes the opened jars and empty the caches.
514:             */
515:            public void terminate() {
516:                MainEditorFrame.debugOut("terminate cfm");
517:
518:                classPath.clear();
519:                classPathClasses.clear();
520:                generatedClasses.clear();
521:                generatedClassesCache.clear();
522:
523:                for (ZipFile zf : openedZipFiles) {
524:                    FileUtils.closeIgnoringExceptions(zf);
525:                }
526:                openedZipFiles.clear();
527:
528:            }
529:
530:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.