Source Code Cross Referenced for JavaSource.java in  » IDE-Netbeans » java » org » netbeans » api » java » source » 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 Netbeans » java » org.netbeans.api.java.source 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003:         *
0004:         * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005:         *
0006:         * The contents of this file are subject to the terms of either the GNU
0007:         * General Public License Version 2 only ("GPL") or the Common
0008:         * Development and Distribution License("CDDL") (collectively, the
0009:         * "License"). You may not use this file except in compliance with the
0010:         * License. You can obtain a copy of the License at
0011:         * http://www.netbeans.org/cddl-gplv2.html
0012:         * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013:         * specific language governing permissions and limitations under the
0014:         * License.  When distributing the software, include this License Header
0015:         * Notice in each file and include the License file at
0016:         * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
0017:         * particular file as subject to the "Classpath" exception as provided
0018:         * by Sun in the GPL Version 2 section of the License file that
0019:         * accompanied this code. If applicable, add the following below the
0020:         * License Header, with the fields enclosed by brackets [] replaced by
0021:         * your own identifying information:
0022:         * "Portions Copyrighted [year] [name of copyright owner]"
0023:         *
0024:         * Contributor(s):
0025:         *
0026:         * The Original Software is NetBeans. The Initial Developer of the Original
0027:         * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
0028:         * Microsystems, Inc. All Rights Reserved.
0029:         *
0030:         * If you wish your version of this file to be governed by only the CDDL
0031:         * or only the GPL Version 2, indicate your decision by adding
0032:         * "[Contributor] elects to include this software in this distribution
0033:         * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034:         * single choice of license, a recipient has the option to distribute
0035:         * your version of this file under either the CDDL, the GPL Version 2 or
0036:         * to extend the choice of license to its licensees as provided above.
0037:         * However, if you add GPL Version 2 code and therefore, elected the GPL
0038:         * Version 2 license, then the option applies only if the new code is
0039:         * made subject to such option by the copyright holder.
0040:         */
0041:
0042:        package org.netbeans.api.java.source;
0043:
0044:        import com.sun.source.tree.ClassTree;
0045:        import com.sun.source.tree.CompilationUnitTree;
0046:        import com.sun.source.tree.MethodTree;
0047:        import com.sun.source.tree.Tree;
0048:        import com.sun.source.util.SimpleTreeVisitor;
0049:        import com.sun.source.util.SourcePositions;
0050:        import com.sun.source.util.TreePath;
0051:        import com.sun.source.util.TreeScanner;
0052:        import com.sun.source.util.Trees;
0053:        import com.sun.tools.javac.api.ClassNamesForFileOraculum;
0054:        import com.sun.tools.javac.api.JavacTaskImpl;
0055:        import com.sun.tools.javac.api.JavacTrees;
0056:        import com.sun.tools.javac.code.Source;
0057:        import com.sun.tools.javac.code.Symbol.CompletionFailure;
0058:        import com.sun.tools.javac.comp.AttrContext;
0059:        import com.sun.tools.javac.comp.Enter;
0060:        import com.sun.tools.javac.comp.Env;
0061:        import com.sun.tools.javac.parser.DocCommentScanner;
0062:        import com.sun.tools.javac.tree.JCTree;
0063:        import com.sun.tools.javac.tree.JCTree.JCBlock;
0064:        import com.sun.tools.javac.tree.JCTree.JCClassDecl;
0065:        import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
0066:        import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
0067:        import com.sun.tools.javac.util.Abort;
0068:        import com.sun.tools.javac.util.CancelAbort;
0069:        import com.sun.tools.javac.util.CancelService;
0070:        import com.sun.tools.javac.util.Context;
0071:        import com.sun.tools.javac.util.CouplingAbort;
0072:        import com.sun.tools.javac.util.FlowListener;
0073:        import com.sun.tools.javac.util.Log;
0074:        import com.sun.tools.javadoc.JavadocEnter;
0075:        import com.sun.tools.javadoc.JavadocMemberEnter;
0076:        import com.sun.tools.javadoc.Messager;
0077:        import java.beans.PropertyChangeEvent;
0078:        import java.beans.PropertyChangeListener;
0079:        import java.io.File;
0080:        import java.io.FileOutputStream;
0081:        import java.io.IOException;
0082:        import java.io.InterruptedIOException;
0083:        import java.io.OutputStream;
0084:        import java.io.OutputStreamWriter;
0085:        import java.io.PrintWriter;
0086:        import java.io.Writer;
0087:        import java.lang.ref.Reference;
0088:        import java.lang.ref.WeakReference;
0089:        import java.lang.reflect.Method;
0090:        import java.net.URL;
0091:        import java.util.ArrayList;
0092:        import java.util.Arrays;
0093:        import java.util.Collection;
0094:        import java.util.Collections;
0095:        import java.util.Comparator;
0096:        import java.util.HashMap;
0097:        import java.util.HashSet;
0098:        import java.util.Iterator;
0099:        import java.util.LinkedList;
0100:        import java.util.List;
0101:        import java.util.Map;
0102:        import java.util.Set;
0103:        import java.util.WeakHashMap;
0104:        import java.util.concurrent.CountDownLatch;
0105:        import java.util.concurrent.ExecutionException;
0106:        import java.util.concurrent.Executors;
0107:        import java.util.concurrent.Future;
0108:        import java.util.concurrent.PriorityBlockingQueue;
0109:        import java.util.concurrent.ThreadFactory;
0110:        import java.util.concurrent.TimeUnit;
0111:        import java.util.concurrent.TimeoutException;
0112:        import java.util.concurrent.atomic.AtomicBoolean;
0113:        import java.util.concurrent.atomic.AtomicReference;
0114:        import java.util.concurrent.locks.ReentrantLock;
0115:        import java.util.logging.Level;
0116:        import java.util.logging.Logger;
0117:        import java.util.regex.Pattern;
0118:        import java.util.regex.PatternSyntaxException;
0119:        import javax.swing.event.CaretEvent;
0120:        import javax.swing.event.CaretListener;
0121:        import javax.swing.event.ChangeEvent;
0122:        import javax.swing.event.ChangeListener;
0123:        import javax.swing.text.AbstractDocument;
0124:        import javax.swing.text.BadLocationException;
0125:        import javax.swing.text.Document;
0126:        import javax.swing.text.JTextComponent;
0127:        import javax.swing.text.StyledDocument;
0128:        import javax.tools.Diagnostic;
0129:        import javax.tools.DiagnosticListener;
0130:        import javax.tools.JavaCompiler;
0131:        import javax.tools.JavaFileObject;
0132:        import javax.tools.ToolProvider;
0133:        import org.netbeans.api.editor.EditorRegistry;
0134:        import org.netbeans.api.java.classpath.ClassPath;
0135:        import org.netbeans.api.java.lexer.JavaTokenId;
0136:        import org.netbeans.api.java.platform.JavaPlatformManager;
0137:        import org.netbeans.api.java.queries.SourceLevelQuery;
0138:        import org.netbeans.api.java.source.ClasspathInfo.PathKind;
0139:        import org.netbeans.api.java.source.ModificationResult.Difference;
0140:        import org.netbeans.api.lexer.TokenChange;
0141:        import org.netbeans.api.lexer.TokenHierarchy;
0142:        import org.netbeans.api.lexer.TokenHierarchyEvent;
0143:        import org.netbeans.api.lexer.TokenHierarchyEventType;
0144:        import org.netbeans.api.lexer.TokenHierarchyListener;
0145:        import org.netbeans.api.lexer.TokenSequence;
0146:        import org.netbeans.lib.editor.util.swing.PositionRegion;
0147:        import org.netbeans.modules.java.source.JavaFileFilterQuery;
0148:        import org.netbeans.modules.java.source.JavaSourceAccessor;
0149:        import org.netbeans.modules.java.source.JavadocEnv;
0150:        import org.netbeans.modules.java.source.parsing.FileObjects;
0151:        import org.netbeans.modules.java.preprocessorbridge.spi.JavaFileFilterImplementation;
0152:        import org.netbeans.modules.java.preprocessorbridge.spi.JavaSourceProvider;
0153:        import org.netbeans.modules.java.source.TreeLoader;
0154:        import org.netbeans.modules.java.source.parsing.SourceFileObject;
0155:        import org.netbeans.modules.java.source.tasklist.CompilerSettings;
0156:        import org.netbeans.modules.java.source.usages.ClassIndexImpl;
0157:        import org.netbeans.modules.java.source.usages.ClassIndexManager;
0158:        import org.netbeans.modules.java.source.usages.Index;
0159:        import org.netbeans.modules.java.source.usages.Pair;
0160:        import org.netbeans.modules.java.source.usages.RepositoryUpdater;
0161:        import org.netbeans.modules.java.source.util.LowMemoryEvent;
0162:        import org.netbeans.modules.java.source.util.LowMemoryListener;
0163:        import org.netbeans.modules.java.source.util.LowMemoryNotifier;
0164:        import org.netbeans.modules.java.source.usages.SymbolClassReader;
0165:        import org.netbeans.spi.java.classpath.support.ClassPathSupport;
0166:        import org.openide.cookies.EditorCookie;
0167:        import org.openide.filesystems.FileChangeAdapter;
0168:        import org.openide.filesystems.FileChangeListener;
0169:        import org.openide.filesystems.FileEvent;
0170:        import org.openide.filesystems.FileObject;
0171:        import org.openide.filesystems.FileRenameEvent;
0172:        import org.openide.filesystems.FileStateInvalidException;
0173:        import org.openide.filesystems.FileUtil;
0174:        import org.openide.loaders.DataObject;
0175:        import org.openide.loaders.DataObjectNotFoundException;
0176:        import org.openide.modules.SpecificationVersion;
0177:        import org.openide.text.CloneableEditorSupport;
0178:        import org.openide.util.Exceptions;
0179:        import org.openide.util.Lookup;
0180:        import org.openide.util.NbBundle;
0181:        import org.openide.util.RequestProcessor;
0182:        import org.openide.util.WeakListeners;
0183:
0184:        /** Class representing Java source file opened in the editor.
0185:         *
0186:         * @author Petr Hrebejk, Tomas Zezula
0187:         */
0188:        public final class JavaSource {
0189:
0190:            public static enum Phase {
0191:                MODIFIED,
0192:
0193:                PARSED,
0194:
0195:                ELEMENTS_RESOLVED,
0196:
0197:                RESOLVED,
0198:
0199:                UP_TO_DATE;
0200:
0201:            };
0202:
0203:            public static enum Priority {
0204:                MAX, HIGH, ABOVE_NORMAL, NORMAL, BELOW_NORMAL, LOW, MIN
0205:            };
0206:
0207:            /**
0208:             * This specialization of {@link IOException} signals that a {@link JavaSource#runUserActionTask}
0209:             * or {@link JavaSource#runModificationTask} failed due to lack of memory. The {@link InsufficientMemoryException#getFile}
0210:             * method returns a file which cannot be processed.
0211:             */
0212:            public static final class InsufficientMemoryException extends
0213:                    IOException {
0214:
0215:                private FileObject fo;
0216:
0217:                private InsufficientMemoryException(final String message,
0218:                        final FileObject fo) {
0219:                    super (message);
0220:                    this .fo = fo;
0221:                }
0222:
0223:                private InsufficientMemoryException(FileObject fo) {
0224:                    this (NbBundle.getMessage(JavaSource.class,
0225:                            "MSG_UnsufficientMemoryException", FileUtil
0226:                                    .getFileDisplayName(fo)), fo);
0227:                }
0228:
0229:                /**
0230:                 * Returns file which cannot be processed due to lack of memory.
0231:                 * @return {@link FileObject}
0232:                 */
0233:                public FileObject getFile() {
0234:                    return this .fo;
0235:                }
0236:            }
0237:
0238:            /**Constants for JavaSource.flags*/
0239:            private static final int INVALID = 1;
0240:            private static final int CHANGE_EXPECTED = INVALID << 1;
0241:            private static final int RESCHEDULE_FINISHED_TASKS = CHANGE_EXPECTED << 1;
0242:            private static final int UPDATE_INDEX = RESCHEDULE_FINISHED_TASKS << 1;
0243:            private static final int IS_CLASS_FILE = UPDATE_INDEX << 1;
0244:
0245:            private static final Pattern excludedTasks;
0246:            private static final Pattern includedTasks;
0247:            /**Limit for task to be marked as a slow one, in ms*/
0248:            private static final int SLOW_CANCEL_LIMIT = 50;
0249:            private static final PrintWriter DEV_NULL = new PrintWriter(
0250:                    new DevNullWriter(), false);
0251:
0252:            private static final int REPARSE_DELAY = 500;
0253:            private int reparseDelay;
0254:
0255:            /**Used by unit tests*/
0256:            static JavaFileObjectProvider jfoProvider = new DefaultJavaFileObjectProvider();
0257:
0258:            /**
0259:             * Helper map mapping the {@link Phase} to message for performance logger
0260:             */
0261:            private static Map<Phase, String> phase2Message = new HashMap<Phase, String>();
0262:
0263:            private static class InternalLock {
0264:            };
0265:
0266:            private static final Object INTERNAL_LOCK = new InternalLock();
0267:
0268:            /**
0269:             * Init the maps
0270:             */
0271:            static {
0272:                JavaSourceAccessor.setINSTANCE(new JavaSourceAccessorImpl());
0273:                phase2Message.put(Phase.PARSED, "Parsed"); //NOI18N
0274:                phase2Message.put(Phase.ELEMENTS_RESOLVED,
0275:                        "Signatures Attributed"); //NOI18N
0276:                phase2Message.put(Phase.RESOLVED, "Attributed"); //NOI18N
0277:
0278:                //Initialize the excludedTasks
0279:                Pattern _excludedTasks = null;
0280:                try {
0281:                    String excludedValue = System
0282:                            .getProperty("org.netbeans.api.java.source.JavaSource.excludedTasks"); //NOI18N
0283:                    if (excludedValue != null) {
0284:                        _excludedTasks = Pattern.compile(excludedValue);
0285:                    }
0286:                } catch (PatternSyntaxException e) {
0287:                    e.printStackTrace();
0288:                }
0289:                excludedTasks = _excludedTasks;
0290:                Pattern _includedTasks = null;
0291:                try {
0292:                    String includedValue = System
0293:                            .getProperty("org.netbeans.api.java.source.JavaSource.includedTasks"); //NOI18N
0294:                    if (includedValue != null) {
0295:                        _includedTasks = Pattern.compile(includedValue);
0296:                    }
0297:                } catch (PatternSyntaxException e) {
0298:                    e.printStackTrace();
0299:                }
0300:                includedTasks = _includedTasks;
0301:
0302:            }
0303:
0304:            private final static PriorityBlockingQueue<Request> requests = new PriorityBlockingQueue<Request>(
0305:                    10, new RequestComparator());
0306:            private final static Map<JavaSource, Collection<Request>> finishedRequests = new WeakHashMap<JavaSource, Collection<Request>>();
0307:            private final static Map<JavaSource, Collection<Request>> waitingRequests = new WeakHashMap<JavaSource, Collection<Request>>();
0308:            private final static Collection<CancellableTask> toRemove = new LinkedList<CancellableTask>();
0309:            private final static SingleThreadFactory factory = new SingleThreadFactory();
0310:            private final static CurrentRequestReference currentRequest = new CurrentRequestReference();
0311:            private final static EditorRegistryListener editorRegistryListener = new EditorRegistryListener();
0312:            private final static List<DeferredTask> todo = Collections
0313:                    .synchronizedList(new LinkedList<DeferredTask>());
0314:            //Only single thread can operate on the single javac
0315:            private final static ReentrantLock javacLock = new ReentrantLock(
0316:                    true);
0317:
0318:            private final Collection<FileObject> files;
0319:            final FileObject rootFo;
0320:            private final FileChangeListener fileChangeListener;
0321:            private DocListener listener;
0322:            private DataObjectListener dataObjectListener;
0323:
0324:            private final ClasspathInfo classpathInfo;
0325:            private CompilationInfoImpl currentInfo;
0326:            private java.util.Stack<CompilationInfoImpl> infoStack = new java.util.Stack<CompilationInfoImpl>();
0327:
0328:            //Incremental parsing support
0329:            private final List<Pair<DocPositionRegion, MethodTree>> positions = Collections
0330:                    .synchronizedList(new LinkedList<Pair<DocPositionRegion, MethodTree>>());
0331:
0332:            private int flags = 0;
0333:
0334:            //Preprocessor support
0335:            private FilterListener filterListener;
0336:
0337:            private PositionConverter binding;
0338:            private final boolean supportsReparse;
0339:
0340:            private static final Logger LOGGER = Logger
0341:                    .getLogger(JavaSource.class.getName());
0342:
0343:            static {
0344:                Executors.newSingleThreadExecutor(factory).submit(
0345:                        new CompilationJob());
0346:            }
0347:
0348:            /**
0349:             * Returns a {@link JavaSource} instance representing given {@link org.openide.filesystems.FileObject}s
0350:             * and classpath represented by given {@link ClasspathInfo}.
0351:             * @param cpInfo the classpaths to be used.
0352:             * @param files for which the {@link JavaSource} should be created
0353:             * @return a new {@link JavaSource}
0354:             * @throws {@link IllegalArgumentException} if fileObject or cpInfo is null
0355:             */
0356:            public static JavaSource create(final ClasspathInfo cpInfo,
0357:                    final Collection<? extends FileObject> files)
0358:                    throws IllegalArgumentException {
0359:                if (files == null || cpInfo == null) {
0360:                    throw new IllegalArgumentException();
0361:                }
0362:                return create(cpInfo, null, files);
0363:            }
0364:
0365:            /**
0366:             * Returns a {@link JavaSource} instance representing given {@link org.openide.filesystems.FileObject}s
0367:             * and classpath represented by given {@link ClasspathInfo}.
0368:             * @param cpInfo the classpaths to be used.
0369:             * @param files for which the {@link JavaSource} should be created
0370:             * @return a new {@link JavaSource}
0371:             * @throws {@link IllegalArgumentException} if fileObject or cpInfo is null        
0372:             */
0373:            public static JavaSource create(final ClasspathInfo cpInfo,
0374:                    final FileObject... files) throws IllegalArgumentException {
0375:                if (files == null || cpInfo == null) {
0376:                    throw new IllegalArgumentException();
0377:                }
0378:                return create(cpInfo, null, Arrays.asList(files));
0379:            }
0380:
0381:            private static JavaSource create(final ClasspathInfo cpInfo,
0382:                    final PositionConverter binding,
0383:                    final Collection<? extends FileObject> files)
0384:                    throws IllegalArgumentException {
0385:                try {
0386:                    return new JavaSource(cpInfo, binding, files);
0387:                } catch (DataObjectNotFoundException donf) {
0388:                    Logger.getLogger("global").warning(
0389:                            "Ignoring non existent file: "
0390:                                    + FileUtil.getFileDisplayName(donf
0391:                                            .getFileObject())); //NOI18N
0392:                } catch (IOException ex) {
0393:                    Exceptions.printStackTrace(ex);
0394:                }
0395:                return null;
0396:            }
0397:
0398:            private static Map<FileObject, Reference<JavaSource>> file2JavaSource = new WeakHashMap<FileObject, Reference<JavaSource>>();
0399:
0400:            /**
0401:             * Returns a {@link JavaSource} instance associated to given {@link org.openide.filesystems.FileObject},
0402:             * it returns null if the {@link Document} is not associanted with data type providing the {@link JavaSource}.
0403:             * @param fileObject for which the {@link JavaSource} should be found/created.
0404:             * @return {@link JavaSource} or null
0405:             * @throws {@link IllegalArgumentException} if fileObject is null
0406:             */
0407:            public static JavaSource forFileObject(FileObject fileObject)
0408:                    throws IllegalArgumentException {
0409:                if (fileObject == null) {
0410:                    throw new IllegalArgumentException("fileObject == null"); //NOI18N
0411:                }
0412:                if (!fileObject.isValid()) {
0413:                    return null;
0414:                }
0415:
0416:                try {
0417:                    if (fileObject.getFileSystem().isDefault()
0418:                            && fileObject
0419:                                    .getAttribute("javax.script.ScriptEngine") != null
0420:                            && fileObject.getAttribute("template") == Boolean.TRUE) {
0421:                        return null;
0422:                    }
0423:                    DataObject od = DataObject.find(fileObject);
0424:
0425:                    EditorCookie ec = od.getLookup().lookup(EditorCookie.class);
0426:
0427:                    if (!(ec instanceof  CloneableEditorSupport)) {
0428:                        //allow creation of JavaSource for .class files:
0429:                        if (!("application/x-class-file".equals(FileUtil
0430:                                .getMIMEType(fileObject)) || "class"
0431:                                .equals(fileObject.getExt()))) {
0432:                            return null;
0433:                        }
0434:                    }
0435:                } catch (FileStateInvalidException ex) {
0436:                    LOGGER.log(Level.FINE, null, ex);
0437:                    return null;
0438:                } catch (DataObjectNotFoundException ex) {
0439:                    LOGGER.log(Level.FINE, null, ex);
0440:                    return null;
0441:                }
0442:
0443:                Reference<JavaSource> ref = file2JavaSource.get(fileObject);
0444:                JavaSource js = ref != null ? ref.get() : null;
0445:                if (js == null) {
0446:                    if ("application/x-class-file".equals(FileUtil
0447:                            .getMIMEType(fileObject))
0448:                            || "class".equals(fileObject.getExt())) { //NOI18N
0449:                        ClassPath bootPath = ClassPath.getClassPath(fileObject,
0450:                                ClassPath.BOOT);
0451:                        ClassPath compilePath = ClassPath.getClassPath(
0452:                                fileObject, ClassPath.COMPILE);
0453:                        if (compilePath == null) {
0454:                            compilePath = ClassPathSupport
0455:                                    .createClassPath(new URL[0]);
0456:                        }
0457:                        ClassPath srcPath = ClassPath.getClassPath(fileObject,
0458:                                ClassPath.SOURCE);
0459:                        if (srcPath == null) {
0460:                            srcPath = ClassPathSupport
0461:                                    .createClassPath(new URL[0]);
0462:                        }
0463:                        ClassPath execPath = ClassPath.getClassPath(fileObject,
0464:                                ClassPath.EXECUTE);
0465:                        if (execPath != null) {
0466:                            bootPath = ClassPathSupport.createProxyClassPath(
0467:                                    execPath, bootPath);
0468:                        }
0469:                        final ClasspathInfo info = ClasspathInfo.create(
0470:                                bootPath, compilePath, srcPath);
0471:                        FileObject root = ClassPathSupport
0472:                                .createProxyClassPath(bootPath, compilePath,
0473:                                        srcPath).findOwnerRoot(fileObject);
0474:                        if (root == null) {
0475:                            return null;
0476:                        }
0477:                        try {
0478:                            js = new JavaSource(info, fileObject, root);
0479:                        } catch (IOException ioe) {
0480:                            Exceptions.printStackTrace(ioe);
0481:                        }
0482:                    } else {
0483:                        PositionConverter binding = null;
0484:                        if (!"text/x-java".equals(FileUtil
0485:                                .getMIMEType(fileObject))
0486:                                && !"java".equals(fileObject.getExt())) { //NOI18N
0487:                            for (JavaSourceProvider provider : Lookup
0488:                                    .getDefault().lookupAll(
0489:                                            JavaSourceProvider.class)) {
0490:                                JavaFileFilterImplementation filter = provider
0491:                                        .forFileObject(fileObject);
0492:                                if (filter != null) {
0493:                                    binding = new PositionConverter(fileObject,
0494:                                            filter);
0495:                                    break;
0496:                                }
0497:                            }
0498:                            if (binding == null)
0499:                                return null;
0500:                        }
0501:                        js = create(ClasspathInfo.create(fileObject), binding,
0502:                                Collections.singletonList(fileObject));
0503:                    }
0504:                    file2JavaSource.put(fileObject,
0505:                            new WeakReference<JavaSource>(js));
0506:                }
0507:                return js;
0508:            }
0509:
0510:            /**
0511:             * Returns a {@link JavaSource} instance associated to the given {@link javax.swing.Document},
0512:             * it returns null if the {@link Document} is not
0513:             * associated with data type providing the {@link JavaSource}.
0514:             * @param doc {@link Document} for which the {@link JavaSource} should be found/created.
0515:             * @return {@link JavaSource} or null
0516:             * @throws {@link IllegalArgumentException} if doc is null
0517:             */
0518:            public static JavaSource forDocument(Document doc)
0519:                    throws IllegalArgumentException {
0520:                if (doc == null) {
0521:                    throw new IllegalArgumentException("doc == null"); //NOI18N
0522:                }
0523:                Reference<?> ref = (Reference<?>) doc
0524:                        .getProperty(JavaSource.class);
0525:                JavaSource js = ref != null ? (JavaSource) ref.get() : null;
0526:                if (js == null) {
0527:                    Object source = doc
0528:                            .getProperty(Document.StreamDescriptionProperty);
0529:
0530:                    if (source instanceof  DataObject) {
0531:                        DataObject dObj = (DataObject) source;
0532:                        if (dObj != null) {
0533:                            js = forFileObject(dObj.getPrimaryFile());
0534:                        }
0535:                    }
0536:                }
0537:                return js;
0538:            }
0539:
0540:            /**
0541:             * Creates a new instance of JavaSource
0542:             * @param files to create JavaSource for
0543:             * @param cpInfo classpath info
0544:             */
0545:            private JavaSource(ClasspathInfo cpInfo, PositionConverter binding,
0546:                    Collection<? extends FileObject> files) throws IOException {
0547:                this .reparseDelay = REPARSE_DELAY;
0548:                this .files = Collections
0549:                        .unmodifiableList(new ArrayList<FileObject>(files)); //Create a defensive copy, prevent modification
0550:                this .fileChangeListener = new FileChangeListenerImpl();
0551:                this .binding = binding;
0552:                this .supportsReparse = this .binding == null;
0553:                boolean multipleSources = this .files.size() > 1, filterAssigned = false;
0554:                for (Iterator<? extends FileObject> it = this .files.iterator(); it
0555:                        .hasNext();) {
0556:                    FileObject file = it.next();
0557:                    try {
0558:                        Logger.getLogger("TIMER").log(Level.FINE, "JavaSource",
0559:                                new Object[] { file, this  });
0560:                        if (!multipleSources) {
0561:                            file.addFileChangeListener(FileUtil
0562:                                    .weakFileChangeListener(
0563:                                            this .fileChangeListener, file));
0564:                            this .assignDocumentListener(DataObject.find(file));
0565:                            this .dataObjectListener = new DataObjectListener(
0566:                                    file);
0567:                        }
0568:                        if (!filterAssigned) {
0569:                            filterAssigned = true;
0570:                            if (this .binding == null) {
0571:                                this .binding = new PositionConverter(file,
0572:                                        JavaFileFilterQuery.getFilter(file));
0573:                            }
0574:                            JavaFileFilterImplementation filter = this .binding
0575:                                    .getFilter();
0576:                            if (filter != null) {
0577:                                this .filterListener = new FilterListener(filter);
0578:                            }
0579:                        }
0580:                    } catch (DataObjectNotFoundException donf) {
0581:                        if (multipleSources) {
0582:                            LOGGER.warning("Ignoring non existent file: "
0583:                                    + FileUtil.getFileDisplayName(file)); //NOI18N
0584:                            it.remove();
0585:                        } else {
0586:                            throw donf;
0587:                        }
0588:                    }
0589:                }
0590:                this .classpathInfo = cpInfo;
0591:                if (this .files.size() == 1) {
0592:                    this .rootFo = classpathInfo.getClassPath(PathKind.SOURCE)
0593:                            .findOwnerRoot(this .files.iterator().next());
0594:                } else {
0595:                    this .rootFo = null;
0596:                }
0597:                this .classpathInfo.addChangeListener(WeakListeners.change(
0598:                        this .listener, this .classpathInfo));
0599:            }
0600:
0601:            private JavaSource(final ClasspathInfo info,
0602:                    final FileObject classFileObject, final FileObject root)
0603:                    throws IOException {
0604:                assert info != null;
0605:                assert classFileObject != null;
0606:                assert root != null;
0607:                this .reparseDelay = REPARSE_DELAY;
0608:                this .files = Collections
0609:                        .<FileObject> singletonList(classFileObject);
0610:                this .fileChangeListener = new FileChangeListenerImpl();
0611:                classFileObject.addFileChangeListener(FileUtil
0612:                        .weakFileChangeListener(this .fileChangeListener,
0613:                                classFileObject));
0614:                this .dataObjectListener = new DataObjectListener(
0615:                        classFileObject);
0616:                this .classpathInfo = info;
0617:                this .rootFo = root;
0618:                this .classpathInfo.addChangeListener(WeakListeners.change(
0619:                        this .listener, this .classpathInfo));
0620:                this .flags |= IS_CLASS_FILE;
0621:                this .supportsReparse = false;
0622:                this .binding = new PositionConverter(classFileObject, null);
0623:            }
0624:
0625:            private static final Set<StackTraceElement> warnedAboutRunInEQ = new HashSet<StackTraceElement>();
0626:
0627:            /** Runs a task which permits for controlling phases of the parsing process.
0628:             * You probably do not want to call this method unless you are reacting to
0629:             * some user's GUI input which requires immediate action (e.g. code completion popup). 
0630:             * In all other cases use {@link JavaSourceTaskFactory}.<BR>
0631:             * Call to this method will cancel processing of all the phase completion tasks until
0632:             * this task does not finish.<BR>
0633:             * @see org.netbeans.api.java.source.CancellableTask for information about implementation requirements
0634:             * @param task The task which.
0635:             * @param shared if true the java compiler may be reused by other {@link org.netbeans.api.java.source.CancellableTasks},
0636:             * the value false may have negative impact on the IDE performance.     
0637:             * <div class="nonnormative">
0638:             * <p>
0639:             * It's legal to nest the {@link JavaSource#runUserActionTask} into another {@link JavaSource#runUserActionTask}.
0640:             * It's also legal to nest the {@link JavaSource#runModificationTask} into {@link JavaSource#runUserActionTask},
0641:             * the outer {@link JavaSource#runUserActionTask} does not see changes caused by nested {@link JavaSource#runModificationTask},
0642:             * but the following nested task see them. 
0643:             * </p>
0644:             * </div>
0645:             */
0646:            public void runUserActionTask(
0647:                    final Task<CompilationController> task, final boolean shared)
0648:                    throws IOException {
0649:                if (task == null) {
0650:                    throw new IllegalArgumentException("Task cannot be null"); //NOI18N
0651:                }
0652:
0653:                assert javacLock.isHeldByCurrentThread()
0654:                        || !holdsDocumentWriteLock(files) : "JavaSource.runCompileControlTask called under Document write lock."; //NOI18N
0655:
0656:                boolean a = false;
0657:                assert a = true;
0658:                if (a && javax.swing.SwingUtilities.isEventDispatchThread()) {
0659:                    StackTraceElement stackTraceElement = findCaller(Thread
0660:                            .currentThread().getStackTrace());
0661:                    if (stackTraceElement != null
0662:                            && warnedAboutRunInEQ.add(stackTraceElement)) {
0663:                        LOGGER
0664:                                .warning("JavaSource.runUserActionTask called in AWT event thread by: "
0665:                                        + stackTraceElement); // NOI18N
0666:                    }
0667:                }
0668:
0669:                if (this .files.size() <= 1) {
0670:                    final JavaSource.Request request = currentRequest
0671:                            .getTaskToCancel();
0672:                    try {
0673:                        if (request != null) {
0674:                            request.task.cancel();
0675:                        }
0676:                        this .javacLock.lock();
0677:                        try {
0678:                            CompilationInfoImpl currentInfo = null;
0679:                            boolean jsInvalid;
0680:                            Pair<DocPositionRegion, MethodTree> changedMethod = null;
0681:                            synchronized (this ) {
0682:                                jsInvalid = this .currentInfo == null
0683:                                        || (this .flags & INVALID) != 0;
0684:                                currentInfo = this .currentInfo;
0685:                                changedMethod = (currentInfo == null ? null
0686:                                        : this .currentInfo.getChangedTree());
0687:                                if (!shared) {
0688:                                    this .flags |= INVALID;
0689:                                }
0690:                            }
0691:                            if (jsInvalid) {
0692:                                boolean needsFullReparse = true;
0693:                                if (changedMethod != null
0694:                                        && currentInfo != null) {
0695:                                    needsFullReparse = !reparseMethod(
0696:                                            currentInfo, changedMethod.second,
0697:                                            changedMethod.first.getText());
0698:                                }
0699:                                if (needsFullReparse) {
0700:                                    currentInfo = createCurrentInfo(this ,
0701:                                            binding, null);
0702:                                }
0703:                                if (shared) {
0704:                                    synchronized (this ) {
0705:                                        if (this .currentInfo == null
0706:                                                || (this .flags & INVALID) != 0) {
0707:                                            this .currentInfo = currentInfo;
0708:                                            this .flags &= ~INVALID;
0709:                                        } else {
0710:                                            currentInfo = this .currentInfo;
0711:                                        }
0712:                                    }
0713:                                }
0714:                            }
0715:                            assert currentInfo != null;
0716:                            if (shared) {
0717:                                if (!infoStack.isEmpty()) {
0718:                                    currentInfo = infoStack.peek();
0719:                                }
0720:                            } else {
0721:                                infoStack.push(currentInfo);
0722:                            }
0723:                            try {
0724:                                final CompilationController clientController = new CompilationController(
0725:                                        currentInfo);
0726:                                try {
0727:                                    task.run(clientController);
0728:                                } finally {
0729:                                    if (shared) {
0730:                                        clientController.invalidate();
0731:                                    }
0732:                                }
0733:                            } finally {
0734:                                if (!shared) {
0735:                                    infoStack.pop();
0736:                                }
0737:                            }
0738:                        } catch (CompletionFailure e) {
0739:                            IOException ioe = new IOException();
0740:                            ioe.initCause(e);
0741:                            throw ioe;
0742:                        } catch (RuntimeException e) {
0743:                            throw e;
0744:                        } catch (Exception e) {
0745:                            IOException ioe = new IOException();
0746:                            ioe.initCause(e);
0747:                            throw ioe;
0748:                        } finally {
0749:                            this .javacLock.unlock();
0750:                        }
0751:                    } finally {
0752:                        currentRequest.cancelCompleted(request);
0753:                    }
0754:                } else {
0755:                    final JavaSource.Request request = currentRequest
0756:                            .getTaskToCancel();
0757:                    try {
0758:                        if (request != null) {
0759:                            request.task.cancel();
0760:                        }
0761:                        this .javacLock.lock();
0762:                        try {
0763:                            JavacTaskImpl jt = null;
0764:                            FileObject activeFile = null;
0765:                            Iterator<FileObject> files = this .files.iterator();
0766:                            while (files.hasNext() || activeFile != null) {
0767:                                boolean restarted;
0768:                                if (activeFile == null) {
0769:                                    activeFile = files.next();
0770:                                    restarted = false;
0771:                                } else {
0772:                                    restarted = true;
0773:                                }
0774:                                CompilationInfoImpl ci = createCurrentInfo(
0775:                                        this , new PositionConverter(activeFile,
0776:                                                null), jt);
0777:                                CompilationController clientController = new CompilationController(
0778:                                        ci);
0779:                                try {
0780:                                    task.run(clientController);
0781:                                } finally {
0782:                                    if (shared) {
0783:                                        clientController.invalidate();
0784:                                    }
0785:                                }
0786:                                if (!ci.needsRestart) {
0787:                                    jt = ci.getJavacTask();
0788:                                    Log.instance(jt.getContext()).nerrors = 0;
0789:                                    activeFile = null;
0790:                                } else {
0791:                                    jt = null;
0792:                                    ci = null;
0793:                                    System.gc();
0794:                                    if (restarted) {
0795:                                        throw new InsufficientMemoryException(
0796:                                                activeFile);
0797:                                    }
0798:                                }
0799:                            }
0800:                        } catch (CompletionFailure e) {
0801:                            IOException ioe = new IOException();
0802:                            ioe.initCause(e);
0803:                            throw ioe;
0804:                        } catch (RuntimeException e) {
0805:                            throw e;
0806:                        } catch (Exception e) {
0807:                            IOException ioe = new IOException();
0808:                            ioe.initCause(e);
0809:                            throw ioe;
0810:                        } finally {
0811:                            this .javacLock.unlock();
0812:                        }
0813:                    } finally {
0814:                        currentRequest.cancelCompleted(request);
0815:                    }
0816:                }
0817:            }
0818:
0819:            private void runUserActionTask(
0820:                    final CancellableTask<CompilationController> task,
0821:                    final boolean shared) throws IOException {
0822:                final Task<CompilationController> _task = task;
0823:                this .runUserActionTask(_task, shared);
0824:            }
0825:
0826:            /**
0827:             * Performs the given task when the scan finished. When no background scan is running
0828:             * it performs the given task synchronously. When the background scan is active it queues
0829:             * the given task and returns, the task is performed when the background scan completes by
0830:             * the thread doing the background scan.
0831:             * @param task to be performed
0832:             * @param shared if true the java compiler may be reused by other {@link org.netbeans.api.java.source.CancellableTasks},
0833:             * the value false may have negative impact on the IDE performance.
0834:             * @return {@link Future} which can be used to find out the sate of the task {@link Future#isDone} or {@link Future#isCancelled}.
0835:             * The caller may cancel the task using {@link Future#cancel} or wait until the task is performed {@link Future#get}.
0836:             * @throws IOException encapsulating the exception thrown by {@link CancellableTasks#run}
0837:             * @since 0.12
0838:             */
0839:            public Future<Void> runWhenScanFinished(
0840:                    final Task<CompilationController> task, final boolean shared)
0841:                    throws IOException {
0842:                assert task != null;
0843:                final ScanSync sync = new ScanSync(task);
0844:                final DeferredTask r = new DeferredTask(this , task, shared,
0845:                        sync);
0846:                //0) Add speculatively task to be performed at the end of background scan
0847:                todo.add(r);
0848:                if (RepositoryUpdater.getDefault().isScanInProgress()) {
0849:                    return sync;
0850:                }
0851:                //1) Try to aquire javac lock, if successfull no task is running
0852:                //   perform the given taks synchronously if it wasn't already performed
0853:                //   by background scan.
0854:                final boolean locked = javacLock.tryLock();
0855:                if (locked) {
0856:                    try {
0857:                        if (todo.remove(r)) {
0858:                            try {
0859:                                runUserActionTask(task, shared);
0860:                            } finally {
0861:                                sync.taskFinished();
0862:                            }
0863:                        }
0864:                    } finally {
0865:                        javacLock.unlock();
0866:                    }
0867:                } else {
0868:                    //Otherwise interrupt currently running task and try to aquire lock
0869:                    do {
0870:                        final JavaSource.Request[] request = new JavaSource.Request[1];
0871:                        boolean isScanner = currentRequest
0872:                                .getUserTaskToCancel(request);
0873:                        try {
0874:                            if (isScanner) {
0875:                                return sync;
0876:                            }
0877:                            if (request[0] != null) {
0878:                                request[0].task.cancel();
0879:                            }
0880:                            if (javacLock.tryLock(100, TimeUnit.MILLISECONDS)) {
0881:                                try {
0882:                                    if (todo.remove(r)) {
0883:                                        try {
0884:                                            runUserActionTask(task, shared);
0885:                                            return sync;
0886:                                        } finally {
0887:                                            sync.taskFinished();
0888:                                        }
0889:                                    } else {
0890:                                        return sync;
0891:                                    }
0892:                                } finally {
0893:                                    javacLock.unlock();
0894:                                }
0895:                            }
0896:                        } catch (InterruptedException e) {
0897:                            throw (InterruptedIOException) new InterruptedIOException()
0898:                                    .initCause(e);
0899:                        } finally {
0900:                            if (!isScanner) {
0901:                                currentRequest.cancelCompleted(request[0]);
0902:                            }
0903:                        }
0904:                    } while (true);
0905:                }
0906:                return sync;
0907:            }
0908:
0909:            private Future<Void> runWhenScanFinished(
0910:                    final CancellableTask<CompilationController> task,
0911:                    final boolean shared) throws IOException {
0912:                final Task<CompilationController> _task = task;
0913:                return this .runWhenScanFinished(_task, shared);
0914:            }
0915:
0916:            /** Runs a task which permits for modifying the sources.
0917:             * Call to this method will cancel processing of all the phase completion tasks until
0918:             * this task does not finish.<BR>
0919:             * @see Task for information about implementation requirements
0920:             * @param task The task which.
0921:             */
0922:            public ModificationResult runModificationTask(Task<WorkingCopy> task)
0923:                    throws IOException {
0924:                if (task == null) {
0925:                    throw new IllegalArgumentException("Task cannot be null"); //NOI18N
0926:                }
0927:
0928:                assert javacLock.isHeldByCurrentThread()
0929:                        || !holdsDocumentWriteLock(files) : "JavaSource.runModificationTask called under Document write lock."; //NOI18N
0930:
0931:                boolean a = false;
0932:                assert a = true;
0933:                if (a && javax.swing.SwingUtilities.isEventDispatchThread()) {
0934:                    StackTraceElement stackTraceElement = findCaller(Thread
0935:                            .currentThread().getStackTrace());
0936:                    if (stackTraceElement != null
0937:                            && warnedAboutRunInEQ.add(stackTraceElement)) {
0938:                        LOGGER
0939:                                .warning("JavaSource.runModificationTask called in AWT event thread by: "
0940:                                        + stackTraceElement); //NOI18N
0941:                    }
0942:                }
0943:
0944:                ModificationResult result = new ModificationResult(this );
0945:                if (this .files.size() <= 1) {
0946:                    long start = System.currentTimeMillis();
0947:                    final JavaSource.Request request = currentRequest
0948:                            .getTaskToCancel();
0949:                    try {
0950:                        if (request != null) {
0951:                            request.task.cancel();
0952:                        }
0953:                        this .javacLock.lock();
0954:                        try {
0955:                            CompilationInfoImpl currentInfo = null;
0956:                            boolean jsInvalid;
0957:                            Pair<DocPositionRegion, MethodTree> changedMethod;
0958:                            synchronized (this ) {
0959:                                jsInvalid = this .currentInfo == null
0960:                                        || (this .flags & INVALID) != 0;
0961:                                currentInfo = this .currentInfo;
0962:                                changedMethod = currentInfo == null ? null
0963:                                        : currentInfo.getChangedTree();
0964:                            }
0965:                            if (jsInvalid) {
0966:                                boolean needsFullReparse = true;
0967:                                if (changedMethod != null
0968:                                        && currentInfo != null) {
0969:                                    needsFullReparse = !reparseMethod(
0970:                                            currentInfo, changedMethod.second,
0971:                                            changedMethod.first.getText());
0972:                                }
0973:                                if (needsFullReparse) {
0974:                                    currentInfo = createCurrentInfo(this ,
0975:                                            binding, null);
0976:                                }
0977:                                synchronized (this ) {
0978:                                    if (this .currentInfo == null
0979:                                            || (this .flags & INVALID) != 0) {
0980:                                        this .currentInfo = currentInfo;
0981:                                        this .flags &= ~INVALID;
0982:                                    } else {
0983:                                        currentInfo = this .currentInfo;
0984:                                    }
0985:                                }
0986:                            }
0987:                            assert currentInfo != null;
0988:                            WorkingCopy copy = new WorkingCopy(currentInfo);
0989:                            task.run(copy);
0990:                            List<Difference> diffs = copy.getChanges();
0991:                            if (diffs != null && diffs.size() > 0)
0992:                                result.diffs.put(currentInfo.getFileObject(),
0993:                                        diffs);
0994:                        } catch (CompletionFailure e) {
0995:                            IOException ioe = new IOException();
0996:                            ioe.initCause(e);
0997:                            throw ioe;
0998:                        } catch (RuntimeException e) {
0999:                            throw e;
1000:                        } catch (Exception e) {
1001:                            IOException ioe = new IOException();
1002:                            ioe.initCause(e);
1003:                            throw ioe;
1004:                        } finally {
1005:                            this .javacLock.unlock();
1006:                        }
1007:                    } finally {
1008:                        currentRequest.cancelCompleted(request);
1009:                    }
1010:                    Logger.getLogger("TIMER").log(
1011:                            Level.FINE,
1012:                            "Modification Task",
1013:                            new Object[] { currentInfo.getFileObject(),
1014:                                    System.currentTimeMillis() - start });
1015:                } else {
1016:                    final JavaSource.Request request = currentRequest
1017:                            .getTaskToCancel();
1018:                    try {
1019:                        if (request != null) {
1020:                            request.task.cancel();
1021:                        }
1022:                        this .javacLock.lock();
1023:                        try {
1024:                            JavacTaskImpl jt = null;
1025:                            FileObject activeFile = null;
1026:                            Iterator<FileObject> files = this .files.iterator();
1027:                            while (files.hasNext() || activeFile != null) {
1028:                                boolean restarted;
1029:                                if (activeFile == null) {
1030:                                    activeFile = files.next();
1031:                                    restarted = false;
1032:                                } else {
1033:                                    restarted = true;
1034:                                }
1035:                                CompilationInfoImpl ci = createCurrentInfo(
1036:                                        this , new PositionConverter(activeFile,
1037:                                                null), jt);
1038:                                WorkingCopy copy = new WorkingCopy(ci);
1039:                                task.run(copy);
1040:                                if (!ci.needsRestart) {
1041:                                    jt = ci.getJavacTask();
1042:                                    Log.instance(jt.getContext()).nerrors = 0;
1043:                                    List<Difference> diffs = copy.getChanges();
1044:                                    if (diffs != null && diffs.size() > 0)
1045:                                        result.diffs.put(ci.getFileObject(),
1046:                                                diffs);
1047:                                    activeFile = null;
1048:                                } else {
1049:                                    jt = null;
1050:                                    ci = null;
1051:                                    System.gc();
1052:                                    if (restarted) {
1053:                                        throw new InsufficientMemoryException(
1054:                                                activeFile);
1055:                                    }
1056:                                }
1057:                            }
1058:                        } catch (CompletionFailure e) {
1059:                            IOException ioe = new IOException();
1060:                            ioe.initCause(e);
1061:                            throw ioe;
1062:                        } catch (RuntimeException e) {
1063:                            throw e;
1064:                        } catch (Exception e) {
1065:                            IOException ioe = new IOException();
1066:                            ioe.initCause(e);
1067:                            throw ioe;
1068:                        } finally {
1069:                            this .javacLock.unlock();
1070:                        }
1071:                    } finally {
1072:                        currentRequest.cancelCompleted(request);
1073:                    }
1074:                }
1075:                synchronized (this ) {
1076:                    this .flags |= INVALID;
1077:                }
1078:                return result;
1079:            }
1080:
1081:            private ModificationResult runModificationTask(
1082:                    CancellableTask<WorkingCopy> task) throws IOException {
1083:                final Task<WorkingCopy> _task = task;
1084:                return this .runModificationTask(_task);
1085:            }
1086:
1087:            /** Adds a task to given compilation phase. The tasks will run sequentially by
1088:             * priority after given phase is reached.
1089:             * @see CancellableTask for information about implementation requirements 
1090:             * @task The task to run.
1091:             * @phase In which phase should the task run
1092:             * @priority Priority of the task.
1093:             */
1094:            void addPhaseCompletionTask(CancellableTask<CompilationInfo> task,
1095:                    Phase phase, Priority priority) throws IOException {
1096:                if (task == null) {
1097:                    throw new IllegalArgumentException("Task cannot be null"); //NOI18N
1098:                }
1099:                if (phase == null || phase == Phase.MODIFIED) {
1100:                    throw new IllegalArgumentException(String.format(
1101:                            "The %s is not a legal value of phase", phase)); //NOI18N
1102:                }
1103:                if (priority == null) {
1104:                    throw new IllegalArgumentException(
1105:                            "The priority cannot be null"); //NOI18N
1106:                }
1107:                final String taskClassName = task.getClass().getName();
1108:                if (excludedTasks != null
1109:                        && excludedTasks.matcher(taskClassName).matches()) {
1110:                    if (includedTasks == null
1111:                            || !includedTasks.matcher(taskClassName).matches())
1112:                        return;
1113:                }
1114:                handleAddRequest(new Request(task, this , phase, priority, true));
1115:            }
1116:
1117:            /** Removes the task from the phase queue.
1118:             * @task The task to remove.
1119:             */
1120:            void removePhaseCompletionTask(CancellableTask<CompilationInfo> task) {
1121:                final String taskClassName = task.getClass().getName();
1122:                if (excludedTasks != null
1123:                        && excludedTasks.matcher(taskClassName).matches()) {
1124:                    if (includedTasks == null
1125:                            || !includedTasks.matcher(taskClassName).matches()) {
1126:                        return;
1127:                    }
1128:                }
1129:                synchronized (INTERNAL_LOCK) {
1130:                    toRemove.add(task);
1131:                    Collection<Request> rqs = finishedRequests.get(this );
1132:                    if (rqs != null) {
1133:                        for (Iterator<Request> it = rqs.iterator(); it
1134:                                .hasNext();) {
1135:                            Request rq = it.next();
1136:                            if (rq.task == task) {
1137:                                it.remove();
1138:                            }
1139:                        }
1140:                    }
1141:                }
1142:            }
1143:
1144:            /**Rerun the task in case it was already run. Does nothing if the task was not already run.
1145:             *
1146:             * @task to reschedule
1147:             */
1148:            void rescheduleTask(CancellableTask<CompilationInfo> task) {
1149:                synchronized (INTERNAL_LOCK) {
1150:                    JavaSource.Request request = this .currentRequest
1151:                            .getTaskToCancel(task);
1152:                    if (request == null) {
1153:                        out: for (Iterator<Collection<Request>> it = finishedRequests
1154:                                .values().iterator(); it.hasNext();) {
1155:                            Collection<Request> cr = it.next();
1156:                            for (Iterator<Request> it2 = cr.iterator(); it2
1157:                                    .hasNext();) {
1158:                                Request fr = it2.next();
1159:                                if (task == fr.task) {
1160:                                    it2.remove();
1161:                                    JavaSource.requests.add(fr);
1162:                                    if (cr.size() == 0) {
1163:                                        it.remove();
1164:                                    }
1165:                                    break out;
1166:                                }
1167:                            }
1168:                        }
1169:                    } else {
1170:                        currentRequest.cancelCompleted(request);
1171:                    }
1172:                }
1173:            }
1174:
1175:            /**
1176:             * Marks this {@link JavaSource} as modified, causes that the cached information are
1177:             * cleared and all the PhaseCompletionTasks are restarted.    
1178:             * The only client of this method should be the JavaDataObject or other DataObjects
1179:             * providing the {@link JavaSource}. If you call this method in another case you are
1180:             * probably doing something incorrect.
1181:             */
1182:            void revalidate() {
1183:                this .resetState(true, false);
1184:            }
1185:
1186:            /**
1187:             * Returns the classpaths ({@link ClasspathInfo}) used by this
1188:             * {@link JavaSource}
1189:             * @return {@link ClasspathInfo}, never returns null.
1190:             */
1191:            public ClasspathInfo getClasspathInfo() {
1192:                return classpathInfo;
1193:            }
1194:
1195:            /**
1196:             * Returns unmodifiable {@link Collection} of {@link FileObject}s used by this {@link JavaSource}
1197:             * @return the {@link FileObject}s
1198:             */
1199:            public Collection<FileObject> getFileObjects() {
1200:                return files;
1201:            }
1202:
1203:            JavacTaskImpl createJavacTask(
1204:                    final DiagnosticListener<? super  JavaFileObject> diagnosticListener,
1205:                    ClassNamesForFileOraculum oraculum) {
1206:                String sourceLevel = null;
1207:                if (!this .files.isEmpty()) {
1208:                    if (LOGGER.isLoggable(Level.FINER)) {
1209:                        LOGGER
1210:                                .finer("Created new JavacTask for: "
1211:                                        + this .files);
1212:                    }
1213:                    FileObject file = files.iterator().next();
1214:
1215:                    sourceLevel = SourceLevelQuery.getSourceLevel(file);
1216:
1217:                    FileObject root = getClasspathInfo().getClassPath(
1218:                            PathKind.SOURCE).findOwnerRoot(file);
1219:
1220:                    if (root != null && sourceLevel != null) {
1221:                        try {
1222:                            RepositoryUpdater.getDefault().verifySourceLevel(
1223:                                    root.getURL(), sourceLevel);
1224:                        } catch (IOException ex) {
1225:                            LOGGER.log(Level.FINE, null, ex);
1226:                        }
1227:                    }
1228:                }
1229:                if (sourceLevel == null) {
1230:                    sourceLevel = JavaPlatformManager.getDefault()
1231:                            .getDefaultPlatform().getSpecification()
1232:                            .getVersion().toString();
1233:                }
1234:                JavacTaskImpl javacTask = createJavacTask(getClasspathInfo(),
1235:                        diagnosticListener, sourceLevel, false, oraculum);
1236:                Context context = javacTask.getContext();
1237:                JSCancelService.preRegister(context);
1238:                JSFlowListener.preRegister(context);
1239:                TreeLoader.preRegister(context, getClasspathInfo());
1240:                Messager.preRegister(context, null, DEV_NULL, DEV_NULL,
1241:                        DEV_NULL);
1242:                ErrorHandlingJavadocEnter.preRegister(context);
1243:                JavadocMemberEnter.preRegister(context);
1244:                JavadocEnv.preRegister(context, getClasspathInfo());
1245:                DocCommentScanner.Factory.preRegister(context);
1246:                com.sun.tools.javac.main.JavaCompiler.instance(context).keepComments = true;
1247:                return javacTask;
1248:            }
1249:
1250:            private static JavacTaskImpl createJavacTask(
1251:                    final ClasspathInfo cpInfo,
1252:                    final DiagnosticListener<? super  JavaFileObject> diagnosticListener,
1253:                    final String sourceLevel,
1254:                    final boolean backgroundCompilation,
1255:                    ClassNamesForFileOraculum cnih) {
1256:                ArrayList<String> options = new ArrayList<String>();
1257:                String lintOptions = CompilerSettings.getCommandLine();
1258:
1259:                if (lintOptions.length() > 0) {
1260:                    options.addAll(Arrays.asList(lintOptions.split(" ")));
1261:                }
1262:                if (!backgroundCompilation) {
1263:                    options.add("-Xjcov"); //NOI18N, Make the compiler store end positions
1264:                    options.add("-XDdisableStringFolding"); //NOI18N
1265:                } else {
1266:                    options.add("-XDbackgroundCompilation"); //NOI18N
1267:                    options.add("-XDcompilePolicy=byfile"); //NOI18N
1268:                }
1269:                options.add("-XDide"); // NOI18N, javac runs inside the IDE
1270:                options.add("-g:"); // NOI18N, Enable some debug info
1271:                options.add("-g:lines"); // NOI18N, Make the compiler to maintain line table
1272:                options.add("-g:vars"); // NOI18N, Make the compiler to maintain local variables table
1273:                options.add("-source"); // NOI18N
1274:                options.add(validateSourceLevel(sourceLevel));
1275:
1276:                ClassLoader orig = Thread.currentThread()
1277:                        .getContextClassLoader();
1278:                try {
1279:                    //The ToolProvider.defaultJavaCompiler will use the context classloader to load the javac implementation
1280:                    //it should be load by the current module's classloader (should delegate to other module's classloaders as necessary)
1281:                    Thread.currentThread().setContextClassLoader(
1282:                            ClasspathInfo.class.getClassLoader());
1283:                    JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
1284:                    JavacTaskImpl task = (JavacTaskImpl) tool.getTask(null,
1285:                            cpInfo.getFileManager(), diagnosticListener,
1286:                            options, null, Collections
1287:                                    .<JavaFileObject> emptySet());
1288:                    Context context = task.getContext();
1289:
1290:                    if (backgroundCompilation) {
1291:                        SymbolClassReader.preRegister(context, false);
1292:                    } else {
1293:                        SymbolClassReader.preRegister(context, true);
1294:                    }
1295:
1296:                    if (cnih != null) {
1297:                        context.put(ClassNamesForFileOraculum.class, cnih);
1298:                    }
1299:                    return task;
1300:                } finally {
1301:                    Thread.currentThread().setContextClassLoader(orig);
1302:                }
1303:            }
1304:
1305:            private static class ErrorHandlingJavadocEnter extends JavadocEnter {
1306:
1307:                private Messager messager;
1308:
1309:                public static void preRegister(final Context context) {
1310:                    context.put(enterKey, new Context.Factory<Enter>() {
1311:                        public Enter make() {
1312:                            return new ErrorHandlingJavadocEnter(context);
1313:                        }
1314:                    });
1315:                }
1316:
1317:                protected ErrorHandlingJavadocEnter(Context context) {
1318:                    super (context);
1319:                    messager = Messager.instance0(context);
1320:                }
1321:
1322:                public @Override
1323:                void main(com.sun.tools.javac.util.List<JCCompilationUnit> trees) {
1324:                    //Todo: Check everytime after the java update that JavaDocEnter.main or Enter.main
1325:                    //are not changed.
1326:                    this .complete(trees, null);
1327:                }
1328:            }
1329:
1330:            /**
1331:             * Not synchronized, only the CompilationJob's thread can call it!!!!
1332:             *
1333:             */
1334:            static Phase moveToPhase(final Phase phase,
1335:                    final CompilationInfoImpl currentInfo,
1336:                    final boolean cancellable) throws IOException {
1337:                Phase parserError = currentInfo.parserCrashed;
1338:                assert parserError != null;
1339:                Phase currentPhase = currentInfo.getPhase();
1340:                final boolean isMultiFiles = currentInfo.getJavaSource().files
1341:                        .size() > 1;
1342:                LowMemoryNotifier lm = null;
1343:                LMListener lmListener = null;
1344:                if (isMultiFiles) {
1345:                    lm = LowMemoryNotifier.getDefault();
1346:                    assert lm != null;
1347:                    lmListener = new LMListener();
1348:                    lm.addLowMemoryListener(lmListener);
1349:                }
1350:                try {
1351:                    if (lmListener != null
1352:                            && lmListener.lowMemory.getAndSet(false)) {
1353:                        currentInfo.needsRestart = true;
1354:                        return currentPhase;
1355:                    }
1356:                    if (currentPhase.compareTo(Phase.PARSED) < 0
1357:                            && phase.compareTo(Phase.PARSED) >= 0
1358:                            && phase.compareTo(parserError) <= 0) {
1359:                        if (cancellable && currentRequest.isCanceled()) {
1360:                            //Keep the currentPhase unchanged, it may happen that an userActionTask
1361:                            //runnig after the phace completion task may still use it.
1362:                            return Phase.MODIFIED;
1363:                        }
1364:                        long start = System.currentTimeMillis();
1365:                        // XXX - this might be with wrong encoding
1366:                        Iterable<? extends CompilationUnitTree> trees = currentInfo
1367:                                .getJavacTask()
1368:                                .parse(new JavaFileObject[] { currentInfo.jfo });
1369:                        assert trees != null : "Did not parse anything"; //NOI18N
1370:                        Iterator<? extends CompilationUnitTree> it = trees
1371:                                .iterator();
1372:                        assert it.hasNext();
1373:                        CompilationUnitTree unit = it.next();
1374:                        currentInfo.setCompilationUnit(unit);
1375:                        assert !it.hasNext();
1376:                        final Document doc = currentInfo.javaSource.listener == null ? null
1377:                                : currentInfo.javaSource.listener.document;
1378:                        if (doc != null
1379:                                && currentInfo.javaSource.supportsReparse) {
1380:                            FindMethodRegionsVisitor v = new FindMethodRegionsVisitor(
1381:                                    doc, Trees.instance(
1382:                                            currentInfo.getJavacTask())
1383:                                            .getSourcePositions());
1384:                            v.visit(unit, null);
1385:                            synchronized (currentInfo.javaSource.positions) {
1386:                                currentInfo.javaSource.positions.clear();
1387:                                currentInfo.javaSource.positions
1388:                                        .addAll(v.posRegions);
1389:                            }
1390:                        }
1391:                        currentPhase = Phase.PARSED;
1392:                        long end = System.currentTimeMillis();
1393:                        FileObject file = currentInfo.getFileObject();
1394:                        Logger.getLogger("TIMER")
1395:                                .log(Level.FINE, "Compilation Unit",
1396:                                        new Object[] { file, unit });
1397:
1398:                        logTime(file, currentPhase, (end - start));
1399:                    }
1400:                    if (lmListener != null
1401:                            && lmListener.lowMemory.getAndSet(false)) {
1402:                        currentInfo.needsRestart = true;
1403:                        return currentPhase;
1404:                    }
1405:                    if (currentPhase == Phase.PARSED
1406:                            && phase.compareTo(Phase.ELEMENTS_RESOLVED) >= 0
1407:                            && phase.compareTo(parserError) <= 0) {
1408:                        if (cancellable && currentRequest.isCanceled()) {
1409:                            return Phase.MODIFIED;
1410:                        }
1411:                        long start = System.currentTimeMillis();
1412:                        currentInfo.getJavacTask().enter();
1413:                        currentPhase = Phase.ELEMENTS_RESOLVED;
1414:                        long end = System.currentTimeMillis();
1415:                        logTime(currentInfo.getFileObject(), currentPhase,
1416:                                (end - start));
1417:                    }
1418:                    if (lmListener != null
1419:                            && lmListener.lowMemory.getAndSet(false)) {
1420:                        currentInfo.needsRestart = true;
1421:                        return currentPhase;
1422:                    }
1423:                    if (currentPhase == Phase.ELEMENTS_RESOLVED
1424:                            && phase.compareTo(Phase.RESOLVED) >= 0
1425:                            && phase.compareTo(parserError) <= 0) {
1426:                        if (cancellable && currentRequest.isCanceled()) {
1427:                            return Phase.MODIFIED;
1428:                        }
1429:                        long start = System.currentTimeMillis();
1430:                        currentInfo.getJavacTask().analyze();
1431:                        currentPhase = Phase.RESOLVED;
1432:                        long end = System.currentTimeMillis();
1433:                        logTime(currentInfo.getFileObject(), currentPhase,
1434:                                (end - start));
1435:                    }
1436:                    if (lmListener != null
1437:                            && lmListener.lowMemory.getAndSet(false)) {
1438:                        currentInfo.needsRestart = true;
1439:                        return currentPhase;
1440:                    }
1441:                    if (currentPhase == Phase.RESOLVED
1442:                            && phase.compareTo(Phase.UP_TO_DATE) >= 0) {
1443:                        currentPhase = Phase.UP_TO_DATE;
1444:                    }
1445:                } catch (CouplingAbort a) {
1446:                    RepositoryUpdater.couplingAbort(a, currentInfo.jfo);
1447:                    currentInfo.needsRestart = true;
1448:                    return currentPhase;
1449:                } catch (CancelAbort ca) {
1450:                    currentPhase = Phase.MODIFIED;
1451:                } catch (Abort abort) {
1452:                    parserError = currentPhase;
1453:                } catch (IOException ex) {
1454:                    currentInfo.parserCrashed = currentPhase;
1455:                    dumpSource(currentInfo, ex);
1456:                    throw ex;
1457:                } catch (RuntimeException ex) {
1458:                    parserError = currentPhase;
1459:                    dumpSource(currentInfo, ex);
1460:                    throw ex;
1461:                } catch (Error ex) {
1462:                    parserError = currentPhase;
1463:                    dumpSource(currentInfo, ex);
1464:                    throw ex;
1465:                }
1466:
1467:                finally {
1468:                    if (isMultiFiles) {
1469:                        assert lm != null;
1470:                        assert lmListener != null;
1471:                        lm.removeLowMemoryListener(lmListener);
1472:                    }
1473:                    currentInfo.setPhase(currentPhase);
1474:                    currentInfo.parserCrashed = parserError;
1475:                }
1476:                return currentPhase;
1477:            }
1478:
1479:            static void logTime(FileObject source, Phase phase, long time) {
1480:                assert source != null && phase != null;
1481:                String message = phase2Message.get(phase);
1482:                assert message != null;
1483:                Logger.getLogger("TIMER").log(Level.FINE, message,
1484:                        new Object[] { source, time });
1485:            }
1486:
1487:            boolean isClassFile() {
1488:                return (this .flags & IS_CLASS_FILE) != 0;
1489:            }
1490:
1491:            private static final RequestProcessor RP = new RequestProcessor(
1492:                    "JavaSource-event-collector", 1); //NOI18N
1493:
1494:            private final RequestProcessor.Task resetTask = RP
1495:                    .create(new Runnable() {
1496:                        public void run() {
1497:                            resetStateImpl();
1498:                        }
1499:                    });
1500:
1501:            private void resetState(boolean invalidate, boolean updateIndex) {
1502:                resetState(invalidate, updateIndex, null);
1503:            }
1504:
1505:            private void resetState(boolean invalidate, boolean updateIndex,
1506:                    Pair<DocPositionRegion, MethodTree> changedMethod) {
1507:                boolean invalid;
1508:                synchronized (this ) {
1509:                    invalid = (this .flags & INVALID) != 0;
1510:                    this .flags |= CHANGE_EXPECTED;
1511:                    if (invalidate) {
1512:                        this .flags |= (INVALID | RESCHEDULE_FINISHED_TASKS);
1513:                        if (this .currentInfo != null) {
1514:                            this .currentInfo.setChangedMethod(changedMethod);
1515:                        }
1516:                    }
1517:                    if (updateIndex) {
1518:                        this .flags |= UPDATE_INDEX;
1519:                    }
1520:                }
1521:                if (updateIndex && !invalid) {
1522:                    //First change set the index as dirty
1523:                    updateIndex();
1524:                }
1525:                Request r = currentRequest.getTaskToCancel(invalidate);
1526:                if (r != null) {
1527:                    r.task.cancel();
1528:                    Request oldR = rst.getAndSet(r);
1529:                    assert oldR == null;
1530:                }
1531:                if (!k24) {
1532:                    resetTask.schedule(reparseDelay);
1533:                }
1534:            }
1535:
1536:            private final AtomicReference<Request> rst = new AtomicReference<JavaSource.Request>();
1537:            private volatile boolean k24;
1538:
1539:            /**
1540:             * Not synchronized, only sets the atomic state and clears the listeners
1541:             *
1542:             */
1543:            private void resetStateImpl() {
1544:                if (!k24) {
1545:                    Request r = rst.getAndSet(null);
1546:                    currentRequest.cancelCompleted(r);
1547:                    synchronized (INTERNAL_LOCK) {
1548:                        boolean reschedule, updateIndex;
1549:                        synchronized (this ) {
1550:                            reschedule = (this .flags & RESCHEDULE_FINISHED_TASKS) != 0;
1551:                            updateIndex = (this .flags & UPDATE_INDEX) != 0;
1552:                            this .flags &= ~(RESCHEDULE_FINISHED_TASKS
1553:                                    | CHANGE_EXPECTED | UPDATE_INDEX);
1554:                        }
1555:                        if (updateIndex) {
1556:                            //Last change set the index as dirty
1557:                            updateIndex();
1558:                        }
1559:                        Collection<Request> cr;
1560:                        if (reschedule) {
1561:                            if ((cr = JavaSource.finishedRequests.remove(this )) != null
1562:                                    && cr.size() > 0) {
1563:                                JavaSource.requests.addAll(cr);
1564:                            }
1565:                        }
1566:                        if ((cr = JavaSource.waitingRequests.remove(this )) != null
1567:                                && cr.size() > 0) {
1568:                            JavaSource.requests.addAll(cr);
1569:                        }
1570:                    }
1571:                }
1572:            }
1573:
1574:            private void updateIndex() {
1575:                if (this .rootFo != null) {
1576:                    try {
1577:                        ClassIndexImpl ciImpl = ClassIndexManager.getDefault()
1578:                                .getUsagesQuery(this .rootFo.getURL());
1579:                        if (ciImpl != null) {
1580:                            ciImpl.setDirty(this );
1581:                        }
1582:                    } catch (IOException ioe) {
1583:                        Exceptions.printStackTrace(ioe);
1584:                    }
1585:                }
1586:            }
1587:
1588:            private void assignDocumentListener(final DataObject od)
1589:                    throws IOException {
1590:                EditorCookie.Observable ec = od
1591:                        .getCookie(EditorCookie.Observable.class);
1592:                if (ec != null) {
1593:                    this .listener = new DocListener(ec);
1594:                } else {
1595:                    LOGGER.log(Level.WARNING, String.format(
1596:                            "File: %s has no EditorCookie.Observable", FileUtil
1597:                                    .getFileDisplayName(od.getPrimaryFile()))); //NOI18N
1598:                }
1599:            }
1600:
1601:            private static class Request {
1602:                private final CancellableTask<? extends CompilationInfo> task;
1603:                private final JavaSource javaSource; //XXX: Maybe week, depends on the semantics
1604:                private final Phase phase;
1605:                private final Priority priority;
1606:                private final boolean reschedule;
1607:
1608:                public Request(
1609:                        final CancellableTask<? extends CompilationInfo> task,
1610:                        final JavaSource javaSource, final Phase phase,
1611:                        final Priority priority, final boolean reschedule) {
1612:                    assert task != null;
1613:                    this .task = task;
1614:                    this .javaSource = javaSource;
1615:                    this .phase = phase;
1616:                    this .priority = priority;
1617:                    this .reschedule = reschedule;
1618:                }
1619:
1620:                public @Override
1621:                String toString() {
1622:                    if (reschedule) {
1623:                        return String
1624:                                .format(
1625:                                        "Periodic request for phase: %s with priority: %s to perform: %s",
1626:                                        phase.name(), priority, task.toString()); //NOI18N
1627:                    } else {
1628:                        return String
1629:                                .format(
1630:                                        "One time request for phase: %s with priority: %s to perform: %s",
1631:                                        phase != null ? phase.name() : "<null>",
1632:                                        priority, task.toString()); //NOI18N
1633:                    }
1634:                }
1635:
1636:                public @Override
1637:                int hashCode() {
1638:                    return this .priority.ordinal();
1639:                }
1640:
1641:                public @Override
1642:                boolean equals(Object other) {
1643:                    if (other instanceof  Request) {
1644:                        Request otherRequest = (Request) other;
1645:                        return priority == otherRequest.priority
1646:                                && reschedule == otherRequest.reschedule
1647:                                && (phase == null ? otherRequest.phase == null
1648:                                        : phase.equals(otherRequest.phase))
1649:                                && task.equals(otherRequest.task);
1650:                    } else {
1651:                        return false;
1652:                    }
1653:                }
1654:            }
1655:
1656:            private static class RequestComparator implements 
1657:                    Comparator<Request> {
1658:                public int compare(Request r1, Request r2) {
1659:                    assert r1 != null && r2 != null;
1660:                    return r1.priority.compareTo(r2.priority);
1661:                }
1662:            }
1663:
1664:            private static class CompilationJob implements  Runnable {
1665:
1666:                @SuppressWarnings("unchecked")
1667:                //NOI18N
1668:                public void run() {
1669:                    try {
1670:                        while (true) {
1671:                            try {
1672:                                synchronized (INTERNAL_LOCK) {
1673:                                    //Clean up toRemove tasks
1674:                                    if (!toRemove.isEmpty()) {
1675:                                        for (Iterator<Collection<Request>> it = finishedRequests
1676:                                                .values().iterator(); it
1677:                                                .hasNext();) {
1678:                                            Collection<Request> cr = it.next();
1679:                                            for (Iterator<Request> it2 = cr
1680:                                                    .iterator(); it2.hasNext();) {
1681:                                                Request fr = it2.next();
1682:                                                if (toRemove.remove(fr.task)) {
1683:                                                    it2.remove();
1684:                                                }
1685:                                            }
1686:                                            if (cr.size() == 0) {
1687:                                                it.remove();
1688:                                            }
1689:                                        }
1690:                                    }
1691:                                }
1692:                                Request r = JavaSource.requests.poll(2,
1693:                                        TimeUnit.SECONDS);
1694:                                if (r != null) {
1695:                                    currentRequest.setCurrentTask(r);
1696:                                    try {
1697:                                        JavaSource js = r.javaSource;
1698:                                        if (js == null) {
1699:                                            assert r.phase == null;
1700:                                            assert r.reschedule == false;
1701:                                            javacLock.lock();
1702:                                            try {
1703:                                                try {
1704:                                                    r.task.run(null);
1705:                                                } finally {
1706:                                                    currentRequest
1707:                                                            .clearCurrentTask();
1708:                                                    boolean cancelled = requests
1709:                                                            .contains(r);
1710:                                                    if (!cancelled) {
1711:                                                        DeferredTask[] _todo;
1712:                                                        synchronized (todo) {
1713:                                                            _todo = todo
1714:                                                                    .toArray(new DeferredTask[todo
1715:                                                                            .size()]);
1716:                                                            todo.clear();
1717:                                                        }
1718:                                                        for (DeferredTask rq : _todo) {
1719:                                                            try {
1720:                                                                rq.js
1721:                                                                        .runUserActionTask(
1722:                                                                                rq.task,
1723:                                                                                rq.shared);
1724:                                                            } finally {
1725:                                                                rq.sync
1726:                                                                        .taskFinished();
1727:                                                            }
1728:                                                        }
1729:                                                    }
1730:                                                }
1731:                                            } catch (RuntimeException re) {
1732:                                                Exceptions.printStackTrace(re);
1733:                                            } finally {
1734:                                                javacLock.unlock();
1735:                                            }
1736:                                        } else {
1737:                                            assert js.files.size() <= 1;
1738:                                            boolean jsInvalid;
1739:                                            Pair<DocPositionRegion, MethodTree> changedMethod;
1740:                                            CompilationInfoImpl ci;
1741:                                            synchronized (INTERNAL_LOCK) {
1742:                                                //jl:what does this comment mean?
1743:                                                //Not only the finishedRequests for the current request.javaSource should be cleaned,
1744:                                                //it will cause a starvation
1745:                                                if (toRemove.remove(r.task)) {
1746:                                                    continue;
1747:                                                }
1748:                                                synchronized (js) {
1749:                                                    boolean changeExpected = (js.flags & CHANGE_EXPECTED) != 0;
1750:                                                    if (changeExpected) {
1751:                                                        //Skeep the task, another invalidation is comming
1752:                                                        Collection<Request> rc = JavaSource.waitingRequests
1753:                                                                .get(r.javaSource);
1754:                                                        if (rc == null) {
1755:                                                            rc = new LinkedList<Request>();
1756:                                                            JavaSource.waitingRequests
1757:                                                                    .put(
1758:                                                                            r.javaSource,
1759:                                                                            rc);
1760:                                                        }
1761:                                                        rc.add(r);
1762:                                                        continue;
1763:                                                    }
1764:                                                    jsInvalid = js.currentInfo == null
1765:                                                            || (js.flags & INVALID) != 0;
1766:                                                    ci = js.currentInfo;
1767:                                                    changedMethod = ci == null ? null
1768:                                                            : ci
1769:                                                                    .getChangedTree();
1770:
1771:                                                }
1772:                                            }
1773:                                            try {
1774:                                                //createCurrentInfo has to be out of synchronized block, it aquires an editor lock                                    
1775:                                                if (jsInvalid) {
1776:                                                    boolean needsFullReparse = true;
1777:                                                    if (changedMethod != null
1778:                                                            && ci != null) {
1779:                                                        javacLock.lock();
1780:                                                        try {
1781:                                                            needsFullReparse = !reparseMethod(
1782:                                                                    ci,
1783:                                                                    changedMethod.second,
1784:                                                                    changedMethod.first
1785:                                                                            .getText());
1786:                                                        } finally {
1787:                                                            javacLock.unlock();
1788:                                                        }
1789:                                                    }
1790:                                                    if (needsFullReparse) {
1791:                                                        ci = createCurrentInfo(
1792:                                                                js, js.binding,
1793:                                                                null);
1794:                                                    }
1795:                                                    synchronized (js) {
1796:                                                        if (js.currentInfo == null
1797:                                                                || (js.flags & INVALID) != 0) {
1798:                                                            js.currentInfo = ci;
1799:                                                            js.flags &= ~INVALID;
1800:                                                        } else {
1801:                                                            ci = js.currentInfo;
1802:                                                        }
1803:                                                    }
1804:                                                }
1805:                                                assert ci != null;
1806:                                                javacLock.lock();
1807:                                                try {
1808:                                                    boolean shouldCall;
1809:                                                    final JSCancelService cancelService = JSCancelService
1810:                                                            .instance(ci
1811:                                                                    .getJavacTask()
1812:                                                                    .getContext());
1813:                                                    if (cancelService != null) {
1814:                                                        cancelService.active = true;
1815:                                                    }
1816:
1817:                                                    try {
1818:                                                        final Phase phase = JavaSource
1819:                                                                .moveToPhase(
1820:                                                                        r.phase,
1821:                                                                        ci,
1822:                                                                        true);
1823:                                                        shouldCall = phase
1824:                                                                .compareTo(r.phase) >= 0;
1825:                                                    } finally {
1826:                                                        if (cancelService != null) {
1827:                                                            cancelService.active = false;
1828:                                                        }
1829:                                                    }
1830:                                                    if (shouldCall) {
1831:                                                        synchronized (js) {
1832:                                                            shouldCall &= (js.flags & INVALID) == 0;
1833:                                                        }
1834:                                                        if (shouldCall) {
1835:                                                            //The state (or greater) was reached and document was not modified during moveToPhase
1836:                                                            try {
1837:                                                                final long startTime = System
1838:                                                                        .currentTimeMillis();
1839:                                                                Index.cancel
1840:                                                                        .set(currentRequest
1841:                                                                                .getCanceledRef());
1842:                                                                try {
1843:                                                                    final CompilationInfo clientCi = new CompilationInfo(
1844:                                                                            ci);
1845:                                                                    try {
1846:                                                                        ((CancellableTask<CompilationInfo>) r.task)
1847:                                                                                .run(clientCi); //XXX: How to do it in save way?
1848:                                                                    } finally {
1849:                                                                        clientCi
1850:                                                                                .invalidate();
1851:                                                                    }
1852:                                                                } finally {
1853:                                                                    Index.cancel
1854:                                                                            .remove();
1855:                                                                }
1856:                                                                final long endTime = System
1857:                                                                        .currentTimeMillis();
1858:                                                                if (LOGGER
1859:                                                                        .isLoggable(Level.FINEST)) {
1860:                                                                    LOGGER
1861:                                                                            .finest(String
1862:                                                                                    .format(
1863:                                                                                            "executed task: %s in %d ms.", //NOI18N
1864:                                                                                            r.task
1865:                                                                                                    .getClass()
1866:                                                                                                    .toString(),
1867:                                                                                            (endTime - startTime)));
1868:                                                                }
1869:                                                                if (LOGGER
1870:                                                                        .isLoggable(Level.FINER)) {
1871:                                                                    final long cancelTime = currentRequest
1872:                                                                            .getCancelTime();
1873:                                                                    if (cancelTime >= startTime
1874:                                                                            && (endTime - cancelTime) > SLOW_CANCEL_LIMIT) {
1875:                                                                        LOGGER
1876:                                                                                .finer(String
1877:                                                                                        .format(
1878:                                                                                                "Task: %s ignored cancel for %d ms.", //NOI18N
1879:                                                                                                r.task
1880:                                                                                                        .getClass()
1881:                                                                                                        .toString(),
1882:                                                                                                (endTime - cancelTime)));
1883:                                                                    }
1884:                                                                }
1885:                                                            } catch (CancelAbort ca) {
1886:                                                                //Handled below by: canceled = currentRequest.setCurrentTask(null);
1887:                                                            } catch (Exception re) {
1888:                                                                Exceptions
1889:                                                                        .printStackTrace(re);
1890:                                                            }
1891:                                                        }
1892:                                                    }
1893:                                                } finally {
1894:                                                    javacLock.unlock();
1895:                                                }
1896:
1897:                                                if (r.reschedule) {
1898:                                                    synchronized (INTERNAL_LOCK) {
1899:                                                        boolean canceled = currentRequest
1900:                                                                .setCurrentTask(null);
1901:                                                        synchronized (js) {
1902:                                                            if ((js.flags & INVALID) != 0
1903:                                                                    || canceled) {
1904:                                                                //The JavaSource was changed or canceled rechedule it now
1905:                                                                JavaSource.requests
1906:                                                                        .add(r);
1907:                                                            } else {
1908:                                                                //Up to date JavaSource add it to the finishedRequests
1909:                                                                Collection<Request> rc = JavaSource.finishedRequests
1910:                                                                        .get(r.javaSource);
1911:                                                                if (rc == null) {
1912:                                                                    rc = new LinkedList<Request>();
1913:                                                                    JavaSource.finishedRequests
1914:                                                                            .put(
1915:                                                                                    r.javaSource,
1916:                                                                                    rc);
1917:                                                                }
1918:                                                                rc.add(r);
1919:                                                            }
1920:                                                        }
1921:                                                    }
1922:                                                }
1923:                                            } catch (final FileObjects.InvalidFileException invalidFile) {
1924:                                                //Ideally the requests should be removed by JavaSourceTaskFactory and task should be put to finishedRequests,
1925:                                                //but the reality is different, the task cannot be put to finished request because of possible memory leak
1926:                                            }
1927:                                        }
1928:                                    } finally {
1929:                                        currentRequest.setCurrentTask(null);
1930:                                    }
1931:                                }
1932:                            } catch (Throwable e) {
1933:                                if (e instanceof  InterruptedException) {
1934:                                    throw (InterruptedException) e;
1935:                                } else if (e instanceof  ThreadDeath) {
1936:                                    throw (ThreadDeath) e;
1937:                                } else {
1938:                                    Exceptions.printStackTrace(e);
1939:                                }
1940:                            }
1941:                        }
1942:                    } catch (InterruptedException ie) {
1943:                        ie.printStackTrace();
1944:                        // stop the service.
1945:                    }
1946:                }
1947:            }
1948:
1949:            private class DocListener implements  PropertyChangeListener,
1950:                    ChangeListener, TokenHierarchyListener {
1951:
1952:                private EditorCookie.Observable ec;
1953:                private TokenHierarchyListener lexListener;
1954:                private volatile Document document;
1955:
1956:                public DocListener(EditorCookie.Observable ec) {
1957:                    assert ec != null;
1958:                    this .ec = ec;
1959:                    this .ec.addPropertyChangeListener(WeakListeners
1960:                            .propertyChange(this , this .ec));
1961:                    Document doc = ec.getDocument();
1962:                    if (doc != null) {
1963:                        TokenHierarchy th = TokenHierarchy.get(doc);
1964:                        th
1965:                                .addTokenHierarchyListener(lexListener = WeakListeners
1966:                                        .create(TokenHierarchyListener.class,
1967:                                                this , th));
1968:                        document = doc;
1969:                    }
1970:                }
1971:
1972:                public void propertyChange(PropertyChangeEvent evt) {
1973:                    if (EditorCookie.Observable.PROP_DOCUMENT.equals(evt
1974:                            .getPropertyName())) {
1975:                        Object old = evt.getOldValue();
1976:                        if (old instanceof  Document && lexListener != null) {
1977:                            TokenHierarchy th = TokenHierarchy
1978:                                    .get((Document) old);
1979:                            th.removeTokenHierarchyListener(lexListener);
1980:                            lexListener = null;
1981:                        }
1982:                        Document doc = ec.getDocument();
1983:                        if (doc != null) {
1984:                            TokenHierarchy th = TokenHierarchy.get(doc);
1985:                            th
1986:                                    .addTokenHierarchyListener(lexListener = WeakListeners
1987:                                            .create(
1988:                                                    TokenHierarchyListener.class,
1989:                                                    this , th));
1990:                            this .document = doc; //set before rescheduling task to avoid race condition
1991:                            resetState(true, false);
1992:                        } else {
1993:                            //reset document
1994:                            this .document = doc;
1995:                        }
1996:                    }
1997:                }
1998:
1999:                public void stateChanged(ChangeEvent e) {
2000:                    JavaSource.this .resetState(true, false);
2001:                }
2002:
2003:                public void tokenHierarchyChanged(TokenHierarchyEvent evt) {
2004:                    Pair<DocPositionRegion, MethodTree> changedMethod = null;
2005:                    if (evt.type() == TokenHierarchyEventType.MODIFICATION) {
2006:                        if (supportsReparse) {
2007:                            int start = evt.affectedStartOffset();
2008:                            int end = evt.affectedEndOffset();
2009:                            synchronized (positions) {
2010:                                for (Pair<DocPositionRegion, MethodTree> pe : positions) {
2011:                                    PositionRegion p = pe.first;
2012:                                    if (start > p.getStartOffset()
2013:                                            && end < p.getEndOffset()) {
2014:                                        changedMethod = pe;
2015:                                        break;
2016:                                    }
2017:                                }
2018:                                if (changedMethod != null) {
2019:                                    TokenChange<JavaTokenId> change = evt
2020:                                            .tokenChange(JavaTokenId.language());
2021:                                    if (change != null) {
2022:                                        TokenSequence<JavaTokenId> ts = change
2023:                                                .removedTokenSequence();
2024:                                        if (ts != null) {
2025:                                            while (ts.moveNext()) {
2026:                                                switch (ts.token().id()) {
2027:                                                case LBRACE:
2028:                                                case RBRACE:
2029:                                                    changedMethod = null;
2030:                                                    break;
2031:                                                }
2032:                                            }
2033:                                        }
2034:                                        if (changedMethod != null) {
2035:                                            TokenSequence<JavaTokenId> current = change
2036:                                                    .currentTokenSequence();
2037:                                            current.moveIndex(change.index());
2038:                                            for (int i = 0; i < change
2039:                                                    .addedTokenCount(); i++) {
2040:                                                current.moveNext();
2041:                                                switch (current.token().id()) {
2042:                                                case LBRACE:
2043:                                                case RBRACE:
2044:                                                    changedMethod = null;
2045:                                                    break;
2046:                                                }
2047:                                            }
2048:                                        }
2049:                                    }
2050:                                }
2051:                                positions.clear();
2052:                                if (changedMethod != null) {
2053:                                    positions.add(changedMethod);
2054:                                }
2055:                            }
2056:                        }
2057:                    }
2058:                    JavaSource.this .resetState(true, changedMethod == null,
2059:                            changedMethod);
2060:                }
2061:            }
2062:
2063:            private static class EditorRegistryListener implements 
2064:                    CaretListener, PropertyChangeListener {
2065:
2066:                private Request request;
2067:                private JTextComponent lastEditor;
2068:
2069:                public EditorRegistryListener() {
2070:                    EditorRegistry
2071:                            .addPropertyChangeListener(new PropertyChangeListener() {
2072:                                public void propertyChange(
2073:                                        PropertyChangeEvent evt) {
2074:                                    editorRegistryChanged();
2075:                                }
2076:                            });
2077:                    editorRegistryChanged();
2078:                }
2079:
2080:                public void editorRegistryChanged() {
2081:                    final JTextComponent editor = EditorRegistry
2082:                            .lastFocusedComponent();
2083:                    if (lastEditor != editor) {
2084:                        if (lastEditor != null) {
2085:                            lastEditor.removeCaretListener(this );
2086:                            lastEditor.removePropertyChangeListener(this );
2087:                            final Document doc = lastEditor.getDocument();
2088:                            JavaSource js = null;
2089:                            if (doc != null) {
2090:                                js = forDocument(doc);
2091:                            }
2092:                            if (js != null) {
2093:                                js.k24 = false;
2094:                            }
2095:                        }
2096:                        lastEditor = editor;
2097:                        if (lastEditor != null) {
2098:                            lastEditor.addCaretListener(this );
2099:                            lastEditor.addPropertyChangeListener(this );
2100:                        }
2101:                    }
2102:                }
2103:
2104:                public void caretUpdate(CaretEvent event) {
2105:                    if (lastEditor != null) {
2106:                        Document doc = lastEditor.getDocument();
2107:                        if (doc != null) {
2108:                            JavaSource js = forDocument(doc);
2109:                            if (js != null) {
2110:                                js.resetState(false, false);
2111:                            }
2112:                        }
2113:                    }
2114:                }
2115:
2116:                public void propertyChange(final PropertyChangeEvent evt) {
2117:                    String propName = evt.getPropertyName();
2118:                    if ("completion-active".equals(propName)) {
2119:                        JavaSource js = null;
2120:                        final Document doc = lastEditor.getDocument();
2121:                        if (doc != null) {
2122:                            js = forDocument(doc);
2123:                        }
2124:                        if (js != null) {
2125:                            Object rawValue = evt.getNewValue();
2126:                            assert rawValue instanceof  Boolean;
2127:                            if (rawValue instanceof  Boolean) {
2128:                                final boolean value = (Boolean) rawValue;
2129:                                if (value) {
2130:                                    assert this .request == null;
2131:                                    this .request = currentRequest
2132:                                            .getTaskToCancel(false);
2133:                                    if (this .request != null) {
2134:                                        this .request.task.cancel();
2135:                                    }
2136:                                    js.k24 = true;
2137:                                } else {
2138:                                    Request _request = this .request;
2139:                                    this .request = null;
2140:                                    js.k24 = false;
2141:                                    js.resetTask.schedule(js.reparseDelay);
2142:                                    currentRequest.cancelCompleted(_request);
2143:                                }
2144:                            }
2145:                        }
2146:                    }
2147:                }
2148:
2149:            }
2150:
2151:            private class FileChangeListenerImpl extends FileChangeAdapter {
2152:
2153:                public @Override
2154:                void fileChanged(final FileEvent fe) {
2155:                    JavaSource.this .resetState(true, false);
2156:                }
2157:
2158:                public @Override
2159:                void fileRenamed(FileRenameEvent fe) {
2160:                    JavaSource.this .resetState(true, false);
2161:                }
2162:            }
2163:
2164:            private final class DataObjectListener implements 
2165:                    PropertyChangeListener {
2166:
2167:                private DataObject dobj;
2168:                private final FileObject fobj;
2169:                private PropertyChangeListener wlistener;
2170:
2171:                public DataObjectListener(FileObject fo)
2172:                        throws DataObjectNotFoundException {
2173:                    this .fobj = fo;
2174:                    this .dobj = DataObject.find(fo);
2175:                    wlistener = WeakListeners.propertyChange(this , dobj);
2176:                    this .dobj.addPropertyChangeListener(wlistener);
2177:                }
2178:
2179:                public void propertyChange(PropertyChangeEvent pce) {
2180:                    DataObject invalidDO = (DataObject) pce.getSource();
2181:                    if (invalidDO != dobj)
2182:                        return;
2183:                    if (DataObject.PROP_VALID.equals(pce.getPropertyName())) {
2184:                        handleInvalidDataObject(invalidDO);
2185:                    } else if (pce.getPropertyName() == null && !dobj.isValid()) {
2186:                        handleInvalidDataObject(invalidDO);
2187:                    }
2188:                }
2189:
2190:                private void handleInvalidDataObject(final DataObject invalidDO) {
2191:                    RequestProcessor.getDefault().post(new Runnable() {
2192:                        public void run() {
2193:                            handleInvalidDataObjectImpl(invalidDO);
2194:                        }
2195:                    });
2196:                }
2197:
2198:                private void handleInvalidDataObjectImpl(DataObject invalidDO) {
2199:                    invalidDO.removePropertyChangeListener(wlistener);
2200:                    if (fobj.isValid()) {
2201:                        // file object still exists try to find new data object
2202:                        try {
2203:                            DataObject dobjNew = DataObject.find(fobj);
2204:                            synchronized (DataObjectListener.this ) {
2205:                                if (dobjNew == dobj) {
2206:                                    return;
2207:                                }
2208:                                dobj = dobjNew;
2209:                                dobj.addPropertyChangeListener(wlistener);
2210:                            }
2211:                            assignDocumentListener(dobjNew);
2212:                            resetState(true, true);
2213:                        } catch (DataObjectNotFoundException e) {
2214:                            //Ignore - invalidated after fobj.isValid () was called
2215:                        } catch (IOException ex) {
2216:                            // should not occur
2217:                            LOGGER.log(Level.SEVERE, ex.getMessage(), ex);
2218:                        }
2219:                    }
2220:                }
2221:
2222:            }
2223:
2224:            private final class FilterListener implements  ChangeListener {
2225:
2226:                public FilterListener(final JavaFileFilterImplementation filter) {
2227:                    filter
2228:                            .addChangeListener(WeakListeners.change(this ,
2229:                                    filter));
2230:                }
2231:
2232:                public void stateChanged(ChangeEvent event) {
2233:                    JavaSource.this .resetState(true, false);
2234:                }
2235:            }
2236:
2237:            private static CompilationInfoImpl createCurrentInfo(
2238:                    final JavaSource js, final PositionConverter binding,
2239:                    final JavacTaskImpl javac) throws IOException {
2240:                CompilationInfoImpl info = new CompilationInfoImpl(js, binding,
2241:                        javac);
2242:                if (binding != null) {
2243:                    Logger.getLogger("TIMER").log(Level.FINE,
2244:                            "CompilationInfo",
2245:                            new Object[] { binding.getFileObject(), info });
2246:                }
2247:                return info;
2248:            }
2249:
2250:            private static void handleAddRequest(final Request nr) {
2251:                assert nr != null;
2252:                requests.add(nr);
2253:                JavaSource.Request request = currentRequest
2254:                        .getTaskToCancel(nr.priority);
2255:                try {
2256:                    if (request != null) {
2257:                        request.task.cancel();
2258:                    }
2259:                } finally {
2260:                    currentRequest.cancelCompleted(request);
2261:                }
2262:            }
2263:
2264:            private static StackTraceElement findCaller(
2265:                    StackTraceElement[] elements) {
2266:                for (StackTraceElement e : elements) {
2267:                    if (JavaSource.class.getName().equals(e.getClassName())) {
2268:                        continue;
2269:                    }
2270:
2271:                    if (e.getClassName().startsWith("java.lang.")) {
2272:                        continue;
2273:                    }
2274:
2275:                    return e;
2276:                }
2277:
2278:                return null;
2279:            }
2280:
2281:            private static class SingleThreadFactory implements  ThreadFactory {
2282:
2283:                private Thread t;
2284:
2285:                public Thread newThread(Runnable r) {
2286:                    assert this .t == null;
2287:                    this .t = new Thread(r, "Java Source Worker Thread"); //NOI18N
2288:                    return this .t;
2289:                }
2290:
2291:                public boolean isDispatchThread(Thread t) {
2292:                    assert t != null;
2293:                    return this .t == t;
2294:                }
2295:            }
2296:
2297:            private static class JavaSourceAccessorImpl extends
2298:                    JavaSourceAccessor {
2299:
2300:                private StackTraceElement[] javacLockedStackTrace;
2301:
2302:                protected @Override
2303:                void runSpecialTaskImpl(CancellableTask<CompilationInfo> task,
2304:                        Priority priority) {
2305:                    handleAddRequest(new Request(task, null, null, priority,
2306:                            false));
2307:                }
2308:
2309:                @Override
2310:                public JavacTaskImpl createJavacTask(
2311:                        ClasspathInfo cpInfo,
2312:                        DiagnosticListener<? super  JavaFileObject> diagnosticListener,
2313:                        String sourceLevel, ClassNamesForFileOraculum oraculum) {
2314:                    if (sourceLevel == null)
2315:                        sourceLevel = JavaPlatformManager.getDefault()
2316:                                .getDefaultPlatform().getSpecification()
2317:                                .getVersion().toString();
2318:                    return JavaSource.createJavacTask(cpInfo,
2319:                            diagnosticListener, sourceLevel, true, oraculum);
2320:                }
2321:
2322:                @Override
2323:                public JavacTaskImpl getJavacTask(
2324:                        final CompilationInfo compilationInfo) {
2325:                    assert compilationInfo != null;
2326:                    return compilationInfo.impl.getJavacTask();
2327:                }
2328:
2329:                @Override
2330:                public CompilationInfo getCurrentCompilationInfo(
2331:                        final JavaSource js, final Phase phase)
2332:                        throws IOException {
2333:                    assert js != null;
2334:                    assert isDispatchThread();
2335:                    CompilationInfoImpl info = null;
2336:                    synchronized (js) {
2337:                        if ((js.flags & INVALID) == 0) {
2338:                            info = js.currentInfo;
2339:                        }
2340:                    }
2341:                    if (info == null) {
2342:                        return null;
2343:                    }
2344:                    Phase currentPhase = moveToPhase(phase, info, true);
2345:                    return currentPhase.compareTo(phase) < 0 ? null
2346:                            : new CompilationInfo(info);
2347:                }
2348:
2349:                @Override
2350:                public void revalidate(JavaSource js) {
2351:                    js.revalidate();
2352:                }
2353:
2354:                @Override
2355:                public boolean isDispatchThread() {
2356:                    return factory.isDispatchThread(Thread.currentThread());
2357:                }
2358:
2359:                @Override
2360:                public void lockJavaCompiler() {
2361:                    javacLock.lock();
2362:                    try {
2363:                        this .javacLockedStackTrace = Thread.currentThread()
2364:                                .getStackTrace();
2365:                    } catch (RuntimeException e) {
2366:                        //Not important, thrown by logging code
2367:                    }
2368:                }
2369:
2370:                @Override
2371:                public void unlockJavaCompiler() {
2372:                    try {
2373:                        this .javacLockedStackTrace = null;
2374:                    } finally {
2375:                        javacLock.unlock();
2376:                    }
2377:                }
2378:
2379:                @Override
2380:                public boolean isJavaCompilerLocked() {
2381:                    return javacLock.isLocked();
2382:                }
2383:
2384:                public JavaSource create(ClasspathInfo cpInfo,
2385:                        PositionConverter binding,
2386:                        Collection<? extends FileObject> files)
2387:                        throws IllegalArgumentException {
2388:                    return JavaSource.create(cpInfo, binding, files);
2389:                }
2390:
2391:                public PositionConverter create(FileObject fo, int offset,
2392:                        int length, JTextComponent component) {
2393:                    return new PositionConverter(fo, offset, length, component);
2394:                }
2395:            }
2396:
2397:            /**
2398:             *  Only encapsulates current request. May be trasformed into 
2399:             *  JavaSource private static methods, but it may be less readable.
2400:             */
2401:            private static final class CurrentRequestReference {
2402:
2403:                private static JavaSource.Request DUMMY_RQ = new JavaSource.Request(
2404:                        new CancellableTask<CompilationInfo>() {
2405:                            public void cancel() {
2406:                            };
2407:
2408:                            public void run(CompilationInfo info) {
2409:                            }
2410:                        }, null, null, null, false);
2411:
2412:                private JavaSource.Request reference;
2413:                private JavaSource.Request canceledReference;
2414:                private long cancelTime;
2415:                private final AtomicBoolean canceled;
2416:                private boolean mayCancelJavac;
2417:
2418:                CurrentRequestReference() {
2419:                    this .canceled = new AtomicBoolean();
2420:                }
2421:
2422:                boolean setCurrentTask(JavaSource.Request reference)
2423:                        throws InterruptedException {
2424:                    boolean result = false;
2425:                    synchronized (INTERNAL_LOCK) {
2426:                        while (this .canceledReference != null) {
2427:                            INTERNAL_LOCK.wait();
2428:                        }
2429:                        result = this .canceled.getAndSet(false);
2430:                        this .mayCancelJavac = false;
2431:                        this .cancelTime = 0;
2432:                        this .reference = reference;
2433:                    }
2434:                    return result;
2435:                }
2436:
2437:                /**
2438:                 * Prevents race-condition in runWhenScanFinished. This method may be called only from
2439:                 * the Java-Source-Worker-Thread right after the initial scan finished. The problem was
2440:                 * that the task was added into the todo after the todo was drained into the list of pending
2441:                 * tasks but the getTaskToCancel thought that the task is still the RepositoryUpdater. So the
2442:                 * Java-Source-Worker-Thread has to clean the task after calling RU.run but before draining the
2443:                 * pending tasks into the array, it cannot use setCurrentTaks (null) since it is under javac lock
2444:                 * and the setCurrentTaks methods may block the caller thread => deadlock.
2445:                 */
2446:                void clearCurrentTask() {
2447:                    synchronized (INTERNAL_LOCK) {
2448:                        this .reference = null;
2449:                    }
2450:                }
2451:
2452:                JavaSource.Request getTaskToCancel(final Priority priority) {
2453:                    JavaSource.Request request = null;
2454:                    if (!factory.isDispatchThread(Thread.currentThread())) {
2455:                        synchronized (INTERNAL_LOCK) {
2456:                            if (this .reference != null
2457:                                    && priority
2458:                                            .compareTo(this .reference.priority) < 0) {
2459:                                assert this .canceledReference == null;
2460:                                request = this .reference;
2461:                                this .canceledReference = request;
2462:                                this .reference = null;
2463:                                this .canceled.set(true);
2464:                                this .cancelTime = System.currentTimeMillis();
2465:                            }
2466:                        }
2467:                    }
2468:                    return request;
2469:                }
2470:
2471:                JavaSource.Request getTaskToCancel(final boolean mayCancelJavac) {
2472:                    JavaSource.Request request = null;
2473:                    if (!factory.isDispatchThread(Thread.currentThread())) {
2474:                        synchronized (INTERNAL_LOCK) {
2475:                            if (this .reference != null) {
2476:                                assert this .canceledReference == null;
2477:                                request = this .reference;
2478:                                this .canceledReference = request;
2479:                                this .reference = null;
2480:                                this .canceled.set(true);
2481:                                this .mayCancelJavac = mayCancelJavac;
2482:                                this .cancelTime = System.currentTimeMillis();
2483:                            } else if (canceledReference == null) {
2484:                                request = DUMMY_RQ;
2485:                                this .canceledReference = request;
2486:                                this .mayCancelJavac = mayCancelJavac;
2487:                                this .cancelTime = System.currentTimeMillis();
2488:                            }
2489:                        }
2490:                    }
2491:                    return request;
2492:                }
2493:
2494:                JavaSource.Request getTaskToCancel(final CancellableTask task) {
2495:                    JavaSource.Request request = null;
2496:                    if (!factory.isDispatchThread(Thread.currentThread())) {
2497:                        synchronized (INTERNAL_LOCK) {
2498:                            if (this .reference != null
2499:                                    && task == this .reference.task) {
2500:                                assert this .canceledReference == null;
2501:                                request = this .reference;
2502:                                this .canceledReference = request;
2503:                                this .reference = null;
2504:                                this .canceled.set(true);
2505:                            }
2506:                        }
2507:                    }
2508:                    return request;
2509:                }
2510:
2511:                JavaSource.Request getTaskToCancel() {
2512:                    JavaSource.Request request = null;
2513:                    if (!factory.isDispatchThread(Thread.currentThread())) {
2514:                        synchronized (INTERNAL_LOCK) {
2515:                            request = this .reference;
2516:                            if (request != null) {
2517:                                assert this .canceledReference == null;
2518:                                this .canceledReference = request;
2519:                                this .reference = null;
2520:                                this .canceled.set(true);
2521:                                this .cancelTime = System.currentTimeMillis();
2522:                            }
2523:                        }
2524:                    }
2525:                    return request;
2526:                }
2527:
2528:                /**
2529:                 * Called by {@link JavaSource#runWhenScanFinished} to find out which
2530:                 * task is currently running. Returns true when the running task in backgroud
2531:                 * scan otherwise returns false. The caller is expected not to call cancel on
2532:                 * the background scanner, so this method do not reset reference and do not set
2533:                 * cancelled flag when running task is background scan. But it sets the canceledReference
2534:                 * to prevent java source thread to dispatch next queued task.
2535:                 * @param request is filled by currently running task or null when there is no running task.
2536:                 * @return true when running task is background scan
2537:                 */
2538:                boolean getUserTaskToCancel(JavaSource.Request[] request) {
2539:                    assert request != null;
2540:                    assert request.length == 1;
2541:                    boolean result = false;
2542:                    if (!factory.isDispatchThread(Thread.currentThread())) {
2543:                        synchronized (INTERNAL_LOCK) {
2544:                            request[0] = this .reference;
2545:                            if (request[0] != null) {
2546:                                result = request[0].phase == null;
2547:                                assert this .canceledReference == null;
2548:                                if (!result) {
2549:                                    this .canceledReference = request[0];
2550:                                    this .reference = null;
2551:                                }
2552:                                this .canceled.set(result);
2553:                                this .cancelTime = System.currentTimeMillis();
2554:                            }
2555:                        }
2556:                    }
2557:                    return result;
2558:                }
2559:
2560:                boolean isCanceled() {
2561:                    synchronized (INTERNAL_LOCK) {
2562:                        return this .canceled.get();
2563:                    }
2564:                }
2565:
2566:                AtomicBoolean getCanceledRef() {
2567:                    return this .canceled;
2568:                }
2569:
2570:                boolean isInterruptJavac() {
2571:                    synchronized (INTERNAL_LOCK) {
2572:                        boolean ret = this .mayCancelJavac
2573:                                && this .canceledReference != null
2574:                                && this .canceledReference.javaSource != null
2575:                                && (this .canceledReference.javaSource.flags & INVALID) != 0;
2576:                        return ret;
2577:                    }
2578:                }
2579:
2580:                long getCancelTime() {
2581:                    synchronized (INTERNAL_LOCK) {
2582:                        return this .cancelTime;
2583:                    }
2584:                }
2585:
2586:                void cancelCompleted(final JavaSource.Request request) {
2587:                    if (request != null) {
2588:                        synchronized (INTERNAL_LOCK) {
2589:                            assert request == this .canceledReference;
2590:                            this .canceledReference = null;
2591:                            INTERNAL_LOCK.notify();
2592:                        }
2593:                    }
2594:                }
2595:            }
2596:
2597:            static final class ScanSync implements  Future<Void> {
2598:
2599:                private Task<CompilationController> task;
2600:                private final CountDownLatch sync;
2601:                private final AtomicBoolean canceled;
2602:
2603:                public ScanSync(final Task<CompilationController> task) {
2604:                    assert task != null;
2605:                    this .task = task;
2606:                    this .sync = new CountDownLatch(1);
2607:                    this .canceled = new AtomicBoolean(false);
2608:                }
2609:
2610:                public boolean cancel(boolean mayInterruptIfRunning) {
2611:                    if (this .sync.getCount() == 0) {
2612:                        return false;
2613:                    }
2614:                    synchronized (todo) {
2615:                        boolean _canceled = canceled.getAndSet(true);
2616:                        if (!_canceled) {
2617:                            for (Iterator<DeferredTask> it = todo.iterator(); it
2618:                                    .hasNext();) {
2619:                                DeferredTask task = it.next();
2620:                                if (task.task == this .task) {
2621:                                    it.remove();
2622:                                    return true;
2623:                                }
2624:                            }
2625:                        }
2626:                    }
2627:                    return false;
2628:                }
2629:
2630:                public boolean isCancelled() {
2631:                    return this .canceled.get();
2632:                }
2633:
2634:                public synchronized boolean isDone() {
2635:                    return this .sync.getCount() == 0;
2636:                }
2637:
2638:                public Void get() throws InterruptedException,
2639:                        ExecutionException {
2640:                    this .sync.await();
2641:                    return null;
2642:                }
2643:
2644:                public Void get(long timeout, TimeUnit unit)
2645:                        throws InterruptedException, ExecutionException,
2646:                        TimeoutException {
2647:                    this .sync.await(timeout, unit);
2648:                    return null;
2649:                }
2650:
2651:                private void taskFinished() {
2652:                    this .sync.countDown();
2653:                }
2654:            }
2655:
2656:            static final class DeferredTask {
2657:                final JavaSource js;
2658:                final Task<CompilationController> task;
2659:                final boolean shared;
2660:                final ScanSync sync;
2661:
2662:                public DeferredTask(final JavaSource js,
2663:                        final Task<CompilationController> task,
2664:                        final boolean shared, final ScanSync sync) {
2665:                    assert js != null;
2666:                    assert task != null;
2667:                    assert sync != null;
2668:
2669:                    this .js = js;
2670:                    this .task = task;
2671:                    this .shared = shared;
2672:                    this .sync = sync;
2673:                }
2674:            }
2675:
2676:            /**
2677:             * Only for unit tests
2678:             */
2679:            static interface JavaFileObjectProvider {
2680:                public JavaFileObject createJavaFileObject(FileObject fo,
2681:                        FileObject root, JavaFileFilterImplementation filter)
2682:                        throws IOException;
2683:
2684:                public void update(JavaFileObject jfo) throws IOException;
2685:            }
2686:
2687:            static final class DefaultJavaFileObjectProvider implements 
2688:                    JavaFileObjectProvider {
2689:                public JavaFileObject createJavaFileObject(FileObject fo,
2690:                        FileObject root, JavaFileFilterImplementation filter)
2691:                        throws IOException {
2692:                    return FileObjects.nbFileObject(fo, root, filter, true);
2693:                }
2694:
2695:                public void update(final JavaFileObject jfo) throws IOException {
2696:                    assert jfo instanceof  SourceFileObject;
2697:                    ((SourceFileObject) jfo).update();
2698:                }
2699:
2700:            }
2701:
2702:            private static class LMListener implements  LowMemoryListener {
2703:                private AtomicBoolean lowMemory = new AtomicBoolean(false);
2704:
2705:                public void lowMemory(LowMemoryEvent event) {
2706:                    lowMemory.set(true);
2707:                }
2708:            }
2709:
2710:            private static class JSCancelService extends CancelService {
2711:
2712:                boolean active;
2713:
2714:                public static JSCancelService instance(final Context context) {
2715:                    final CancelService cancelService = CancelService
2716:                            .instance(context);
2717:                    return (cancelService instanceof  JSCancelService) ? (JSCancelService) cancelService
2718:                            : null;
2719:                }
2720:
2721:                static void preRegister(final Context context) {
2722:                    context.put(cancelServiceKey, new JSCancelService());
2723:                }
2724:
2725:                @Override
2726:                public boolean isCanceled() {
2727:                    final boolean res = active
2728:                            && currentRequest.isInterruptJavac();
2729:                    return res;
2730:                }
2731:
2732:            }
2733:
2734:            private static class JSFlowListener extends FlowListener {
2735:
2736:                private boolean flowCompleted;
2737:
2738:                public static JSFlowListener instance(final Context context) {
2739:                    final FlowListener flowListener = FlowListener
2740:                            .instance(context);
2741:                    return (flowListener instanceof  JSFlowListener) ? (JSFlowListener) flowListener
2742:                            : null;
2743:                }
2744:
2745:                static void preRegister(final Context context) {
2746:                    context.put(flowListenerKey, new JSFlowListener());
2747:                }
2748:
2749:                final boolean hasFlowCompleted() {
2750:                    return this .flowCompleted;
2751:                }
2752:
2753:                @Override
2754:                public void flowFinished(final Env<AttrContext> env) {
2755:                    this .flowCompleted = true;
2756:                }
2757:            }
2758:
2759:            /**
2760:             *Ugly and slow, called only when -ea
2761:             *
2762:             */
2763:            private static boolean holdsDocumentWriteLock(
2764:                    Iterable<FileObject> files) {
2765:                final Class<AbstractDocument> docClass = AbstractDocument.class;
2766:                try {
2767:                    final Method method = docClass
2768:                            .getDeclaredMethod("getCurrentWriter"); //NOI18N
2769:                    method.setAccessible(true);
2770:                    final Thread currentThread = Thread.currentThread();
2771:                    for (FileObject fo : files) {
2772:                        try {
2773:                            final DataObject dobj = DataObject.find(fo);
2774:                            final EditorCookie ec = dobj
2775:                                    .getCookie(EditorCookie.class);
2776:                            if (ec != null) {
2777:                                final StyledDocument doc = ec.getDocument();
2778:                                if (doc instanceof  AbstractDocument) {
2779:                                    Object result = method.invoke(doc);
2780:                                    if (result == currentThread) {
2781:                                        return true;
2782:                                    }
2783:                                }
2784:                            }
2785:                        } catch (Exception e) {
2786:                            Exceptions.printStackTrace(e);
2787:                        }
2788:                    }
2789:                } catch (NoSuchMethodException e) {
2790:                    Exceptions.printStackTrace(e);
2791:                }
2792:                return false;
2793:            }
2794:
2795:            private static String validateSourceLevel(String sourceLevel) {
2796:                Source[] sources = Source.values();
2797:                if (sourceLevel == null) {
2798:                    //Should never happen but for sure
2799:                    return sources[sources.length - 1].name;
2800:                }
2801:                for (Source source : sources) {
2802:                    if (source.name.equals(sourceLevel)) {
2803:                        return sourceLevel;
2804:                    }
2805:                }
2806:                SpecificationVersion specVer = new SpecificationVersion(
2807:                        sourceLevel);
2808:                SpecificationVersion JAVA_12 = new SpecificationVersion("1.2"); //NOI18N
2809:                if (JAVA_12.compareTo(specVer) > 0) {
2810:                    //Some SourceLevelQueries return 1.1 source level which is invalid, use 1.2
2811:                    return sources[0].name;
2812:                } else {
2813:                    return sources[sources.length - 1].name;
2814:                }
2815:            }
2816:
2817:            private static final int MAX_DUMPS = 255;
2818:
2819:            /**
2820:             * Dumps the source code to the file. Used for parser debugging. Only a limited number
2821:             * of dump files is used. If the last file exists, this method doesn't dump anything.
2822:             *
2823:             * @param  info  CompilationInfo for which the error occurred.
2824:             * @param  exc  exception to write to the end of dump file
2825:             */
2826:            private static void dumpSource(CompilationInfoImpl info,
2827:                    Throwable exc) {
2828:                String userDir = System.getProperty("netbeans.user");
2829:                if (userDir == null) {
2830:                    return;
2831:                }
2832:                String dumpDir = userDir + "/var/log/"; //NOI18N
2833:                String src = info.getText();
2834:                FileObject file = info.getFileObject();
2835:                String fileName = FileUtil.getFileDisplayName(file);
2836:                String origName = file.getName();
2837:                File f = new File(dumpDir + origName + ".dump"); // NOI18N
2838:                boolean dumpSucceeded = false;
2839:                int i = 1;
2840:                while (i < MAX_DUMPS) {
2841:                    if (!f.exists())
2842:                        break;
2843:                    f = new File(dumpDir + origName + '_' + i + ".dump"); // NOI18N
2844:                    i++;
2845:                }
2846:                if (!f.exists()) {
2847:                    try {
2848:                        OutputStream os = new FileOutputStream(f);
2849:                        PrintWriter writer = new PrintWriter(
2850:                                new OutputStreamWriter(os, "UTF-8")); // NOI18N
2851:                        try {
2852:                            writer.println(src);
2853:                            writer
2854:                                    .println("----- Classpath: ---------------------------------------------"); // NOI18N
2855:
2856:                            final ClassPath bootPath = info.getClasspathInfo()
2857:                                    .getClassPath(ClasspathInfo.PathKind.BOOT);
2858:                            final ClassPath classPath = info.getClasspathInfo()
2859:                                    .getClassPath(
2860:                                            ClasspathInfo.PathKind.COMPILE);
2861:                            final ClassPath sourcePath = info
2862:                                    .getClasspathInfo().getClassPath(
2863:                                            ClasspathInfo.PathKind.SOURCE);
2864:
2865:                            writer.println("bootPath: "
2866:                                    + (bootPath != null ? bootPath.toString()
2867:                                            : "null"));
2868:                            writer.println("classPath: "
2869:                                    + (classPath != null ? classPath.toString()
2870:                                            : "null"));
2871:                            writer.println("sourcePath: "
2872:                                    + (sourcePath != null ? sourcePath
2873:                                            .toString() : "null"));
2874:
2875:                            writer
2876:                                    .println("----- Original exception ---------------------------------------------"); // NOI18N
2877:                            exc.printStackTrace(writer);
2878:                        } finally {
2879:                            writer.close();
2880:                            dumpSucceeded = true;
2881:                        }
2882:                    } catch (IOException ioe) {
2883:                        LOGGER.log(Level.INFO,
2884:                                "Error when writing parser dump file!", ioe); // NOI18N
2885:                    }
2886:                }
2887:                if (dumpSucceeded) {
2888:                    Throwable t = Exceptions
2889:                            .attachMessage(
2890:                                    exc,
2891:                                    "An error occurred during parsing of \'"
2892:                                            + fileName
2893:                                            + "\'. Please report a bug against java/source and attach dump file '" // NOI18N
2894:                                            + f.getAbsolutePath() + "'."); // NOI18N
2895:                    Exceptions.printStackTrace(t);
2896:                } else {
2897:                    LOGGER
2898:                            .log(Level.WARNING,
2899:                                    "Dump could not be written. Either dump file could not "
2900:                                            + // NOI18N
2901:                                            "be created or all dump files were already used. Please "
2902:                                            + // NOI18N
2903:                                            "check that you have write permission to '"
2904:                                            + dumpDir + "' and " + // NOI18N
2905:                                            "clean all *.dump files in that directory."); // NOI18N
2906:                }
2907:            }
2908:
2909:            private static final class DevNullWriter extends Writer {
2910:                public void write(char[] cbuf, int off, int len)
2911:                        throws IOException {
2912:                }
2913:
2914:                public void flush() throws IOException {
2915:                }
2916:
2917:                public void close() throws IOException {
2918:                }
2919:            }
2920:
2921:            private static class FindMethodRegionsVisitor extends
2922:                    SimpleTreeVisitor<Void, Void> {
2923:
2924:                final Document doc;
2925:                final SourcePositions pos;
2926:                CompilationUnitTree cu;
2927:
2928:                final List<Pair<DocPositionRegion, MethodTree>> posRegions = new LinkedList<Pair<JavaSource.DocPositionRegion, MethodTree>>();
2929:
2930:                public FindMethodRegionsVisitor(final Document doc,
2931:                        final SourcePositions pos) {
2932:                    assert doc != null;
2933:                    assert pos != null;
2934:                    this .doc = doc;
2935:                    this .pos = pos;
2936:                }
2937:
2938:                @Override
2939:                public Void visitCompilationUnit(CompilationUnitTree node,
2940:                        Void p) {
2941:                    cu = node;
2942:                    for (Tree t : node.getTypeDecls()) {
2943:                        visit(t, p);
2944:                    }
2945:                    return null;
2946:                }
2947:
2948:                @Override
2949:                public Void visitClass(ClassTree node, Void p) {
2950:                    for (Tree t : node.getMembers()) {
2951:                        visit(t, p);
2952:                    }
2953:                    return null;
2954:                }
2955:
2956:                @Override
2957:                public Void visitMethod(MethodTree node, Void p) {
2958:                    assert cu != null;
2959:                    int startPos = (int) pos.getStartPosition(cu, node
2960:                            .getBody());
2961:                    int endPos = (int) pos.getEndPosition(cu, node.getBody());
2962:                    if (startPos >= 0) {
2963:                        try {
2964:                            posRegions.add(Pair
2965:                                    .<DocPositionRegion, MethodTree> of(
2966:                                            new DocPositionRegion(doc,
2967:                                                    startPos, endPos), node));
2968:                        } catch (BadLocationException e) {
2969:                            //todo: reocvery
2970:                            e.printStackTrace();
2971:                        }
2972:                    }
2973:                    return null;
2974:                }
2975:
2976:            }
2977:
2978:            private static boolean reparseMethod(final CompilationInfoImpl ci,
2979:                    final MethodTree orig, final String newBody)
2980:                    throws IOException {
2981:                assert ci != null;
2982:                final FileObject fo = ci.getFileObject();
2983:                if (LOGGER.isLoggable(Level.FINER)) {
2984:                    LOGGER.finer("Reparse method in: " + fo); //NOI18N
2985:                }
2986:                if (!ci.getJavaSource().supportsReparse) {
2987:                    return false;
2988:                }
2989:                if (((JCMethodDecl) orig).localEnv == null) {
2990:                    //We are seeing interface method or abstract or native method with body.
2991:                    //Don't do any optimalization of this broken code - has no attr env.
2992:                    return false;
2993:                }
2994:                final Phase currentPhase = ci.getPhase();
2995:                if (Phase.PARSED.compareTo(currentPhase) > 0) {
2996:                    return false;
2997:                }
2998:                try {
2999:                    final CompilationUnitTree cu = ci.getCompilationUnit();
3000:                    if (cu == null || newBody == null) {
3001:                        return false;
3002:                    }
3003:                    final JavacTaskImpl task = ci.getJavacTask();
3004:                    final JavacTrees jt = JavacTrees.instance(task);
3005:                    final int origStartPos = (int) jt.getSourcePositions()
3006:                            .getStartPosition(cu, orig.getBody());
3007:                    final int origEndPos = (int) jt.getSourcePositions()
3008:                            .getEndPosition(cu, orig.getBody());
3009:                    if (origStartPos > origEndPos) {
3010:                        LOGGER.warning("Javac returned startpos: "
3011:                                + origStartPos + " > endpos: " + origEndPos); //NOI18N
3012:                        return false;
3013:                    }
3014:                    final FindAnnonVisitor fav = new FindAnnonVisitor();
3015:                    fav.scan(orig.getBody(), null);
3016:                    if (fav.hasLocalClass) {
3017:                        if (LOGGER.isLoggable(Level.FINER)) {
3018:                            LOGGER
3019:                                    .finer("Skeep reparse method (old local classes): "
3020:                                            + fo); //NOI18N
3021:                        }
3022:                        return false;
3023:                    }
3024:                    final int firstInner = fav.firstInner;
3025:                    final int noInner = fav.noInner;
3026:                    final Context ctx = task.getContext();
3027:                    final Log l = Log.instance(ctx);
3028:                    l.startPartialReparse();
3029:                    final JavaFileObject prevLogged = l.useSource(cu
3030:                            .getSourceFile());
3031:                    JCBlock block;
3032:                    try {
3033:                        DiagnosticListener dl = ctx
3034:                                .get(DiagnosticListener.class);
3035:                        assert dl instanceof  CompilationInfoImpl.DiagnosticListenerImpl;
3036:                        ((CompilationInfoImpl.DiagnosticListenerImpl) dl)
3037:                                .startPartialReparse(origStartPos, origEndPos);
3038:                        long start = System.currentTimeMillis();
3039:                        block = task.reparseMethodBody(cu, orig, newBody,
3040:                                firstInner);
3041:                        if (LOGGER.isLoggable(Level.FINER)) {
3042:                            LOGGER.finer("Reparsed method in: " + fo); //NOI18N
3043:                        }
3044:                        assert block != null;
3045:                        fav.reset();
3046:                        fav.scan(block, null);
3047:                        final int newNoInner = fav.noInner;
3048:                        if (fav.hasLocalClass || noInner != newNoInner) {
3049:                            if (LOGGER.isLoggable(Level.FINER)) {
3050:                                LOGGER
3051:                                        .finer("Skeep reparse method (new local classes): "
3052:                                                + fo); //NOI18N
3053:                            }
3054:                            return false;
3055:                        }
3056:                        long end = System.currentTimeMillis();
3057:                        if (fo != null) {
3058:                            logTime(fo, Phase.PARSED, (end - start));
3059:                        }
3060:                        final int newEndPos = (int) jt.getSourcePositions()
3061:                                .getEndPosition(cu, block);
3062:                        final int delta = newEndPos - origEndPos;
3063:                        final Map<JCTree, Integer> endPos = ((JCCompilationUnit) cu).endPositions;
3064:                        final TranslatePosVisitor tpv = new TranslatePosVisitor(
3065:                                orig, endPos, delta);
3066:                        tpv.scan(cu, null);
3067:                        ((JCMethodDecl) orig).body = block;
3068:                        if (Phase.RESOLVED.compareTo(currentPhase) <= 0) {
3069:                            start = System.currentTimeMillis();
3070:                            task.reattrMethodBody(orig, block);
3071:                            if (LOGGER.isLoggable(Level.FINER)) {
3072:                                LOGGER.finer("Resolved method in: " + fo); //NOI18N
3073:                            }
3074:                            if (!((CompilationInfoImpl.DiagnosticListenerImpl) dl)
3075:                                    .hasPartialReparseErrors()) {
3076:                                final JSFlowListener fl = JSFlowListener
3077:                                        .instance(ctx);
3078:                                if (fl != null && fl.hasFlowCompleted()) {
3079:                                    if (LOGGER.isLoggable(Level.FINER)) {
3080:                                        final List<? extends Diagnostic> diag = ci
3081:                                                .getDiagnostics();
3082:                                        if (!diag.isEmpty()) {
3083:                                            LOGGER.finer("Reflow with errors: "
3084:                                                    + fo + " " + diag); //NOI18N
3085:                                        }
3086:                                    }
3087:                                    TreePath tp = TreePath.getPath(cu, orig); //todo: store treepath in changed method => improve speed
3088:                                    Tree t = tp.getParentPath().getLeaf();
3089:                                    task.reflowMethodBody(cu, (ClassTree) t,
3090:                                            orig);
3091:                                    if (LOGGER.isLoggable(Level.FINER)) {
3092:                                        LOGGER.finer("Reflowed method in: "
3093:                                                + fo); //NOI18N
3094:                                    }
3095:                                }
3096:                            }
3097:                            end = System.currentTimeMillis();
3098:                            if (fo != null) {
3099:                                logTime(fo, Phase.ELEMENTS_RESOLVED, 0L);
3100:                                logTime(fo, Phase.RESOLVED, (end - start));
3101:                            }
3102:                        }
3103:                        ((CompilationInfoImpl.DiagnosticListenerImpl) dl)
3104:                                .endPartialReparse(delta);
3105:                    } finally {
3106:                        l.endPartialReparse();
3107:                        l.useSource(prevLogged);
3108:                    }
3109:                    jfoProvider.update(ci.jfo);
3110:                } catch (Throwable t) {
3111:                    if (t instanceof  ThreadDeath) {
3112:                        throw (ThreadDeath) t;
3113:                    }
3114:                    dumpSource(ci, t);
3115:                    return false;
3116:                }
3117:                return true;
3118:            }
3119:
3120:            //where
3121:
3122:            private static class FindAnnonVisitor extends
3123:                    TreeScanner<Void, Void> {
3124:                private int firstInner = -1;
3125:                private int noInner;
3126:                private boolean hasLocalClass;
3127:
3128:                public final void reset() {
3129:                    this .firstInner = -1;
3130:                    this .noInner = 0;
3131:                    this .hasLocalClass = false;
3132:                }
3133:
3134:                @Override
3135:                public Void visitClass(ClassTree node, Void p) {
3136:                    if (firstInner == -1) {
3137:                        firstInner = ((JCClassDecl) node).index;
3138:                    }
3139:                    if (node.getSimpleName().length() != 0) {
3140:                        hasLocalClass = true;
3141:                    }
3142:                    noInner++;
3143:                    return super .visitClass(node, p);
3144:                }
3145:
3146:            }
3147:
3148:            private static class TranslatePosVisitor extends
3149:                    TreeScanner<Void, Void> {
3150:
3151:                private final MethodTree changedMethod;
3152:                private final Map<JCTree, Integer> endPos;
3153:                private final int delta;
3154:                boolean active;
3155:                boolean inMethod;
3156:
3157:                public TranslatePosVisitor(final MethodTree changedMethod,
3158:                        final Map<JCTree, Integer> endPos, final int delta) {
3159:                    assert changedMethod != null;
3160:                    assert endPos != null;
3161:                    this .changedMethod = changedMethod;
3162:                    this .endPos = endPos;
3163:                    this .delta = delta;
3164:                }
3165:
3166:                @Override
3167:                public Void scan(Tree node, Void p) {
3168:                    if (active && node != null) {
3169:                        if (((JCTree) node).pos >= 0) {
3170:                            ((JCTree) node).pos += delta;
3171:                        }
3172:                    }
3173:                    Void result = super .scan(node, p);
3174:                    if (inMethod && node != null) {
3175:                        endPos.remove(node);
3176:                    }
3177:                    if (active && node != null) {
3178:                        Integer pos = endPos.remove(node);
3179:                        if (pos != null) {
3180:                            int newPos;
3181:                            if (pos < 0) {
3182:                                newPos = pos;
3183:                            } else {
3184:                                newPos = pos + delta;
3185:                            }
3186:                            endPos.put((JCTree) node, newPos);
3187:                        }
3188:                    }
3189:                    return result;
3190:                }
3191:
3192:                @Override
3193:                public Void visitCompilationUnit(CompilationUnitTree node,
3194:                        Void p) {
3195:                    return scan(node.getTypeDecls(), p);
3196:                }
3197:
3198:                @Override
3199:                public Void visitMethod(MethodTree node, Void p) {
3200:                    if (active || inMethod) {
3201:                        scan(node.getModifiers(), p);
3202:                        scan(node.getReturnType(), p);
3203:                        scan(node.getTypeParameters(), p);
3204:                        scan(node.getParameters(), p);
3205:                        scan(node.getThrows(), p);
3206:                    }
3207:                    if (node == changedMethod) {
3208:                        inMethod = true;
3209:                    }
3210:                    if (active || inMethod) {
3211:                        scan(node.getBody(), p);
3212:                    }
3213:                    if (inMethod) {
3214:                        active = inMethod;
3215:                        inMethod = false;
3216:                    }
3217:                    if (active || inMethod) {
3218:                        scan(node.getDefaultValue(), p);
3219:                    }
3220:                    return null;
3221:                }
3222:
3223:            }
3224:
3225:            static final class DocPositionRegion extends PositionRegion {
3226:
3227:                private final Document doc;
3228:
3229:                public DocPositionRegion(final Document doc,
3230:                        final int startPos, final int endPos)
3231:                        throws BadLocationException {
3232:                    super (doc, startPos, endPos);
3233:                    assert doc != null;
3234:                    this .doc = doc;
3235:                }
3236:
3237:                public Document getDocument() {
3238:                    return this .doc;
3239:                }
3240:
3241:                public String getText() {
3242:                    final String[] result = new String[1];
3243:                    this .doc.render(new Runnable() {
3244:                        public void run() {
3245:                            try {
3246:                                result[0] = doc.getText(getStartOffset(),
3247:                                        getLength());
3248:                            } catch (BadLocationException ex) {
3249:                                Exceptions.printStackTrace(ex);
3250:                            }
3251:                        }
3252:                    });
3253:                    return result[0];
3254:                }
3255:
3256:            }
3257:
3258:            //Package private test utility methods
3259:            int getReparseDelay() {
3260:                return this .reparseDelay;
3261:            }
3262:
3263:            void setReparseDelay(int reparseDelay, boolean reset) {
3264:                this .reparseDelay = reparseDelay;
3265:                if (reset) {
3266:                    resetState(true, false);
3267:                }
3268:            }
3269:
3270:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.