Skip to content

Commit 630082b

Browse files
committed
Implement according to spec
1 parent 782a489 commit 630082b

File tree

3 files changed

+160
-71
lines changed

3 files changed

+160
-71
lines changed

gbfs-validator-java-api/src/main/java/org/entur/gbfs/validator/api/handler/ValidateApiDelegateHandler.java

Lines changed: 72 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -20,85 +20,109 @@
2020

2121
package org.entur.gbfs.validator.api.handler;
2222

23+
import com.google.common.collect.Multimap;
24+
import com.google.common.collect.MultimapBuilder;
2325
import org.entur.gbfs.validation.GbfsValidator;
2426
import org.entur.gbfs.validation.GbfsValidatorFactory;
2527
import org.entur.gbfs.validation.model.FileValidationError;
2628
import org.entur.gbfs.validation.model.FileValidationResult;
2729
import org.entur.gbfs.validation.model.ValidationResult;
28-
import org.entur.gbfs.validator.api.gen.ValidateOption1ApiDelegate;
30+
import org.entur.gbfs.validator.api.gen.ValidateApiDelegate;
31+
2932
import org.entur.gbfs.validator.api.model.FileError;
30-
import org.entur.gbfs.validator.api.model.FileLangOption1;
31-
import org.entur.gbfs.validator.api.model.FileOption1;
32-
import org.entur.gbfs.validator.api.model.ValidateOption1PostRequest;
33-
import org.entur.gbfs.validator.api.model.ValidationResultOption1;
34-
import org.entur.gbfs.validator.api.model.ValidationResultOption1Summary;
35-
import org.entur.gbfs.validator.api.model.ValidationResultOption1SummaryFilesInner;
33+
import org.entur.gbfs.validator.api.model.GbfsFile;
34+
import org.entur.gbfs.validator.api.model.ValidatePostRequest;
35+
import org.entur.gbfs.validator.api.model.ValidationResultSummary;
36+
import org.entur.gbfs.validator.loader.LoadedFile;
3637
import org.entur.gbfs.validator.loader.Loader;
38+
import org.openapitools.jackson.nullable.JsonNullable;
3739
import org.springframework.http.ResponseEntity;
3840
import org.springframework.stereotype.Service;
3941

42+
import javax.annotation.Nullable;
4043
import java.io.IOException;
4144
import java.io.InputStream;
4245
import java.util.ArrayList;
46+
import java.util.HashMap;
4347
import java.util.List;
4448
import java.util.Map;
4549

