View Javadoc
1   package org.apache.maven.plugins.pmd.exec;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.File;
23  import java.io.FileInputStream;
24  import java.io.FilterReader;
25  import java.io.IOException;
26  import java.io.InputStreamReader;
27  import java.io.Reader;
28  import java.util.ArrayList;
29  import java.util.Collection;
30  import java.util.List;
31  
32  import org.apache.maven.plugins.pmd.model.PmdErrorDetail;
33  import org.apache.maven.plugins.pmd.model.PmdFile;
34  import org.apache.maven.plugins.pmd.model.ProcessingError;
35  import org.apache.maven.plugins.pmd.model.Violation;
36  import org.apache.maven.plugins.pmd.model.io.xpp3.PmdXpp3Reader;
37  import org.apache.maven.reporting.MavenReportException;
38  
39  /**
40   * Provides access to the result of the pmd analysis.
41   */
42  public class PmdResult
43  {
44      private final List<ProcessingError> processingErrors = new ArrayList<>();
45      private final List<Violation> violations = new ArrayList<>();
46  
47      public static final PmdResult EMPTY = new PmdResult();
48  
49      private PmdResult()
50      {
51      }
52  
53      public PmdResult( File pmdFile, String encoding ) throws MavenReportException
54      {
55          loadResult( pmdFile, encoding );
56      }
57  
58      public boolean hasViolations()
59      {
60          return !violations.isEmpty();
61      }
62  
63      private void loadResult( File pmdFile, String encoding ) throws MavenReportException
64      {
65          try ( Reader reader1 = new BomFilter( encoding, new InputStreamReader(
66                  new FileInputStream( pmdFile ), encoding ) ) )
67          {
68              PmdXpp3Reader reader = new PmdXpp3Reader();
69              PmdErrorDetail details = reader.read( reader1, false );
70              processingErrors.addAll( details.getErrors() );
71  
72              for ( PmdFile file : details.getFiles() )
73              {
74                  String filename = file.getName();
75                  for ( Violation violation : file.getViolations() )
76                  {
77                      violation.setFileName( filename );
78                      violations.add( violation );
79                  }
80              }
81          }
82          catch ( Exception e )
83          {
84              throw new MavenReportException( e.getMessage(), e );
85          }
86      }
87  
88      // Note: This seems to be a bug in PMD's XMLRenderer. The BOM is rendered multiple times.
89      // once at the beginning of the file, which is Ok, but also in the middle of the file.
90      // This filter just skips all BOMs if the encoding is not UTF-8
91      private static class BomFilter extends FilterReader
92      {
93          private static final char BOM = '\uFEFF';
94          private final boolean filter;
95  
96          BomFilter( String encoding, Reader in )
97          {
98              super( in );
99              filter = !"UTF-8".equalsIgnoreCase( encoding );
100         }
101 
102         @Override
103         public int read() throws IOException
104         {
105             int c = super.read();
106 
107             if ( !filter )
108             {
109                 return c;
110             }
111 
112             while ( c != -1 && c == BOM )
113             {
114                 c = super.read();
115             }
116             return c;
117         }
118 
119         @Override
120         public int read( char[] cbuf, int off, int len ) throws IOException
121         {
122             int count = super.read( cbuf, off, len );
123 
124             if ( !filter )
125             {
126                 return count;
127             }
128 
129             if ( count != -1 )
130             {
131                 for ( int i = off; i < off + count; i++ )
132                 {
133                     if ( cbuf[i] == BOM )
134                     {
135                         // shift the content one char to the left
136                         System.arraycopy( cbuf, i + 1, cbuf, i, off + count - 1 - i );
137                         count--;
138                     }
139                 }
140             }
141             return count;
142         }
143     }
144 
145     public Collection<Violation> getViolations()
146     {
147         return violations;
148     }
149 
150     public Collection<ProcessingError> getErrors()
151     {
152         return processingErrors;
153     }
154 }