• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

kit-data-manager / pit-service / #355

29 Aug 2024 01:11PM UTC coverage: 72.027% (-0.6%) from 72.606%
#355

Pull #218

github

web-flow
Merge 385421b4a into 86457be39
Pull Request #218: Validation speedup experiments

65 of 93 new or added lines in 4 files covered. (69.89%)

4 existing lines in 3 files now uncovered.

860 of 1194 relevant lines covered (72.03%)

0.72 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

85.71
/src/main/java/edu/kit/datamanager/pit/domain/Operations.java
1
package edu.kit.datamanager.pit.domain;
2

3
import java.io.IOException;
4
import java.util.ArrayList;
5
import java.util.Arrays;
6
import java.util.Collection;
7
import java.util.Comparator;
8
import java.util.Date;
9
import java.util.List;
10
import java.util.Optional;
11
import java.util.concurrent.CompletableFuture;
12
import java.util.stream.Collectors;
13

14
import org.apache.commons.lang3.stream.Streams;
15
import org.joda.time.DateTime;
16
import org.joda.time.format.DateTimeFormatter;
17
import org.joda.time.format.ISODateTimeFormat;
18

19
import edu.kit.datamanager.pit.pitservice.ITypingService;
20

21
/**
22
 * Simple operations on PID records.
23
 * 
24
 * Caches results e.g. for type queries
25
 */
