Skip to content

Commit b3c9a49

Browse files
committed
[ITB-578] Localisation support for non-UI APIs
1 parent 18886ae commit b3c9a49

File tree

6 files changed

+63
-17
lines changed

6 files changed

+63
-17
lines changed

jsonvalidator-common/src/main/java/eu/europa/ec/itb/json/ApplicationConfig.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,15 @@
1818
public class ApplicationConfig extends eu.europa.ec.itb.validation.commons.config.ApplicationConfig {
1919

2020
private Set<String> acceptedSchemaExtensions;
21-
private Map<String, String> defaultLabels = new HashMap<>();
21+
private final Map<String, String> defaultLabels = new HashMap<>();
2222
private Set<String> acceptedMimeTypes;
2323
private String defaultContentToValidateDescription;
2424
private String defaultEmbeddingMethodDescription;
2525
private String defaultExternalSchemasDescription;
2626
private String defaultExternalSchemaCombinationApproachDescription;
2727
private String defaultValidationTypeDescription;
2828
private String defaultLocationAsPointerDescription;
29+
private String defaultLocaleDescription;
2930
private Map<String, String> branchErrorMessages;
3031
private Set<String> branchErrorMessageValues;
3132

@@ -169,6 +170,20 @@ public void setDefaultExternalSchemaCombinationApproachDescription(String defaul
169170
this.defaultExternalSchemaCombinationApproachDescription = defaultExternalSchemaCombinationApproachDescription;
170171
}
171172

173+
/**
174+
* @return The default web service input description for the locale to use.
175+
*/
176+
public String getDefaultLocaleDescription() {
177+
return defaultLocaleDescription;
178+
}
179+
180+
/**
181+
* @param defaultLocaleDescription The default web service input description for the locale to use.
182+
*/
183+
public void setDefaultLocaleDescription(String defaultLocaleDescription) {
184+
this.defaultLocaleDescription = defaultLocaleDescription;
185+
}
186+
172187
/**
173188
* Initialise the configuration.
174189
*/
@@ -182,6 +197,7 @@ public void init() {
182197
defaultLabels.put(ValidationConstants.INPUT_VALIDATION_TYPE, defaultValidationTypeDescription);
183198
defaultLabels.put(ValidationConstants.INPUT_LOCATION_AS_POINTER, defaultLocationAsPointerDescription);
184199
defaultLabels.put(ValidationConstants.INPUT_EXTERNAL_SCHEMA_COMBINATION_APPROACH, defaultExternalSchemaCombinationApproachDescription);
200+
defaultLabels.put(ValidationConstants.INPUT_LOCALE, defaultLocaleDescription);
185201
// Branch error messages.
186202
branchErrorMessageValues = new HashSet<>(getBranchErrorMessages().values());
187203
}

jsonvalidator-common/src/main/java/eu/europa/ec/itb/json/validation/ValidationConstants.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,7 @@ public class ValidationConstants {
2121
public static String INPUT_EXTERNAL_SCHEMA_COMBINATION_APPROACH = "externalSchemaCombinationApproach";
2222
/** Whether the validated content should be added to the TAR report. */
2323
public static String INPUT_ADD_INPUT_TO_REPORT = "addInputToReport";
24+
/** The locale string to consider. */
25+
public static String INPUT_LOCALE = "locale";
26+
2427
}

jsonvalidator-common/src/main/resources/application.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ validator.defaultValidationTypeDescription = The type of validation to perform (
4141
validator.defaultExternalSchemasDescription = A list of maps that defines external schemas to consider in addition to any preconfigured ones. Each map item corresponds to a schema file and defines the following keys: 'content' (the schema content to consider, see 'contentToValidate' for its semantics), 'embeddingMethod' (the way to consider the 'content' value).
4242
validator.defaultLocationAsPointerDescription = Whether or not the location reported for returned errors will be a JSON pointer (default false). False will return the line number in the input.
4343
validator.defaultSchemaCombinationApproachDescription = The way to combine externally provided schemas in case multiple are defined ('allOf', 'anyOf', 'oneOf'). Default is 'allOf'.
44+
validator.defaultLocaleDescription = Locale (language code) to use for reporting of results. If the provided locale is not supported by the validator the default locale will be used instead (e.g. "fr", "fr_FR").
4445
# Special engine messages for branch reporting.
4546
validator.branchErrorMessages.anyOf = At least one of the following sets of problems must be resolved.
4647
validator.branchErrorMessages.oneOf = Exactly one of the following sets of problems must be resolved.

jsonvalidator-jar/src/main/java/eu/europa/ec/itb/json/standalone/ValidationRunner.java

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,21 @@
66
import eu.europa.ec.itb.json.validation.JSONValidator;
77
import eu.europa.ec.itb.validation.commons.FileInfo;
88
import eu.europa.ec.itb.validation.commons.LocalisationHelper;
9+
import eu.europa.ec.itb.validation.commons.Utils;
910
import eu.europa.ec.itb.validation.commons.artifact.ValidationArtifactCombinationApproach;
1011
import eu.europa.ec.itb.validation.commons.error.ValidatorException;
1112
import eu.europa.ec.itb.validation.commons.jar.BaseValidationRunner;
1213
import eu.europa.ec.itb.validation.commons.jar.FileReport;
1314
import eu.europa.ec.itb.validation.commons.jar.ValidationInput;
1415
import eu.europa.ec.itb.validation.commons.report.ReportGeneratorBean;
15-
import org.apache.commons.io.FileUtils;
16+
import org.apache.commons.lang3.LocaleUtils;
1617
import org.springframework.beans.factory.annotation.Autowired;
1718
import org.springframework.context.ApplicationContext;
1819
import org.springframework.context.annotation.Scope;
1920
import org.springframework.stereotype.Component;
2021

21-
import javax.annotation.PostConstruct;
2222
import java.io.File;
2323
import java.io.IOException;
24-
import java.net.MalformedURLException;
25-
import java.net.URL;
2624
import java.nio.file.Files;
2725
import java.nio.file.Path;
2826
import java.nio.file.Paths;
@@ -42,6 +40,7 @@ public class ValidationRunner extends BaseValidationRunner<DomainConfig> {
4240
private static final String FLAG__INPUT = "-input";
4341
private static final String FLAG__SCHEMA = "-schema";
4442
private static final String FLAG__SCHEMA_COMBINATION = "-combination";
43+
private static final String FLAG__LOCALE = "-locale";
4544
private static final ValidationArtifactCombinationApproach DEFAULT_COMBINATION_APPROACH = ValidationArtifactCombinationApproach.ALL;
4645

4746
@Autowired
@@ -65,6 +64,7 @@ protected void bootstrapInternal(String[] args, File parentFolder) {
6564
List<FileInfo> externalSchemaFileInfo = new ArrayList<>();
6665
boolean noReports = false;
6766
String validationType = null;
67+
String locale = null;
6868
ValidationArtifactCombinationApproach externalSchemaCombinationApproach = DEFAULT_COMBINATION_APPROACH;
6969
try {
7070
int i = 0;
@@ -89,6 +89,10 @@ protected void bootstrapInternal(String[] args, File parentFolder) {
8989
if (args.length > i + 1) {
9090
externalSchemaCombinationApproach = ValidationArtifactCombinationApproach.byName(args[++i]);
9191
}
92+
} else if (FLAG__LOCALE.equalsIgnoreCase(args[i])) {
93+
if (args.length > i+1) {
94+
locale = args[++i];
95+
}
9296
}
9397
i++;
9498
}
@@ -119,10 +123,11 @@ protected void bootstrapInternal(String[] args, File parentFolder) {
119123
StringBuilder summary = new StringBuilder();
120124
summary.append("\n");
121125
int i = 0;
126+
var localiser = new LocalisationHelper(domainConfig, Utils.getSupportedLocale(LocaleUtils.toLocale(locale), domainConfig));
122127
for (ValidationInput input: inputs) {
123128
LOGGER_FEEDBACK.info(String.format("\nValidating %s of %s ...", i+1, inputs.size()));
124129
try {
125-
JSONValidator validator = ctx.getBean(JSONValidator.class, input.getInputFile(), validationType, externalSchemaFileInfo, externalSchemaCombinationApproach, domainConfig, new LocalisationHelper(domainConfig, Locale.ENGLISH), false);
130+
JSONValidator validator = ctx.getBean(JSONValidator.class, input.getInputFile(), validationType, externalSchemaFileInfo, externalSchemaCombinationApproach, domainConfig, localiser, false);
126131
TAR report = validator.validate();
127132
if (report == null) {
128133
summary.append("\nNo validation report was produced.\n");
@@ -142,7 +147,7 @@ protected void bootstrapInternal(String[] args, File parentFolder) {
142147
// Create PDF report
143148
File pdfReportFile = new File(xmlReportFile.getParentFile(), "report."+i+".pdf");
144149
Files.deleteIfExists(pdfReportFile.toPath());
145-
reportGenerator.writeReport(xmlReportFile, pdfReportFile, new LocalisationHelper(domainConfig, Locale.ENGLISH));
150+
reportGenerator.writeReport(xmlReportFile, pdfReportFile, localiser);
146151
summary.append("- Detailed reports in [").append(xmlReportFile.getAbsolutePath()).append("] and [").append(pdfReportFile.getAbsolutePath()).append("] \n");
147152
} else if (report.getCounters() != null && (report.getCounters().getNrOfAssertions().longValue() + report.getCounters().getNrOfErrors().longValue() + report.getCounters().getNrOfWarnings().longValue()) <= domainConfig.getMaximumReportsForXmlOutput()) {
148153
summary.append("- Detailed report in [").append(xmlReportFile.getAbsolutePath()).append("] (PDF report skipped due to large number of report items) \n");
@@ -152,7 +157,7 @@ protected void bootstrapInternal(String[] args, File parentFolder) {
152157
}
153158
}
154159
} catch (ValidatorException e) {
155-
LOGGER_FEEDBACK.info("\nAn error occurred while executing the validation: "+e.getMessageForDisplay(new LocalisationHelper(domainConfig, Locale.ENGLISH)));
160+
LOGGER_FEEDBACK.info("\nAn error occurred while executing the validation: "+e.getMessageForDisplay(localiser));
156161
LOGGER.error("An error occurred while executing the validation: "+e.getMessageForLog(), e);
157162
break;
158163

@@ -207,7 +212,7 @@ private File getContent(String contentPath, File parentFolder) throws IOExceptio
207212
private void printUsage(boolean requireType) {
208213
StringBuilder usageMessage = new StringBuilder();
209214
StringBuilder parametersMessage = new StringBuilder();
210-
usageMessage.append("\nExpected usage: java -jar validator.jar ").append(FLAG__INPUT).append(" FILE_OR_URI_1 ... [").append(FLAG__INPUT).append(" FILE_OR_URI_N] [").append(FLAG__NO_REPORTS).append("]");
215+
usageMessage.append("\nExpected usage: java -jar validator.jar ").append(FLAG__INPUT).append(" FILE_OR_URI_1 ... [").append(FLAG__INPUT).append(" FILE_OR_URI_N] [").append(FLAG__NO_REPORTS).append("] [").append(FLAG__LOCALE).append(" LOCALE]");
211216
if (requireType) {
212217
usageMessage.append(" [").append(FLAG__VALIDATION_TYPE).append(" VALIDATION_TYPE]");
213218
parametersMessage.append("\n").append(PAD).append(PAD).append("- VALIDATION_TYPE is the type of validation to perform, one of [").append(String.join("|", domainConfig.getType())).append("].");
@@ -222,6 +227,7 @@ private void printUsage(boolean requireType) {
222227
}
223228
usageMessage.append("\n").append(PAD).append("Where:");
224229
usageMessage.append("\n").append(PAD).append(PAD).append("- FILE_OR_URI_X is the full file path or URI to the content to validate.");
230+
usageMessage.append("\n").append(PAD).append(PAD).append("- LOCALE is the language code to consider for reporting of results. If the provided locale is not supported by the validator the default locale will be used instead (e.g. 'fr', 'fr_FR').");
225231
usageMessage.append(parametersMessage);
226232
usageMessage.append("\n\nThe summary of each validation will be printed and the detailed reports produced in the current directory (as \"report.X.xml\" and \"report.X.pdf\").");
227233
System.out.println(usageMessage);

jsonvalidator-service/src/main/java/eu/europa/ec/itb/json/gitb/ValidationServiceImpl.java

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,12 @@
1111
import eu.europa.ec.itb.validation.commons.FileInfo;
1212
import eu.europa.ec.itb.validation.commons.LocalisationHelper;
1313
import eu.europa.ec.itb.validation.commons.Utils;
14-
import eu.europa.ec.itb.validation.commons.error.ValidatorException;
1514
import eu.europa.ec.itb.validation.commons.artifact.ExternalArtifactSupport;
1615
import eu.europa.ec.itb.validation.commons.artifact.TypedValidationArtifactInfo;
1716
import eu.europa.ec.itb.validation.commons.artifact.ValidationArtifactCombinationApproach;
17+
import eu.europa.ec.itb.validation.commons.error.ValidatorException;
1818
import org.apache.commons.io.FileUtils;
19+
import org.apache.commons.lang3.LocaleUtils;
1920
import org.slf4j.Logger;
2021
import org.slf4j.LoggerFactory;
2122
import org.slf4j.MDC;
@@ -27,10 +28,8 @@
2728
import javax.annotation.Resource;
2829
import javax.jws.WebParam;
2930
import javax.xml.ws.WebServiceContext;
30-
3131
import java.io.File;
3232
import java.util.List;
33-
import java.util.Locale;
3433

3534
/**
3635
* Spring component that realises the validation SOAP service.
@@ -87,6 +86,7 @@ public GetModuleDefinitionResponse getModuleDefinition(@WebParam(name = "GetModu
8786
}
8887
response.getModule().getInputs().getParam().add(Utils.createParameter(ValidationConstants.INPUT_LOCATION_AS_POINTER, "boolean", UsageEnumeration.O, domainConfig.getWebServiceDescription().get(ValidationConstants.INPUT_LOCATION_AS_POINTER)));
8988
response.getModule().getInputs().getParam().add(Utils.createParameter(ValidationConstants.INPUT_ADD_INPUT_TO_REPORT, "boolean", UsageEnumeration.O, ConfigurationType.SIMPLE, domainConfig.getWebServiceDescription().get(ValidationConstants.INPUT_ADD_INPUT_TO_REPORT)));
89+
response.getModule().getInputs().getParam().add(Utils.createParameter(ValidationConstants.INPUT_LOCALE, "string", UsageEnumeration.O, ConfigurationType.SIMPLE, domainConfig.getWebServiceDescription().get(ValidationConstants.INPUT_LOCALE)));
9090
return response;
9191
}
9292

@@ -117,6 +117,7 @@ private boolean definesTypeWithExternalSchemas() {
117117
public ValidationResponse validate(@WebParam(name = "ValidateRequest", targetNamespace = "http://www.gitb.com/vs/v1/", partName = "parameters") ValidateRequest validateRequest) {
118118
MDC.put("domain", domainConfig.getDomain());
119119
File tempFolderPath = fileManager.createTemporaryFolderPath();
120+
var localiser = new LocalisationHelper(domainConfig, Utils.getSupportedLocale(LocaleUtils.toLocale(getInputAsString(validateRequest, ValidationConstants.INPUT_LOCALE, null)), domainConfig));
120121
try {
121122
// Validation of the input data
122123
ValueEmbeddingEnumeration contentEmbeddingMethod = inputHelper.validateContentEmbeddingMethod(validateRequest, ValidationConstants.INPUT_EMBEDDING_METHOD);
@@ -128,15 +129,15 @@ public ValidationResponse validate(@WebParam(name = "ValidateRequest", targetNam
128129
ValidationArtifactCombinationApproach externalSchemaCombinationApproach = validateExternalSchemaCombinationApproach(validateRequest, validationType);
129130
ValidationResponse result = new ValidationResponse();
130131
// Execute validation
131-
JSONValidator validator = ctx.getBean(JSONValidator.class, contentToValidate, validationType, externalSchemas, externalSchemaCombinationApproach, domainConfig, new LocalisationHelper(domainConfig, Locale.ENGLISH), locationAsPointer, addInputToReport);
132+
JSONValidator validator = ctx.getBean(JSONValidator.class, contentToValidate, validationType, externalSchemas, externalSchemaCombinationApproach, domainConfig, localiser, locationAsPointer, addInputToReport);
132133
result.setReport(validator.validate());
133134
return result;
134135
} catch (ValidatorException e) {
135136
logger.error(e.getMessageForLog(), e);
136-
throw new ValidatorException(e.getMessageForDisplay(new LocalisationHelper(Locale.ENGLISH)), true);
137+
throw new ValidatorException(e.getMessageForDisplay(localiser), true);
137138
} catch (Exception e) {
138139
logger.error("Unexpected error", e);
139-
var message = new LocalisationHelper(Locale.ENGLISH).localise(ValidatorException.MESSAGE_DEFAULT);
140+
var message = localiser.localise(ValidatorException.MESSAGE_DEFAULT);
140141
throw new ValidatorException(message, e, true, (Object[]) null);
141142
} finally {
142143
// Cleanup.
@@ -184,6 +185,22 @@ private boolean getInputAsBoolean(ValidateRequest validateRequest, String inputN
184185
return defaultIfMissing;
185186
}
186187

188+
/**
189+
* Get the provided (optional) input as a string value.
190+
*
191+
* @param validateRequest The input parameters.
192+
* @param inputName The name of the input to look for.
193+
* @param defaultIfMissing The default value to use if the input is not provided.
194+
* @return The value to use.
195+
*/
196+
private String getInputAsString(ValidateRequest validateRequest, String inputName, String defaultIfMissing) {
197+
List<AnyContent> input = Utils.getInputFor(validateRequest, inputName);
198+
if (!input.isEmpty()) {
199+
return input.get(0).getValue();
200+
}
201+
return defaultIfMissing;
202+
}
203+
187204
/**
188205
* @return The web service context.
189206
*/

jsonvalidator-service/src/test/java/eu/europa/ec/itb/json/gitb/ValidationServiceImplTest.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,16 @@ void testGetModuleDefinition() {
3434
ValidationConstants.INPUT_EMBEDDING_METHOD, "Description of INPUT_EMBEDDING_METHOD",
3535
ValidationConstants.INPUT_VALIDATION_TYPE, "Description of INPUT_VALIDATION_TYPE",
3636
ValidationConstants.INPUT_LOCATION_AS_POINTER, "Description of INPUT_LOCATION_AS_POINTER",
37-
ValidationConstants.INPUT_ADD_INPUT_TO_REPORT, "Description of INPUT_ADD_INPUT_TO_REPORT"
37+
ValidationConstants.INPUT_ADD_INPUT_TO_REPORT, "Description of INPUT_ADD_INPUT_TO_REPORT",
38+
ValidationConstants.INPUT_LOCALE, "Description of INPUT_LOCALE"
3839
)).when(domainConfig).getWebServiceDescription();
3940
var service = new ValidationServiceImpl(domainConfig);
4041
var result = service.getModuleDefinition(new Void());
4142
assertNotNull(result);
4243
assertNotNull(result.getModule());
4344
assertEquals("service1", result.getModule().getId());
4445
assertNotNull(result.getModule().getInputs());
45-
assertEquals(5, result.getModule().getInputs().getParam().size());
46+
assertEquals(6, result.getModule().getInputs().getParam().size());
4647
assertEquals(ValidationConstants.INPUT_CONTENT, result.getModule().getInputs().getParam().get(0).getName());
4748
assertEquals("Description of INPUT_CONTENT", result.getModule().getInputs().getParam().get(0).getDesc());
4849
assertEquals(UsageEnumeration.R, result.getModule().getInputs().getParam().get(0).getUse());
@@ -57,6 +58,8 @@ void testGetModuleDefinition() {
5758
assertEquals(UsageEnumeration.O, result.getModule().getInputs().getParam().get(3).getUse());
5859
assertEquals("Description of INPUT_ADD_INPUT_TO_REPORT", result.getModule().getInputs().getParam().get(4).getDesc());
5960
assertEquals(UsageEnumeration.O, result.getModule().getInputs().getParam().get(4).getUse());
61+
assertEquals("Description of INPUT_LOCALE", result.getModule().getInputs().getParam().get(5).getDesc());
62+
assertEquals(UsageEnumeration.O, result.getModule().getInputs().getParam().get(5).getUse());
6063
}
6164

6265
}

0 commit comments

Comments
 (0)