4650
@Service
47-
public class ValidateApiDelegateHandler implements ValidateOption1ApiDelegate {
51+
public class ValidateApiDelegateHandler implements ValidateApiDelegate {
4852

4953
@Override
50-
public ResponseEntity<ValidationResultOption1> validateOption1Post(ValidateOption1PostRequest validateOption1PostRequest) {
54+
public ResponseEntity<org.entur.gbfs.validator.api.model.ValidationResult> validatePost(ValidatePostRequest validatePostRequest) {
5155
Loader loader = new Loader();
52-
Map<String, InputStream> fileMap = null;
5356
try {
54-
fileMap = loader.load(validateOption1PostRequest.getFeedUrl());
57+
List<LoadedFile> loadedFiles = loader.load(validatePostRequest.getFeedUrl());
58+
59+
Multimap<String, LoadedFile> fileMap = MultimapBuilder.hashKeys().arrayListValues().build();
60+
for (LoadedFile loadedFile : loadedFiles) {
61+
fileMap.put(loadedFile.language(), loadedFile);
62+
}
63+
64+
GbfsValidator validator = GbfsValidatorFactory.getGbfsJsonValidator();
65+
66+
List<org.entur.gbfs.validator.api.model.ValidationResult> results = new ArrayList<>();
67+
68+
fileMap.keySet().forEach(language -> {
69+
Map<String, InputStream> validatorInputMap = new HashMap<>();
70+
fileMap.get(language).forEach(file -> validatorInputMap.put(file.fileName(), file.fileContents()));
71+
results.add(
72+
mapValidationResult(
73+
validator.validate(
74+
validatorInputMap
75+
),
76+
language
77+
)
78+
);
79+
});
80+
81+
82+
// merge the list of ValidationResult into a single validation result
83+
return ResponseEntity.ok(
84+
mergeValidationResults(results)
85+
);
86+
5587
} catch (IOException e) {
5688
throw new RuntimeException(e);
5789
}
58-
GbfsValidator validator = GbfsValidatorFactory.getGbfsJsonValidator();
59-
return ResponseEntity.ok(
60-
mapValidationResult(validator.validate(fileMap))
61-
);
6290
}
6391

64-
private ValidationResultOption1 mapValidationResult(ValidationResult validationResult) {
65-
ValidationResultOption1Summary validationResultOption1Summary = new ValidationResultOption1Summary();
66-
validationResultOption1Summary.setValidatorVersion("2.0.30-SNAPSHOT"); // TODO inject this value
67-
validationResultOption1Summary.setGbfsVersion(validationResult.summary().version());
68-
validationResultOption1Summary.setFiles(mapFiles(validationResult.files()));
69-
ValidationResultOption1 validationResultOption1 = new ValidationResultOption1();
70-
validationResultOption1.setSummary(validationResultOption1Summary);
92+
private org.entur.gbfs.validator.api.model.ValidationResult mergeValidationResults(List<org.entur.gbfs.validator.api.model.ValidationResult> results) {
93+
org.entur.gbfs.validator.api.model.ValidationResult mergedResult = new org.entur.gbfs.validator.api.model.ValidationResult();
94+
ValidationResultSummary summary = new ValidationResultSummary();
95+
summary.setValidatorVersion(results.get(0).getSummary().getValidatorVersion());
96+
summary.setFiles(new ArrayList<>());
97+
results.forEach(result -> summary.getFiles().addAll(result.getSummary().getFiles()));
98+
mergedResult.setSummary(summary);
99+
return mergedResult;
100+
}
101+
102+
private org.entur.gbfs.validator.api.model.ValidationResult mapValidationResult(ValidationResult validationResult, @Nullable String language) {
103+
ValidationResultSummary validationResultSummary = new ValidationResultSummary();
104+
validationResultSummary.setValidatorVersion("2.0.30-SNAPSHOT"); // TODO inject this value
105+
validationResultSummary.setFiles(mapFiles(validationResult.files(), language));
106+
org.entur.gbfs.validator.api.model.ValidationResult validationResultOption1 = new org.entur.gbfs.validator.api.model.ValidationResult();
107+
validationResultOption1.setSummary(validationResultSummary);
71108
return validationResultOption1;
72109
}
73110

74-
private List<ValidationResultOption1SummaryFilesInner> mapFiles(Map<String, FileValidationResult> files) {
75-
List<ValidationResultOption1SummaryFilesInner> summaryFiles = new ArrayList<>();
76-
files.entrySet().stream().forEach(entry -> {
111+
private List<GbfsFile> mapFiles(Map<String, FileValidationResult> files, @Nullable String language) {
112+
return files.entrySet().stream().map(entry -> {
77113
String fileName = entry.getKey();
78114
FileValidationResult fileValidationResult = entry.getValue();
79115

80-
FileLangOption1 filesInner = new FileLangOption1();
81-
filesInner.setName(fileName);
82-
filesInner.setExists(fileValidationResult.exists());
83-
filesInner.setRequired(fileValidationResult.required());
84-
//filesInner.setRecommended(); // TODO not available
85-
filesInner.setSchema(fileValidationResult.schema());
86-
filesInner.setVersion(fileValidationResult.version());
87-
88-
FileOption1 file = new FileOption1();
89-
file.exists(fileValidationResult.exists());
90-
file.errors(
91-
mapFileErrors(fileValidationResult.errors())
92-
);
93-
file.fileContent(fileValidationResult.fileContents());
94-
95-
96-
filesInner.setFiles(
97-
List.of(file)
98-
);
99-
summaryFiles.add(filesInner);
100-
});
101-
return summaryFiles;
116+
GbfsFile file = new GbfsFile();
117+
file.setName(fileName);
118+
//file.setUrl(); // TODO must be carried from loader
119+
file.setSchema(fileValidationResult.schema());
120+
file.setVersion(fileValidationResult.version());
121+
file.setLanguage(JsonNullable.of(language));
122+
file.setErrors(mapFileErrors(fileValidationResult.errors()));
123+
return file;
124+
}).toList();
125+
102126
}
103127

104128
private List<FileError> mapFileErrors(List<FileValidationError> errors) {
@@ -108,7 +132,7 @@ private List<FileError> mapFileErrors(List<FileValidationError> errors) {
108132
mapped.setInstancePath(error.violationPath());
109133
mapped.setSchemaPath(error.schemaPath());
110134
//mapped.setParams(error.); // TODO no source?
111-
//mapped.setKeyword(error.); // TODO no source?
135+
//mapped.setKeyword(error.); // TODO get from source
112136
return mapped;
113137
}).toList();
114138
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
*
3+
* *
4+
* *
5+
* * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by
6+
* * * the European Commission - subsequent versions of the EUPL (the "Licence");
7+
* * * You may not use this work except in compliance with the Licence.
8+
* * * You may obtain a copy of the Licence at:
9+
* * *
10+
* * * https://joinup.ec.europa.eu/software/page/eupl
11+
* * *
12+
* * * Unless required by applicable law or agreed to in writing, software
13+
* * * distributed under the Licence is distributed on an "AS IS" basis,
14+
* * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* * * See the Licence for the specific language governing permissions and
16+
* * * limitations under the Licence.
17+
* *
18+
*
19+
*/
20+
21+
package org.entur.gbfs.validator.loader;
22+
23+
import javax.annotation.Nullable;
24+
import java.io.InputStream;
25+
26+
public record LoadedFile(
27+
String fileName,
28+
InputStream fileContents,
29+
@Nullable String language
30+
) {
31+
public LoadedFile(String fileName, InputStream fileContents) {
32+
this(fileName, fileContents, null);
33+
}
34+
}

gbfs-validator-java-loader/src/main/java/org/entur/gbfs/validator/loader/Loader.java

Lines changed: 54 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020

2121
package org.entur.gbfs.validator.loader;
2222

23-
import org.json.JSONArray;
2423
import org.json.JSONObject;
2524
import org.json.JSONTokener;
2625

@@ -36,51 +35,83 @@
3635
import java.net.HttpURLConnection;
3736
import java.net.URI;
3837
import java.net.URL;
38+
import java.util.ArrayList;
3939
import java.util.HashMap;
40-
import java.util.Map;
40+
import java.util.List;
4141

4242
public class Loader {
4343

44-
public Map<String, InputStream> load(String discoveryURI) throws IOException {
45-
Map<String, InputStream> result = new HashMap<>();
44+
public List<LoadedFile> load(String discoveryURI) throws IOException {
4645
InputStream discoveryFileStream = loadFile(URI.create(discoveryURI));
4746

4847
ByteArrayOutputStream discoveryFileCopy = new ByteArrayOutputStream();
4948
org.apache.commons.io.IOUtils.copy(discoveryFileStream, discoveryFileCopy);
5049
byte[] discoveryFileBytes = discoveryFileCopy.toByteArray();
5150

52-
result.put("gbfs", new ByteArrayInputStream(discoveryFileBytes));
53-
5451
JSONObject discoveryFile = new JSONObject(new JSONTokener(new ByteArrayInputStream(discoveryFileBytes)));
5552

5653
String version = (String) discoveryFile.get("version");
5754

58-
JSONArray files;
55+
List<LoadedFile> loadedFiles = new ArrayList<>();
56+
57+
5958

6059
if (version.matches("^3\\.\\d")) {
61-
files = getV3Files(discoveryFile);
60+
loadedFiles.addAll(getV3Files(discoveryFile, discoveryFileBytes));
6261
} else {
63-
files = getPreV3Files(discoveryFile);
62+
loadedFiles.addAll(getPreV3Files(discoveryFile, discoveryFileBytes));
6463
}
6564

66-
files.forEach(file -> {
67-
JSONObject fileObj = (JSONObject) file;
68-
String fileName = (String) fileObj.get("name");
69-
String fileURL = (String) fileObj.get("url");
70-
InputStream fileStream = loadFile(URI.create(fileURL));
71-
result.put(fileName, fileStream);
72-
});
73-
74-
return result;
65+
return loadedFiles;
7566
}
7667

77-
private JSONArray getV3Files(JSONObject discoveryFile) {
78-
return discoveryFile.getJSONObject("data").getJSONArray("feeds");
68+
private List<LoadedFile> getV3Files(JSONObject discoveryFile, byte[] discoveryFileBytes) {
69+
List<LoadedFile> loadedFiles = new ArrayList<>();
70+
loadedFiles.add(
71+
new LoadedFile(
72+
"discovery",
73+
new ByteArrayInputStream(discoveryFileBytes)
74+
));
75+
76+
loadedFiles.addAll(
77+
discoveryFile.getJSONObject("data").getJSONArray("feeds").toList().stream().map(feed -> {
78+
var feedObj = (HashMap) feed;
79+
var file = loadFile(URI.create((String) feedObj.get("url")));
80+
return new LoadedFile(
81+
(String) feedObj.get("name"),
82+
file
83+
);
84+
}).toList());
85+
86+
return loadedFiles;
7987
}
8088

81-
private JSONArray getPreV3Files(JSONObject discoveryFile) {
82-
String firstLanguageKey = discoveryFile.getJSONObject("data").keys().next();
83-
return discoveryFile.getJSONObject("data").getJSONObject(firstLanguageKey).getJSONArray("feeds");
89+
private List<LoadedFile> getPreV3Files(JSONObject discoveryFile, byte[] discoveryFileBytes) {
90+
List<LoadedFile> result = new ArrayList<>();
91+
discoveryFile.getJSONObject("data")
92+
.keys()
93+
.forEachRemaining(key -> {
94+
result.add(
95+
new LoadedFile(
96+
"discovery",
97+
new ByteArrayInputStream(discoveryFileBytes),
98+
key
99+
)
100+
);
101+
discoveryFile.getJSONObject("data").getJSONObject(key).getJSONArray("feeds").toList().forEach(feed -> {
102+
var feedObj = (HashMap) feed;
103+
var file = loadFile(URI.create((String) feedObj.get("url")));
104+
result.add(
105+
new LoadedFile(
106+
(String) feedObj.get("name"),
107+
file,
108+
key
109+
)
110+
);
111+
});
112+
});
113+
114+
return result;
84115
}
85116

86117
private InputStream loadFile(URI fileURI) {

0 commit comments

Comments
 (0)