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

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

29 Aug 2024 12:53PM UTC coverage: 72.027% (-0.6%) from 72.606%
#354

Pull #218

github

web-flow
Merge efb4bf5b4 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

90.48
/src/main/java/edu/kit/datamanager/pit/typeregistry/impl/TypeRegistry.java
1
package edu.kit.datamanager.pit.typeregistry.impl;
2

3
import java.io.IOException;
4
import java.util.Date;
5
import java.util.List;
6
import java.util.Map;
7

8
import com.fasterxml.jackson.core.JsonProcessingException;
9
import com.fasterxml.jackson.databind.JsonNode;
10
import com.fasterxml.jackson.databind.ObjectMapper;
11
import com.github.benmanes.caffeine.cache.AsyncLoadingCache;
12
import edu.kit.datamanager.pit.configuration.ApplicationProperties;
13
import edu.kit.datamanager.pit.domain.ProvenanceInformation;
14
import edu.kit.datamanager.pit.domain.TypeDefinition;
15
import edu.kit.datamanager.pit.typeregistry.ITypeRegistry;
16
import java.net.URISyntaxException;
17
import java.time.Instant;
18
import java.time.format.DateTimeParseException;
19
import java.util.concurrent.*;
20
import java.util.stream.Collectors;
21
import java.util.stream.StreamSupport;
22

23
import org.apache.commons.lang3.stream.Streams;
24
import org.slf4j.Logger;
25
import org.slf4j.LoggerFactory;
26
import org.springframework.beans.factory.annotation.Autowired;
27
import org.springframework.http.HttpEntity;
28
import org.springframework.http.HttpMethod;
29
import org.springframework.http.ResponseEntity;
30
import org.springframework.web.client.RestTemplate;
31
import org.springframework.web.util.UriComponentsBuilder;
32

33
/**
34
 * Accessor for a specific instance of a TypeRegistry. The TypeRegistry is
35
 * uniquely identified by a baseUrl and an identifierPrefix which all types of
36
 * this particular registry are using. The prefix also allows to determine,
37
 * whether a given PID might be a type or property registered at this
38
 * TypeRegistry.
39
 */
