View Javadoc
1   ////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code for adherence to a set of rules.
3   // Copyright (C) 2001-2015 the original author or authors.
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  package com.puppycrawl.tools.checkstyle.checks.header;
20  
21  import java.io.BufferedInputStream;
22  import java.io.File;
23  import java.io.FileNotFoundException;
24  import java.io.IOException;
25  import java.io.InputStreamReader;
26  import java.io.LineNumberReader;
27  import java.io.Reader;
28  import java.io.StringReader;
29  import java.io.UnsupportedEncodingException;
30  import java.net.MalformedURLException;
31  import java.net.URI;
32  import java.net.URISyntaxException;
33  import java.net.URL;
34  import java.nio.charset.Charset;
35  import java.util.List;
36  
37  import org.apache.commons.beanutils.ConversionException;
38  
39  import com.google.common.collect.ImmutableList;
40  import com.google.common.collect.Lists;
41  import com.puppycrawl.tools.checkstyle.api.AbstractFileSetCheck;
42  import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
43  import com.puppycrawl.tools.checkstyle.api.Utils;
44  
45  /**
46   * Abstract super class for header checks.
47   * Provides support for header and headerFile properties.
48   * @author o_sukhosolsky
49   */
50  public abstract class AbstractHeaderCheck extends AbstractFileSetCheck
51  {
52      /** The file that contains the header to check against. */
53      private String filename;
54  
55      /** Name of a charset to use for loading the header from a file. */
56      private String charset = System.getProperty("file.encoding", "UTF-8");
57  
58      /** the lines of the header file. */
59      private final List<String> readerLines = Lists.newArrayList();
60  
61  
62      /**
63       * Return the header lines to check against.
64       * @return the header lines to check against.
65       */
66      protected ImmutableList<String> getHeaderLines()
67      {
68          return ImmutableList.copyOf(readerLines);
69      }
70  
71      /**
72       * Set the charset to use for loading the header from a file.
73       * @param charset the charset to use for loading the header from a file
74       * @throws UnsupportedEncodingException if charset is unsupported
75       */
76      public void setCharset(String charset) throws UnsupportedEncodingException
77      {
78          if (!Charset.isSupported(charset)) {
79              final String message = "unsupported charset: '" + charset + "'";
80              throw new UnsupportedEncodingException(message);
81          }
82          this.charset = charset;
83      }
84  
85      /**
86       * Set the header file to check against.
87       * @param fileName the file that contains the header to check against.
88       */
89      public void setHeaderFile(String fileName)
90      {
91          // Handle empty param
92          if (fileName == null || fileName.trim().length() == 0) {
93              return;
94          }
95  
96          filename = fileName;
97      }
98  
99      /**
100      * Load the header from a file.
101      * @throws CheckstyleException if the file cannot be loaded
102      */
103     private void loadHeaderFile() throws CheckstyleException
104     {
105         checkHeaderNotInitialized();
106         Reader headerReader = null;
107         try {
108             final URI uri = resolveHeaderFile();
109             headerReader = new InputStreamReader(new BufferedInputStream(
110                     uri.toURL().openStream()), charset);
111             loadHeader(headerReader);
112         }
113         catch (final IOException ex) {
114             throw new CheckstyleException(
115                     "unable to load header file " + filename, ex);
116         }
117         finally {
118             Utils.closeQuietly(headerReader);
119         }
120     }
121 
122     /**
123      * Resolve the specified filename param to a URI.
124      * @return resolved header file URI
125      * @throws IOException on failure
126      */
127     private URI resolveHeaderFile() throws IOException
128     {
129         // figure out if this is a File or a URL
130         URI uri;
131         try {
132             final URL url = new URL(filename);
133             uri = url.toURI();
134         }
135         catch (final MalformedURLException ex) {
136             uri = null;
137         }
138         catch (final URISyntaxException ex) {
139             // URL violating RFC 2396
140             uri = null;
141         }
142         if (uri == null) {
143             final File file = new File(filename);
144             if (file.exists()) {
145                 uri = file.toURI();
146             }
147             else {
148                 // check to see if the file is in the classpath
149                 try {
150                     final URL configUrl = AbstractHeaderCheck.class
151                             .getResource(filename);
152                     if (configUrl == null) {
153                         throw new FileNotFoundException(filename);
154                     }
155                     uri = configUrl.toURI();
156                 }
157                 catch (final URISyntaxException e) {
158                     throw new FileNotFoundException(filename);
159                 }
160             }
161         }
162         return uri;
163     }
164 
165     /**
166      * Called before initializing the header.
167      * @throws ConversionException if header has already been set
168      */
169     private void checkHeaderNotInitialized()
170     {
171         if (!readerLines.isEmpty()) {
172             throw new ConversionException(
173                     "header has already been set - "
174                     + "set either header or headerFile, not both");
175         }
176     }
177 
178     /**
179      * Set the header to check against. Individual lines in the header
180      * must be separated by '\n' characters.
181      * @param header header content to check against.
182      * @throws ConversionException if the header cannot be interpreted
183      */
184     public void setHeader(String header)
185     {
186         if (header == null || header.trim().length() == 0) {
187             return;
188         }
189 
190         checkHeaderNotInitialized();
191 
192         final String headerExpandedNewLines = header.replaceAll("\\\\n", "\n");
193 
194         final Reader headerReader = new StringReader(headerExpandedNewLines);
195         try {
196             loadHeader(headerReader);
197         }
198         catch (final IOException ex) {
199             throw new ConversionException("unable to load header", ex);
200         }
201         finally {
202             Utils.closeQuietly(headerReader);
203         }
204     }
205 
206     /**
207      * Load header to check against from a Reader into readerLines.
208      * @param headerReader delivers the header to check against
209      * @throws IOException if
210      */
211     private void loadHeader(final Reader headerReader) throws IOException
212     {
213         final LineNumberReader lnr = new LineNumberReader(headerReader);
214         readerLines.clear();
215         while (true) {
216             final String l = lnr.readLine();
217             if (l == null) {
218                 break;
219             }
220             readerLines.add(l);
221         }
222         postprocessHeaderLines();
223     }
224 
225     /**
226      * Hook method for post processing header lines.
227      * This implementation does nothing.
228      */
229     protected void postprocessHeaderLines()
230     {
231     }
232 
233     @Override
234     protected final void finishLocalSetup() throws CheckstyleException
235     {
236         if (filename != null) {
237             loadHeaderFile();
238         }
239         if (readerLines.isEmpty()) {
240             throw new CheckstyleException(
241                     "property 'headerFile' is missing or invalid in module "
242                     + getConfiguration().getName());
243         }
244     }
245 }