-
Notifications
You must be signed in to change notification settings - Fork 1
/
DwCOtherDateDQ.java
501 lines (465 loc) · 26.1 KB
/
DwCOtherDateDQ.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
package org.filteredpush.qc.date;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.datakurator.ffdq.annotations.ActedUpon;
import org.datakurator.ffdq.annotations.Amendment;
import org.datakurator.ffdq.annotations.Consulted;
import org.datakurator.ffdq.annotations.Mechanism;
import org.datakurator.ffdq.annotations.Parameter;
import org.datakurator.ffdq.annotations.Provides;
import org.datakurator.ffdq.annotations.ProvidesVersion;
import org.datakurator.ffdq.annotations.Specification;
import org.datakurator.ffdq.annotations.Validation;
import org.datakurator.ffdq.api.DQResponse;
import org.datakurator.ffdq.api.result.AmendmentValue;
import org.datakurator.ffdq.api.result.ComplianceValue;
import org.datakurator.ffdq.model.ResultState;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.HashMap;
import java.util.Map;
/**
* FFDQ tests for Date related concepts in Darwin Core outside of the Event class.
*
* Provides Core TG2 tests:
* #76 VALIDATION_DATEIDENTIFIED_INRANGE dc8aae4b-134f-4d75-8a71-c4186239178e
* #69 VALIDATION_DATEIDENTIFIED_STANDARD 66269bdd-9271-4e76-b25c-7ab81eebe1d8
* #26 AMENDMENT_DATEIDENTIFIED_STANDARDIZED 39bb2280-1215-447b-9221-fd13bc990641
*
* Also provides:
* Date Modified Format Correction (supplemental)
* ModifiedDateValid (supplemental)
*
* @author mole
*
*/
@Mechanism(
value = "urn:uuid:bf5b7706-d0a6-4c65-9644-c750e7188ee0",
label = "Kurator: Date Validator - DwCOtherDateDQ:v3.0.0-SNAPSHOT")
public class DwCOtherDateDQ {
private static final Log logger = LogFactory.getLog(DwCOtherDateDQ.class);
/**
* Is the value of dwc:dateIdentified a valid ISO date?
*
* #69 Validation SingleRecord Conformance: dateidentified notstandard
*
* Provides: VALIDATION_DATEIDENTIFIED_STANDARD
* Version: 2023-03-29
*
* @param dateIdentified the provided dwc:dateIdentified to evaluate
* @return DQResponse the response of type ComplianceValue to return
*/
@Validation(label="VALIDATION_DATEIDENTIFIED_STANDARD", description="Is the value of dwc:dateIdentified a valid ISO date?")
@Provides("66269bdd-9271-4e76-b25c-7ab81eebe1d8")
@ProvidesVersion("https://rs.tdwg.org/bdq/terms/66269bdd-9271-4e76-b25c-7ab81eebe1d8/2023-03-29")
public static DQResponse<ComplianceValue> validationDateidentifiedStandard(@ActedUpon("dwc:dateIdentified") String dateIdentified) {
DQResponse<ComplianceValue> result = new DQResponse<ComplianceValue>();
// Specification
// INTERNAL_PREREQUISITES_NOT_MET if dwc:dateIdentified is
// EMPTY; COMPLIANT if the value of dwc:dateIdentified contains
// a valid ISO 8601-1 date; otherwise NOT_COMPLIANT
if (DateUtils.isEmpty(dateIdentified)) {
result.addComment("No value provided for dwc:dateIdentified.");
result.setResultState(ResultState.INTERNAL_PREREQUISITES_NOT_MET);
} else {
try {
if (DateUtils.eventDateValid(dateIdentified)) {
result.setValue(ComplianceValue.COMPLIANT);
result.addComment("Provided value for dwc:dateIdentified '" + dateIdentified + "' is formated as an ISO date. ");
} else {
result.setValue(ComplianceValue.NOT_COMPLIANT);
result.addComment("Provided value for dwc:dateIdentified '" + dateIdentified + "' is not a validly formatted ISO date .");
}
result.setResultState(ResultState.RUN_HAS_RESULT);
} catch (Exception e) {
logger.debug(e.getMessage());
result.setResultState(ResultState.INTERNAL_PREREQUISITES_NOT_MET);
result.addComment(e.getMessage());
}
}
return result;
}
//
/**
* Is the value of dwc:dateIdentified within Parameter ranges and either overlap or is later than dwc:eventDate?
*
* #76 Validation SingleRecord Likelihood: dateidentified outofrange
* with default values: bdq:earliestVaidDate="1753-01-01"; bdq:latestValidDate=current day
*
* Provides: VALIDATION_DATEIDENTIFIED_INRANGE
* Version: 2023-03-29
*
* @param dateIdentified the provided dwc:dateIdentified to evaluate
* @param eventDate the provided dwc:eventDate to evaluate as preceding dateIdentified
* @return DQResponse the response of type ComplianceValue to return
*/
@Validation(label="VALIDATION_DATEIDENTIFIED_INRANGE", description="Is the value of dwc:dateIdentified within Parameter ranges and either overlap or is later than dwc:eventDate?")
@Provides("dc8aae4b-134f-4d75-8a71-c4186239178e")
@ProvidesVersion("https://rs.tdwg.org/bdq/terms/dc8aae4b-134f-4d75-8a71-c4186239178e/2023-03-29")
public static DQResponse<ComplianceValue> validationDateidentifiedInrange(
@ActedUpon("dwc:dateIdentified") String dateIdentified,
@Consulted("dwc:eventDate") String eventDate
) {
// Parameters. This test is defined as parameterized.
// Default values:
// bdq:earliestValidDate default="1753-01-01"; bdq:latestValidDate default=[current day]; bdq:includeEventDate default=true
String currentDay = LocalDate.now().format(DateTimeFormatter.ISO_LOCAL_DATE);
return DwCOtherDateDQ.validationDateidentifiedInrange(dateIdentified, eventDate, "1753-01-01", currentDay, "true");
}
//TODO: Issue tagged as NEEDS WORK
/**
* Is the value of dwc:dateIdentified within Parameter ranges and either overlap or is later than dwc:eventDate?
*
* #76 Validation SingleRecord Likelihood: dateidentified outofrange
*
* Provides: VALIDATION_DATEIDENTIFIED_INRANGE
* Version: 2023-03-29
*
* @param dateIdentified the provided dwc:dateIdentified to evaluate
* @param eventDate the provided dwc:eventDate to evaluate as preceding dateIdentified
* @param earliestValidDate the earliest dateIdentified considered to be within range
* @param latestValidDate the most recent dateIdentified considered to be within range
* @return DQResponse the response of type ComplianceValue to return
*/
@Validation(label="VALIDATION_DATEIDENTIFIED_INRANGE", description="Is the value of dwc:dateIdentified within Parameter ranges and either overlap or is later than dwc:eventDate?")
@Provides("dc8aae4b-134f-4d75-8a71-c4186239178e")
@ProvidesVersion("https://rs.tdwg.org/bdq/terms/dc8aae4b-134f-4d75-8a71-c4186239178e/2023-03-29")
public static DQResponse<ComplianceValue> validationDateidentifiedInrange(
@ActedUpon("dwc:dateIdentified") String dateIdentified,
@Consulted("dwc:eventDate") String eventDate,
@Parameter(name="bdq:earliestVaidDate") String earliestValidDate,
@Parameter(name="bdq:latestValidDate") String latestValidDate,
@Parameter(name="bdq:includeEventDate") String includeEventDate
) {
// Specification
// INTERNAL_PREREQUISITES_NOT_MET if dwc:dateIdentified is
// EMPTY or contains and invalid value according to ISO 8601-1;
// COMPLIANT if the value of dwc:dateIdentified is between
// bdq:earliestValidDate and bdq:latestValidDate inclusive
// and either (1) dwc:eventDate is EMPTY or bdq:includeEventDate=false
// or (2) if dwc:eventDate is a valid ISO 8601-1 date and dwc:dateIdentified
// overlaps or is later than the dwc:eventDate; otherwise NOT_COMPLIANT
// bdq:sourceAuthority is "ISO 8601-1:2019" [https://www.iso.org/obp/ui/]
// TODO: NEEDS WORK tag on issue, needs to evaluate invalid eventDate as INTERNAL_PREREQUISITES_NOT_MET,
// not NOT_COMPLIANT
// Parameters. This test is defined as parameterized.
// Default values:
// bdq:earliestValidDate default="1753-01-01"; bdq:latestValidDate default=[current day]; bdq:includeEventDate default=true
DQResponse<ComplianceValue> result = new DQResponse<ComplianceValue>();
if (DateUtils.isEmpty(earliestValidDate)) {
earliestValidDate = "1753-01-01";
}
if (DateUtils.isEmpty(earliestValidDate)) {
latestValidDate = LocalDate.now().format(DateTimeFormatter.ISO_LOCAL_DATE);
}
if (DateUtils.isEmpty(includeEventDate)) {
includeEventDate = "true";
}
Boolean includeEventDateBoolean = false;
if (includeEventDate.toLowerCase().equals("true")) {
includeEventDateBoolean = true;
} else if (includeEventDate.toLowerCase().equals("false")) {
includeEventDateBoolean = false;
} else {
result.addComment("Uninterpretable value provided for bdq:includeEventDate, treating as true.");
includeEventDateBoolean = true;
}
String range = earliestValidDate + "/" + latestValidDate;
LocalDateInterval withinInterval = DateUtils.extractInterval(range);
logger.debug(dateIdentified);
logger.debug(eventDate);
if (DateUtils.isEmpty(dateIdentified)) {
// INTERNAL_PREREQUISITES_NOT_MET if dwc:dateIdentified is
// EMPTY
result.addComment("No value provided for dwc:dateIdentified.");
result.setResultState(ResultState.INTERNAL_PREREQUISITES_NOT_MET);
} else if (!DateUtils.eventDateValid(dateIdentified)) {
// INTERNAL_PREREQUISITES_NOT_MET if dwc:dateIdentified is
// ... or contains and invalid value according to ISO 8601-1;
result.addComment("Value provided for dwc:dateIdentified ["+dateIdentified+"] is not a valid date.");
result.setResultState(ResultState.INTERNAL_PREREQUISITES_NOT_MET);
} else if (DateUtils.isEmpty(eventDate) || !includeEventDateBoolean) {
// COMPLIANT if the value of dwc:dateIdentified is between
// bdq:earliestValidDate and bdq:latestValidDate inclusive
// and either (1) dwc:eventDate is EMPTY or bdq:includeEventDate=false
if (DateUtils.isEmpty(eventDate)) {
result.addComment("No valid value provided for dwc:eventDate to compare with dwc:dateIdentified.");
}
LocalDateInterval identifiedInterval = DateUtils.extractInterval(dateIdentified);
if (withinInterval.overlaps(identifiedInterval)) {
result.setValue(ComplianceValue.COMPLIANT);
result.setResultState(ResultState.RUN_HAS_RESULT);
result.addComment("Provided value for dateIdentified [" + dateIdentified + "] overlaps the limits ["+earliestValidDate +"]-["+latestValidDate +"].");
} else {
result.setValue(ComplianceValue.NOT_COMPLIANT);
result.setResultState(ResultState.RUN_HAS_RESULT);
result.addComment("Provided value for dateIdentified [" + dateIdentified + "] is outside the limits ["+earliestValidDate +"]-["+latestValidDate +"].");
}
} else {
LocalDateInterval identifiedInterval = DateUtils.extractInterval(dateIdentified);
// COMPLIANT if the value of dwc:dateIdentified is between
// bdq:earliestValidDate and bdq:latestValidDate inclusive
// and either
// or (2) if dwc:eventDate is a valid ISO 8601-1 date and dwc:dateIdentified
// overlaps or is later than the dwc:eventDate;
if (identifiedInterval==null) {
// INTERNAL_PREREQUISITES_NOT_MET if dwc:dateIdentified is
// ... or contains and invalid value according to ISO 8601-1;
result.addComment("Value provided for dwc:dateIdentified ["+dateIdentified+"] is not a valid date.");
result.setResultState(ResultState.INTERNAL_PREREQUISITES_NOT_MET);
} else if (withinInterval==null) {
// INTERNAL_PREREQUISITES_NOT_MET if dwc:dateIdentified is
// ... or contains and invalid value according to ISO 8601-1;
logger.error("Error Constructing interval from earliest date to latest date");
result.addComment("Error constructing an interpretable earliest/latest date range to test against ["+range+"] .");
result.setResultState(ResultState.INTERNAL_PREREQUISITES_NOT_MET);
} else if (!withinInterval.contains(identifiedInterval)) {
result.setValue(ComplianceValue.NOT_COMPLIANT);
result.setResultState(ResultState.RUN_HAS_RESULT);
result.addComment("Provided value for dateIdentified [" + dateIdentified + "] starts extends beyond the limits ["+earliestValidDate +"]-["+latestValidDate +"].");
} else if (!DateUtils.eventDateValid(eventDate)) {
result.addComment("Provided value for dwc:eventDate ["+eventDate+"] is not a valid date, unable to compare with dwc:dateIdentified.");
result.setResultState(ResultState.RUN_HAS_RESULT);
result.setValue(ComplianceValue.NOT_COMPLIANT);
// Note: changed behavior in v2023-03-29, invalid eventDate is not compliant, not a prerequisites failure.
// result.setResultState(ResultState.INTERNAL_PREREQUISITES_NOT_MET);
} else {
LocalDateInterval eventInterval = DateUtils.extractInterval(eventDate);
if (eventInterval==null) {
result.addComment("Unable to extract date from provided value for dwc:eventDate ["+eventDate+"], unable to compare with dwc:dateIdentified.");
result.setResultState(ResultState.RUN_HAS_RESULT);
result.setValue(ComplianceValue.NOT_COMPLIANT);
// Note: changed behavior in v2023-03-29, invalid eventDate is not compliant, not a prerequisites failure.
// result.setResultState(ResultState.INTERNAL_PREREQUISITES_NOT_MET);
} else if (eventInterval.contains(identifiedInterval)) {
result.setValue(ComplianceValue.COMPLIANT);
result.addComment("Provided value for dateIdentified [" + dateIdentified + "] falls within the eventDate ["+eventDate+"].");
result.setResultState(ResultState.RUN_HAS_RESULT);
} else if (identifiedInterval.getStartDate().isAfter(eventInterval.getEndDate())) {
result.setValue(ComplianceValue.COMPLIANT);
result.addComment("Provided value for dateIdentified [" + dateIdentified + "] is after the end of the eventDate ["+eventDate+"].");;
result.setResultState(ResultState.RUN_HAS_RESULT);
} else if (identifiedInterval.getStartDate().equals(eventInterval.getStartDate())) {
result.setValue(ComplianceValue.COMPLIANT);
result.addComment("Provided value for dateIdentified [" + dateIdentified + "] starts at the same time as the eventDate ["+eventDate+"].");;
result.setResultState(ResultState.RUN_HAS_RESULT);
} else if (identifiedInterval.overlaps(eventInterval)) {
result.setValue(ComplianceValue.COMPLIANT);
result.addComment("Provided value for dateIdentified [" + dateIdentified + "] overlaps the eventDate ["+eventDate+"].");;
result.setResultState(ResultState.RUN_HAS_RESULT);
} else if (identifiedInterval.getEndDate().isBefore(eventInterval.getStartDate())) {
result.setValue(ComplianceValue.NOT_COMPLIANT);
result.addComment("Provided value for dateIdentified [" + dateIdentified + "] ends before the eventDate starts.");
result.setResultState(ResultState.RUN_HAS_RESULT);
} else {
result.setValue(ComplianceValue.NOT_COMPLIANT);
result.addComment("Provided value for dateIdentified [" + dateIdentified + "] is within allowed range but is not more recent than the eventDate ["+eventDate+"].");
result.setResultState(ResultState.RUN_HAS_RESULT);
}
}
}
return result;
}
//TODO: Issue tagged as NEEDS WORK
/**
* Propose amendment to the value of dwc:dateIdentified to a valid ISO date.
*
* #26 Amendment SingleRecord Conformance: dateidentified standardized
*
* Provides: AMENDMENT_DATEIDENTIFIED_STANDARDIZED
* Version: 2023-03-29
*
* @param dateIdentified the provided dwc:dateIdentified to evaluate
* @return DQResponse the response of type AmendmentValue to return
*/
@Amendment(label="AMENDMENT_DATEIDENTIFIED_STANDARDIZED", description="Propose amendment to the value of dwc:dateIdentified to a valid ISO date.")
@Provides("39bb2280-1215-447b-9221-fd13bc990641")
@ProvidesVersion("https://rs.tdwg.org/bdq/terms/39bb2280-1215-447b-9221-fd13bc990641/2023-03-29")
public static DQResponse<AmendmentValue> amendmentDateidentifiedStandardized(@ActedUpon("dwc:dateIdentified") String dateIdentified) {
DQResponse<AmendmentValue> result = new DQResponse<AmendmentValue>();
// Specification
// INTERNAL_PREREQUISITES_NOT_MET if dwc:dateIdentified is
// EMPTY; AMENDED if the value of dwc:dateIdentified was altered
// to unambiguously conform with the ISO 8601-1:2019 date format;
// otherwise NOT_AMENDED
// TODO: The current text is ambiguous and needs to be corrected.
// INTERNAL_PREREQUISITES_NOT_MET if dwc:dateIdentified is
// EMPTY; AMENDED the value of dwc:dateIdentified if it was
// unambiguous and formatted as a valid ISO 8601-1 date; otherwise
// NOT_AMENDED
if (DateUtils.eventDateValid(dateIdentified)) {
result.setResultState(ResultState.NOT_AMENDED);
result.addComment("dwc:dateIdentified contains a correctly formatted date, not changing.");
} else {
if (DateUtils.isEmpty(dateIdentified)) {
result.setResultState(ResultState.INTERNAL_PREREQUISITES_NOT_MET);
result.addComment("dwc:dateIdentified does not contains a value.");
} else {
EventResult extractResponse = DateUtils.extractDateFromVerbatimER(dateIdentified);
if (!extractResponse.getResultState().equals(EventResult.EventQCResultState.NOT_RUN) &&
(extractResponse.getResultState().equals(EventResult.EventQCResultState.RANGE) ||
extractResponse.getResultState().equals(EventResult.EventQCResultState.DATE) ||
extractResponse.getResultState().equals(EventResult.EventQCResultState.AMBIGUOUS) ||
extractResponse.getResultState().equals(EventResult.EventQCResultState.SUSPECT)
)
)
{
Map<String, String> correctedValues = new HashMap<>();
correctedValues.put("dwc:dateIdentified", extractResponse.getResult());
if (extractResponse.getResultState().equals(EventResult.EventQCResultState.AMBIGUOUS)) {
result.setResultState(ResultState.NOT_AMENDED);
// result.setResultState(ResultState.AMBIGUOUS); // Excluded to conform with AMENDMENT_EVENTDATE_STANDARDIZED
result.addComment("Potential interpretation of dwc:dateIdentified [" + dateIdentified + "] as ["+ extractResponse.getResult() +"], but such interpretation is ambiguous." );
result.addComment(extractResponse.getComment());
} else {
if (extractResponse.getResultState().equals(EventResult.EventQCResultState.SUSPECT)) {
result.setResultState(ResultState.NOT_AMENDED);
result.addComment("Potential interpretation of dwc:dateIdentified [" + dateIdentified + "] as ["+ extractResponse.getResult() +"] is suspect.");
result.addComment(extractResponse.getComment());
} else {
result.addComment("Unabmiguous interpretation of dwc:dateIdentified [" + dateIdentified + "] as ["+ extractResponse.getResult() +"].");
result.setResultState(ResultState.AMENDED);
result.setValue(new AmendmentValue(correctedValues));
}
}
} else {
boolean matched = false;
logger.debug(dateIdentified);
if (dateIdentified.matches("^[0-9]{4}.[0-9]{2}.[0-9]{2}$")) {
try {
// try to see if this is yyyy-dd-mm error for yyyy-mm-dd
Integer secondBit = Integer.parseInt(dateIdentified.substring(5,7));
Integer thirdBit = Integer.parseInt(dateIdentified.substring(8));
if (secondBit>12 && thirdBit<12) {
// try switching second and third parts of date.
String toTest = dateIdentified.substring(0, 4).concat("-").concat(dateIdentified.substring(8)).concat("-").concat(dateIdentified.substring(5, 7));
logger.debug(toTest);
LocalDateInterval testingToTest = new LocalDateInterval(toTest);
if (testingToTest!=null && testingToTest.isSingleDay()) {
Map<String, String> correctedValues = new HashMap<>();
correctedValues.put("dwc:dateIdentified", testingToTest.toString());
result.addComment("Unabmiguous interpretation of dwc:dateIdentified [" + dateIdentified + "] as ["+ extractResponse.getResult() +"].");
result.setResultState(ResultState.AMENDED);
result.setValue(new AmendmentValue(correctedValues));
matched = true;
}
}
} catch (Exception e) {
logger.debug(e.getMessage());
}
}
if (!matched) {
EventResult tryVerbatimResult = DateUtils.extractDateFromVerbatimER(dateIdentified);
if (tryVerbatimResult.getResultState().equals(EventResult.EventQCResultState.DATE)) {
Map<String, String> correctedValues = new HashMap<>();
correctedValues.put("dwc:dateIdentified", tryVerbatimResult.getResult());
result.addComment("Unabmiguous interpretation of dwc:dateIdentified [" + dateIdentified + "] as ["+ extractResponse.getResult() +"].");
result.setResultState(ResultState.AMENDED);
result.setValue(new AmendmentValue(correctedValues));
} else {
// per specification, internal prerequisites not met only if empty, failure result is NOT_AMENDED.
result.setResultState(ResultState.NOT_AMENDED);
result.addComment("Unable to extract a date from " + dateIdentified);
}
}
}
}
}
return result;
}
/**
* Given a dateModified, check to see if it is empty or contains a valid date value. If it contains
* a value that is not a valid date, propose a properly formatted dateModified as an amendment.
*
* @param modified dcterms:modified (date last modified) to check
* @return an implementation of DQAmendmentResponse, with a value containing a key for dwc:eventDate and a
* resultState is AMENDED if a new value is proposed.
*/
@Provides(value = "urn:uuid:367bf43f-9cb6-45b2-b45f-b8152f1d334a")
@Amendment(label = "Date Modified Format Correction", description = "Try to propose a correction for a date modified")
@Specification(value = "Check dcterms:modified to see if it is empty or contains a valid date value. If it contains a " +
"value that is not a valid date, propose a properly formatted dcterms:modified as an amendment.")
public static DQResponse<AmendmentValue> correctModifiedDateFormat(@ActedUpon(value = "dcterms:modified") String modified) {
DQResponse<AmendmentValue> result = new DQResponse<>();
if (DateUtils.eventDateValid(modified)) {
result.setResultState(ResultState.NOT_AMENDED);
result.addComment("dcterms:modified contains a correctly formatted date, not changing.");
} else {
if (DateUtils.isEmpty(modified)) {
result.setResultState(ResultState.INTERNAL_PREREQUISITES_NOT_MET);
result.addComment("dcterms:modified does not contains a value.");
} else {
EventResult extractResponse = DateUtils.extractDateFromVerbatimER(modified);
if (!extractResponse.getResultState().equals(EventResult.EventQCResultState.NOT_RUN) &&
(extractResponse.getResultState().equals(EventResult.EventQCResultState.RANGE) ||
extractResponse.getResultState().equals(EventResult.EventQCResultState.DATE) ||
extractResponse.getResultState().equals(EventResult.EventQCResultState.AMBIGUOUS) ||
extractResponse.getResultState().equals(EventResult.EventQCResultState.SUSPECT)
)
)
{
Map<String, String> correctedValues = new HashMap<String, String>();
correctedValues.put("dcterms:modified", extractResponse.getResult());
result.setValue(new AmendmentValue(correctedValues));
if (extractResponse.getResultState().equals(EventResult.EventQCResultState.AMBIGUOUS)) {
result.setResultState(ResultState.AMBIGUOUS);
result.addComment(extractResponse.getComment());
} else {
if (extractResponse.getResultState().equals(EventResult.EventQCResultState.SUSPECT)) {
result.addComment("Interpretation of dcterms:modified [" + modified + "] is suspect.");
result.addComment(extractResponse.getComment());
}
result.setResultState(ResultState.AMENDED);
}
} else {
result.setResultState(ResultState.INTERNAL_PREREQUISITES_NOT_MET);
result.addComment("Unable to extract a date from " + modified);
}
}
}
return result;
}
/**
* Test to see whether a provided dcterms:modified is a validly formated ISO date.
*
* Provides: ModifiedDateValid
*
* @param modified a string to test
* @return COMPLIANT if modified is a validly formated ISO date/time with a duration of less than one day, NOT_COMPLIANT if
* not an ISO date/time or a range of days, INTERNAL_PREREQUSISITES_NOT_MET if modified is empty.
*/
@Provides(value = "urn:uuid:62a9c256-43e4-41ee-8938-d2d2e99479ef") // MODIFIED_DATE_INVALID/MODIFIED_DATE_VALID
@Validation(label = "Modified date correctly formatted", description = "Test to see whether a provided dcterms:modified " +
"is a validly formated ISO date/time.")
@Specification(value = "Compliant if dcterms:modified can to parsed to an explicit date/time, otherwise not compliant. " +
"Internal prerequisites not met if dcterms:modified is empty.")
public static DQResponse<ComplianceValue> isModifiedDateValid(@ActedUpon(value = "dcterms:modified") String modified) {
DQResponse<ComplianceValue> result = new DQResponse<>();
if (DateUtils.isEmpty(modified)) {
result.addComment("No value provided for dcterms:modified.");
result.setResultState(ResultState.INTERNAL_PREREQUISITES_NOT_MET);
} else {
try {
if (DateUtils.eventDateValid(modified) && DateUtils.specificToDay(modified)) {
result.setValue(ComplianceValue.COMPLIANT);
result.addComment("Provided value for dcterms:modified '" + modified + "' is formated as an ISO date tha can be parsed to an explicit date/time ");
} else {
if (!DateUtils.eventDateValid(modified)) {
result.setValue(ComplianceValue.NOT_COMPLIANT);
result.addComment("Provided value for dcterms:modified '" + modified + "' is not a validly formatted ISO date .");
} else {
result.setValue(ComplianceValue.NOT_COMPLIANT);
result.addComment("Provided value for dcterms:modified '" + modified + "' is a validly formatted ISO date, but has a duration of more than one day, modified is expected to be an explicit date/time.");
}
}
result.setResultState(ResultState.RUN_HAS_RESULT);
} catch (Exception e) {
logger.debug(e.getMessage());
result.setResultState(ResultState.INTERNAL_PREREQUISITES_NOT_MET);
result.addComment(e.getMessage());
}
}
return result;
}
}