40
public class TypeRegistry implements ITypeRegistry {
1✔
41

42
    private static final Logger LOG = LoggerFactory.getLogger(TypeRegistry.class);
1✔
43

44
    @Autowired
45
    public AsyncLoadingCache<String, TypeDefinition> typeCache;
46
    @Autowired
47
    private ApplicationProperties applicationProperties;
48

49
    protected RestTemplate restTemplate = new RestTemplate();
1✔
50

51
    @Override
52
    public TypeDefinition queryTypeDefinition(String typeIdentifier) throws IOException, URISyntaxException {
53
        LOG.trace("Performing queryTypeDefinition({}).", typeIdentifier);
1✔
54
        String[] segments = typeIdentifier.split("/");
1✔
55
        UriComponentsBuilder uriBuilder = UriComponentsBuilder
1✔
56
                .fromUri(
1✔
57
                        applicationProperties
58
                                .getHandleBaseUri()
1✔
59
                                .toURI())
1✔
60
                .pathSegment(segments);
1✔
61
        LOG.trace("Querying for type definition at URI {}.", uriBuilder);
1✔
62
        ResponseEntity<String> response = restTemplate.exchange(uriBuilder.build().toUri(), HttpMethod.GET,
1✔
63
                HttpEntity.EMPTY, String.class);
64
        ObjectMapper mapper = new ObjectMapper();
1✔
65
        JsonNode rootNode = mapper.readTree(response.getBody());
1✔
66
        LOG.trace("Constructing type definition from response.");
1✔
67
        return constructTypeDefinition(rootNode);
1✔
68
    }
69

70
    /**
71
     * Helper method to construct a type definition from a JSON response
72
     * received from the TypeRegistry.
73
     *
74
     * @param registryRepresentation The type definition.
75
     * @return The TypeDefinition as object.
76
     */
77
    private TypeDefinition constructTypeDefinition(JsonNode registryRepresentation)
78
            throws JsonProcessingException, IOException, URISyntaxException {
79
        // TODO We are doing things too complicated here. Deserialization should be
80
        // easy.
81
        // But before we change the domain model to do so, we need a lot of tests to
82
        // make sure things work as before after the changes.
83
        LOG.trace("Performing constructTypeDefinition(<rootNode>).");
1✔
84
        final String identifier = registryRepresentation.path("identifier").asText(null);
1✔
85
        if (identifier == null) {
1✔
NEW
86
            LOG.error("No 'identifier' property found in entry: {}", registryRepresentation);
×
UNCOV
87
            throw new IOException("No 'identifier' attribute found in type definition.");
×
88
        }
89

90
        LOG.trace("Checking for 'properties' attribute.");
1✔
91
        Map<String, TypeDefinition> properties = new ConcurrentHashMap<>();
1✔
92
        List<CompletableFuture<?>> propertiesHandling = Streams.stream(StreamSupport.stream(
1✔
93
                        registryRepresentation.path("properties").spliterator(), false))
1✔
94
                .filter(property -> property.hasNonNull("name"))
1✔
95
                .filter(property -> property.hasNonNull("identifier"))
1✔
96
                .map(property -> {
1✔
97
                    final String name = property.path("name").asText();
1✔
98
                    final String pid = property.path("identifier").asText();
1✔
99
                    return typeCache.get(pid).thenAcceptAsync(
1✔
100
                            typeDefinition -> {
101
                                final JsonNode semantics = property.path("representationsAndSemantics").path(0);
1✔
102
                                final String expression = semantics.path("expression").asText(null);
1✔
103
                                typeDefinition.setExpression(expression);
1✔
104
                                final String value = semantics.path("value").asText(null);
1✔
105
                                typeDefinition.setValue(value);
1✔
106
                                final String obligation = semantics.path("obligation").asText("Mandatory");
1✔
107
                                typeDefinition.setOptional("Optional".equalsIgnoreCase(obligation));
1✔
108
                                final String repeatable = semantics.path("repeatable").asText("No");
1✔
109
                                typeDefinition.setRepeatable(!"No".equalsIgnoreCase(repeatable));
1✔
110
                                properties.put(name, typeDefinition);
1✔
111
                            });
1✔
112
                })
113
                .collect(Collectors.toList());
1✔
114

115
        TypeDefinition result = new TypeDefinition();
1✔
116
        result.setIdentifier(identifier);
1✔
117
        final String description = registryRepresentation.path("description").asText(null);
1✔
118
        result.setDescription(description);
1✔
119
        final String name = registryRepresentation.path("name").asText(null);
1✔
120
        result.setName(name);
1✔
121
        final String validationSchema = registryRepresentation.path("validationSchema").asText(null);
1✔
122
        result.setSchema(validationSchema);
1✔
123

124
        if (registryRepresentation.has("provenance")) {
1✔
125
            ProvenanceInformation prov = new ProvenanceInformation();
1✔
126
            JsonNode provNode = registryRepresentation.get("provenance");
1✔
127
            if (provNode.has("creationDate")) {
1✔
128
                String creationDate = provNode.get("creationDate").asText();
1✔
129
                try {
130
                    prov.setCreationDate(Date.from(Instant.parse(creationDate)));
1✔
131
                } catch (DateTimeParseException ex) {
×
132
                    LOG.error("Failed to parse creationDate from value " + creationDate + ".", ex);
×
133
                }
1✔
134
            }
135
            if (provNode.has("lastModificationDate")) {
1✔
136
                String lastModificationDate = provNode.get("lastModificationDate").asText();
1✔
137
                try {
138
                    prov.setLastModificationDate(Date.from(Instant.parse(lastModificationDate)));
1✔
139
                } catch (DateTimeParseException ex) {
×
140
                    LOG.error("Failed to parse lastModificationDate from value " + lastModificationDate + ".", ex);
×
141
                }
1✔
142
            }
143
            for (JsonNode entryKV : provNode.get("contributors")) {
1✔
144
                String identified = null;
1✔
145
                String contributorName = null;
1✔
146
                String details = null;
1✔
147

148
                if (registryRepresentation.has("identifiedBy")) {
1✔
149
                    identified = entryKV.get("identifiedBy").asText();
×
150
                }
151
                if (registryRepresentation.has("name")) {
1✔
152
                    contributorName = entryKV.get("name").asText();
1✔
153
                }
154
                if (registryRepresentation.has("details")) {
1✔
155
                    details = entryKV.get("details").asText();
×
156
                }
157
                prov.addContributor(identified, contributorName, details);
1✔
158
            }
1✔
159
            result.setProvenance(prov);
1✔
160
        }
161

162
        LOG.trace("Finalizing and returning type definition.");
1✔
163
        CompletableFuture.allOf(propertiesHandling.toArray(new CompletableFuture<?>[0])).join();
1✔
164
        properties.keySet().forEach(pd -> result.addSubType(properties.get(pd)));
1✔
165
        this.typeCache.put(identifier, CompletableFuture.completedFuture(result));
1✔
166
        return result;
1✔
167
    }
168
}
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

© 2025 Coveralls, Inc