001////////////////////////////////////////////////////////////////////////////////
002// checkstyle: Checks Java source code for adherence to a set of rules.
003// Copyright (C) 2001-2014  Oliver Burn
004//
005// This library is free software; you can redistribute it and/or
006// modify it under the terms of the GNU Lesser General Public
007// License as published by the Free Software Foundation; either
008// version 2.1 of the License, or (at your option) any later version.
009//
010// This library is distributed in the hope that it will be useful,
011// but WITHOUT ANY WARRANTY; without even the implied warranty of
012// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013// Lesser General Public License for more details.
014//
015// You should have received a copy of the GNU Lesser General Public
016// License along with this library; if not, write to the Free Software
017// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
018////////////////////////////////////////////////////////////////////////////////
019package com.puppycrawl.tools.checkstyle;
020
021import java.io.OutputStream;
022import java.io.PrintWriter;
023
024import com.puppycrawl.tools.checkstyle.api.AuditEvent;
025import com.puppycrawl.tools.checkstyle.api.AuditListener;
026import com.puppycrawl.tools.checkstyle.api.AutomaticBean;
027import com.puppycrawl.tools.checkstyle.api.SeverityLevel;
028
029/**
030 * Simple plain logger for text output.
031 * This is maybe not very suitable for a text output into a file since it
032 * does not need all 'audit finished' and so on stuff, but it looks good on
033 * stdout anyway. If there is really a problem this is what XMLLogger is for.
034 * It gives structure.
035 *
036 * @author <a href="mailto:stephane.bailliez@wanadoo.fr">Stephane Bailliez</a>
037 * @see XMLLogger
038 */
039public class DefaultLogger
040    extends AutomaticBean
041    implements AuditListener
042{
043    /** cushion for avoiding StringBuffer.expandCapacity */
044    private static final int BUFFER_CUSHION = 12;
045
046    /** where to write info messages **/
047    private final PrintWriter mInfoWriter;
048    /** close info stream after use */
049    private final boolean mCloseInfo;
050
051    /** where to write error messages **/
052    private final PrintWriter mErrorWriter;
053    /** close error stream after use */
054    private final boolean mCloseError;
055
056    /**
057     * Creates a new <code>DefaultLogger</code> instance.
058     * @param aOS where to log infos and errors
059     * @param aCloseStreamsAfterUse if aOS should be closed in auditFinished()
060     */
061    public DefaultLogger(OutputStream aOS, boolean aCloseStreamsAfterUse)
062    {
063        // no need to close aOS twice
064        this(aOS, aCloseStreamsAfterUse, aOS, false);
065    }
066
067    /**
068     * Creates a new <code>DefaultLogger</code> instance.
069     *
070     * @param aInfoStream the <code>OutputStream</code> for info messages
071     * @param aCloseInfoAfterUse auditFinished should close aInfoStream
072     * @param aErrorStream the <code>OutputStream</code> for error messages
073     * @param aCloseErrorAfterUse auditFinished should close aErrorStream
074     */
075    public DefaultLogger(OutputStream aInfoStream,
076                         boolean aCloseInfoAfterUse,
077                         OutputStream aErrorStream,
078                         boolean aCloseErrorAfterUse)
079    {
080        mCloseInfo = aCloseInfoAfterUse;
081        mCloseError = aCloseErrorAfterUse;
082        mInfoWriter = new PrintWriter(aInfoStream);
083        mErrorWriter = (aInfoStream == aErrorStream)
084            ? mInfoWriter
085            : new PrintWriter(aErrorStream);
086    }
087
088    /**
089     * Print an Emacs compliant line on the error stream.
090     * If the column number is non zero, then also display it.
091     * @param aEvt {@inheritDoc}
092     * @see AuditListener
093     **/
094    public void addError(AuditEvent aEvt)
095    {
096        final SeverityLevel severityLevel = aEvt.getSeverityLevel();
097        if (!SeverityLevel.IGNORE.equals(severityLevel)) {
098
099            final String fileName = aEvt.getFileName();
100            final String message = aEvt.getMessage();
101
102            // avoid StringBuffer.expandCapacity
103            final int bufLen = fileName.length() + message.length()
104                + BUFFER_CUSHION;
105            final StringBuffer sb = new StringBuffer(bufLen);
106
107            sb.append(fileName);
108            sb.append(':').append(aEvt.getLine());
109            if (aEvt.getColumn() > 0) {
110                sb.append(':').append(aEvt.getColumn());
111            }
112            if (SeverityLevel.WARNING.equals(severityLevel)) {
113                sb.append(": warning");
114            }
115            sb.append(": ").append(message);
116            mErrorWriter.println(sb.toString());
117        }
118    }
119
120    /** {@inheritDoc} */
121    public void addException(AuditEvent aEvt, Throwable aThrowable)
122    {
123        synchronized (mErrorWriter) {
124            mErrorWriter.println("Error auditing " + aEvt.getFileName());
125            aThrowable.printStackTrace(mErrorWriter);
126        }
127    }
128
129    /** {@inheritDoc} */
130    public void auditStarted(AuditEvent aEvt)
131    {
132        mInfoWriter.println("Starting audit...");
133    }
134
135    /** {@inheritDoc} */
136    public void fileFinished(AuditEvent aEvt)
137    {
138    }
139
140    /** {@inheritDoc} */
141    public void fileStarted(AuditEvent aEvt)
142    {
143    }
144
145    /** {@inheritDoc} */
146    public void auditFinished(AuditEvent aEvt)
147    {
148        mInfoWriter.println("Audit done.");
149        closeStreams();
150    }
151
152    /**
153     * Flushes the output streams and closes them if needed.
154     */
155    protected void closeStreams()
156    {
157        mInfoWriter.flush();
158        if (mCloseInfo) {
159            mInfoWriter.close();
160        }
161
162        mErrorWriter.flush();
163        if (mCloseError) {
164            mErrorWriter.close();
165        }
166    }
167}