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

kit-data-manager / ro-crate-java / #419

05 May 2025 08:11AM UTC coverage: 90.169% (+0.8%) from 89.357%
#419

Pull #255

github

web-flow
Merge pull request #256 from kit-data-manager/make-spec-examples-executable

Make specification examples (from readme) executable
Pull Request #255: Next Version (v2.1.0-rc2 | v2.1.0)

63 of 70 new or added lines in 16 files covered. (90.0%)

14 existing lines in 5 files now uncovered.

1917 of 2126 relevant lines covered (90.17%)

0.9 hits per line

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

96.55
/src/main/java/edu/kit/datamanager/ro_crate/context/RoCrateMetadataContext.java
1
package edu.kit.datamanager.ro_crate.context;
2

3
import com.fasterxml.jackson.core.type.TypeReference;
4
import com.fasterxml.jackson.databind.JsonNode;
5
import com.fasterxml.jackson.databind.ObjectMapper;
6
import com.fasterxml.jackson.databind.node.ArrayNode;
7
import com.fasterxml.jackson.databind.node.ObjectNode;
8

9
import edu.kit.datamanager.ro_crate.entities.AbstractEntity;
10
import edu.kit.datamanager.ro_crate.objectmapper.MyObjectMapper;
11

12
import java.io.IOException;
13
import java.util.*;
14
import java.util.function.Consumer;
15

16
import edu.kit.datamanager.ro_crate.special.IdentifierUtils;
17
import org.apache.http.client.methods.CloseableHttpResponse;
18
import org.apache.http.client.methods.HttpGet;
19
import org.apache.http.impl.client.CloseableHttpClient;
20
import org.apache.http.impl.client.HttpClients;
21

22
/**
23
 * The class representing the crate json-ld context.
24
 *
25
 * @author Nikola Tzotchev on 6.2.2022 г.
26
 * @version 1
27
 */
