/** * Copyright 2014-2017 Linagora, Université Joseph Fourier, Floralis * * The present code is developed in the scope of the joint LINAGORA - * Université Joseph Fourier - Floralis research program and is designated * as a "Result" pursuant to the terms and conditions of the LINAGORA * - Université Joseph Fourier - Floralis research program. Each copyright * holder of Results enumerated here above fully & independently holds complete * ownership of the complete Intellectual Property rights applicable to the whole * of said Results, and may freely exploit it in any manner which does not infringe * the moral rights of the other copyright holders. * * Licensed 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. */ package net.roboconf.core.model.helpers; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import net.roboconf.core.ErrorCode; import net.roboconf.core.ErrorCode.ErrorLevel; import net.roboconf.core.RoboconfError; import net.roboconf.core.model.ModelError; import net.roboconf.core.model.ParsingError; import net.roboconf.core.model.RuntimeModelIo.ApplicationLoadResult; import net.roboconf.core.model.SourceReference; import net.roboconf.core.utils.Utils; /** * @author Vincent Zurczak - Linagora */ public final class RoboconfErrorHelpers { /** * Private empty constructor. */ private RoboconfErrorHelpers() { // nothing } /** * Determines whether a collection of errors contains at least one critical error. * @param errors a non-null collection of errors * @return true if at least one critical error, false otherwise */ public static boolean containsCriticalErrors( Collection<? extends RoboconfError> errors ) { boolean result = false; for( RoboconfError error : errors ) { if(( result = error.getErrorCode().getLevel() == ErrorLevel.SEVERE )) break; } return result; } /** * Finds all the warnings among a collection of Roboconf errors. * @param errors a non-null collection of errors * @return a non-null collection of warnings */ public static Collection<RoboconfError> findWarnings( Collection<? extends RoboconfError> errors ) { Collection<RoboconfError> result = new ArrayList<> (); for( RoboconfError error : errors ) { if( error.getErrorCode().getLevel() == ErrorLevel.WARNING ) result.add( error ); } return result; } /** * Extracts and formats warnings so that they can be displayed by a logger. * @param errors a non-null list of errors * @return a list of string, each one being readable information about a warning */ public static List<String> extractAndFormatWarnings( Collection<? extends RoboconfError> errors ) { List<String> result = new ArrayList<> (); for( RoboconfError warning : RoboconfErrorHelpers.findWarnings( errors )) { StringBuilder sb = new StringBuilder(); sb.append( warning.getErrorCode().getMsg()); if( ! Utils.isEmptyOrWhitespaces( warning.getDetails())) sb.append( " " + warning.getDetails()); result.add( sb.toString()); } return result; } /** * Resolves errors with their location when it is possible. * <p> * Parsing and conversion errors already have location information (file and line * number). This is not the case of runtime errors (validation of the runtime model). * However, these errors keep a reference to the object that contains the error. * </p> * <p> * When we load an application from a file, we keep an association between a runtime model * object and its location (file and line number). Therefore, we can resolve the location * of runtime errors too (provided the model was loaded from a file). * </p> * <p> * So, this method replaces (runtime) model errors by errors that contain location data. * </p> * * @param alr the result of an application load operation * @return a non-null list of errors */ public static List<RoboconfError> resolveErrorsWithLocation( ApplicationLoadResult alr ) { List<RoboconfError> result = new ArrayList<> (); for( RoboconfError error : alr.getLoadErrors()) { RoboconfError errorToAdd = error; if( error instanceof ModelError ) { Object modelObject = ((ModelError) error).getModelObject(); SourceReference sr = alr.getObjectToSource().get( modelObject ); if( sr != null ) errorToAdd = new ParsingError( error.getErrorCode(), sr.getSourceFile(), sr.getLine(), error.getDetails()); } result.add( errorToAdd ); } return result; } /** * Filters errors for recipes. * <p> * Indeed, some errors only make sense for complete applications, not for * reusable recipes. This method removes them from the input list of errors. * </p> * * @param alr an {@link ApplicationLoadResult} */ public static void filterErrorsForRecipes( ApplicationLoadResult alr ) { filterErrorsForRecipes( alr.getLoadErrors()); } /** * Filters errors for recipes. * <p> * Indeed, some errors only make sense for complete applications, not for * reusable recipes. This method removes them from the input list of errors. * </p> * * @param errors a non-null list of errors */ public static void filterErrorsForRecipes( Collection<? extends RoboconfError> errors ) { filterErrors( errors, ErrorCode.RM_ROOT_INSTALLER_MUST_BE_TARGET, ErrorCode.RM_UNRESOLVABLE_FACET_VARIABLE, ErrorCode.RM_UNREACHABLE_COMPONENT, ErrorCode.RM_ORPHAN_FACET, ErrorCode.RM_ORPHAN_FACET_WITH_CHILDREN ); } /** * Filters errors by removing those associated with specific error codes. * @param errors a non-null list of errors * @param errorCodes error codes */ public static void filterErrors( Collection<? extends RoboconfError> errors, ErrorCode... errorCodes ) { List<ErrorCode> codesToSkip = new ArrayList<> (); if( errorCodes != null ) codesToSkip.addAll( Arrays.asList( errorCodes )); Collection<RoboconfError> toRemove = new ArrayList<> (); for( RoboconfError error : errors ) { if( codesToSkip.contains( error.getErrorCode())) toRemove.add( error ); } errors.removeAll( toRemove ); } }