/* | |
* 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]); | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} |