28
public class RoCrateMetadataContext implements CrateMetadataContext {
29

30
  public static final String DEFAULT_CONTEXT = "https://w3id.org/ro/crate/1.1/context";
31
  protected static final String DEFAULT_CONTEXT_LOCATION = "default_context/version1.1.json";
32
  protected static JsonNode defaultContext = null;
1✔
33

34
  protected final Set<String> urls = new HashSet<>();
1✔
35
  protected final HashMap<String, String> contextMap = new HashMap<>();
1✔
36
  // we need to keep the ones that are no coming from url
37
  // for the final representation
38
  protected final HashMap<String, String> other = new HashMap<>();
1✔
39

40
  /**
41
   * Default constructor for the creation of the default context.
42
   */
43
  public RoCrateMetadataContext() {
1✔
44
    this.addToContextFromUrl(DEFAULT_CONTEXT);
1✔
45
  }
1✔
46

47
  /**
48
   * Constructor for creating the context from a list of url.
49
   *
50
   * @param urls the url list with different context.
51
   */
52
  public RoCrateMetadataContext(Collection<String> urls) {
1✔
53
    urls.forEach(this::addToContextFromUrl);
1✔
54
  }
1✔
55

56
  /**
57
   * Constructor for creating the context from a json object.
58
   *
59
   * @param context the Json object of the context.
60
   */
61
  public RoCrateMetadataContext(JsonNode context) {
1✔
62

63
    Consumer<JsonNode> addPairs = x -> {
1✔
64
      var iterate = x.fields();
1✔
65
      while (iterate.hasNext()) {
1✔
66
        var next = iterate.next();
1✔
67
        this.other.put(next.getKey(), next.getValue().asText());
1✔
68
        this.contextMap.put(next.getKey(), next.getValue().asText());
1✔
69
      }
1✔
70
    };
1✔
71
    if (context.isArray()) {
1✔
72
      for (JsonNode jsonNode : context) {
1✔
73
        if (jsonNode.isTextual()) {
1✔
74
          this.addToContextFromUrl(jsonNode.asText());
1✔
75
        } else if (jsonNode.isObject()) {
1✔
76
          addPairs.accept(jsonNode);
1✔
77
        }
78
      }
1✔
79
    } else if (context.isObject()) {
1✔
80
      addPairs.accept(context);
1✔
81
    } else {
82
      this.addToContextFromUrl(context.asText());
1✔
83
    }
84
  }
1✔
85

86
  @Override
87
  public ObjectNode getContextJsonEntity() {
88
    ObjectMapper objectMapper = MyObjectMapper.getMapper();
1✔
89
    ArrayNode array = objectMapper.createArrayNode();
1✔
90
    ObjectNode jsonNode = objectMapper.createObjectNode();
1✔
91
    ObjectNode finalNode = objectMapper.createObjectNode();
1✔
92
    for (String e : urls) {
1✔
93
      array.add(e);
1✔
94
    }
1✔
95
    for (Map.Entry<String, String> s : other.entrySet()) {
1✔
96
      jsonNode.put(s.getKey(), s.getValue());
1✔
97
    }
1✔
98
    if (!jsonNode.isEmpty()) {
1✔
99
      array.add(jsonNode);
1✔
100
    }
101
    if (array.size() == 1) {
1✔
102
      finalNode.set("@context", array.get(0));
1✔
103
      return finalNode;
1✔
104
    }
105
    finalNode.set("@context", array);
1✔
106
    return finalNode;
1✔
107
  }
108

109
  @Override
110
  public boolean checkEntity(AbstractEntity entity) {
111
    ObjectMapper objectMapper = MyObjectMapper.getMapper();
1✔
112
    ObjectNode node = entity.getProperties().deepCopy();
1✔
113
    node.remove("@id");
1✔
114
    node.remove("@type");
1✔
115

116
    Set<String> types = objectMapper.convertValue(entity.getProperties().get("@type"),
1✔
117
        new TypeReference<>() {
1✔
118
        });
119
    // check if the items in the array of types are present in the context
120
    for (String s : types) {
1✔
121
      // special cases:
122
      if (s.equals("@id")) {
1✔
123
        // @id will refer to the value of the id of the node
124
        // so we need to extract this value
125
        s = entity.getId();
1✔
126
      }
127
      if (s.equals("@json")) {
1✔
128
        // A linked data builtin type, which is fine.
129
        continue;
1✔
130
      }
131
      if (IdentifierUtils.isUrl(s)) {
1✔
132
        // full URLs are considered fine
133
        continue;
1✔
134
      }
135

136
      if (this.contextMap.get(s) == null) {
1✔
137
        System.err.println("type " + s + " is missing from the context!");
1✔
138
        return false;
1✔
139
      }
140
    }
1✔
141

142
    // check if the fields of the entity are present in the context
143
    for (var names = node.fieldNames(); names.hasNext();) {
1✔
144
      String s = names.next();
1✔
145
      if (IdentifierUtils.isUrl(s)) {
1✔
146
        // full URLs are considered fine
147
        continue;
1✔
148
      }
149
      if (this.contextMap.get(s) == null) {
1✔
150
        System.err.println("attribute name " + s + " is missing from context;");
1✔
151
        return false;
1✔
152
      }
153
    }
1✔
154
    return true;
1✔
155
  }
156

157
  @Override
158
  public void addToContextFromUrl(String url) {
159
    this.urls.add(url);
1✔
160

161
    ObjectMapper objectMapper = MyObjectMapper.getMapper();
1✔
162

163
    JsonNode jsonNode = null;
1✔
164
    if (url.equals(DEFAULT_CONTEXT)) {
1✔
165
      if (defaultContext != null) {
1✔
UNCOV
166
        jsonNode = defaultContext;
×
167
      } else {
168
        try {
169
          jsonNode = objectMapper.readTree(
1✔
170
              getClass().getClassLoader().getResource(DEFAULT_CONTEXT_LOCATION));
1✔
UNCOV
171
        } catch (IOException e) {
×
172
          e.printStackTrace();
×
173
        }
1✔
174
      }
175
    }
176
    if (jsonNode == null) {
1✔
177
      CloseableHttpClient httpclient = HttpClients.createDefault();
1✔
178
      HttpGet httpGet = new HttpGet(url);
1✔
179
      CloseableHttpResponse response;
180
      try {
181
        response = httpclient.execute(httpGet);
1✔
182
        jsonNode = objectMapper.readValue(response.getEntity().getContent(),
1✔
183
            JsonNode.class);
184
      } catch (IOException e) {
1✔
185
        System.err.println(String.format("Cannot get context from url %s", url));
1✔
186
        return;
1✔
187
      }
1✔
188
      if (url.equals(DEFAULT_CONTEXT)) {
1✔
189
        defaultContext = jsonNode;
×
190
      }
191
    }
192
    this.contextMap.putAll(objectMapper.convertValue(jsonNode.get("@context"),
1✔
193
        new TypeReference<>() {
1✔
194
        }));
195
  }
1✔
196

197
  @Override
198
  public void addToContext(String key, String value) {
199
    this.contextMap.put(key, value);
1✔
200
    this.other.put(key, value);
1✔
201
  }
1✔
202

203
  @Override
204
  public String getValueOf(String key) {
205
    return Optional.ofNullable(this.contextMap.get(key))
1✔
206
            .orElseGet(() -> this.other.get(key));
1✔
207
  }
208

209
  @Override
210
  public Set<String> getKeys() {
211
    List<String> merged = new ArrayList<>();
1✔
212
    merged.addAll(this.contextMap.keySet());
1✔
213
    merged.addAll(this.other.keySet());
1✔
214
    return Set.copyOf(merged);
1✔
215
  }
216

217
  @Override
218
  public Map<String, String> getPairs() {
219
    Map<String, String> merged = new HashMap<>();
1✔
220
    merged.putAll(this.contextMap);
1✔
221
    merged.putAll(this.other);
1✔
222
    return Map.copyOf(merged);
1✔
223
  }
224

225

226
  @Override
227
  public void deleteValuePairFromContext(String key) {
228
    this.contextMap.remove(key);
1✔
229
    this.other.remove(key);
1✔
230
  }
1✔
231

232
  @Override
233
  public void deleteUrlFromContext(String url) {
234
    this.urls.remove(url);
1✔
235
  }
1✔
236

237
}
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