/*
* 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.checkers.localizationStrings;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import org.eclipse.core.runtime.IStatus;
import com.motorolamobility.preflighting.checkers.CheckerPlugin;
import com.motorolamobility.preflighting.checkers.i18n.CheckerNLS;
import com.motorolamobility.preflighting.core.applicationdata.ApplicationData;
import com.motorolamobility.preflighting.core.applicationdata.ResourcesFolderElement;
import com.motorolamobility.preflighting.core.applicationdata.StringsElement;
import com.motorolamobility.preflighting.core.checker.condition.CanExecuteConditionStatus;
import com.motorolamobility.preflighting.core.checker.condition.Condition;
import com.motorolamobility.preflighting.core.checker.condition.ICondition;
import com.motorolamobility.preflighting.core.devicespecification.DeviceSpecification;
import com.motorolamobility.preflighting.core.exception.PreflightingCheckerException;
import com.motorolamobility.preflighting.core.internal.cond.utils.ConditionUtils;
import com.motorolamobility.preflighting.core.validation.ValidationManagerConfiguration;
import com.motorolamobility.preflighting.core.validation.ValidationResult;
import com.motorolamobility.preflighting.core.validation.ValidationResultData;
/**
* Check if there are keys with empty values.
*
*/
public class MissingValueCondition extends Condition implements ICondition
{
private LocalizationStringsChecker checker;
private ValidationManagerConfiguration valManagerConfig;
private ResourcesFolderElement resFolder;
private Locale defaultLocale;
/**
* The string element for the default locale
*/
StringsElement stringsKeysDefault;
/**
* Check if there is at least one string key defined in default or alternate locales.
* @see com.motorolamobility.preflighting.core.checker.condition.Condition#canExecute(com.motorolamobility.preflighting.core.applicationdata.ApplicationData, java.util.List)
*/
@Override
public CanExecuteConditionStatus canExecute(ApplicationData data,
List<DeviceSpecification> deviceSpecs) throws PreflightingCheckerException
{
CanExecuteConditionStatus status;
this.checker = (LocalizationStringsChecker) getChecker();
this.resFolder = checker.getResourcesFolder();
this.stringsKeysDefault = checker.getStringsKeysDefault();
List<Locale> availableLocales = resFolder.getAvailableLocales();
//check if there is at least one key in default or non-default locales
if ((stringsKeysDefault != null) && (stringsKeysDefault.getKeyList() != null)
&& (stringsKeysDefault.getKeyList().size() > 0))
{
//at least one string key found at stringsKeyDefault
status = new CanExecuteConditionStatus(IStatus.OK, CheckerPlugin.PLUGIN_ID, ""); //$NON-NLS-1$
status.setConditionId(getId());
}
else if ((availableLocales != null) && (availableLocales.size() > 0))
{
//default locale has no string key defined
//look for string keys in non-default languages
boolean nonDefaultLanguageStringKeyFound = false;
for (Locale locale : availableLocales)
{
if (resFolder.getValuesElement(locale).getKeyList().size() > 0)
{
nonDefaultLanguageStringKeyFound = true;
break;
}
}
if (nonDefaultLanguageStringKeyFound)
{
//at least one string key found in non default languages (availableLocales)
status = new CanExecuteConditionStatus(IStatus.OK, CheckerPlugin.PLUGIN_ID, ""); //$NON-NLS-1$
status.setConditionId(getId());
}
else
{
//both default and non-default localization files are empty
status =
new CanExecuteConditionStatus(
IStatus.ERROR,
CheckerPlugin.PLUGIN_ID,
CheckerNLS
.bind(CheckerNLS.LocalizationStringsChecker_conditionMissingValue_CouldNotBeRun_EmptyLocalizationFiles,
getId()));
status.setConditionId(getId());
}
}
else
{
//default localization file is empty and there is no non-default locale set
status =
new CanExecuteConditionStatus(
IStatus.ERROR,
CheckerPlugin.PLUGIN_ID,
CheckerNLS
.bind(CheckerNLS.LocalizationStringsChecker_conditionMissingValue_CouldNotBeRun_EmptyLocalizationFiles,
getId()));
status.setConditionId(getId());
}
return status;
}
/**
* Check if there are keys with empty values in default and alternate locales.
* @see com.motorolamobility.preflighting.core.checker.condition.Condition#execute(com.motorolamobility.preflighting.core.applicationdata.ApplicationData, java.util.List, com.motorolamobility.preflighting.core.validation.ValidationManagerConfiguration, com.motorolamobility.preflighting.core.validation.ValidationResult)
*/
@Override
public void execute(ApplicationData data, List<DeviceSpecification> deviceSpecs,
ValidationManagerConfiguration valManagerConfig, ValidationResult results)
throws PreflightingCheckerException
{
this.valManagerConfig = valManagerConfig;
this.defaultLocale = checker.getDefaultLocale();
// Check for keys with empty values - First the default localization and then the locales
checkForEmptyValues(null, results);
/*
* Check for problems related to the non-default localization files
*/
for (Locale l : resFolder.getAvailableLocales())
{
if (!l.equals(defaultLocale))
{
// Check for keys with empty values
checkForEmptyValues(l, results);
}
}
}
/**
* Auxiliary method to check for keys with empty values.
* @param locale - The locale to be validated. If null, the method will validate the default localization resource
* @param results
* @return A validation result
* @throws PreflightingCheckerException
*/
private void checkForEmptyValues(Locale locale, ValidationResult results)
throws PreflightingCheckerException
{
// Strings element to be validated. Can either be from the default localization resource or a locale one.
StringsElement localeStringsElement;
// Construct a list of missing keys
List<String> keysWithEmptyValues = new ArrayList<String>();
if (locale != null)
{
localeStringsElement = resFolder.getValuesElement(locale);
}
else
{
// Validate default localization resource
localeStringsElement = stringsKeysDefault;
}
try
{
if (localeStringsElement != null)
{
// Find keys with empty values
keysWithEmptyValues = findKeysWithMissingValues(localeStringsElement);
ValidationResultData result;
for (String key : keysWithEmptyValues)
{
result = new ValidationResultData();
// Builders to construct the description and quickfix
String resultDescription;
// Create a result and return it
result.setSeverity(getSeverityLevel());
result.setConditionID(getId());
//Associate the result to the resFolder
result.addFileToIssueLines(resFolder.getFile(),
Collections.<Integer> emptyList());
// The result is different depending if we are validating the default localization files or not
if (locale != null)
{
String localeDisplayName = null;
if ((locale.getCountry() != null) && (locale.getCountry().length() > 0))
{
localeDisplayName = locale.getLanguage() + "_" + locale.getCountry(); //$NON-NLS-1$
}
else
{
localeDisplayName = locale.getLanguage();
}
// Construct description
resultDescription =
CheckerNLS
.bind(CheckerNLS.LocalizationStringsChecker_localeStringEmptyValue,
key, localeDisplayName);
result.setIssueDescription(resultDescription.toString());
}
else
{
//Set description
result.setIssueDescription(CheckerNLS.bind(
CheckerNLS.LocalizationStringsChecker_defaultStringEmptyValue, key));
}
// Set quickfix
result.setQuickFixSuggestion(CheckerNLS.LocalizationStringsChecker_stringEmptyValueQuickFix);
result.setInfoURL(ConditionUtils.getDescriptionLink(checker.getId(), getId(),
valManagerConfig));
// Add result to the result list
results.addValidationResult(result);
}
}
}
catch (Exception e)
{
String exceptionMessage;
if (locale == null)
{
exceptionMessage =
CheckerNLS.LocalizationStringsChecker_Exception_EmptyValuesDefault;
}
else
{
exceptionMessage =
CheckerNLS.LocalizationStringsChecker_Exception_EmptyValuesLocale;
}
throw new PreflightingCheckerException(exceptionMessage, e);
}
}
/**
* Auxiliary method to look for empty values in a StringsElement
* @param localeStringsElement - A strings element representing a localization resource.
* @return A list containing keys with empty values.
*/
private List<String> findKeysWithMissingValues(StringsElement localeStringsElement)
{
List<String> missingValues = new ArrayList<String>();
if (localeStringsElement != null)
{
for (String key : localeStringsElement.getKeyList())
{
// Check value associated with the key
if (localeStringsElement.getValue(key) != null)
{
Object value = localeStringsElement.getValue(key);
// The value can either be a String or a List<String>.
if (value instanceof String)
{
if (((String) value).length() < 1)
{
// Empty value found!
missingValues.add(key);
}
}
else if (value instanceof List<?>)
{
if (((List<?>) value).size() < 1)
{
// Empty value found!
missingValues.add(key);
}
}
}
else
{
missingValues.add(key);
}
}
}
return missingValues;
}
}