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 static com.google.common.base.Predicates.in;
023import static com.google.common.collect.Iterables.any;
024import static com.google.common.collect.Iterables.concat;
025import static com.google.common.collect.Iterables.transform;
026import static java.util.Collections.singleton;
027import static java.util.EnumSet.of;
028import static org.apache.maven.model.building.ModelProblem.Severity.ERROR;
029import static org.apache.maven.model.building.ModelProblem.Severity.FATAL;
030
031import java.util.Arrays;
032import java.util.Collections;
033
034import org.apache.maven.model.building.ModelProblem.Severity;
035
036import com.google.common.base.Function;
037import com.google.common.base.Predicates;
038import com.google.common.collect.Iterables;
039
040/**
041 * There are various forms of results that are represented by this class:
042 * <ol>
043 * <li>success - in which case only the model field is set
044 * <li>success with warnings - model field + non-error model problems
045 * <li>error - no model, but diagnostics
046 * <li>error - (partial) model and diagnostics
047 * </ol>
048 * Could encode these variants as subclasses, but kept in one for now
049 * 
050 * @author bbusjaeger
051 * @param <T>
052 */
053public class Result<T>
054{
055
056    /**
057     * Success without warnings
058     * 
059     * @param model
060     * @return
061     */
062    public static <T> Result<T> success( T model )
063    {
064        return success( model, Collections.<ModelProblem>emptyList() );
065    }
066
067    /**
068     * Success with warnings
069     * 
070     * @param model
071     * @param problems
072     * @return
073     */
074    public static <T> Result<T> success( T model, Iterable<? extends ModelProblem> problems )
075    {
076        assert !hasErrors( problems );
077        return new Result<>( false, model, problems );
078    }
079
080    /**
081     * Success with warnings
082     * 
083     * @param model
084     * @param results
085     * @return
086     */
087    public static <T> Result<T> success( T model, Result<?>... results )
088    {
089        return success( model, Iterables.concat( Iterables.transform( Arrays.asList( results ), GET_PROBLEMS ) ) );
090    }
091
092    /**
093     * Error with problems describing the cause
094     *
095     * @param problems
096     * @return
097     */
098    public static <T> Result<T> error( Iterable<? extends ModelProblem> problems )
099    {
100        return error( null, problems );
101    }
102
103    public static <T> Result<T> error( T model )
104    {
105        return error( model, Collections.<ModelProblem>emptyList() );
106    }
107
108    public static <T> Result<T> error( Result<?> result )
109    {
110        return error( result.getProblems() );
111    }
112
113    public static <T> Result<T> error( Result<?>... results )
114    {
115        return error( Iterables.concat( Iterables.transform( Arrays.asList( results ), GET_PROBLEMS ) ) );
116    }
117
118    /**
119     * Error with partial result and problems describing the cause
120     *
121     * @param model
122     * @param problems
123     * @return
124     */
125    public static <T> Result<T> error( T model, Iterable<? extends ModelProblem> problems )
126    {
127        return new Result<>( true, model, problems );
128    }
129
130    /**
131     * New result - determine whether error or success by checking problems for errors
132     * 
133     * @param model
134     * @param problems
135     * @return
136     */
137    public static <T> Result<T> newResult( T model, Iterable<? extends ModelProblem> problems )
138    {
139        return new Result<>( hasErrors( problems ), model, problems );
140    }
141
142    /**
143     * New result consisting of given result and new problem. Convenience for newResult(result.get(),
144     * concat(result.getProblems(),problems)).
145     * 
146     * @param result
147     * @param problem
148     * @return
149     */
150    public static <T> Result<T> addProblem( Result<T> result, ModelProblem problem )
151    {
152        return addProblems( result, singleton( problem ) );
153    }
154
155    /**
156     * New result that includes the given
157     *
158     * @param result
159     * @param problems
160     * @return
161     */
162    public static <T> Result<T> addProblems( Result<T> result, Iterable<? extends ModelProblem> problems )
163    {
164        return new Result<>( result.hasErrors() || hasErrors( problems ), result.get(), concat( result.getProblems(),
165                                                                                                 problems ) );
166    }
167
168    public static <T> Result<T> addProblems( Result<T> result, Result<?>... results )
169    {
170        return addProblems( result, Iterables.concat( Iterables.transform( Arrays.asList( results ), GET_PROBLEMS ) ) );
171    }
172
173    /**
174     * Turns the given results into a single result by combining problems and models into single collection.
175     * 
176     * @param results
177     * @return
178     */
179    public static <T> Result<Iterable<T>> newResultSet( Iterable<? extends Result<? extends T>> results )
180    {
181        final boolean hasErrors = any( transform( results, new Function<Result<?>, Boolean>()
182        {
183            @Override
184            public Boolean apply( Result<?> input )
185            {
186                return input.hasErrors();
187            }
188        } ), Predicates.equalTo( true ) );
189        final Iterable<T> models = transform( results, new Function<Result<? extends T>, T>()
190        {
191            @Override
192            public T apply( Result<? extends T> input )
193            {
194                return input.get();
195            }
196        } );
197        final Iterable<ModelProblem> problems = concat( transform( results, GET_PROBLEMS ) );
198        return new Result<>( hasErrors, models, problems );
199    }
200
201    // helper to determine if problems contain error
202    private static boolean hasErrors( Iterable<? extends ModelProblem> problems )
203    {
204        return any( transform( problems, new Function<ModelProblem, Severity>()
205        {
206            @Override
207            public Severity apply( ModelProblem input )
208            {
209                return input.getSeverity();
210            }
211        } ), in( of( ERROR, FATAL ) ) );
212    }
213
214    /**
215     * Class definition
216     */
217
218    private final boolean errors;
219
220    private final T value;
221
222    private final Iterable<? extends ModelProblem> problems;
223
224    private Result( boolean errors, T model, Iterable<? extends ModelProblem> problems )
225    {
226        this.errors = errors;
227        this.value = model;
228        this.problems = problems;
229    }
230
231    public Iterable<? extends ModelProblem> getProblems()
232    {
233        return problems;
234    }
235
236    public T get()
237    {
238        return value;
239    }
240
241    public boolean hasErrors()
242    {
243        return errors;
244    }
245
246    private static final Function<Result<?>, Iterable<? extends ModelProblem>> GET_PROBLEMS =
247        new Function<Result<?>, Iterable<? extends ModelProblem>>()
248        {
249            @Override
250            public Iterable<? extends ModelProblem> apply( Result<?> input )
251            {
252                return input.getProblems();
253            }
254        };
255}