diff --git a/src/main/java/com/crowdin/client/Crowdin.java b/src/main/java/com/crowdin/client/Crowdin.java index f213e8b..2eaa4c6 100644 --- a/src/main/java/com/crowdin/client/Crowdin.java +++ b/src/main/java/com/crowdin/client/Crowdin.java @@ -407,17 +407,16 @@ private T executeRequest(Supplier exec) { try { return exec.get(); } catch (HttpException e) { - HttpException ex = (HttpException) e; - String code = (ex.getError() != null && ex.getError().getCode() != null) ? ex.getError().getCode() : ""; - String message = (ex.getError() != null && ex.getError().getMessage() != null) ? ex.getError().getMessage() : ""; + String code = (e.getError() != null && e.getError().getCode() != null) ? e.getError().getCode() : "empty_code"; + String message = (e.getError() != null && e.getError().getMessage() != null) ? e.getError().getMessage() : "empty_message"; String errorMessage = ("401".equals(code)) ? MESSAGES_BUNDLE.getString("errors.authorize") - : String.format("Error from server: ", code, message); + : String.format("Error from server: Code: %s, Message: %s", code, message); throw new RuntimeException(errorMessage, e); } catch (HttpBadRequestException e) { String errorMessage; if (e.getErrors() == null) { - errorMessage = "Wrong parameters: , Code: , Message: "; + errorMessage = "Wrong parameters: Key: empty_key, Code: empty_code, Message: empty_message"; } else { errorMessage = "Wrong parameters: \n" + e.getErrors() .stream() @@ -426,10 +425,10 @@ private T executeRequest(Supplier exec) { .stream() .filter(Objects::nonNull) .map(error -> - String.format("", - (holder.getKey() != null) ? holder.getKey() : "", - (error.getCode() != null) ? error.getCode() : "", - (error.getMessage() != null) ? error.getMessage() : ""))) + String.format("Key: %s, Code: %s, Message: %s", + (holder.getKey() != null) ? holder.getKey() : "empty_key", + (error.getCode() != null) ? error.getCode() : "empty_code", + (error.getMessage() != null) ? error.getMessage() : "empty_message"))) .collect(Collectors.joining("\n")); } throw new RuntimeException(errorMessage, e); diff --git a/src/main/java/com/crowdin/client/config/CrowdinFileProvider.java b/src/main/java/com/crowdin/client/config/CrowdinFileProvider.java index 2552a04..e78a239 100644 --- a/src/main/java/com/crowdin/client/config/CrowdinFileProvider.java +++ b/src/main/java/com/crowdin/client/config/CrowdinFileProvider.java @@ -23,6 +23,8 @@ public static Map load(Project project) { } try (InputStream in = crowdinPropertyFile.getInputStream()) { return YAML.load(in); + } catch (ClassCastException e) { + throw new RuntimeException(MESSAGES_BUNDLE.getString("errors.config.has_errors") + "The Yaml file is not in the correct format"); } catch (IOException e) { throw new RuntimeException(MESSAGES_BUNDLE.getString("errors.config.has_errors") + e.getMessage()); } diff --git a/src/main/java/com/crowdin/client/config/CrowdinPropertiesLoader.java b/src/main/java/com/crowdin/client/config/CrowdinPropertiesLoader.java index e5b255f..5c007e5 100644 --- a/src/main/java/com/crowdin/client/config/CrowdinPropertiesLoader.java +++ b/src/main/java/com/crowdin/client/config/CrowdinPropertiesLoader.java @@ -11,6 +11,7 @@ import java.util.List; import java.util.Map; import java.util.regex.Pattern; +import java.util.stream.Collectors; import static com.crowdin.Constants.CONFIG_FILE; import static com.crowdin.Constants.MESSAGES_BUNDLE; @@ -59,7 +60,7 @@ protected static CrowdinConfig load(Map properties, CrowdingSett try { Object propProjectId = properties.get(PROJECT_ID); - String propProjectIdEnv = (String) properties.get(PROJECT_ID_ENV); + String propProjectIdEnv = getStringProperty(properties, PROJECT_ID_ENV); if (propProjectId != null) { try { @@ -88,8 +89,8 @@ protected static CrowdinConfig load(Map properties, CrowdingSett errors.add(String.format(MESSAGES_BUNDLE.getString("errors.config.missing_property"), PROJECT_ID)); } - String propApiToken = (String) properties.get(API_TOKEN); - String propApiTokenEnv = (String) properties.get(API_TOKEN_ENV); + String propApiToken = getStringProperty(properties, API_TOKEN); + String propApiTokenEnv = getStringProperty(properties, API_TOKEN_ENV); if (!StringUtils.isEmpty(propApiToken)) { crowdinProperties.setApiToken(propApiToken); } else if (!StringUtils.isEmpty(propApiTokenEnv)) { @@ -105,8 +106,8 @@ protected static CrowdinConfig load(Map properties, CrowdingSett errors.add(String.format(MESSAGES_BUNDLE.getString("errors.config.missing_property"), API_TOKEN)); } - String propBaseUrl = (String) properties.get(BASE_URL); - String propBaseUrlEnv = (String) properties.get(BASE_URL_ENV); + String propBaseUrl = getStringProperty(properties, BASE_URL); + String propBaseUrlEnv = getStringProperty(properties, BASE_URL_ENV); if (!StringUtils.isEmpty(propBaseUrl)) { if (isBaseUrlValid(propBaseUrl)) { crowdinProperties.setBaseUrl(propBaseUrl); @@ -144,22 +145,22 @@ protected static CrowdinConfig load(Map properties, CrowdingSett crowdinProperties.setAutocompletionEnabled(settings.enableCompletion); crowdinProperties.setUseGitBranch(settings.useGitBranch); - Boolean preserveHierarchy = (Boolean) properties.get(PROPERTY_PRESERVE_HIERARCHY); + Boolean preserveHierarchy = getBooleanProperty(properties, PROPERTY_PRESERVE_HIERARCHY); crowdinProperties.setPreserveHierarchy(preserveHierarchy); - Boolean debug = (Boolean) properties.get(PROPERTY_DEBUG); + Boolean debug = getBooleanProperty(properties, PROPERTY_DEBUG); crowdinProperties.setDebug(debug); - Boolean importEqSuggestions = (Boolean) properties.get(PROPERTY_IMPORT_EQ_SUGGESTIONS); + Boolean importEqSuggestions = getBooleanProperty(properties, PROPERTY_IMPORT_EQ_SUGGESTIONS); crowdinProperties.setImportEqSuggestions(importEqSuggestions); - Boolean autoApproveImported = (Boolean) properties.get(PROPERTY_AUTO_APPROVE_IMPORTED); + Boolean autoApproveImported = getBooleanProperty(properties, PROPERTY_AUTO_APPROVE_IMPORTED); crowdinProperties.setAutoApproveImported(autoApproveImported); - Boolean translateHidden = (Boolean) properties.get(PROPERTY_TRANSLATE_HIDDEN); + Boolean translateHidden = getBooleanProperty(properties, PROPERTY_TRANSLATE_HIDDEN); crowdinProperties.setTranslateHidden(translateHidden); - String branch = (String) properties.get(PROPERTY_BRANCH); + String branch = getStringProperty(properties, PROPERTY_BRANCH); crowdinProperties.setBranch(branch); } catch (Exception e) { e.printStackTrace(); - throw new RuntimeException(MESSAGES_BUNDLE.getString("errors.config.has_errors") + e.getMessage()); + throw new RuntimeException(MESSAGES_BUNDLE.getString("errors.config.has_errors") + " " + e.getMessage()); } } @@ -173,16 +174,16 @@ protected static CrowdinConfig load(Map properties, CrowdingSett private static List getSourcesWithTranslations(Map properties, List errors) { List fileBeans = new ArrayList<>(); - List> files = (List>) properties.get(PROPERTY_FILES); + List> files = getListOfObjectsProperty(properties, PROPERTY_FILES); if (files != null) { files.forEach(file -> { - String source = (String) file.get(PROPERTY_FILES_SOURCE); - String translation = (String) file.get(PROPERTY_FILES_TRANSLATION); - Boolean updateStrings = (Boolean) file.get(PROPERTY_FILES_UPDATE_STRINGS); - Boolean cleanupMode = (Boolean) file.get(PROPERTY_FILES_CLEANUP_MODE); - List labels = (List) file.get(PROPERTY_LABELS); - List excludedTargetLanguages = (List) file.get(PROPERTY_EXCLUDED_TARGET_LANGUAGES); + String source = getStringProperty(file, PROPERTY_FILES_SOURCE); + String translation = getStringProperty(file, PROPERTY_FILES_TRANSLATION); + Boolean updateStrings = getBooleanProperty(file, PROPERTY_FILES_UPDATE_STRINGS); + Boolean cleanupMode = getBooleanProperty(file, PROPERTY_FILES_CLEANUP_MODE); + List labels = getListStringsProperty(file, PROPERTY_LABELS); + List excludedTargetLanguages = getListStringsProperty(file, PROPERTY_EXCLUDED_TARGET_LANGUAGES); if (!StringUtils.isEmpty(source) && !StringUtils.isEmpty(translation)) { FileBean fb = new FileBean(); @@ -193,9 +194,9 @@ private static List getSourcesWithTranslations(Map pro fb.setUpdateStrings(updateStrings); fb.setCleanupMode(cleanupMode); fileBeans.add(fb); - } else if (StringUtils.isEmpty(translation)) { - errors.add(String.format(MESSAGES_BUNDLE.getString("errors.config.missing_property"), PROPERTY_FILES_SOURCE)); } else if (StringUtils.isEmpty(source)) { + errors.add(String.format(MESSAGES_BUNDLE.getString("errors.config.missing_property"), PROPERTY_FILES_SOURCE)); + } else if (StringUtils.isEmpty(translation)) { errors.add(String.format(MESSAGES_BUNDLE.getString("errors.config.missing_property"), PROPERTY_FILES_TRANSLATION)); } }); @@ -204,6 +205,75 @@ private static List getSourcesWithTranslations(Map pro return fileBeans; } + private static String getStringProperty(Map map, String property) { + return getProperty(map, property, String.class); + } + + private static List getListStringsProperty(Map map, String property) { + List list = getProperty(map, property, List.class); + if (list == null) { + return null; + } + List res = new ArrayList<>(); + for (int i = 0; i < list.size(); i++) { + Object el = list.get(i); + try { + res.add(String.class.cast(el)); + } catch (ClassCastException e) { + throw new RuntimeException(String.format(MESSAGES_BUNDLE.getString("errors.config.invalid_format"), String.format("%s[%s]", property, i))); + } + } + return res; + } + + private static List> getListOfObjectsProperty(Map map, String property) { + List list = getProperty(map, property, List.class); + if (list == null) { + return null; + } + List> res = new ArrayList<>(); + for (int i = 0; i < list.size(); i++) { + Object el = list.get(i); + try { + Map object = Map.class.cast(el); + + int finalI = i; + Map castedObject = object + .entrySet() + .stream() + .peek(entry -> { + if (entry.getKey() == null || entry.getValue() == null) { + throw new RuntimeException(String.format(MESSAGES_BUNDLE.getString("errors.config.invalid_format"), String.format("%s[%s]", property, finalI))); + } + }) + .collect(Collectors.toMap( + field -> String.class.cast(field.getKey()), + Map.Entry::getValue + )); + res.add(castedObject); + } catch (ClassCastException e) { + throw new RuntimeException(String.format(MESSAGES_BUNDLE.getString("errors.config.invalid_format"), String.format("%s[%s]", property, i))); + } + } + return res; + } + + private static Boolean getBooleanProperty(Map map, String property) { + return getProperty(map, property, Boolean.class); + } + + private static T getProperty(Map map, String property, Class clazz) { + try { + Object value = map.get(property); + if (value != null) { + return clazz.cast(value); + } + return null; + } catch (ClassCastException e) { + throw new RuntimeException(String.format(MESSAGES_BUNDLE.getString("errors.config.invalid_format"), property)); + } + } + protected static boolean isBaseUrlValid(String baseUrl) { return BASE_URL_PATTERN.matcher(baseUrl).matches(); } diff --git a/src/main/resources/messages/messages.properties b/src/main/resources/messages/messages.properties index c68072e..b409a58 100644 --- a/src/main/resources/messages/messages.properties +++ b/src/main/resources/messages/messages.properties @@ -11,7 +11,7 @@ labels.loading_text.download_source_file_from_context=Downloading Source File '% errors.config.project_id_format=Project Id '%s' should be a number errors.config.sysenv_not_exist.single=Environment variables do not contain '%s' key errors.config.sysenv_not_exist.plural=Environment variables do not contain %s keys -errors.settings.api_token_missing=API Token is not defined for this workspace +errors.config.invalid_format=Property '%s' has wrong format errors.config.has_errors=Errors in the configuration file: errors.config.missing_config_file=File '%s' with Crowdin plugin configuration doesn't exist in the project root directory errors.config.missing_property=Required property '%s' is missing in the configuration file