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 infoWriter; 048 /** close info stream after use */ 049 private final boolean closeInfo; 050 051 /** where to write error messages **/ 052 private final PrintWriter errorWriter; 053 /** close error stream after use */ 054 private final boolean closeError; 055 056 /** 057 * Creates a new <code>DefaultLogger</code> instance. 058 * @param os where to log infos and errors 059 * @param closeStreamsAfterUse if oS should be closed in auditFinished() 060 */ 061 public DefaultLogger(OutputStream os, boolean closeStreamsAfterUse) 062 { 063 // no need to close oS twice 064 this(os, closeStreamsAfterUse, os, false); 065 } 066 067 /** 068 * Creates a new <code>DefaultLogger</code> instance. 069 * 070 * @param infoStream the <code>OutputStream</code> for info messages 071 * @param closeInfoAfterUse auditFinished should close infoStream 072 * @param errorStream the <code>OutputStream</code> for error messages 073 * @param closeErrorAfterUse auditFinished should close errorStream 074 */ 075 public DefaultLogger(OutputStream infoStream, 076 boolean closeInfoAfterUse, 077 OutputStream errorStream, 078 boolean closeErrorAfterUse) 079 { 080 closeInfo = closeInfoAfterUse; 081 closeError = closeErrorAfterUse; 082 infoWriter = new PrintWriter(infoStream); 083 errorWriter = (infoStream == errorStream) 084 ? infoWriter 085 : new PrintWriter(errorStream); 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 evt {@inheritDoc} 092 * @see AuditListener 093 **/ 094 @Override 095 public void addError(AuditEvent evt) 096 { 097 final SeverityLevel severityLevel = evt.getSeverityLevel(); 098 if (!SeverityLevel.IGNORE.equals(severityLevel)) { 099 100 final String fileName = evt.getFileName(); 101 final String message = evt.getMessage(); 102 103 // avoid StringBuffer.expandCapacity 104 final int bufLen = fileName.length() + message.length() 105 + BUFFER_CUSHION; 106 final StringBuffer sb = new StringBuffer(bufLen); 107 108 sb.append(fileName); 109 sb.append(':').append(evt.getLine()); 110 if (evt.getColumn() > 0) { 111 sb.append(':').append(evt.getColumn()); 112 } 113 if (SeverityLevel.WARNING.equals(severityLevel)) { 114 sb.append(": warning"); 115 } 116 sb.append(": ").append(message); 117 errorWriter.println(sb.toString()); 118 } 119 } 120 121 /** {@inheritDoc} */ 122 @Override 123 public void addException(AuditEvent evt, Throwable throwable) 124 { 125 synchronized (errorWriter) { 126 errorWriter.println("Error auditing " + evt.getFileName()); 127 throwable.printStackTrace(errorWriter); 128 } 129 } 130 131 /** {@inheritDoc} */ 132 @Override 133 public void auditStarted(AuditEvent evt) 134 { 135 infoWriter.println("Starting audit..."); 136 } 137 138 /** {@inheritDoc} */ 139 @Override 140 public void fileFinished(AuditEvent evt) 141 { 142 } 143 144 /** {@inheritDoc} */ 145 @Override 146 public void fileStarted(AuditEvent evt) 147 { 148 } 149 150 /** {@inheritDoc} */ 151 @Override 152 public void auditFinished(AuditEvent evt) 153 { 154 infoWriter.println("Audit done."); 155 closeStreams(); 156 } 157 158 /** 159 * Flushes the output streams and closes them if needed. 160 */ 161 protected void closeStreams() 162 { 163 infoWriter.flush(); 164 if (closeInfo) { 165 infoWriter.close(); 166 } 167 168 errorWriter.flush(); 169 if (closeError) { 170 errorWriter.close(); 171 } 172 } 173}