26
public class Operations {
27

28
    private static final String[] KNOWN_DATE_CREATED = {
1✔
29
        "21.T11148/29f92bd203dd3eaa5a1f",
30
        "21.T11148/aafd5fb4c7222e2d950a"
31
    };
32

33
    private static final String[] KNOWN_DATE_MODIFIED = {
1✔
34
        "21.T11148/397d831aa3a9d18eb52c"
35
    };
36

37
    private ITypingService typingService;
38

39
    public Operations(ITypingService typingService) {
1✔
40
        this.typingService = typingService;
1✔
41
    }
1✔
42

43
    /**
44
     * Tries to get the date when a FAIR DO was created from a PID record.
45
     * 
46
     * Strategy:
47
     * - try to get it from known "dateCreated" types
48
     * - as a fallback, try to get it by its human readable name
49
     * 
50
     * Semantic reasoning in some sense is planned but not yet supported.
51
     * 
52
     * @param pidRecord the record to extract the information from.
53
     * @return the date, if it could been extracted.
54
     * @throws IOException on IO errors regarding resolving types.
55
     */
56
    public Optional<Date> findDateCreated(PIDRecord pidRecord) throws IOException {
57
        /* try known types */
58
        List<String> knownDateTypes = Arrays.asList(Operations.KNOWN_DATE_CREATED);
1✔
59
        Optional<Date> date = knownDateTypes
1✔
60
            .stream()
1✔
61
            .map(pidRecord::getPropertyValues)
1✔
62
            .map(Arrays::asList)
1✔
63
            .flatMap(List<String>::stream)
1✔
64
            .map(this::extractDate)
1✔
65
            .filter(Optional<Date>::isPresent)
1✔
66
            .map(Optional<Date>::get)
1✔
67
            .sorted(Comparator.comparingLong(Date::getTime))
1✔
68
            .findFirst();
1✔
69
        if (date.isPresent()) {
1✔
70
            return date;
1✔
71
        }
72

73
        /* TODO try to find types extending or relating otherwise to known types
74
         *      (currently not supported by our TypeDefinition) */
75
        Collection<TypeDefinition> types = new ArrayList<>();
1✔
76
        List<CompletableFuture<?>> futures = Streams
1✔
77
                .stream(pidRecord.getPropertyIdentifiers().stream())
1✔
78
                .filter(attributePid -> this.typingService.isIdentifierRegistered(attributePid))
1✔
79
                .map(attributePid -> {
1✔
NEW
80
                    return this.typingService
×
NEW
81
                            .describeType(attributePid)
×
NEW
82
                            .thenAcceptAsync(types::add);
×
83
                })
84
                .collect(Collectors.toList());
1✔
85
        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
1✔
86

87
        /*
88
         * as a last fallback, try find types with human readable names containing
89
         * "dateCreated" or "createdAt" or "creationDate".
90
         * 
91
         * This can be removed as soon as we have some default FAIR DO types new type
92
         * definitions can refer to (e.g. "extend" them or declare the same meaning as
93
         * our known types, see above)
94
         */
95
        return types
1✔
96
            .stream()
1✔
97
            .filter(type -> 
1✔
98
                type.getName().equals("dateCreated")
×
99
                || type.getName().equals("createdAt")
×
100
                || type.getName().equals("creationDate"))
×
101
            .map(type -> pidRecord.getPropertyValues(type.getIdentifier()))
1✔
102
            .map(Arrays::asList)
1✔
103
            .flatMap(List<String>::stream)
1✔
104
            .map(this::extractDate)
1✔
105
            .filter(Optional<Date>::isPresent)
1✔
106
            .map(Optional<Date>::get)
1✔
107
            .sorted(Comparator.comparingLong(Date::getTime))
1✔
108
            .findFirst();
1✔
109
    }
110

111
    /**
112
     * Tries to get the date when a FAIR DO was modified from a PID record.
113
     * 
114
     * Strategy:
115
     * - try to get it from known "dateModified" types
116
     * - as a fallback, try to get it by its human readable name
117
     * 
118
     * Semantic reasoning in some sense is planned but not yet supported.
119
     * 
120
     * @param pidRecord the record to extract the information from.
121
     * @return the date, if it could been extracted.
122
     * @throws IOException on IO errors regarding resolving types.
123
     */
124
    public Optional<Date> findDateModified(PIDRecord pidRecord) throws IOException {
125
        /* try known types */
126
        List<String> knownDateTypes = Arrays.asList(Operations.KNOWN_DATE_MODIFIED);
1✔
127
        Optional<Date> date = knownDateTypes
1✔
128
            .stream()
1✔
129
            .map(pidRecord::getPropertyValues)
1✔
130
            .map(Arrays::asList)
1✔
131
            .flatMap(List<String>::stream)
1✔
132
            .map(this::extractDate)
1✔
133
            .filter(Optional<Date>::isPresent)
1✔
134
            .map(Optional<Date>::get)
1✔
135
            .sorted(Comparator.comparingLong(Date::getTime))
1✔
136
            .findFirst();
1✔
137
        if (date.isPresent()) {
1✔
138
            return date;
1✔
139
        }
140

141
        /* TODO try to find types extending or relating otherwise to known types
142
         *      (currently not supported by our TypeDefinition) */
143
        Collection<TypeDefinition> types = new ArrayList<>();
1✔
144
        List<CompletableFuture<?>> futures = Streams
1✔
145
                .stream(pidRecord.getPropertyIdentifiers().stream())
1✔
146
                .filter(attributePid -> this.typingService.isIdentifierRegistered(attributePid))
1✔
147
                .map(attributePid -> {
1✔
NEW
148
                    return this.typingService
×
NEW
149
                            .describeType(attributePid)
×
NEW
150
                            .thenAcceptAsync(types::add);
×
151
                })
152
                .collect(Collectors.toList());
1✔
153
        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
1✔
154

155
        /*
156
         * as a last fallback, try find types with human readable names containing
157
         * "dateModified" or "lastModified" or "modificationDate".
158
         * 
159
         * This can be removed as soon as we have some default FAIR DO types new type
160
         * definitions can refer to (e.g. "extend" them or declare the same meaning as
161
         * our known types, see above)
162
         */
163
        return types
1✔
164
            .stream()
1✔
165
            .filter(type -> 
1✔
166
                type.getName().equals("dateModified")
×
167
                || type.getName().equals("lastModified")
×
168
                || type.getName().equals("modificationDate"))
×
169
            .map(type -> pidRecord.getPropertyValues(type.getIdentifier()))
1✔
170
            .map(Arrays::asList)
1✔
171
            .flatMap(List<String>::stream)
1✔
172
            .map(this::extractDate)
1✔
173
            .filter(Optional<Date>::isPresent)
1✔
174
            .map(Optional<Date>::get)
1✔
175
            .sorted(Comparator.comparingLong(Date::getTime))
1✔
176
            .findFirst();
1✔
177
    }
178

179
    /**
180
     * Tries to extract a Date object from a String.
181
     * 
182
     * @param dateString the date string to extract the date from.
183
     * @return the extracted Date object.
184
     */
185
    protected Optional<Date> extractDate(String dateString) {
186
        DateTimeFormatter dateFormatter = ISODateTimeFormat.dateTime();
1✔
187
        try {
188
            DateTime dateTime = dateFormatter.parseDateTime(dateString);
1✔
189
            return Optional.of(dateTime.toDate());
1✔
190
        } catch (Exception e) {
1✔
191
            return Optional.empty();
1✔
192
        }
193
    }
194
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc