Skip to content

Commit fb8a86b

Browse files
authored
Merge pull request #7 from marmoure/web/views
Adds validation View and some code fixes
2 parents 9ef2dfc + 6f04bd2 commit fb8a86b

27 files changed

Lines changed: 1595 additions & 164 deletions

README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,16 @@ mvn clean compile
1212
```bash
1313
mvn mn:run
1414
```
15+
16+
## Using Docker:
17+
18+
```bash
19+
mvn clean install
20+
```
21+
Use the absolute path to the schemas directory when running the docker container.
22+
23+
```bash
24+
docker run -p 8080:8080 -v /path/to/schemas:/app/schemas:ro evolvedbinary/bbl-validator:1.0.0-SNAPSHOT
25+
```
26+
27+

pom.xml

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,20 @@
7777
<version>3.9.1</version>
7878
</dependency>
7979

80+
<!-- Micronaut view render -->
81+
<dependency>
82+
<groupId>io.micronaut.views</groupId>
83+
<artifactId>micronaut-views-core</artifactId>
84+
<version>5.9.0</version>
85+
</dependency>
86+
87+
<!-- Velocity template engine -->
88+
<dependency>
89+
<groupId>io.micronaut.views</groupId>
90+
<artifactId>micronaut-views-velocity</artifactId>
91+
<version>5.9.0</version>
92+
</dependency>
93+
8094
<!-- Logback for logging -->
8195
<dependency>
8296
<groupId>ch.qos.logback</groupId>
@@ -226,6 +240,42 @@
226240
<shared>true</shared>
227241
</configuration>
228242
</plugin>
243+
<plugin>
244+
<groupId>io.fabric8</groupId>
245+
<artifactId>docker-maven-plugin</artifactId>
246+
<version>0.46.0</version>
247+
<configuration>
248+
<verbose>true</verbose>
249+
<images>
250+
<image>
251+
<name>evolvedbinary/bbl-validator:%v</name>
252+
<build>
253+
<dockerFile>${project.build.outputDirectory}/Dockerfile</dockerFile>
254+
<assembly>
255+
<mode>dir</mode>
256+
<inline>
257+
<files>
258+
<file>
259+
<source>${project.build.directory}/${project.build.finalName}.jar</source>
260+
<destName>bbl-validator-${project.version}.jar</destName>
261+
</file>
262+
</files>
263+
</inline>
264+
</assembly>
265+
</build>
266+
</image>
267+
</images>
268+
</configuration>
269+
<executions>
270+
<execution>
271+
<id>default</id>
272+
<phase>install</phase>
273+
<goals>
274+
<goal>build</goal>
275+
</goals>
276+
</execution>
277+
</executions>
278+
</plugin>
229279
</plugins>
230280
</build>
231281
</project>

