View Javadoc

1   package org.apache.maven.exception;
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.net.UnknownHostException;
23  import java.util.ArrayList;
24  import java.util.List;
25  
26  import org.apache.maven.lifecycle.LifecycleExecutionException;
27  import org.apache.maven.model.building.ModelProblem;
28  import org.apache.maven.model.building.ModelProblemUtils;
29  import org.apache.maven.plugin.AbstractMojoExecutionException;
30  import org.apache.maven.plugin.MojoExecutionException;
31  import org.apache.maven.plugin.MojoFailureException;
32  import org.apache.maven.plugin.PluginExecutionException;
33  import org.apache.maven.project.ProjectBuildingException;
34  import org.apache.maven.project.ProjectBuildingResult;
35  import org.codehaus.plexus.component.annotations.Component;
36  import org.codehaus.plexus.util.StringUtils;
37  
38  /*
39  
40  - test projects for each of these
41  - how to categorize the problems so that the id of the problem can be match to a page with descriptive help and the test
42    project
43  - nice little sample projects that could be run in the core as well as integration tests
44  
45  All Possible Errors
46  - invalid lifecycle phase (maybe same as bad CLI param, though you were talking about embedder too)
47  - <module> specified is not found
48  - malformed settings
49  - malformed POM
50  - local repository not writable
51  - remote repositories not available
52  - artifact metadata missing
53  - extension metadata missing
54  - extension artifact missing
55  - artifact metadata retrieval problem
56  - version range violation
57  - circular dependency
58  - artifact missing
59  - artifact retrieval exception
60  - md5 checksum doesn't match for local artifact, need to redownload this
61  - POM doesn't exist for a goal that requires one
62  - parent POM missing (in both the repository + relative path)
63  - component not found
64  
65  Plugins:
66  - plugin metadata missing
67  - plugin metadata retrieval problem
68  - plugin artifact missing
69  - plugin artifact retrieval problem
70  - plugin dependency metadata missing
71  - plugin dependency metadata retrieval problem
72  - plugin configuration problem
73  - plugin execution failure due to something that is know to possibly go wrong (like compilation failure)
74  - plugin execution error due to something that is not expected to go wrong (the compiler executable missing)
75  - asking to use a plugin for which you do not have a version defined - tools to easily select versions
76  - goal not found in a plugin (probably could list the ones that are)
77  
78   */
79  
80  //PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException, CycleDetectedInPluginGraphException;
81  
82  @Component( role = ExceptionHandler.class )
83  public class DefaultExceptionHandler
84      implements ExceptionHandler
85  {
86  
87      public ExceptionSummary handleException( Throwable exception )
88      {
89          return handle( "", exception );
90      }
91  
92      private ExceptionSummary handle( String message, Throwable exception )
93      {
94          String reference = getReference( exception );
95  
96          List<ExceptionSummary> children = null;
97  
98          if ( exception instanceof ProjectBuildingException )
99          {
100             List<ProjectBuildingResult> results = ( (ProjectBuildingException) exception ).getResults();
101 
102             children = new ArrayList<ExceptionSummary>();
103 
104             for ( ProjectBuildingResult result : results )
105             {
106                 ExceptionSummary child = handle( result );
107                 if ( child != null )
108                 {
109                     children.add( child );
110                 }
111             }
112 
113             message = "The build could not read " + children.size() + " project" + ( children.size() == 1 ? "" : "s" );
114         }
115         else
116         {
117             message = getMessage( message, exception );
118         }
119 
120         return new ExceptionSummary( exception, message, reference, children );
121     }
122 
123     private ExceptionSummary handle( ProjectBuildingResult result )
124     {
125         List<ExceptionSummary> children = new ArrayList<ExceptionSummary>();
126 
127         for ( ModelProblem problem : result.getProblems() )
128         {
129             ExceptionSummary child = handle( problem, result.getProjectId() );
130             if ( child != null )
131             {
132                 children.add( child );
133             }
134         }
135 
136         if ( children.isEmpty() )
137         {
138             return null;
139         }
140 
141         String message =
142             "\nThe project " + result.getProjectId() + " (" + result.getPomFile() + ") has "
143                 + children.size() + " error" + ( children.size() == 1 ? "" : "s" );
144 
145         return new ExceptionSummary( null, message, null, children );
146     }
147 
148     private ExceptionSummary handle( ModelProblem problem, String projectId )
149     {
150         if ( ModelProblem.Severity.ERROR.compareTo( problem.getSeverity() ) >= 0 )
151         {
152             String message = problem.getMessage();
153 
154             String location = ModelProblemUtils.formatLocation( problem, projectId );
155 
156             if ( StringUtils.isNotEmpty( location ) )
157             {
158                 message += " @ " + location;
159             }
160 
161             return handle( message, problem.getException() );
162         }
163         else
164         {
165             return null;
166         }
167     }
168 
169     private String getReference( Throwable exception )
170     {
171         String reference = "";
172 
173         if ( exception != null )
174         {
175             if ( exception instanceof MojoExecutionException )
176             {
177                 reference = MojoExecutionException.class.getSimpleName();
178             }
179             else if ( exception instanceof MojoFailureException )
180             {
181                 reference = MojoFailureException.class.getSimpleName();
182             }
183             else if ( exception instanceof LinkageError )
184             {
185                 reference = LinkageError.class.getSimpleName();
186             }
187             else if ( exception instanceof PluginExecutionException )
188             {
189                 reference = getReference( exception.getCause() );
190 
191                 if ( StringUtils.isEmpty( reference ) )
192                 {
193                     reference = exception.getClass().getSimpleName();
194                 }
195             }
196             else if ( exception instanceof LifecycleExecutionException )
197             {
198                 reference = getReference( exception.getCause() );
199             }
200             else if ( isNoteworthyException( exception ) )
201             {
202                 reference = exception.getClass().getSimpleName();
203             }
204         }
205 
206         if ( StringUtils.isNotEmpty( reference ) && !reference.startsWith( "http:" ) )
207         {
208             reference = "http://cwiki.apache.org/confluence/display/MAVEN/" + reference;
209         }
210 
211         return reference;
212     }
213 
214     private boolean isNoteworthyException( Throwable exception )
215     {
216         if ( exception == null )
217         {
218             return false;
219         }
220         else if ( exception instanceof Error )
221         {
222             return true;
223         }
224         else if ( exception instanceof RuntimeException )
225         {
226             return false;
227         }
228         else if ( exception.getClass().getName().startsWith( "java" ) )
229         {
230             return false;
231         }
232         return true;
233     }
234 
235     private String getMessage( String message, Throwable exception )
236     {
237         String fullMessage = ( message != null ) ? message : "";
238 
239         for ( Throwable t = exception; t != null; t = t.getCause() )
240         {
241             String exceptionMessage = t.getMessage();
242 
243             if ( t instanceof AbstractMojoExecutionException )
244             {
245                 String longMessage = ( (AbstractMojoExecutionException) t ).getLongMessage();
246                 if ( StringUtils.isNotEmpty( longMessage ) )
247                 {
248                     if ( StringUtils.isEmpty( exceptionMessage ) || longMessage.contains( exceptionMessage ) )
249                     {
250                         exceptionMessage = longMessage;
251                     }
252                     else if ( !exceptionMessage.contains( longMessage ) )
253                     {
254                         exceptionMessage = join( exceptionMessage, '\n' + longMessage );
255                     }
256                 }
257             }
258 
259             if ( StringUtils.isEmpty( exceptionMessage ) )
260             {
261                 exceptionMessage = t.getClass().getSimpleName();
262             }
263 
264             if ( t instanceof UnknownHostException && !fullMessage.contains( "host" ) )
265             {
266                 fullMessage = join( fullMessage, "Unknown host " + exceptionMessage );
267             }
268             else if ( !fullMessage.contains( exceptionMessage ) )
269             {
270                 fullMessage = join( fullMessage, exceptionMessage );
271             }
272         }
273 
274         return fullMessage.trim();
275     }
276 
277     private String join( String message1, String message2 )
278     {
279         String message = "";
280 
281         if ( StringUtils.isNotEmpty( message1 ) )
282         {
283             message = message1.trim();
284         }
285 
286         if ( StringUtils.isNotEmpty( message2 ) )
287         {
288             if ( StringUtils.isNotEmpty( message ) )
289             {
290                 if ( message.endsWith( "." ) || message.endsWith( "!" ) || message.endsWith( ":" ) )
291                 {
292                     message += " ";
293                 }
294                 else
295                 {
296                     message += ": ";
297                 }
298             }
299 
300             message += message2;
301         }
302 
303         return message;
304     }
305 
306 }