001 package org.apache.maven.exception; 002 003 /* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022 import java.net.UnknownHostException; 023 import java.util.ArrayList; 024 import java.util.List; 025 026 import org.apache.maven.lifecycle.LifecycleExecutionException; 027 import org.apache.maven.model.building.ModelProblem; 028 import org.apache.maven.model.building.ModelProblemUtils; 029 import org.apache.maven.plugin.AbstractMojoExecutionException; 030 import org.apache.maven.plugin.MojoExecutionException; 031 import org.apache.maven.plugin.MojoFailureException; 032 import org.apache.maven.plugin.PluginExecutionException; 033 import org.apache.maven.project.ProjectBuildingException; 034 import org.apache.maven.project.ProjectBuildingResult; 035 import org.codehaus.plexus.component.annotations.Component; 036 import org.codehaus.plexus.util.StringUtils; 037 038 /* 039 040 - test projects for each of these 041 - how to categorize the problems so that the id of the problem can be match to a page with descriptive help and the test 042 project 043 - nice little sample projects that could be run in the core as well as integration tests 044 045 All Possible Errors 046 - invalid lifecycle phase (maybe same as bad CLI param, though you were talking about embedder too) 047 - <module> specified is not found 048 - malformed settings 049 - malformed POM 050 - local repository not writable 051 - remote repositories not available 052 - artifact metadata missing 053 - extension metadata missing 054 - extension artifact missing 055 - artifact metadata retrieval problem 056 - version range violation 057 - circular dependency 058 - artifact missing 059 - artifact retrieval exception 060 - md5 checksum doesn't match for local artifact, need to redownload this 061 - POM doesn't exist for a goal that requires one 062 - parent POM missing (in both the repository + relative path) 063 - component not found 064 065 Plugins: 066 - plugin metadata missing 067 - plugin metadata retrieval problem 068 - plugin artifact missing 069 - plugin artifact retrieval problem 070 - plugin dependency metadata missing 071 - plugin dependency metadata retrieval problem 072 - plugin configuration problem 073 - plugin execution failure due to something that is know to possibly go wrong (like compilation failure) 074 - plugin execution error due to something that is not expected to go wrong (the compiler executable missing) 075 - asking to use a plugin for which you do not have a version defined - tools to easily select versions 076 - goal not found in a plugin (probably could list the ones that are) 077 078 */ 079 080 //PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException, CycleDetectedInPluginGraphException; 081 082 @Component( role = ExceptionHandler.class ) 083 public class DefaultExceptionHandler 084 implements ExceptionHandler 085 { 086 087 public ExceptionSummary handleException( Throwable exception ) 088 { 089 return handle( "", exception ); 090 } 091 092 private ExceptionSummary handle( String message, Throwable exception ) 093 { 094 String reference = getReference( exception ); 095 096 List<ExceptionSummary> children = null; 097 098 if ( exception instanceof ProjectBuildingException ) 099 { 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 }