blob: e63f20b60d0028483f0b6a113b76e3c8ab6b30ad [file] [log] [blame]
/*
* Copyright (C) 2012 The Android Open Source Project
*
* 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 com.motorolamobility.preflighting.core.verbose;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.motorolamobility.preflighting.core.i18n.PreflightingCoreNLS;
import com.motorolamobility.preflighting.core.utils.LimitedList;
import com.motorolamobility.preflighting.core.validation.ValidationResult;
import com.motorolamobility.preflighting.core.validation.ValidationResultData;
import com.motorolamobility.preflighting.core.validation.ValidationResultData.SEVERITY;
import com.motorolamobility.preflighting.core.verbose.DebugVerboseOutputter.VerboseLevel;
/**
* Abstract class responsible for defining warning levels, setting the current warning level,
* and filtering results and returning appropriate messages based on current warning
* level set.
* The warning level will be passed as a parameter to the application, if not,
* {@link WarningLevelFilter#DEFAULT_WARNING_LEVEL} will be assumed (default warning level).
*/
public abstract class WarningLevelFilter
{
/**
* The terminator string for the total message.
*/
private static final String TOTAL_MESSAGE_TERMINATOR = "."; //$NON-NLS-1$
/**
* The level separator string for the total message.
*/
private static final String TOTAL_MESSAGE_LEVEL_SEPARATOR = ", "; //$NON-NLS-1$
/**
* Enumeration representing the various warning levels available to the application.
*/
public enum WarningLevel
{
/**
* Suppress all messages, just return success or failure.
*/
w0,
/**
* Only indicate extremely severe conditions that could cause immediate failure of
* the application on launch (fatal errors).
*/
w1,
/**
* Indicate improper conditions that will lead to failure or possible problems on
* different handsets (fatal errors + errors). This is the default warning level.
*/
w2,
/**
* Indicate all improper conditions (fatal errors + errors + warnings).
*/
w3,
/**
* Indicate all improper conditions (fatal errors + errors + warnings) and their
* potential fixes, if known.
*/
w4;
}
/**
* The default warning level ({@link WarningLevel#w2}).
*/
public static WarningLevel DEFAULT_WARNING_LEVEL = WarningLevel.w2;
/**
* The current warning level being used.
*/
private static WarningLevel currentWarningLevel = DEFAULT_WARNING_LEVEL;
/**
* Retrieve the current warning level for the application.
*
* @return Current warning level.
*/
public static WarningLevel getCurrentWarningLevel()
{
return currentWarningLevel;
}
/**
* Set the current warning level to the given one. If <code>null</code> is
* passed, the default warning level is used ({@link WarningLevelFilter#DEFAULT_WARNING_LEVEL}).
*
* @param warningLevel Warning level to be set.
*/
public static void setCurrentWarningLevel(WarningLevel warningLevel)
{
if (warningLevel != null)
{
currentWarningLevel = warningLevel;
}
else
{
currentWarningLevel = DEFAULT_WARNING_LEVEL;
}
}
/**
* Return whether quick fix suggestions should be printed
* (warning level equals {@link WarningLevel#w4}) or not.
*
* @return <code>true</code> if quick fix suggestions should be printed,
* <code>false</code> otherwise.
*/
public static boolean printQuickFixSuggestions()
{
return currentWarningLevel.equals(WarningLevel.w4);
}
/**
* Return whether the severities should be printed or not
* (severities are not printed if warning level equals {@link WarningLevel#w0}).
*
* @return <code>true</code> if severities should be printed,
* <code>false</code> otherwise.
*/
public static boolean printSeverity()
{
return !currentWarningLevel.equals(WarningLevel.w0);
}
/**
* Filters the given list of validation results so that the returning list
* of validation results contain only the appropriate issues, according to
* warning level set.
*
* @param validationResultList The list of validation results found by the application
*
* @return The filtered validation results list, according to warning level set
*/
public static List<ValidationResult> filterValidationResultsForCurrentWarningLevel(
List<ValidationResult> validationResultList)
{
if (validationResultList == null)
{
throw new IllegalArgumentException("List<ValidationResult> cannot be null"); //$NON-NLS-1$
}
List<ValidationResult> filteredValidationResult = new ArrayList<ValidationResult>();
if (validationResultList.size() > 0)
{
DebugVerboseOutputter.printVerboseMessage(
PreflightingCoreNLS.WarningLevelFilter_VerboseMessage_FilterningResult,
VerboseLevel.v2);
if (currentWarningLevel.equals(WarningLevel.w0))
{
boolean fatalErrorsDetected = false, potentialErrorsDetected = false;
for (ValidationResult result : validationResultList)
{
for (ValidationResultData resultData : result.getValidationResult())
{
if (resultData.getSeverity().equals(SEVERITY.FATAL))
{
fatalErrorsDetected = true;
break;
}
else if (resultData.getSeverity().equals(SEVERITY.ERROR))
{
potentialErrorsDetected = true;
}
}
}
ValidationResult result = null;
if (fatalErrorsDetected)
{
result =
createValidationResultObject(
PreflightingCoreNLS.WarningLevelFilter_FatalErrorsMessage,
SEVERITY.FATAL);
}
else if (potentialErrorsDetected)
{
result =
createValidationResultObject(
PreflightingCoreNLS.WarningLevelFilter_ErrorsMessage,
SEVERITY.ERROR);
}
else
{
result =
createValidationResultObject(
PreflightingCoreNLS.WarningLevelFilter_NoProblemsMessage,
SEVERITY.OK);
}
filteredValidationResult.add(result);
}
else if (currentWarningLevel.equals(WarningLevel.w1)) // fatal errors only
{
boolean fatalErrorsDetected =
filterValidationResultForSeverity(validationResultList,
filteredValidationResult, SEVERITY.FATAL);
if (!fatalErrorsDetected)
{
ValidationResult result =
createValidationResultObject(
PreflightingCoreNLS.WarningLevelFilter_NoFatalErrorsMessage,
SEVERITY.OK);
filteredValidationResult.add(result);
}
}
else if (currentWarningLevel.equals(WarningLevel.w2)) // fatal errors and errors only
{
boolean errorsOrFatalErrorsDetected =
filterValidationResultForSeverity(validationResultList,
filteredValidationResult, SEVERITY.ERROR);
if (!errorsOrFatalErrorsDetected)
{
ValidationResult result =
createValidationResultObject(
PreflightingCoreNLS.WarningLevelFilter_NoFatalNorErrorsMessage,
SEVERITY.OK);
filteredValidationResult.add(result);
}
}
else if (currentWarningLevel.compareTo(WarningLevel.w3) >= 0) // all levels
{
boolean warningsErrorsOrFatalErrorsDetected =
filterValidationResultForSeverity(validationResultList,
filteredValidationResult, SEVERITY.WARNING);
if (!warningsErrorsOrFatalErrorsDetected)
{
ValidationResult result =
createValidationResultObject(
PreflightingCoreNLS.WarningLevelFilter_NoFatalErrorsNorWarningsMessage,
SEVERITY.OK);
filteredValidationResult.add(result);
}
}
DebugVerboseOutputter.printVerboseMessage(
PreflightingCoreNLS.WarningLevelFilter_VerboseMessage_ResultFiltered,
VerboseLevel.v2);
}
return filteredValidationResult;
}
private static ValidationResult createValidationResultObject(String message, SEVERITY severity)
{
ValidationResult result = new ValidationResult(null, LimitedList.UNLIMITED);
ValidationResultData resultData = new ValidationResultData();
result.addValidationResult(resultData);
resultData.setSeverity(severity);
resultData.setIssueDescription(message);
return result;
}
/**
* Filter the validation results of a particular checker, given the limit severity
* (which is defined according to warning level set). The result is added to the filtered
* list also passed.
* Returns a flag indicating if any issues were found of at least the given severity.
*
* @param validationResultList The original list of validation results
* @param filteredValidationResult The filtered list; entries are added to it by this method
* @param limitSeverity The limit severity for issues entering the filtered list or not
*
* @return <code>true</code> if any issues were found with at least the severity passed
* (or more severe), <code>false</code> otherwise
*/
private static boolean filterValidationResultForSeverity(
List<ValidationResult> validationResultList,
List<ValidationResult> filteredValidationResult, SEVERITY limitSeverity)
{
boolean expectedLevelDetected = false;
for (ValidationResult result : validationResultList)
{
ValidationResult filteredResult = null;
for (ValidationResultData resultData : result.getValidationResult())
{
if (resultData.getSeverity().compareTo(limitSeverity) <= 0)
{
if (filteredResult == null)
{
filteredResult =
new ValidationResult(result.getCheckerId(), LimitedList.UNLIMITED);
}
filteredResult.addValidationResult(resultData);
expectedLevelDetected = true;
}
}
if (filteredResult != null)
{
filteredValidationResult.add(filteredResult);
}
}
return expectedLevelDetected;
}
/**
* Retrieves the total message summing up fatal errors, errors and warnings, depending
* on current warning level.
*
* @param validationResultList The list of validation results already filtered (as it
* was outputted to used)
*
* @return The total message string, or <code>null</code> if no message applies
*/
public static String getValidationResultTotalMessage(List<ValidationResult> validationResultList)
{
String totalMessage = null;
if (validationResultList != null)
{
if (currentWarningLevel.compareTo(WarningLevel.w0) > 0)
{
int fatalErrorsCount = 0, errorsCount = 0, warningsCount = 0;
for (ValidationResult result : validationResultList)
{
for (ValidationResultData resultData : result.getValidationResult())
{
if (resultData.getSeverity().equals(SEVERITY.FATAL))
{
fatalErrorsCount++;
}
else if (resultData.getSeverity().equals(SEVERITY.ERROR))
{
errorsCount++;
}
else if (resultData.getSeverity().equals(SEVERITY.WARNING))
{
warningsCount++;
}
}
}
StringBuilder stringBuilder = new StringBuilder();
// (some code repetition was used to avoid unnecessary repeated testing that would
// slow performance)
if (currentWarningLevel.compareTo(WarningLevel.w3) >= 0)
{
if ((fatalErrorsCount > 0) || (errorsCount > 0) || (warningsCount > 0))
{
stringBuilder.append(PreflightingCoreNLS.WarningLevelFilter_TotalMessage);
stringBuilder.append(PreflightingCoreNLS.bind(
PreflightingCoreNLS.WarningLevelFilter_FatalErrorsCountMessage,
fatalErrorsCount)
+ TOTAL_MESSAGE_LEVEL_SEPARATOR);
stringBuilder.append(PreflightingCoreNLS.bind(
PreflightingCoreNLS.WarningLevelFilter_ErrorsCountMessage,
errorsCount)
+ TOTAL_MESSAGE_LEVEL_SEPARATOR);
stringBuilder.append(PreflightingCoreNLS.bind(
PreflightingCoreNLS.WarningLevelFilter_WarningsCountMessage,
warningsCount)
+ TOTAL_MESSAGE_TERMINATOR);
}
}
else if (currentWarningLevel.equals(WarningLevel.w2))
{
if ((fatalErrorsCount > 0) || (errorsCount > 0))
{
stringBuilder.append(PreflightingCoreNLS.WarningLevelFilter_TotalMessage);
stringBuilder.append(PreflightingCoreNLS.bind(
PreflightingCoreNLS.WarningLevelFilter_FatalErrorsCountMessage,
fatalErrorsCount)
+ TOTAL_MESSAGE_LEVEL_SEPARATOR);
stringBuilder.append(PreflightingCoreNLS.bind(
PreflightingCoreNLS.WarningLevelFilter_ErrorsCountMessage,
errorsCount)
+ TOTAL_MESSAGE_TERMINATOR);
}
}
else if (currentWarningLevel.equals(WarningLevel.w1))
{
if (fatalErrorsCount > 0)
{
stringBuilder.append(PreflightingCoreNLS.WarningLevelFilter_TotalMessage);
stringBuilder.append(PreflightingCoreNLS.bind(
PreflightingCoreNLS.WarningLevelFilter_FatalErrorsCountMessage,
fatalErrorsCount)
+ TOTAL_MESSAGE_TERMINATOR);
}
}
if (stringBuilder.length() > 0)
{
totalMessage = stringBuilder.toString();
}
}
}
return totalMessage;
}
/**
* Adjusts the warning level on the given validation result list.
* The level can be increased or decreased.
* Only the validation results from checkers or conditions passed on the are adjusted.
*
* @param validationResultList The list of validation results
* @param raiseWarningLevels Whether the warning level should be increased (<code>true</code>
* is passed) or decreased (<code>false</code> is passed)
* @param checkerIdsToAdjustWarningLevel The list of checkers whose validation results should
* have the warning level adjusted
* @param conditionIdsMap specific checkers conditions to adjust, instead of a whole checker.
* @param excludedConditionsIds
*/
public static void adjustWarningLevels(List<ValidationResult> validationResultList,
boolean raiseWarningLevels, List<String> checkerIdsToAdjustWarningLevel,
Map<String, List<String>> conditionIdsMap, Map<String, List<String>> exclusionMap)
{
if (validationResultList == null)
{
throw new IllegalArgumentException("List<ValidationResult> cannot be null"); //$NON-NLS-1$
}
if (checkerIdsToAdjustWarningLevel == null)
{
checkerIdsToAdjustWarningLevel = Collections.emptyList();
}
if (conditionIdsMap == null)
{
conditionIdsMap = new HashMap<String, List<String>>(0);
}
SEVERITY[] severities = SEVERITY.values();
for (ValidationResult result : validationResultList)
{
String checkerId = result.getCheckerId();
if (checkerId != null)
{
//Verify if there's anything to be changed
if (checkerIdsToAdjustWarningLevel.contains(checkerId)
|| (conditionIdsMap.containsKey(checkerId)))
{
List<String> conditionsToAdjust = conditionIdsMap.get(checkerId);
//If something has to be changed, process the whole set, applying the changes.
for (ValidationResultData resultData : result.getValidationResult())
{
boolean mustAdjust = true;
//User specified only some conditions
if (!checkerIdsToAdjustWarningLevel.contains(checkerId)
&& (conditionsToAdjust != null))
{
mustAdjust = conditionsToAdjust.contains(resultData.getConditionID());
}
else if (exclusionMap != null)
{
List<String> conditionsToIgnore = exclusionMap.get(checkerId);
if (conditionsToIgnore != null)
{
mustAdjust =
!conditionsToIgnore.contains(resultData.getConditionID());
}
}
if (mustAdjust)
{
SEVERITY resultSeverity = resultData.getSeverity();
if (raiseWarningLevels)
{
// last level is not raised, and above warning is not raised as well
if ((SEVERITY.FATAL.compareTo(resultSeverity) < 0)
&& !SEVERITY.OK.equals(resultSeverity))
{
resultData
.setSeverity(severities[resultSeverity.ordinal() - 1]);
}
}
else
{
// level is decreased for warning at least (nothing goes deeper than that)
if (SEVERITY.WARNING.compareTo(resultSeverity) > 0)
{
resultData
.setSeverity(severities[resultSeverity.ordinal() + 1]);
}
}
}
}
}
}
}
}
}