Author: bentmann Date: Sat Jun 6 17:28:10 2009 New Revision: 782282 URL: http://svn.apache.org/viewvc?rev=782282&view=rev Log: o Revised exception handling of model builder to collect as much as possible in ModelProblem instances that are stored in the ModelBuildingException when it eventually bails out. This should enable IDE integrators to provide more extensive error feedback.
Added: maven/components/trunk/maven-model-builder/src/main/java/org/apache/maven/model/ModelProblem.java (with props) Removed: maven/components/trunk/maven-model-builder/src/main/java/org/apache/maven/model/InvalidModelException.java maven/components/trunk/maven-model-builder/src/main/java/org/apache/maven/model/InvalidProfileException.java maven/components/trunk/maven-model-builder/src/main/java/org/apache/maven/model/UnparseableModelException.java maven/components/trunk/maven-model-builder/src/main/java/org/apache/maven/model/UnresolvableParentException.java Modified: maven/components/trunk/maven-model-builder/src/main/java/org/apache/maven/model/DefaultModelBuilder.java maven/components/trunk/maven-model-builder/src/main/java/org/apache/maven/model/ModelBuildingException.java maven/components/trunk/maven-model-builder/src/main/java/org/apache/maven/model/path/PathTranslator.java Modified: maven/components/trunk/maven-model-builder/src/main/java/org/apache/maven/model/DefaultModelBuilder.java URL: http://svn.apache.org/viewvc/maven/components/trunk/maven-model-builder/src/main/java/org/apache/maven/model/DefaultModelBuilder.java?rev=782282&r1=782281&r2=782282&view=diff ============================================================================== --- maven/components/trunk/maven-model-builder/src/main/java/org/apache/maven/model/DefaultModelBuilder.java (original) +++ maven/components/trunk/maven-model-builder/src/main/java/org/apache/maven/model/DefaultModelBuilder.java Sat Jun 6 17:28:10 2009 @@ -110,17 +110,19 @@ { DefaultModelBuildingResult result = new DefaultModelBuildingResult(); + List<ModelProblem> problems = new ArrayList<ModelProblem>(); + ProfileActivationContext profileActivationContext = getProfileActivationContext( request ); - List<Profile> activeExternalProfiles = getActiveExternalProfiles( request, profileActivationContext ); + List<Profile> activeExternalProfiles = getActiveExternalProfiles( request, profileActivationContext, problems ); - Model model = readModel( modelSource, request ); + Model model = readModel( modelSource, request, problems ); model.setPomFile( pomFile ); List<Model> rawModels = new ArrayList<Model>(); List<Model> resultModels = new ArrayList<Model>(); - for ( Model current = model; current != null; current = readParent( current, request ) ) + for ( Model current = model; current != null; current = readParent( current, request, problems ) ) { Model resultModel = current; resultModels.add( resultModel ); @@ -130,7 +132,8 @@ modelNormalizer.mergeDuplicates( resultModel, request ); - List<Profile> activeProjectProfiles = getActiveProjectProfiles( rawModel, profileActivationContext ); + List<Profile> activeProjectProfiles = + getActiveProjectProfiles( rawModel, profileActivationContext, problems ); List<Profile> activeProfiles = activeProjectProfiles; if ( current == model ) @@ -147,7 +150,7 @@ result.setActiveProfiles( rawModel, activeProfiles ); - configureResolver( request.getModelResolver(), resultModel ); + configureResolver( request.getModelResolver(), resultModel, problems ); } Model superModel = getSuperModel(); @@ -160,7 +163,7 @@ Model resultModel = resultModels.get( 0 ); - resultModel = interpolateModel( resultModel, request ); + resultModel = interpolateModel( resultModel, request, problems ); resultModels.set( 0, resultModel ); modelPathTranslator.alignToBaseDirectory( resultModel, resultModel.getProjectDirectory(), request ); @@ -177,7 +180,12 @@ pluginConfigurationExpander.expandPluginConfiguration( resultModel, request ); } - validateModel( resultModel, false, request ); + validateModel( resultModel, false, request, problems ); + + if ( !problems.isEmpty() ) + { + throw new ModelBuildingException( problems ); + } result.setEffectiveModel( resultModel ); @@ -193,7 +201,7 @@ return context; } - private Model readModel( ModelSource modelSource, ModelBuildingRequest request ) + private Model readModel( ModelSource modelSource, ModelBuildingRequest request, List<ModelProblem> problems ) throws ModelBuildingException { Model model; @@ -207,21 +215,23 @@ } catch ( ModelParseException e ) { - throw new UnparseableModelException( "Failed to parse POM " + modelSource.getLocation() + ": " - + e.getMessage(), e.getLineNumber(), e.getColumnNumber(), e ); + problems.add( new ModelProblem( "Non-parseable POM " + modelSource.getLocation() + ": " + e.getMessage(), + modelSource.getLocation(), e ) ); + throw new ModelBuildingException( problems ); } catch ( IOException e ) { - throw new UnparseableModelException( "Failed to read POM " + modelSource.getLocation(), -1, -1, e ); + problems.add( new ModelProblem( "Non-readable POM " + modelSource.getLocation() + ": " + e.getMessage(), + modelSource.getLocation(), e ) ); + throw new ModelBuildingException( problems ); } - validateModel( model, true, request ); + validateModel( model, true, request, problems ); return model; } - private void validateModel( Model model, boolean raw, ModelBuildingRequest request ) - throws ModelBuildingException + private void validateModel( Model model, boolean raw, ModelBuildingRequest request, List<ModelProblem> problems ) { ModelValidationResult result; @@ -236,12 +246,17 @@ if ( result.getMessageCount() > 0 ) { - throw new InvalidModelException( "Failed to validate POM " + toSourceHint( model ), result ); + String source = toSourceHint( model ); + + for ( int i = 0; i < result.getMessageCount(); i++ ) + { + problems.add( new ModelProblem( "Invalid POM " + source + ": " + result.getMessage( i ), source ) ); + } } } - private List<Profile> getActiveExternalProfiles( ModelBuildingRequest request, ProfileActivationContext context ) - throws ModelBuildingException + private List<Profile> getActiveExternalProfiles( ModelBuildingRequest request, ProfileActivationContext context, + List<ModelProblem> problems ) { try { @@ -249,12 +264,16 @@ } catch ( ProfileActivationException e ) { - throw new InvalidProfileException( "Failed to determine activation status of external profile " - + e.getProfile(), e.getProfile(), e ); + problems.add( new ModelProblem( "Invalid activation condition for external profile " + + e.getProfile().getId() + ": " + e.getMessage(), "(external profiles)", e ) ); + + // FIXME: Update profile selector to integrate better with the problem reporting + return new ArrayList<Profile>(); } } - private List<Profile> getActiveProjectProfiles( Model model, ProfileActivationContext context ) + private List<Profile> getActiveProjectProfiles( Model model, ProfileActivationContext context, + List<ModelProblem> problems ) throws ModelBuildingException { try @@ -263,13 +282,16 @@ } catch ( ProfileActivationException e ) { - throw new InvalidProfileException( "Failed to determine activation status of project profile " - + e.getProfile() + " for POM " + toSourceHint( model ), e.getProfile(), e ); + problems.add( new ModelProblem( "Invalid activation condition for project profile " + + e.getProfile().getId() + " in POM " + toSourceHint( model ) + ": " + e.getMessage(), + toSourceHint( model ), e ) ); + + // FIXME: Update profile selector to integrate better with the problem reporting + return new ArrayList<Profile>(); } } - private void configureResolver( ModelResolver modelResolver, Model model ) - throws ModelBuildingException + private void configureResolver( ModelResolver modelResolver, Model model, List<ModelProblem> problems ) { if ( modelResolver == null ) { @@ -284,8 +306,8 @@ } catch ( InvalidRepositoryException e ) { - throw new InvalidModelException( "Failed to validate repository " + repository.getId() + " for POM " - + toSourceHint( model ), e ); + problems.add( new ModelProblem( "Invalid repository " + repository.getId() + " in POM " + + toSourceHint( model ) + ": " + e.getMessage(), toSourceHint( model ), e ) ); } } } @@ -300,8 +322,7 @@ } } - private Model interpolateModel( Model model, ModelBuildingRequest request ) - throws ModelBuildingException + private Model interpolateModel( Model model, ModelBuildingRequest request, List<ModelProblem> problems ) { try { @@ -311,11 +332,14 @@ } catch ( ModelInterpolationException e ) { - throw new ModelBuildingException( "Failed to interpolate model " + toSourceHint( model ), e ); + problems.add( new ModelProblem( "Invalid expression in POM " + toSourceHint( model ) + ": " + + e.getMessage(), toSourceHint( model ), e ) ); + + return model; } } - private Model readParent( Model childModel, ModelBuildingRequest request ) + private Model readParent( Model childModel, ModelBuildingRequest request, List<ModelProblem> problems ) throws ModelBuildingException { Model parentModel; @@ -324,11 +348,11 @@ if ( parent != null ) { - parentModel = readParentLocally( childModel, request ); + parentModel = readParentLocally( childModel, request, problems ); if ( parentModel == null ) { - parentModel = readParentExternally( childModel, request ); + parentModel = readParentExternally( childModel, request, problems ); } } else @@ -339,7 +363,7 @@ return parentModel; } - private Model readParentLocally( Model childModel, ModelBuildingRequest request ) + private Model readParentLocally( Model childModel, ModelBuildingRequest request, List<ModelProblem> problems ) throws ModelBuildingException { File projectDirectory = childModel.getProjectDirectory(); @@ -360,7 +384,7 @@ return null; } - Model candidateModel = readModel( new FileModelSource( pomFile ), request ); + Model candidateModel = readModel( new FileModelSource( pomFile ), request, problems ); candidateModel.setPomFile( pomFile ); String groupId = candidateModel.getGroupId(); @@ -391,7 +415,7 @@ return candidateModel; } - private Model readParentExternally( Model childModel, ModelBuildingRequest request ) + private Model readParentExternally( Model childModel, ModelBuildingRequest request, List<ModelProblem> problems ) throws ModelBuildingException { Parent parent = childModel.getParent(); @@ -400,9 +424,9 @@ if ( modelResolver == null ) { - Exception e = new IllegalArgumentException( "No model resolver provided" ); - throw new UnresolvableParentException( "Failed to resolve parent POM " + toId( parent ) + " for POM " - + toSourceHint( childModel ), e ); + problems.add( new ModelProblem( "Non-resolvable parent POM " + toId( parent ) + " for POM " + + toSourceHint( childModel ) + ": " + "No model resolver provided", toSourceHint( childModel ) ) ); + throw new ModelBuildingException( problems ); } ModelSource modelSource; @@ -412,11 +436,12 @@ } catch ( UnresolvableModelException e ) { - throw new UnresolvableParentException( "Failed to resolve parent POM " + toId( parent ) + " for POM " - + toSourceHint( childModel ), e ); + problems.add( new ModelProblem( "Non-resolvable parent POM " + toId( parent ) + " for POM " + + toSourceHint( childModel ) + ": " + e.getMessage(), toSourceHint( childModel ), e ) ); + throw new ModelBuildingException( problems ); } - return readModel( modelSource, request ); + return readModel( modelSource, request, problems ); } private Model getSuperModel() Modified: maven/components/trunk/maven-model-builder/src/main/java/org/apache/maven/model/ModelBuildingException.java URL: http://svn.apache.org/viewvc/maven/components/trunk/maven-model-builder/src/main/java/org/apache/maven/model/ModelBuildingException.java?rev=782282&r1=782281&r2=782282&view=diff ============================================================================== --- maven/components/trunk/maven-model-builder/src/main/java/org/apache/maven/model/ModelBuildingException.java (original) +++ maven/components/trunk/maven-model-builder/src/main/java/org/apache/maven/model/ModelBuildingException.java Sat Jun 6 17:28:10 2009 @@ -19,6 +19,11 @@ * under the License. */ +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.List; + /** * Signals an error during model building. * @@ -28,25 +33,51 @@ extends Exception { + private List<ModelProblem> problems; + /** - * Creates a new exception with specified detail message. + * Creates a new exception with the specified problems. * - * @param message The detail message, may be {...@code null}. + * @param problems The problems that causes this exception, may be {...@code null}. */ - public ModelBuildingException( String message ) + public ModelBuildingException( List<ModelProblem> problems ) { - super( message ); + super( toMessage( problems ) ); + + this.problems = new ArrayList<ModelProblem>(); + if ( problems != null ) + { + this.problems.addAll( problems ); + } } /** - * Creates a new exception with specified detail message and cause. + * Gets the problems that caused this exception. * - * @param message The detail message, may be {...@code null}. - * @param cause The cause, may be {...@code null}. + * @return The problems that caused this exception, never {...@code null}. */ - public ModelBuildingException( String message, Throwable cause ) + public List<ModelProblem> getProblems() + { + return this.problems; + } + + private static String toMessage( List<ModelProblem> problems ) { - super( message, cause ); + StringWriter buffer = new StringWriter( 1024 ); + + PrintWriter writer = new PrintWriter( buffer ); + + writer.print( problems.size() ); + writer.print( ( problems.size() == 1 ) ? " problem was " : " problems were " ); + writer.println( "encountered during construction of the effective model:" ); + + for ( ModelProblem problem : problems ) + { + writer.print( "o " ); + writer.println( problem.getMessage() ); + } + + return buffer.toString(); } } Added: maven/components/trunk/maven-model-builder/src/main/java/org/apache/maven/model/ModelProblem.java URL: http://svn.apache.org/viewvc/maven/components/trunk/maven-model-builder/src/main/java/org/apache/maven/model/ModelProblem.java?rev=782282&view=auto ============================================================================== --- maven/components/trunk/maven-model-builder/src/main/java/org/apache/maven/model/ModelProblem.java (added) +++ maven/components/trunk/maven-model-builder/src/main/java/org/apache/maven/model/ModelProblem.java Sat Jun 6 17:28:10 2009 @@ -0,0 +1,118 @@ +package org.apache.maven.model; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * Describes a problem that was encountered during model building. A problem can either be an exception that was thrown + * or a simple string message. In addition, a problem carries a hint about its source, e.g. the POM file that could not + * be processed. + * + * @author Benjamin Bentmann + */ +public class ModelProblem +{ + + private String source; + + private String message; + + private Exception exception; + + /** + * Creates a new problem with the specified message. + * + * @param message The message describing the problem, may be {...@code null}. + * @param source A hint about the source of the problem, may be {...@code null}. + */ + public ModelProblem( String message, String source ) + { + this.message = message; + this.source = ( source != null ) ? source : ""; + } + + /** + * Creates a new problem with the specified message and exception. + * + * @param message The message describing the problem, may be {...@code null}. + * @param source A hint about the source of the problem, may be {...@code null}. + * @param exception The exception that caused this problem, may be {...@code null}. + */ + public ModelProblem( String message, String source, Exception exception ) + { + this.message = message; + this.source = ( source != null ) ? source : ""; + this.exception = exception; + } + + /** + * Gets the hint about the source of the problem. While the syntax of this hint is unspecified and depends on the + * creator of the problem, the general expectation is that the hint provides sufficient information to the user to + * track the problem back to its origin. + * + * @return The hint about the source of the problem, never {...@code null}. + */ + public String getSource() + { + return source; + } + + /** + * Gets the exception that caused this problem (if any). + * + * @return The exception that caused this problem or {...@code null} if not applicable. + */ + public Exception getException() + { + return exception; + } + + /** + * Gets the message that describes this problem. + * + * @return The message describing this problem, never {...@code null}. + */ + public String getMessage() + { + String msg; + + if ( message != null && message.length() > 0 ) + { + msg = message; + } + else + { + msg = exception.getMessage(); + + if ( msg == null ) + { + msg = ""; + } + } + + return msg; + } + + @Override + public String toString() + { + return getSource() + ": " + getMessage(); + } + +} Propchange: maven/components/trunk/maven-model-builder/src/main/java/org/apache/maven/model/ModelProblem.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: maven/components/trunk/maven-model-builder/src/main/java/org/apache/maven/model/ModelProblem.java ------------------------------------------------------------------------------ svn:keywords = Author Date Id Revision Modified: maven/components/trunk/maven-model-builder/src/main/java/org/apache/maven/model/path/PathTranslator.java URL: http://svn.apache.org/viewvc/maven/components/trunk/maven-model-builder/src/main/java/org/apache/maven/model/path/PathTranslator.java?rev=782282&r1=782281&r2=782282&view=diff ============================================================================== --- maven/components/trunk/maven-model-builder/src/main/java/org/apache/maven/model/path/PathTranslator.java (original) +++ maven/components/trunk/maven-model-builder/src/main/java/org/apache/maven/model/path/PathTranslator.java Sat Jun 6 17:28:10 2009 @@ -31,7 +31,7 @@ /** * Resolves the specified path against the given base directory. The resolved path will be absolute and uses the - * platform-specified file separator. + * platform-specific file separator. * * @param path The path to resolve, may be {...@code null}. * @param basedir The base directory to resolve relative paths against, may be {...@code null}.