001package org.apache.maven.model.building;
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
022import java.io.PrintWriter;
023import java.io.StringWriter;
024import java.util.Collections;
025import java.util.List;
026
027import org.apache.maven.model.Model;
028
029/**
030 * Signals one ore more errors during model building. The model builder tries to collect as many problems as possible
031 * before eventually failing to provide callers with rich error information. Use {@link #getProblems()} to query the
032 * details of the failure.
033 *
034 * @author Benjamin Bentmann
035 */
036public class ModelBuildingException
037    extends Exception
038{
039
040    private final ModelBuildingResult result;
041
042    /**
043     * Creates a new exception with the specified problems.
044     *
045     * @param model The model that could not be built, may be {@code null}.
046     * @param modelId The identifier of the model that could not be built, may be {@code null}.
047     * @param problems The problems that causes this exception, may be {@code null}.
048     * @deprecated Use {@link #ModelBuildingException(ModelBuildingResult)} instead.
049     */
050    @Deprecated
051    public ModelBuildingException( Model model, String modelId, List<ModelProblem> problems )
052    {
053        super( toMessage( modelId, problems ) );
054
055        if ( model != null )
056        {
057            DefaultModelBuildingResult tmp = new DefaultModelBuildingResult();
058            if ( modelId == null )
059            {
060                modelId = "";
061            }
062            tmp.addModelId( modelId );
063            tmp.setRawModel( modelId, model );
064            tmp.setProblems( problems );
065            result = tmp;
066        }
067        else
068        {
069            result = null;
070        }
071    }
072
073    /**
074     * Creates a new exception from the specified interim result and its associated problems.
075     *
076     * @param result The interim result, may be {@code null}.
077     */
078    public ModelBuildingException( ModelBuildingResult result )
079    {
080        super( toMessage( result ) );
081        this.result = result;
082    }
083
084    /**
085     * Gets the interim result of the model building up to the point where it failed.
086     *
087     * @return The interim model building result or {@code null} if not available.
088     */
089    public ModelBuildingResult getResult()
090    {
091        return result;
092    }
093
094    /**
095     * Gets the model that could not be built properly.
096     *
097     * @return The erroneous model or {@code null} if not available.
098     */
099    public Model getModel()
100    {
101        if ( result == null )
102        {
103            return null;
104        }
105        if ( result.getEffectiveModel() != null )
106        {
107            return result.getEffectiveModel();
108        }
109        return result.getRawModel();
110    }
111
112    /**
113     * Gets the identifier of the POM whose effective model could not be built. The general format of the identifier is
114     * {@code <groupId>:<artifactId>:<version>} but some of these coordinates may still be unknown at the point the
115     * exception is thrown so this information is merely meant to assist the user.
116     *
117     * @return The identifier of the POM or an empty string if not known, never {@code null}.
118     */
119    public String getModelId()
120    {
121        if ( result == null || result.getModelIds().isEmpty() )
122        {
123            return "";
124        }
125        return result.getModelIds().get( 0 );
126    }
127
128    /**
129     * Gets the problems that caused this exception.
130     *
131     * @return The problems that caused this exception, never {@code null}.
132     */
133    public List<ModelProblem> getProblems()
134    {
135        if ( result == null )
136        {
137            return Collections.emptyList();
138        }
139        return result.getProblems();
140    }
141
142    private static String toMessage( ModelBuildingResult result )
143    {
144        if ( result != null && !result.getModelIds().isEmpty() )
145        {
146            return toMessage( result.getModelIds().get( 0 ), result.getProblems() );
147        }
148        return null;
149    }
150
151    private static String toMessage( String modelId, List<ModelProblem> problems )
152    {
153        StringWriter buffer = new StringWriter( 1024 );
154
155        PrintWriter writer = new PrintWriter( buffer );
156
157        writer.print( problems.size() );
158        writer.print( ( problems.size() == 1 ) ? " problem was " : " problems were " );
159        writer.print( "encountered while building the effective model" );
160        if ( modelId != null && modelId.length() > 0 )
161        {
162            writer.print( " for " );
163            writer.print( modelId );
164        }
165        writer.println();
166
167        for ( ModelProblem problem : problems )
168        {
169            writer.print( "[" );
170            writer.print( problem.getSeverity() );
171            writer.print( "] " );
172            writer.print( problem.getMessage() );
173            writer.print( " @ " );
174            writer.println( ModelProblemUtils.formatLocation( problem, modelId ) );
175        }
176
177        return buffer.toString();
178    }
179
180}