blob: f9521821054e08b921b992d9cd69af91bd93b59b [file] [log] [blame]
////////////////////////////////////////////////////////////////////////////////
// checkstyle: Checks Java source code for adherence to a set of rules.
// Copyright (C) 2001-2017 the original author or authors.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
////////////////////////////////////////////////////////////////////////////////
package com.puppycrawl.tools.checkstyle;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import com.puppycrawl.tools.checkstyle.api.AuditEvent;
import com.puppycrawl.tools.checkstyle.api.AuditListener;
import com.puppycrawl.tools.checkstyle.api.AutomaticBean;
import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
import com.puppycrawl.tools.checkstyle.api.LocalizedMessage;
import com.puppycrawl.tools.checkstyle.api.SeverityLevel;
/**
* Simple plain logger for text output.
* This is maybe not very suitable for a text output into a file since it
* does not need all 'audit finished' and so on stuff, but it looks good on
* stdout anyway. If there is really a problem this is what XMLLogger is for.
* It gives structure.
*
* @author <a href="mailto:stephane.bailliez@wanadoo.fr">Stephane Bailliez</a>
* @see XMLLogger
* @noinspection ClassWithTooManyConstructors
*/
public class DefaultLogger extends AutomaticBean implements AuditListener {
/**
* A key pointing to the add exception
* message in the "messages.properties" file.
*/
public static final String ADD_EXCEPTION_MESSAGE = "DefaultLogger.addException";
/**
* A key pointing to the started audit
* message in the "messages.properties" file.
*/
public static final String AUDIT_STARTED_MESSAGE = "DefaultLogger.auditStarted";
/**
* A key pointing to the finished audit
* message in the "messages.properties" file.
*/
public static final String AUDIT_FINISHED_MESSAGE = "DefaultLogger.auditFinished";
/** Where to write info messages. **/
private final PrintWriter infoWriter;
/** Close info stream after use. */
private final boolean closeInfo;
/** Where to write error messages. **/
private final PrintWriter errorWriter;
/** Close error stream after use. */
private final boolean closeError;
/** Formatter for the log message. */
private final AuditEventFormatter formatter;
/**
* Creates a new {@code DefaultLogger} instance.
* @param outputStream where to log infos and errors
* @param closeStreamsAfterUse if oS should be closed in auditFinished()
* @deprecated in order to fullfil demands of BooleanParameter IDEA check.
* @noinspection BooleanParameter
*/
@Deprecated
public DefaultLogger(OutputStream outputStream, boolean closeStreamsAfterUse) {
// no need to close oS twice
this(outputStream, closeStreamsAfterUse, outputStream, false);
}
/**
* Creates a new {@code DefaultLogger} instance.
* @param infoStream the {@code OutputStream} for info messages.
* @param closeInfoAfterUse auditFinished should close infoStream.
* @param errorStream the {@code OutputStream} for error messages.
* @param closeErrorAfterUse auditFinished should close errorStream
* @deprecated in order to fullfil demands of BooleanParameter IDEA check.
* @noinspection BooleanParameter
*/
@Deprecated
public DefaultLogger(OutputStream infoStream,
boolean closeInfoAfterUse,
OutputStream errorStream,
boolean closeErrorAfterUse) {
this(infoStream, closeInfoAfterUse, errorStream, closeErrorAfterUse,
new AuditEventDefaultFormatter());
}
/**
* Creates a new {@code DefaultLogger} instance.
*
* @param infoStream the {@code OutputStream} for info messages
* @param closeInfoAfterUse auditFinished should close infoStream
* @param errorStream the {@code OutputStream} for error messages
* @param closeErrorAfterUse auditFinished should close errorStream
* @param messageFormatter formatter for the log message.
* @deprecated in order to fullfil demands of BooleanParameter IDEA check.
* @noinspection BooleanParameter, WeakerAccess
*/
@Deprecated
public DefaultLogger(OutputStream infoStream,
boolean closeInfoAfterUse,
OutputStream errorStream,
boolean closeErrorAfterUse,
AuditEventFormatter messageFormatter) {
closeInfo = closeInfoAfterUse;
closeError = closeErrorAfterUse;
final Writer infoStreamWriter = new OutputStreamWriter(infoStream, StandardCharsets.UTF_8);
infoWriter = new PrintWriter(infoStreamWriter);
if (infoStream == errorStream) {
errorWriter = infoWriter;
}
else {
final Writer errorStreamWriter = new OutputStreamWriter(errorStream,
StandardCharsets.UTF_8);
errorWriter = new PrintWriter(errorStreamWriter);
}
formatter = messageFormatter;
}
/**
* Creates a new {@code DefaultLogger} instance.
* @param outputStream where to log infos and errors
* @param outputStreamOptions if {@code CLOSE} that should be closed in auditFinished()
*/
public DefaultLogger(OutputStream outputStream, OutputStreamOptions outputStreamOptions) {
// no need to close oS twice
this(outputStream, outputStreamOptions, outputStream, OutputStreamOptions.NONE);
}
/**
* Creates a new {@code DefaultLogger} instance.
* @param infoStream the {@code OutputStream} for info messages.
* @param infoStreamOptions if {@code CLOSE} info should be closed in auditFinished()
* @param errorStream the {@code OutputStream} for error messages.
* @param errorStreamOptions if {@code CLOSE} error should be closed in auditFinished()
*/
public DefaultLogger(OutputStream infoStream,
OutputStreamOptions infoStreamOptions,
OutputStream errorStream,
OutputStreamOptions errorStreamOptions) {
this(infoStream, infoStreamOptions, errorStream, errorStreamOptions,
new AuditEventDefaultFormatter());
}
/**
* Creates a new {@code DefaultLogger} instance.
*
* @param infoStream the {@code OutputStream} for info messages
* @param infoStreamOptions if {@code CLOSE} info should be closed in auditFinished()
* @param errorStream the {@code OutputStream} for error messages
* @param errorStreamOptions if {@code CLOSE} error should be closed in auditFinished()
* @param messageFormatter formatter for the log message.
* @noinspection WeakerAccess
*/
public DefaultLogger(OutputStream infoStream,
OutputStreamOptions infoStreamOptions,
OutputStream errorStream,
OutputStreamOptions errorStreamOptions,
AuditEventFormatter messageFormatter) {
closeInfo = infoStreamOptions == OutputStreamOptions.CLOSE;
closeError = errorStreamOptions == OutputStreamOptions.CLOSE;
final Writer infoStreamWriter = new OutputStreamWriter(infoStream, StandardCharsets.UTF_8);
infoWriter = new PrintWriter(infoStreamWriter);
if (infoStream == errorStream) {
errorWriter = infoWriter;
}
else {
final Writer errorStreamWriter = new OutputStreamWriter(errorStream,
StandardCharsets.UTF_8);
errorWriter = new PrintWriter(errorStreamWriter);
}
formatter = messageFormatter;
}
@Override
protected void finishLocalSetup() throws CheckstyleException {
// No code by default
}
/**
* Print an Emacs compliant line on the error stream.
* If the column number is non zero, then also display it.
* @see AuditListener
**/
@Override
public void addError(AuditEvent event) {
final SeverityLevel severityLevel = event.getSeverityLevel();
if (severityLevel != SeverityLevel.IGNORE) {
final String errorMessage = formatter.format(event);
errorWriter.println(errorMessage);
}
}
@Override
public void addException(AuditEvent event, Throwable throwable) {
synchronized (errorWriter) {
final LocalizedMessage addExceptionMessage = new LocalizedMessage(0,
Definitions.CHECKSTYLE_BUNDLE, ADD_EXCEPTION_MESSAGE,
new String[] {event.getFileName()}, null,
LocalizedMessage.class, null);
errorWriter.println(addExceptionMessage.getMessage());
throwable.printStackTrace(errorWriter);
}
}
@Override
public void auditStarted(AuditEvent event) {
final LocalizedMessage auditStartMessage = new LocalizedMessage(0,
Definitions.CHECKSTYLE_BUNDLE, AUDIT_STARTED_MESSAGE, null, null,
LocalizedMessage.class, null);
infoWriter.println(auditStartMessage.getMessage());
infoWriter.flush();
}
@Override
public void auditFinished(AuditEvent event) {
final LocalizedMessage auditFinishMessage = new LocalizedMessage(0,
Definitions.CHECKSTYLE_BUNDLE, AUDIT_FINISHED_MESSAGE, null, null,
LocalizedMessage.class, null);
infoWriter.println(auditFinishMessage.getMessage());
closeStreams();
}
@Override
public void fileStarted(AuditEvent event) {
// No need to implement this method in this class
}
@Override
public void fileFinished(AuditEvent event) {
infoWriter.flush();
}
/**
* Flushes the output streams and closes them if needed.
*/
private void closeStreams() {
infoWriter.flush();
if (closeInfo) {
infoWriter.close();
}
errorWriter.flush();
if (closeError) {
errorWriter.close();
}
}
}