src/main/java/com/evolvedbinary/bblValidator/controller/SchemaController.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public HttpResponse<Object> getSchema(@PathVariable("schema-id") final String sc
4141
final String schema = schemaService.getSchema(schemaId);
4242
if (schema == null) {
4343
return HttpResponse
44-
.badRequest()
44+
.notFound()
4545
.contentType(MediaType.APPLICATION_JSON_TYPE)
4646
.body(new ErrorResponse(ErrorResponse.Code.SCHEMA_NOT_FOUND,"Schema not found with ID: " + schemaId));
4747
}

src/main/java/com/evolvedbinary/bblValidator/controller/ValidateController.java

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -77,18 +77,18 @@ public HttpResponse<ResponseObject> validateCsv(@QueryValue("schema-id") final S
7777
if (csvContent == null || csvContent.isEmpty()) {
7878
return HttpResponse.badRequest().body(new ErrorResponse(ErrorResponse.Code.NO_CSV,"Empty CSV content"));
7979
}
80-
try {
81-
final Path tempFile = fileDownloadService.saveContentToTemp(csvContent);
8280
try {
83-
LOG.trace("CSV content saved to: {}", tempFile);
84-
return HttpResponse.ok(performValidation(tempFile, schemaId));
85-
} finally {
86-
Files.delete(tempFile);
81+
final Path tempFile = fileDownloadService.saveContentToTemp(csvContent);
82+
try {
83+
LOG.trace("CSV content saved to: {}", tempFile);
84+
return HttpResponse.ok(performValidation(tempFile, schemaId));
85+
} finally {
86+
Files.delete(tempFile);
87+
}
88+
} catch (final IOException e) {
89+
LOG.error("Failed to save CSV content to temp file", e);
90+
return HttpResponse.serverError().body(new ErrorResponse(ErrorResponse.Code.UNEXPECTED_ERROR,"Unable to store CSV: " + e.getMessage()));
8791
}
88-
} catch (final IOException e) {
89-
LOG.error("Failed to save CSV content to temp file", e);
90-
return HttpResponse.serverError().body(new ErrorResponse(ErrorResponse.Code.UNEXPECTED_ERROR,"Unable to store CSV: " + e.getMessage()));
91-
}
9292
}
9393

9494
/**
@@ -122,10 +122,6 @@ public HttpResponse<ResponseObject> validateParams(@QueryValue("schema-id") fina
122122
private ResponseObject performValidation(final Path csvFile, final String schemaId) {
123123
final CsvValidationService.ValidationResult result = csvValidationService.validateCsvFile(csvFile, schemaId);
124124

125-
if (result.hasErrorMessage()) {
126-
return new ErrorResponse(ErrorResponse.Code.VALIDATION_ERROR,"An error occurred: " + result.getErrorMessage());
127-
}
128-
129-
return new ValidationResponse(result.isValid(), result.getErrors(), result.getExecutionTimeMs());
125+
return new ValidationResponse(result.isPassed(), result.getFailures(), result.getExecutionTime(), result.isUtf8Valid());
130126
}
131127
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
package com.evolvedbinary.bblValidator.controller;
2+
3+
import com.evolvedbinary.bblValidator.dto.ErrorResponse;
4+
import com.evolvedbinary.bblValidator.dto.ValidationFailure;
5+
import com.evolvedbinary.bblValidator.dto.ValidationResponse;
6+
import com.evolvedbinary.bblValidator.service.CsvValidationService;
7+
import com.evolvedbinary.bblValidator.service.FileDownloadService;
8+
import com.evolvedbinary.bblValidator.service.SchemaService;
9+
import io.micronaut.context.annotation.Value;
10+
import io.micronaut.http.MediaType;
11+
import io.micronaut.http.annotation.Body;
12+
import io.micronaut.http.annotation.Controller;
13+
import io.micronaut.http.annotation.Get;
14+
import io.micronaut.http.annotation.Post;
15+
import io.micronaut.views.View;
16+
import jakarta.inject.Inject;
17+
import org.slf4j.Logger;
18+
import org.slf4j.LoggerFactory;
19+
20+
import java.io.IOException;
21+
import java.nio.file.Files;
22+
import java.nio.file.Path;
23+
import java.util.ArrayList;
24+
import java.util.HashMap;
25+
import java.util.List;
26+
import java.util.Map;
27+
28+
@Controller("/views")
29+
public class ValidationViewController {
30+
31+
@Inject
32+
CsvValidationService csvValidationService;
33+
@Inject
34+
FileDownloadService fileDownloadService;
35+
@Inject
36+
SchemaService schemaService;
37+
38+
@Value("${api.version}")
39+
String version;
40+
41+
@View("validate")
42+
@Get("/validate")
43+
public Map<String, Object> validate() {
44+
final Map<String, Object> model = new HashMap<>();
45+
model.put("version", version);
46+
model.put("schemas", schemaService.listSchemas());
47+
model.put("csvSource", "url");
48+
return model;
49+
}
50+
51+
@View("validate")
52+
@Post(value = "/validate", consumes = MediaType.APPLICATION_FORM_URLENCODED)
53+
public Map<String, Object> validateSubmit(@Body final Map<String, String> formData) {
54+
final String schemaId = formData.get("schemaId");
55+
final String csvSource = formData.get("csvSource");
56+
final String csvUrl = formData.get("csvUrl");
57+
final String csvContent = formData.get("csvContent");
58+
59+
final Map<String, Object> model = new HashMap<>();
60+
model.put("version", version);
61+
model.put("schemas", schemaService.listSchemas());
62+
model.put("schemaId", schemaId);
63+
model.put("csvSource", csvSource);
64+
model.put("csvUrl", csvUrl);
65+
model.put("csvContent", csvContent);
66+
67+
68+
if ((csvContent == null || csvContent.isEmpty()) && (csvUrl == null || csvUrl.isEmpty())) {
69+
model.put("error", new ErrorResponse(ErrorResponse.Code.NO_CSV, "Please provide either CSV content or CSV URL"));
70+
return model;
71+
}
72+
73+
final boolean isUrl = csvSource.equals("url");
74+
75+
try {
76+
final Path tempFile = isUrl ? fileDownloadService.downloadToTemp(csvUrl) : fileDownloadService.saveContentToTemp(csvContent);
77+
try {
78+
final CsvValidationService.ValidationResult result = csvValidationService.validateCsvFile(tempFile, schemaId);
79+
model.put("result", new ValidationResponse(result.isPassed(), result.getFailures(), result.getExecutionTime(), result.isUtf8Valid()));
80+
model.put("errorsTable", getErrorsTable(result.getFailures()));
81+
} finally {
82+
Files.delete(tempFile);
83+
}
84+
} catch (final IOException e) {
85+
model.put("error", new ErrorResponse(ErrorResponse.Code.UNEXPECTED_ERROR, "Internal error processing CSV: " + e.getMessage()));
86+
}
87+
88+
return model;
89+
}
90+
91+
private List<String> getErrorsTable(final List<ValidationFailure> failures) {
92+
final List<String> table = new ArrayList<>();
93+
for (final ValidationFailure failure : failures) {
94+
table.add(failure.getMessage());
95+
}
96+
return table;
97+
}
98+
}

src/main/java/com/evolvedbinary/bblValidator/dto/ValidationError.java

Lines changed: 0 additions & 33 deletions
This file was deleted.
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.evolvedbinary.bblValidator.dto;
2+
3+
import io.micronaut.serde.annotation.Serdeable;
4+
5+
/**
6+
* Data transfer object representing a validation failure with location information.
7+
*/
8+
@Serdeable
9+
public class ValidationFailure {
10+
11+
private final String message;
12+
private final int line;
13+
private final int column;
14+
15+
public ValidationFailure(final String message, final int line, final int column) {
16+
this.message = message;
17+
this.line = line;
18+
this.column = column;
19+
}
20+
21+
public String getMessage() {
22+
return message;
23+
}
24+
25+
public int getLine() {
26+
return line;
27+
}
28+
29+
public int getColumn() {
30+
return column;
31+
}
32+
33+
}

src/main/java/com/evolvedbinary/bblValidator/dto/ValidationResponse.java

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,28 +11,33 @@
1111
@Serdeable
1212
public final class ValidationResponse implements ResponseObject {
1313

14-
private final boolean valid;
15-
private final List<ValidationError> errors;
16-
private final long executionTimeMs;
17-
18-
public ValidationResponse(final boolean valid,
19-
final List<ValidationError> errors,
20-
final long executionTimeMs) {
21-
this.executionTimeMs = executionTimeMs;
22-
this.valid = valid;
23-
this.errors = errors != null ? errors : Collections.emptyList();
14+
private final boolean passed;
15+
private final List<ValidationFailure> failures;
16+
private final long executionTime;
17+
private final boolean utf8Valid;
18+
19+
public ValidationResponse(final boolean passed,
20+
final List<ValidationFailure> failures,
21+
final long executionTime,
22+
final boolean utf8Valid) {
23+
this.executionTime = executionTime;
24+
this.passed = passed;
25+
this.failures = failures != null ? failures : Collections.emptyList();
26+
this.utf8Valid = utf8Valid;
2427
}
2528

26-
public boolean isValid() {
27-
return valid;
28-
}
29+
public boolean isPassed() {
30+
return passed;
31+
}
2932

30-
public List<ValidationError> getErrors() {
31-
return errors;
33+
public List<ValidationFailure> getFailures() {
34+
return failures;
3235
}
3336

34-
public long getExecutionTimeMs() {
35-
return executionTimeMs;
37+
public long getExecutionTime() {
38+
return executionTime;
3639
}
3740

41+
public boolean isUtf8Valid() { return utf8Valid; }
42+
3843
}

0 commit comments

Comments
 (0)