1 package org.codehaus.mojo.clirr;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 import net.sf.clirr.core.ApiDifference;
20 import net.sf.clirr.core.Checker;
21 import net.sf.clirr.core.ClassFilter;
22 import net.sf.clirr.core.PlainDiffListener;
23 import net.sf.clirr.core.Severity;
24 import net.sf.clirr.core.XmlDiffListener;
25 import net.sf.clirr.core.internal.bcel.BcelTypeArrayBuilder;
26 import net.sf.clirr.core.spi.JavaType;
27 import org.apache.maven.artifact.Artifact;
28 import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
29 import org.apache.maven.artifact.resolver.ArtifactResolutionException;
30 import org.apache.maven.plugin.MojoExecutionException;
31 import org.apache.maven.plugin.MojoFailureException;
32 import org.apache.maven.project.ProjectBuildingException;
33 import org.apache.maven.project.artifact.InvalidDependencyVersionException;
34 import org.codehaus.plexus.i18n.I18N;
35
36 import java.io.File;
37 import java.io.IOException;
38 import java.net.MalformedURLException;
39 import java.util.ArrayList;
40 import java.util.Iterator;
41 import java.util.List;
42 import java.util.Locale;
43 import java.util.Set;
44
45
46
47
48
49
50
51
52
53
54 public class ClirrArbitraryCheckMojo
55 extends AbstractClirrMojo
56 {
57
58
59
60
61
62 private boolean failOnError;
63
64
65
66
67
68
69 private boolean failOnWarning;
70
71
72
73
74 private I18N i18n;
75
76
77
78
79
80
81
82 protected ArtifactSpecification[] oldComparisonArtifacts;
83
84
85
86
87
88
89
90 protected ArtifactSpecification[] newComparisonArtifacts;
91
92 protected void doExecute()
93 throws MojoExecutionException, MojoFailureException
94 {
95 if ( oldComparisonArtifacts == null || oldComparisonArtifacts.length == 0 )
96 {
97 getLog().info( "Missing required oldComparisonArtifacts" );
98 }
99
100 if ( newComparisonArtifacts == null || newComparisonArtifacts.length == 0 )
101 {
102 getLog().info( "Missing required newComparisonArtifacts" );
103 }
104
105 ClirrDiffListener listener;
106 try
107 {
108 listener = executeClirr( Severity.INFO );
109 }
110 catch ( MissingPreviousException e )
111 {
112 getLog().debug( e );
113 getLog().info( "No previous version was found. Use 'comparisonArtifacts'"
114 + " for explicit configuration if you think this is wrong." );
115 return;
116 }
117
118 Locale locale = Locale.getDefault();
119
120 int errorCount = listener.getSeverityCount( Severity.ERROR );
121 if ( failOnError && errorCount > 0 )
122 {
123 log( listener, Severity.ERROR );
124 String message;
125 if ( errorCount > 1 )
126 {
127 String[] args = new String[]{ String.valueOf( errorCount ) };
128 message = i18n.format( "clirr-report", locale, "check.clirr.failure.errors", args );
129 }
130 else
131 {
132 message = i18n.getString( "clirr-report", locale, "check.clirr.failure.error" );
133 }
134 throw new MojoFailureException( message );
135 }
136
137 int warningCount = listener.getSeverityCount( Severity.WARNING );
138 if ( failOnWarning && errorCount > 0 )
139 {
140 log( listener, Severity.WARNING );
141 String message;
142 if ( errorCount > 1 )
143 {
144 String[] args = new String[]{ String.valueOf( errorCount ) };
145 message = i18n.format( "clirr-report", locale, "check.clirr.failure.warnings", args );
146 }
147 else
148 {
149 message = i18n.getString( "clirr-report", locale, "check.clirr.failure.warning" );
150 }
151 throw new MojoFailureException( message );
152 }
153
154 int infoCount = listener.getSeverityCount( Severity.INFO );
155 String[] args =
156 new String[]{ String.valueOf( errorCount ), String.valueOf( warningCount ), String.valueOf( infoCount ) };
157 getLog().info( i18n.format( "clirr-report", locale, "check.clirr.success", args ) );
158 }
159
160 private void log( ClirrDiffListener listener, Severity severity )
161 {
162 if ( !logResults )
163 {
164 LogDiffListener l = new LogDiffListener( getLog() );
165 for ( Iterator i = listener.getApiDifferences().iterator(); i.hasNext(); )
166 {
167 ApiDifference difference = (ApiDifference) i.next();
168 if ( difference.getMaximumSeverity().equals( severity ) )
169 {
170 l.reportDiff( difference );
171 }
172 }
173 }
174 }
175
176 protected JavaType[] resolveClasses( ArtifactSpecification[] artifacts, ClassFilter classFilter )
177 throws MojoFailureException, MojoExecutionException
178 {
179 final Set artifactSet;
180
181 artifactSet = resolveArtifacts( artifacts );
182 Artifact a = null;
183 for ( Iterator iter = artifactSet.iterator(); iter.hasNext(); )
184 {
185 Artifact artifact = (Artifact) iter.next();
186 if ( a == null )
187 {
188 a = artifact;
189 }
190 getLog().debug(
191 "Comparing to " + artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" + artifact.getVersion()
192 + ":" + artifact.getClassifier() + ":" + artifact.getType() );
193 }
194
195 try
196 {
197 for ( Iterator iter = artifactSet.iterator(); iter.hasNext(); )
198 {
199 Artifact artifact = (Artifact) iter.next();
200 resolver.resolve( artifact, project.getRemoteArtifactRepositories(), localRepository );
201 }
202
203 final List dependencies = getTransitiveDependencies( artifactSet );
204
205 ClassLoader origDepCL = createClassLoader( dependencies, artifactSet );
206 final File[] files = new File[artifactSet.size()];
207 int i = 0;
208 for ( Iterator iter = artifactSet.iterator(); iter.hasNext(); )
209 {
210 Artifact artifact = (Artifact) iter.next();
211 files[i++] = new File( localRepository.getBasedir(), localRepository.pathOf( artifact ) );
212 }
213 return BcelTypeArrayBuilder.createClassSet( files, origDepCL, classFilter );
214 }
215 catch ( ProjectBuildingException e )
216 {
217 throw new MojoExecutionException( "Failed to build project for previous artifact: " + e.getMessage(), e );
218 }
219 catch ( InvalidDependencyVersionException e )
220 {
221 throw new MojoExecutionException( e.getMessage(), e );
222 }
223 catch ( ArtifactResolutionException e )
224 {
225 throw new MissingPreviousException( "Error resolving previous version: " + e.getMessage(), e );
226 }
227 catch ( ArtifactNotFoundException e )
228 {
229 throw new MojoExecutionException( "Error finding previous version: " + e.getMessage(), e );
230 }
231 catch ( MalformedURLException e )
232 {
233 throw new MojoExecutionException( "Error creating classloader for previous version's classes", e );
234 }
235 }
236
237 protected ClirrDiffListener executeClirr( Severity minSeverity )
238 throws MojoExecutionException, MojoFailureException
239 {
240 ClirrDiffListener listener = new ClirrDiffListener();
241
242 ClassFilter classFilter = new ClirrClassFilter( includes, excludes );
243
244 JavaType[] origClasses = resolveClasses( oldComparisonArtifacts, classFilter );
245
246 JavaType[] currentClasses = resolveClasses( newComparisonArtifacts, classFilter );
247
248
249 Checker checker = new Checker();
250
251 List listeners = new ArrayList();
252
253 listeners.add( listener );
254
255 if ( xmlOutputFile != null )
256 {
257 try
258 {
259 listeners.add( new XmlDiffListener( xmlOutputFile.getAbsolutePath() ) );
260 }
261 catch ( IOException e )
262 {
263 throw new MojoExecutionException( "Error adding '" + xmlOutputFile + "' for output: " + e.getMessage(),
264 e );
265 }
266 }
267
268 if ( textOutputFile != null )
269 {
270 try
271 {
272 listeners.add( new PlainDiffListener( textOutputFile.getAbsolutePath() ) );
273 }
274 catch ( IOException e )
275 {
276 throw new MojoExecutionException( "Error adding '" + textOutputFile + "' for output: " + e.getMessage(),
277 e );
278 }
279 }
280
281 if ( logResults )
282 {
283 listeners.add( new LogDiffListener( getLog() ) );
284 }
285
286 checker.addDiffListener( new DelegatingListener( listeners, minSeverity, getAllIgnored() ) );
287
288 checker.reportDiffs( origClasses, currentClasses );
289
290 return listener;
291 }
292
293 }