Source code: com/puppycrawl/tools/checkstyle/checks/HeaderCheck.java
1 ////////////////////////////////////////////////////////////////////////////////
2 // checkstyle: Checks Java source code for adherence to a set of rules.
3 // Copyright (C) 2001-2003 Oliver Burn
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 ////////////////////////////////////////////////////////////////////////////////
19
20 package com.puppycrawl.tools.checkstyle.checks;
21
22 import java.io.FileReader;
23 import java.io.IOException;
24 import java.io.LineNumberReader;
25 import java.util.ArrayList;
26 import java.util.Arrays;
27
28 import com.puppycrawl.tools.checkstyle.api.Check;
29 import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
30 import com.puppycrawl.tools.checkstyle.api.DetailAST;
31
32 import org.apache.commons.beanutils.ConversionException;
33
34 /**
35 * <p>
36 * Checks the header of the source against a fixed header file.
37 * </p>
38 * <p>
39 * Rationale: In most projects each file must have a fixed header,
40 * since usually the header contains copyright information.
41 * </p>
42 * <p> The header contents are specified in the file identified by property
43 * headerFile.
44 * </p>
45 * <p>Property ignoreLines specifies the line numbers to ignore when
46 * matching lines in a header file.
47 * The property type is a comma-separated list of integers and defaults to an
48 * empty list.
49 * </p>
50 *
51 * <p>This property is very useful for supporting headers that contain copyright
52 * dates. For example, consider the following header:</p>
53 *
54 * <pre>
55 * line 1: ////////////////////////////////////////////////////////////////////
56 * line 2: // checkstyle:
57 * line 3: // Checks Java source code for adherence to a set of rules.
58 * line 4: // Copyright (C) 2001 Oliver Burn
59 * line 5: ////////////////////////////////////////////////////////////////////
60 * </pre>
61 *
62 * <p>Since the year information will change over time, you can tell checkstyle
63 * to ignore line 4 by setting property ignoreLines to <strong>4</strong>.</p>
64 * <p>
65 * An example of how to configure the check to use header file
66 * "java.header" and ignore lines 2, 3, and 4 is:
67 * </p>
68 * <pre>
69 * <module name="Header">
70 * <property name="headerFile" value="java.header"/>
71 * <property name="ignoreLines" value="2, 3, 4"/>
72 * </module>
73 * </pre>
74 * @author Lars Kühne
75 */
76 public class HeaderCheck
77 extends Check
78 {
79 /** empty array to avoid instantiations */
80 private static final int[] EMPTY_INT_ARRAY = new int[0];
81
82 /** the lines of the header file */
83 private String[] mHeaderLines;
84
85 /** the header lines to ignore in the check, sorted */
86 private int[] mIgnoreLines = EMPTY_INT_ARRAY;
87
88 /** @see com.puppycrawl.tools.checkstyle.api.Check */
89 public int[] getDefaultTokens()
90 {
91 return new int[0];
92 }
93
94 /**
95 * Checks that required args were specified.
96 * @see com.puppycrawl.tools.checkstyle.api.AutomaticBean#finishLocalSetup
97 */
98 protected final void finishLocalSetup() throws CheckstyleException
99 {
100 if (mHeaderLines == null) {
101 throw new CheckstyleException(
102 "property 'headerFile' is missing or invalid in module "
103 + getConfiguration().getName());
104 }
105 }
106
107 /** @see com.puppycrawl.tools.checkstyle.api.Check */
108 public void beginTree(DetailAST aRootAST)
109 {
110
111 final String[] lines = getLines();
112
113 if (mHeaderLines.length > lines.length) {
114 log(1, "header.missing");
115 }
116 else {
117 for (int i = 0; i < mHeaderLines.length; i++) {
118 // skip lines we are meant to ignore
119 if (isIgnoreLine(i + 1)) {
120 continue;
121 }
122
123 if (!isMatch(i)) {
124 log(i + 1, "header.mismatch", mHeaderLines[i]);
125 break; // stop checking
126 }
127 }
128 }
129 }
130
131 /**
132 * @param aLineNo a line number
133 * @return if <code>aLineNo</code> is one of the ignored header lines.
134 */
135 private boolean isIgnoreLine(int aLineNo)
136 {
137 return (Arrays.binarySearch(mIgnoreLines, aLineNo) >= 0);
138 }
139
140 /**
141 * Checks if a code line matches the required header line.
142 * @param aLineNumber the linenumber to check against the header
143 * @return true if and only if the line matches the required header line
144 */
145 protected boolean isMatch(int aLineNumber)
146 {
147 final String[] lines = getLines();
148 return mHeaderLines[aLineNumber].equals(lines[aLineNumber]);
149 }
150
151 /**
152 * Set the header file to check against.
153 * @param aFileName the file that contains the header to check against.
154 * @throws ConversionException if the file cannot be loaded
155 */
156 public void setHeaderFile(String aFileName)
157 throws ConversionException
158 {
159 // Handle empty param
160 if ((aFileName == null) || (aFileName.trim().length() == 0)) {
161 return;
162 }
163
164 // load the file
165 try {
166 final LineNumberReader lnr =
167 new LineNumberReader(new FileReader(aFileName));
168 final ArrayList lines = new ArrayList();
169 while (true) {
170 final String l = lnr.readLine();
171 if (l == null) {
172 break;
173 }
174 lines.add(l);
175 }
176 mHeaderLines = (String[]) lines.toArray(new String[0]);
177 }
178 catch (IOException ex) {
179 throw new ConversionException(
180 "unable to load header file " + aFileName, ex);
181 }
182
183 }
184
185 /**
186 * Set the lines numbers to ignore in the header check.
187 * @param aList comma separated list of line numbers to ignore in header.
188 */
189 public void setIgnoreLines(int[] aList)
190 {
191 if (aList == null || aList.length == 0) {
192 mIgnoreLines = EMPTY_INT_ARRAY;
193 return;
194 }
195
196 mIgnoreLines = new int[aList.length];
197 System.arraycopy(aList, 0, mIgnoreLines, 0, aList.length);
198 Arrays.sort(mIgnoreLines);
199 }
200
201 /**
202 * Return the header lines to check against.
203 * @return the header lines to check against.
204 */
205 protected String[] getHeaderLines()
206 {
207 return mHeaderLines;
208 }
209 }