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.SuppressedViolation;
36  import org.apache.maven.plugins.pmd.model.Violation;
37  import org.apache.maven.plugins.pmd.model.io.xpp3.PmdXpp3Reader;
38  import org.apache.maven.reporting.MavenReportException;
39  
40  /**
41   * Provides access to the result of the pmd analysis.
42   */
43  public class PmdResult
44  {
45      private final List<ProcessingError> processingErrors = new ArrayList<>();
46      private final List<Violation> violations = new ArrayList<>();
47      private final List<SuppressedViolation> suppressedViolations = new ArrayList<>();
48  
49      public static final PmdResult EMPTY = new PmdResult();
50  
51      private PmdResult()
52      {
53      }
54  
55      public PmdResult( File pmdFile, String encoding ) throws MavenReportException
56      {
57          loadResult( pmdFile, encoding );
58      }
59  
60      public boolean hasViolations()
61      {
62          return !violations.isEmpty();
63      }
64  
65      private void loadResult( File pmdFile, String encoding ) throws MavenReportException
66      {
67          try ( Reader reader1 = new BomFilter( encoding, new InputStreamReader(
68                  new FileInputStream( pmdFile ), encoding ) ) )
69          {
70              PmdXpp3Reader reader = new PmdXpp3Reader();
71              PmdErrorDetail details = reader.read( reader1, false );
72              processingErrors.addAll( details.getErrors() );
73              suppressedViolations.addAll( details.getSuppressedViolations() );
74  
75              for ( PmdFile file : details.getFiles() )
76              {
77                  String filename = file.getName();
78                  for ( Violation violation : file.getViolations() )
79                  {
80                      violation.setFileName( filename );
81                      violations.add( violation );
82                  }
83              }
84          }
85          catch ( Exception e )
86          {
87              throw new MavenReportException( e.getMessage(), e );
88          }
89      }
90  
91      // Note: This seems to be a bug in PMD's XMLRenderer. The BOM is rendered multiple times.
92      // once at the beginning of the file, which is Ok, but also in the middle of the file.
93      // This filter just skips all BOMs if the encoding is not UTF-8
94      private static class BomFilter extends FilterReader
95      {
96          private static final char BOM = '\uFEFF';
97          private final boolean filter;
98  
99          BomFilter( String encoding, Reader in )
100         {
101             super( in );
102             filter = !"UTF-8".equalsIgnoreCase( encoding );
103         }
104 
105         @Override
106         public int read() throws IOException
107         {
108             int c = super.read();
109 
110             if ( !filter )
111             {
112                 return c;
113             }
114 
115             while ( c != -1 && c == BOM )
116             {
117                 c = super.read();
118             }
119             return c;
120         }
121 
122         @Override
123         public int read( char[] cbuf, int off, int len ) throws IOException
124         {
125             int count = super.read( cbuf, off, len );
126 
127             if ( !filter )
128             {
129                 return count;
130             }
131 
132             if ( count != -1 )
133             {
134                 for ( int i = off; i < off + count; i++ )
135                 {
136                     if ( cbuf[i] == BOM )
137                     {
138                         // shift the content one char to the left
139                         System.arraycopy( cbuf, i + 1, cbuf, i, off + count - 1 - i );
140                         count--;
141                     }
142                 }
143             }
144             return count;
145         }
146     }
147 
148     public Collection<Violation> getViolations()
149     {
150         return violations;
151     }
152 
153     public Collection<SuppressedViolation> getSuppressedViolations()
154     {
155         return suppressedViolations;
156     }
157 
158     public Collection<ProcessingError> getErrors()
159     {
160         return processingErrors;
161     }
162 }