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
;
31 * @author Eugene Zhuravlev
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
) {
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();
59 volatile boolean processing
;
64 if (!myIsUnitTestMode
&& myProcess
== null) {
67 if (myProcessExited
|| isCanceled()) {
70 if (!myOutputParser
.processMessageLine(this)) {
74 if (myClassFileToProcess
!= null) {
75 processCompiledClass(myClassFileToProcess
);
76 myClassFileToProcess
= null;
90 private void killProcess() {
91 if (myProcess
!= null) {
97 public Throwable
getError() {
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;
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) {
127 processCompiledClass(previousPath
);
129 catch (CacheCorruptedException e
) {
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;
160 buffer
= StringBuilderSpinAllocator
.alloc();
162 catch (SpinAllocator
.AllocatorExhaustedException e
) {
164 buffer
= new StringBuilder();
165 releaseBuffer
= false;
169 boolean first
= true;
171 int c
= readNextByte(reader
);
181 else if (c
== '\r') {
187 buffer
.append((char)c
);
193 return buffer
.toString();
197 StringBuilderSpinAllocator
.dispose(buffer
);
202 private int readNextByte(final Reader reader
) {
204 while(!reader
.ready()) {
205 if (isProcessTerminated()) {
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
;