blob: 220bfd917393503293594569205518fbaf7ef8f7 [file] [log] [blame]
/*
* Copyright 2000-2009 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.execution.testframework;
import com.intellij.execution.filters.HyperlinkInfo;
import com.intellij.execution.testframework.stacktrace.DiffHyperlink;
import com.intellij.execution.testframework.ui.TestsOutputConsolePrinter;
import com.intellij.execution.ui.ConsoleViewContentType;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.util.Alarm;
import com.intellij.util.io.IOUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
public class CompositePrintable implements Printable, Disposable {
public static final String NEW_LINE = "\n";
protected final List<Printable> myNestedPrintables = new ArrayList<Printable>();
private final PrintablesWrapper myWrapper = new PrintablesWrapper();
protected int myExceptionMark;
private int myCurrentSize = 0;
private String myOutputFile = null;
private static final Alarm myAlarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD);
public void flush() {
synchronized (myNestedPrintables) {
myWrapper.flush(myNestedPrintables);
clear();
}
}
public static void invokeInAlarm(Runnable runnable) {
invokeInAlarm(runnable, !ApplicationManager.getApplication().isDispatchThread() ||
ApplicationManager.getApplication().isUnitTestMode());
}
public static void invokeInAlarm(Runnable runnable, final boolean sync) {
if (sync) {
runnable.run();
} else {
myAlarm.addRequest(runnable, 0);
}
}
public void printOn(final Printer printer) {
final ArrayList<Printable> printables;
synchronized (myNestedPrintables) {
printables = new ArrayList<Printable>(myNestedPrintables);
}
myWrapper.printOn(printer, printables);
}
public void addLast(@NotNull final Printable printable) {
synchronized (myNestedPrintables) {
myNestedPrintables.add(printable);
if (myNestedPrintables.size() > 500) {
flush();
}
}
}
public void insert(@NotNull final Printable printable, int i) {
synchronized (myNestedPrintables) {
if (i >= myNestedPrintables.size()) {
myNestedPrintables.add(printable);
} else {
myNestedPrintables.add(i, printable);
}
if (myNestedPrintables.size() > 500) {
flush();
}
}
}
protected void clear() {
synchronized (myNestedPrintables) {
myCurrentSize += myNestedPrintables.size();
myNestedPrintables.clear();
}
}
public int getCurrentSize() {
synchronized (myNestedPrintables) {
return myCurrentSize + myNestedPrintables.size();
}
}
@Override
public void dispose() {
clear();
myWrapper.dispose();
}
public int getExceptionMark() {
return myExceptionMark;
}
public void setExceptionMark(int exceptionMark) {
myExceptionMark = exceptionMark;
}
public void setOutputFilePath(String outputFile) {
myOutputFile = outputFile;
}
private static final Logger LOG = Logger.getInstance("#" + PrintablesWrapper.class.getName());
private class PrintablesWrapper {
@NonNls private static final String HYPERLINK = "hyperlink";
private ConsoleViewContentType myLastSelected;
private File myFile;
private final MyFlushToFilePrinter myPrinter = new MyFlushToFilePrinter();
@Nullable
private synchronized File getFile() {
if (myFile == null) {
try {
final File tempFile = FileUtil.createTempFile("idea_test_", ".out");
if (tempFile.exists()) {
myFile = tempFile;
return myFile;
}
}
catch (IOException e) {
LOG.error(e);
return null;
}
}
return myFile;
}
public synchronized void dispose() {
if (myFile != null) FileUtil.delete(myFile);
}
public synchronized boolean hasOutput() {
return myFile != null;
}
public void flush(final List<Printable> printables) {
if (printables.isEmpty()) return;
final ArrayList<Printable> currentPrintables = new ArrayList<Printable>(printables);
//move out from AWT thread
final Runnable request = new Runnable() {
@Override
public void run() {
for (final Printable printable : currentPrintables) {
printable.printOn(myPrinter);
}
myPrinter.close();
if (myOutputFile != null && new File(myOutputFile).exists()) {
PrintStream printStream = null;
try {
printStream = new PrintStream(new FileOutputStream(new File(myOutputFile), true));
final PrintStream finalPrintStream = printStream;
for (Printable currentPrintable : currentPrintables) {
currentPrintable.printOn(new Printer() {
@Override
public void print(String text, ConsoleViewContentType contentType) {
if (contentType != ConsoleViewContentType.SYSTEM_OUTPUT) {
finalPrintStream.print(text);
}
}
@Override
public void printHyperlink(String text, HyperlinkInfo info) {
finalPrintStream.print(text);
}
@Override
public void onNewAvailable(@NotNull Printable printable) {}
@Override
public void mark() {}
});
}
}
catch (FileNotFoundException e) {
LOG.error(e);
}
finally {
if (printStream != null) {
printStream.close();
}
}
}
}
};
invokeInAlarm(request, ApplicationManager.getApplication().isUnitTestMode());
}
public void printOn(final Printer console, final List<Printable> printables) {
final Runnable request = new Runnable() {
@Override
public void run() {
final File file = hasOutput() ? getFile() : null;
final MyFileContentPrinter printer = new MyFileContentPrinter();
printer.printFileContent(console, file, printables);
}
};
invokeInAlarm(request);
}
private class MyFlushToFilePrinter implements Printer {
//all access is performed from alarm thread
private DataOutputStream myFileWriter;
public DataOutputStream getFileWriter() {
if (myFileWriter == null) {
try {
final File file = getFile();
LOG.assertTrue(file != null);
myFileWriter = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file, true)));
}
catch (FileNotFoundException e) {
LOG.info(e);
return null;
}
}
return myFileWriter;
}
public void close() {
if (myFileWriter != null) {
try {
myFileWriter.close();
}
catch (FileNotFoundException e) {
LOG.info(e);
}
catch (IOException e) {
LOG.error(e);
}
myFileWriter = null;
}
}
@Override
public void print(String text, ConsoleViewContentType contentType) {
try {
final DataOutputStream writer = getFileWriter();
if (writer != null) {
IOUtil.writeString(contentType.toString() + text, writer);
}
}
catch (FileNotFoundException e) {
LOG.info(e);
}
catch (IOException e) {
LOG.error(e);
}
}
@Override
public void printHyperlink(String text, HyperlinkInfo info) {
if (info instanceof DiffHyperlink.DiffHyperlinkInfo) {
final DiffHyperlink diffHyperlink = ((DiffHyperlink.DiffHyperlinkInfo)info).getPrintable();
try {
final DataOutputStream fileWriter = getFileWriter();
if (fileWriter != null) {
IOUtil.writeString(HYPERLINK, fileWriter);
IOUtil.writeString(diffHyperlink.getLeft(), fileWriter);
IOUtil.writeString(diffHyperlink.getRight(), fileWriter);
IOUtil.writeString(diffHyperlink.getFilePath(), fileWriter);
}
}
catch (FileNotFoundException e) {
LOG.info(e);
}
catch (IOException e) {
LOG.error(e);
}
}
else {
print(text, ConsoleViewContentType.NORMAL_OUTPUT);
}
}
@Override
public void onNewAvailable(@NotNull Printable printable) {}
@Override
public void mark() {}
}
private class MyFileContentPrinter {
public void printFileContent(Printer printer, @Nullable File file, List<Printable> nestedPrintables) {
if (file != null) {
DataInputStream reader = null;
try {
reader = new DataInputStream(new BufferedInputStream(new FileInputStream(file)));
int lineNum = 0;
while (reader.available() > 0 && !wasPrintableChanged(printer)) {
if (lineNum == CompositePrintable.this.getExceptionMark() && lineNum > 0) printer.mark();
final String line = IOUtil.readString(reader);
boolean printed = false;
for (ConsoleViewContentType contentType : ConsoleViewContentType.OUTPUT_TYPES) {
final String prefix = contentType.toString();
if (line.startsWith(prefix)) {
printer.print(line.substring(prefix.length()), contentType);
myLastSelected = contentType;
printed = true;
break;
}
}
if (!printed) {
if (line.startsWith(HYPERLINK)) {
new DiffHyperlink(IOUtil.readString(reader), IOUtil.readString(reader), IOUtil.readString(reader), false).printOn(printer);
}
else {
printer.print(line, myLastSelected != null ? myLastSelected : ConsoleViewContentType.NORMAL_OUTPUT);
}
}
lineNum++;
}
}
catch (FileNotFoundException e) {
LOG.info(e);
}
catch (IOException e) {
LOG.error(e);
}
finally {
try {
if (reader != null) {
reader.close();
}
}
catch (FileNotFoundException e) {
LOG.info(e);
}
catch (IOException e) {
LOG.error(e);
}
}
}
for (int i = 0; i < nestedPrintables.size(); i++) {
if (i == getExceptionMark() && i > 0) printer.mark();
nestedPrintables.get(i).printOn(printer);
}
}
private boolean wasPrintableChanged(Printer printer) {
return printer instanceof TestsOutputConsolePrinter && !((TestsOutputConsolePrinter)printer).isCurrent(CompositePrintable.this);
}
}
}
}