do not use VFS to read .class file content,
[fedora-idea.git] / java / compiler / impl / src / com / intellij / compiler / impl / javaCompiler / CompilerParsingThread.java
blob2c1fba6db054d3b0ebe7a733588db5b7d28208f2
1 /*
2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.intellij.compiler.impl.javaCompiler;
18 import com.intellij.compiler.OutputParser;
19 import com.intellij.compiler.make.CacheCorruptedException;
20 import com.intellij.openapi.application.ApplicationManager;
21 import com.intellij.openapi.diagnostic.Logger;
22 import com.intellij.openapi.compiler.CompileContext;
23 import com.intellij.openapi.compiler.CompilerMessageCategory;
24 import com.intellij.util.SpinAllocator;
25 import com.intellij.util.StringBuilderSpinAllocator;
26 import org.jetbrains.annotations.NonNls;
28 import java.io.*;
30 /**
31 * @author Eugene Zhuravlev
32 * Date: Mar 30, 2004
34 public class CompilerParsingThread implements Runnable, OutputParser.Callback {
35 private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.impl.javaCompiler.JavaCompilerParsingThread");
36 @NonNls public static final String TERMINATION_STRING = "__terminate_read__";
37 private final Reader myCompilerOutStreamReader;
38 private Process myProcess;
39 private final OutputParser myOutputParser;
40 private final boolean myTrimLines;
41 private boolean mySkipLF = false;
42 private Throwable myError = null;
43 private final boolean myIsUnitTestMode;
44 private FileObject myClassFileToProcess = null;
45 private String myLastReadLine = null;
46 private volatile boolean myProcessExited = false;
47 private final CompileContext myContext;
49 public CompilerParsingThread(Process process, OutputParser outputParser, final boolean readErrorStream, boolean trimLines, CompileContext context) {
50 myProcess = process;
51 myOutputParser = outputParser;
52 myTrimLines = trimLines;
53 InputStream stream = readErrorStream ? process.getErrorStream() : process.getInputStream();
54 myCompilerOutStreamReader = stream == null ? null : new BufferedReader(new InputStreamReader(stream), 16384);
55 myIsUnitTestMode = ApplicationManager.getApplication().isUnitTestMode();
56 myContext = context;
59 volatile boolean processing;
60 public void run() {
61 processing = true;
62 try {
63 while (true) {
64 if (!myIsUnitTestMode && myProcess == null) {
65 break;
67 if (myProcessExited || isCanceled()) {
68 break;
70 if (!myOutputParser.processMessageLine(this)) {
71 break;
74 if (myClassFileToProcess != null) {
75 processCompiledClass(myClassFileToProcess);
76 myClassFileToProcess = null;
79 catch (Throwable e) {
80 e.printStackTrace();
81 myError = e;
82 LOG.info(e);
84 finally {
85 killProcess();
86 processing = false;
90 private void killProcess() {
91 if (myProcess != null) {
92 myProcess.destroy();
93 myProcess = null;
97 public Throwable getError() {
98 return myError;
101 public String getCurrentLine() {
102 return myLastReadLine;
105 public final String getNextLine() {
106 final String line = readLine(myCompilerOutStreamReader);
107 if (LOG.isDebugEnabled()) {
108 LOG.debug("LIne read: #" + line + "#");
110 if (TERMINATION_STRING.equals(line)) {
111 myLastReadLine = null;
113 else {
114 myLastReadLine = line == null ? null : myTrimLines ? line.trim() : line;
116 return myLastReadLine;
119 public final void fileGenerated(FileObject path) {
120 // javac first logs file generated, then starts to write the file to disk,
121 // so this thread sometimes can stumble on not yet existing file,
122 // hence this complex logic
123 FileObject previousPath = myClassFileToProcess;
124 myClassFileToProcess = path;
125 if (previousPath != null) {
126 try {
127 processCompiledClass(previousPath);
129 catch (CacheCorruptedException e) {
130 myError = e;
131 LOG.info(e);
132 killProcess();
137 protected boolean isCanceled() {
138 return myContext.getProgressIndicator().isCanceled();
141 public void setProgressText(String text) {
142 myContext.getProgressIndicator().setText(text);
145 public void fileProcessed(String path) {
148 public void message(CompilerMessageCategory category, String message, String url, int lineNum, int columnNum) {
149 myContext.addMessage(category, message, url, lineNum, columnNum);
152 protected void processCompiledClass(final FileObject classFileToProcess) throws CacheCorruptedException {
156 private String readLine(final Reader reader) {
157 StringBuilder buffer;
158 boolean releaseBuffer = true;
159 try {
160 buffer = StringBuilderSpinAllocator.alloc();
162 catch (SpinAllocator.AllocatorExhaustedException e) {
163 LOG.info(e);
164 buffer = new StringBuilder();
165 releaseBuffer = false;
168 try {
169 boolean first = true;
170 while (true) {
171 int c = readNextByte(reader);
172 if (c == -1) break;
173 first = false;
174 if (c == '\n') {
175 if (mySkipLF) {
176 mySkipLF = false;
177 continue;
179 break;
181 else if (c == '\r') {
182 mySkipLF = true;
183 break;
185 else {
186 mySkipLF = false;
187 buffer.append((char)c);
190 if (first) {
191 return null;
193 return buffer.toString();
195 finally {
196 if (releaseBuffer) {
197 StringBuilderSpinAllocator.dispose(buffer);
202 private int readNextByte(final Reader reader) {
203 try {
204 while(!reader.ready()) {
205 if (isProcessTerminated()) {
206 return -1;
208 try {
209 Thread.sleep(1L);
211 catch (InterruptedException ignore) {
214 return reader.read();
216 catch (IOException e) {
217 return -1; // When process terminated Process.getInputStream()'s underlaying stream becomes closed on Linux.
221 private boolean isProcessTerminated() {
222 return myProcessExited;
225 public void setProcessTerminated(final boolean procesExited) {
226 myProcessExited = procesExited;