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

knowledgepixels / nanodash / 17319343703

29 Aug 2025 08:53AM UTC coverage: 12.007% (-0.3%) from 12.355%
17319343703

push

github

tkuhn
Fix forcedGet(...) also catching RuntimeExceptions

330 of 3844 branches covered (8.58%)

Branch coverage included in aggregate %.

949 of 6808 relevant lines covered (13.94%)

0.61 hits per line

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

20.84
src/main/java/com/knowledgepixels/nanodash/template/Template.java
1
package com.knowledgepixels.nanodash.template;
2

3
import com.knowledgepixels.nanodash.LookupApis;
4
import com.knowledgepixels.nanodash.Utils;
5
import net.trustyuri.TrustyUriUtils;
6
import org.eclipse.rdf4j.common.exception.RDF4JException;
7
import org.eclipse.rdf4j.model.*;
8
import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
9
import org.eclipse.rdf4j.model.util.Literals;
10
import org.eclipse.rdf4j.model.vocabulary.DCTERMS;
11
import org.eclipse.rdf4j.model.vocabulary.RDF;
12
import org.eclipse.rdf4j.model.vocabulary.RDFS;
13
import org.eclipse.rdf4j.model.vocabulary.SHACL;
14
import org.nanopub.Nanopub;
15
import org.nanopub.NanopubUtils;
16
import org.nanopub.vocabulary.NTEMPLATE;
17

18
import java.io.Serializable;
19
import java.util.*;
20

21
/**
22
 * Represents a template for creating nanopublications.
23
 */
24
public class Template implements Serializable {
25

26
    private static final long serialVersionUID = 1L;
27

28
    private static ValueFactory vf = SimpleValueFactory.getInstance();
3✔
29

30
    /**
31
     * Default target namespace for templates.
32
     */
33
    public static final String DEFAULT_TARGET_NAMESPACE = "https://w3id.org/np/";
34

35
    private Nanopub nanopub;
36
    private String label;
37
    private String description;
38

39
    // TODO: Make all these maps more generic and the code simpler:
40
    private IRI templateIri;
41
    private Map<IRI, List<IRI>> typeMap = new HashMap<>();
5✔
42
    private Map<IRI, List<Value>> possibleValueMap = new HashMap<>();
5✔
43
    private Map<IRI, List<IRI>> possibleValuesToLoadMap = new HashMap<>();
5✔
44
    private Map<IRI, List<String>> apiMap = new HashMap<>();
5✔
45
    private Map<IRI, String> labelMap = new HashMap<>();
5✔
46
    private Map<IRI, IRI> datatypeMap = new HashMap<>();
5✔
47
    private Map<IRI, String> languageTagMap = new HashMap<>();
5✔
48
    private Map<IRI, String> prefixMap = new HashMap<>();
5✔
49
    private Map<IRI, String> prefixLabelMap = new HashMap<>();
5✔
50
    private Map<IRI, String> regexMap = new HashMap<>();
5✔
51
    private Map<IRI, List<IRI>> statementMap = new HashMap<>();
5✔
52
    private Map<IRI, IRI> statementSubjects = new HashMap<>();
5✔
53
    private Map<IRI, IRI> statementPredicates = new HashMap<>();
5✔
54
    private Map<IRI, Value> statementObjects = new HashMap<>();
5✔
55
    private Map<IRI, Integer> statementOrder = new HashMap<>();
5✔
56
    private IRI defaultProvenance;
57
    private List<IRI> requiredPubinfoElements = new ArrayList<>();
5✔
58
    private String tag = null;
3✔
59
    private Map<IRI, Value> defaultValues = new HashMap<>();
5✔
60
    private String targetNamespace = null;
3✔
61
    private String nanopubLabelPattern;
62
    private List<IRI> targetNanopubTypes = new ArrayList<>();
5✔
63

64
    /**
65
     * Creates a Template object from a template id.
66
     *
67
     * @param templateId the id of the template, which is the URI of a nanopublication that contains the template definition.
68
     * @throws RDF4JException             if there is an error retrieving the nanopublication.
69
     * @throws MalformedTemplateException if the template is malformed or not a valid nanopub template.
70
     */
71
    Template(String templateId) throws RDF4JException, MalformedTemplateException {
2✔
72
        nanopub = Utils.getNanopub(templateId);
4✔
73
        processTemplate(nanopub);
4✔
74
    }
1✔
75

76
    /**
77
     * Checks if the template is unlisted.
78
     *
79
     * @return true if the template is unlisted, false otherwise.
80
     */
81
    public boolean isUnlisted() {
82
        return typeMap.get(templateIri).contains(NTEMPLATE.UNLISTED_TEMPLATE);
×
83
    }
84

85
    /**
86
     * Returns the Nanopub object representing the template.
87
     *
88
     * @return the Nanopub object of the template.
89
     */
90
    public Nanopub getNanopub() {
91
        return nanopub;
×
92
    }
93

94
    /**
95
     * Returns the ID of the template, which is the URI of the nanopublication.
96
     *
97
     * @return the ID of the template as a string.
98
     */
99
    public String getId() {
100
        return nanopub.getUri().toString();
×
101
    }
102

103
    /**
104
     * Returns the label of the template.
105
     *
106
     * @return the label of the template, or a default label if not set.
107
     */
108
    public String getLabel() {
109
        if (label == null) {
3!
110
            return "Template " + TrustyUriUtils.getArtifactCode(nanopub.getUri().stringValue()).substring(0, 10);
×
111
        }
112
        return label;
3✔
113
    }
114

115
    /**
116
     * Returns the description of the template.
117
     *
118
     * @return the description of the template, or an empty string if not set.
119
     */
120
    public String getDescription() {
121
        return description;
3✔
122
    }
123

124
    /**
125
     * Returns the IRI of the template.
126
     *
127
     * @param iri the IRI to transform.
128
     * @return the transformed IRI, or the original IRI if no transformation is needed.
129
     */
130
    public String getLabel(IRI iri) {
131
        iri = transform(iri);
×
132
        return labelMap.get(iri);
×
133
    }
134

135
    /**
136
     * Returns the IRI of the template, transforming it if necessary.
137
     *
138
     * @param iri the IRI to transform.
139
     * @return the transformed IRI, or the original IRI if no transformation is needed.
140
     */
141
    public IRI getFirstOccurence(IRI iri) {
142
        for (IRI i : getStatementIris()) {
×
143
            if (statementMap.containsKey(i)) {
×
144
                // grouped statement
145
                for (IRI g : getStatementIris(i)) {
×
146
                    if (iri.equals(statementSubjects.get(g))) return g;
×
147
                    if (iri.equals(statementPredicates.get(g))) return g;
×
148
                    if (iri.equals(statementObjects.get(g))) return g;
×
149
                }
×
150
            } else {
151
                // non-grouped statement
152
                if (iri.equals(statementSubjects.get(i))) return i;
×
153
                if (iri.equals(statementPredicates.get(i))) return i;
×
154
                if (iri.equals(statementObjects.get(i))) return i;
×
155
            }
156
        }
×
157
        return null;
×
158
    }
159

160
    /**
161
     * Returns the datatype for the given literal placeholder IRI.
162
     *
163
     * @param iri the literal placeholder IRI.
164
     * @return the datatype for the literal.
165
     */
166
    public IRI getDatatype(IRI iri) {
167
        iri = transform(iri);
×
168
        return datatypeMap.get(iri);
×
169
    }
170

171
    /**
172
     * Returns the language tag for the given literal placeholder IRI.
173
     *
174
     * @param iri the literal placeholder IRI.
175
     * @return the language tag for the literal.
176
     */
177
    public String getLanguageTag(IRI iri) {
178
        iri = transform(iri);
×
179
        return languageTagMap.get(iri);
×
180
    }
181

182
    /**
183
     * Returns the prefix for the given IRI.
184
     *
185
     * @param iri the IRI.
186
     * @return the prefix for the IRI.
187
     */
188
    public String getPrefix(IRI iri) {
189
        iri = transform(iri);
×
190
        return prefixMap.get(iri);
×
191
    }
192

193
    /**
194
     * Returns the prefix label for a given IRI.
195
     *
196
     * @param iri the IRI to get the prefix label for.
197
     * @return the prefix label for the IRI, or null if not found.
198
     */
199
    public String getPrefixLabel(IRI iri) {
200
        iri = transform(iri);
×
201
        return prefixLabelMap.get(iri);
×
202
    }
203

204
    /**
205
     * Returns the regex pattern for a given IRI.
206
     *
207
     * @param iri the IRI to get the regex for.
208
     * @return the regex pattern for the IRI, or null if not found.
209
     */
210
    public String getRegex(IRI iri) {
211
        iri = transform(iri);
×
212
        return regexMap.get(iri);
×
213
    }
214

215
    /**
216
     * Transforms an IRI by removing the artifact code if it is present.
217
     *
218
     * @param iri the IRI to transform.
219
     * @return the transformed IRI, or the original IRI if no transformation is needed.
220
     */
221
    public Value getDefault(IRI iri) {
222
        if (iri.stringValue().matches(".*__[0-9]+")) {
×
223
            String baseIri = iri.stringValue().replaceFirst("__[0-9]+$", "");
×
224
            Value v = defaultValues.get(vf.createIRI(baseIri));
×
225
            if (v instanceof IRI vIri) {
×
226
                int repeatSuffix = Integer.parseInt(iri.stringValue().replaceFirst("^.*__([0-9]+)$", "$1"));
×
227
                return vf.createIRI(vIri.stringValue() + (repeatSuffix + 1));
×
228
            }
229
        }
230
        iri = transform(iri);
×
231
        return defaultValues.get(iri);
×
232
    }
233

234
    /**
235
     * Returns the statement IRIs associated with the template.
236
     *
237
     * @return the list of statement IRIs for the template.
238
     */
239
    public List<IRI> getStatementIris() {
240
        return statementMap.get(templateIri);
×
241
    }
242

243
    /**
244
     * Returns the statement IRIs associated with a specific group IRI.
245
     *
246
     * @param groupIri the IRI of the group for which to retrieve statement IRIs.
247
     * @return the list of statement IRIs for the specified group IRI, or null if no statements are associated with that group.
248
     */
249
    public List<IRI> getStatementIris(IRI groupIri) {
250
        return statementMap.get(groupIri);
×
251
    }
252

253
    /**
254
     * Returns the subject, predicate, and object of a statement given its IRI.
255
     *
256
     * @param statementIri the IRI of the statement to retrieve.
257
     * @return the subject, predicate, and object of the statement as a triple.
258
     */
259
    public IRI getSubject(IRI statementIri) {
260
        return statementSubjects.get(statementIri);
×
261
    }
262

263
    /**
264
     * Returns the predicate of a statement given its IRI.
265
     *
266
     * @param statementIri the IRI of the statement to retrieve.
267
     * @return the predicate of the statement, or null if not found.
268
     */
269
    public IRI getPredicate(IRI statementIri) {
270
        return statementPredicates.get(statementIri);
×
271
    }
272

273
    /**
274
     * Returns the object of a statement given its IRI.
275
     *
276
     * @param statementIri the IRI of the statement to retrieve.
277
     * @return the object of the statement, or null if not found.
278
     */
279
    public Value getObject(IRI statementIri) {
280
        return statementObjects.get(statementIri);
×
281
    }
282

283
    /**
284
     * Checks if the template is a local resource.
285
     *
286
     * @param iri the IRI to check.
287
     * @return true if the IRI is a local resource, false otherwise.
288
     */
289
    public boolean isLocalResource(IRI iri) {
290
        iri = transform(iri);
×
291
        return typeMap.containsKey(iri) && typeMap.get(iri).contains(NTEMPLATE.LOCAL_RESOURCE);
×
292
    }
293

294
    /**
295
     * Checks if the template is an introduced resource.
296
     *
297
     * @param iri the IRI to check.
298
     * @return true if the IRI is an introduced resource, false otherwise.
299
     */
300
    public boolean isIntroducedResource(IRI iri) {
301
        iri = transform(iri);
×
302
        return typeMap.containsKey(iri) && typeMap.get(iri).contains(NTEMPLATE.INTRODUCED_RESOURCE);
×
303
    }
304

305
    /**
306
     * Checks if the template is an embedded resource.
307
     *
308
     * @param iri the IRI to check.
309
     * @return true if the IRI is an embedded resource, false otherwise.
310
     */
311
    public boolean isEmbeddedResource(IRI iri) {
312
        iri = transform(iri);
×
313
        return typeMap.containsKey(iri) && typeMap.get(iri).contains(NTEMPLATE.EMBEDDED_RESOURCE);
×
314
    }
315

316
    /**
317
     * Checks if the IRI is a value placeholder.
318
     *
319
     * @param iri the IRI to check.
320
     * @return true if the IRI is a value placeholder, false otherwise.
321
     */
322
    public boolean isValuePlaceholder(IRI iri) {
323
        iri = transform(iri);
×
324
        return typeMap.containsKey(iri) && typeMap.get(iri).contains(NTEMPLATE.VALUE_PLACEHOLDER);
×
325
    }
326

327
    /**
328
     * Checks if the IRI is a URI placeholder.
329
     *
330
     * @param iri the IRI to check.
331
     * @return true if the IRI is a URI placeholder, false otherwise.
332
     */
333
    public boolean isUriPlaceholder(IRI iri) {
334
        iri = transform(iri);
×
335
        if (!typeMap.containsKey(iri)) return false;
×
336
        for (IRI t : typeMap.get(iri)) {
×
337
            if (t.equals(NTEMPLATE.URI_PLACEHOLDER)) return true;
×
338
            if (t.equals(NTEMPLATE.EXTERNAL_URI_PLACEHOLDER)) return true;
×
339
            if (t.equals(NTEMPLATE.TRUSTY_URI_PLACEHOLDER)) return true;
×
340
            if (t.equals(NTEMPLATE.AUTO_ESCAPE_URI_PLACEHOLDER)) return true;
×
341
            if (t.equals(NTEMPLATE.RESTRICTED_CHOICE_PLACEHOLDER)) return true;
×
342
            if (t.equals(NTEMPLATE.GUIDED_CHOICE_PLACEHOLDER)) return true;
×
343
            if (t.equals(NTEMPLATE.AGENT_PLACEHOLDER)) return true;
×
344
        }
×
345
        return false;
×
346
    }
347

348
    /**
349
     * Checks if the IRI is an external URI placeholder.
350
     *
351
     * @param iri the IRI to check.
352
     * @return true if the IRI is an external URI placeholder, false otherwise.
353
     */
354
    public boolean isExternalUriPlaceholder(IRI iri) {
355
        iri = transform(iri);
×
356
        if (!typeMap.containsKey(iri)) return false;
×
357
        for (IRI t : typeMap.get(iri)) {
×
358
            if (t.equals(NTEMPLATE.EXTERNAL_URI_PLACEHOLDER)) return true;
×
359
            if (t.equals(NTEMPLATE.TRUSTY_URI_PLACEHOLDER)) return true;
×
360
        }
×
361
        return false;
×
362
    }
363

364
    /**
365
     * Checks if the IRI is a trusty URI placeholder.
366
     *
367
     * @param iri the IRI to check.
368
     * @return true if the IRI is a trusty URI placeholder, false otherwise.
369
     */
370
    public boolean isTrustyUriPlaceholder(IRI iri) {
371
        iri = transform(iri);
×
372
        return typeMap.containsKey(iri) && typeMap.get(iri).contains(NTEMPLATE.TRUSTY_URI_PLACEHOLDER);
×
373
    }
374

375
    /**
376
     * Checks if the IRI is an auto-escape URI placeholder.
377
     *
378
     * @param iri the IRI to check.
379
     * @return true if the IRI is an auto-escape URI placeholder, false otherwise.
380
     */
381
    public boolean isAutoEscapePlaceholder(IRI iri) {
382
        iri = transform(iri);
×
383
        return typeMap.containsKey(iri) && typeMap.get(iri).contains(NTEMPLATE.AUTO_ESCAPE_URI_PLACEHOLDER);
×
384
    }
385

386
    /**
387
     * Checks if the IRI is a literal placeholder.
388
     *
389
     * @param iri the IRI to check.
390
     * @return true if the IRI is a literal placeholder, false otherwise.
391
     */
392
    public boolean isLiteralPlaceholder(IRI iri) {
393
        iri = transform(iri);
×
394
        return typeMap.containsKey(iri) && (typeMap.get(iri).contains(NTEMPLATE.LITERAL_PLACEHOLDER) || typeMap.get(iri).contains(NTEMPLATE.LONG_LITERAL_PLACEHOLDER));
×
395
    }
396

397
    /**
398
     * Checks if the IRI is a long literal placeholder.
399
     *
400
     * @param iri the IRI to check.
401
     * @return true if the IRI is a long literal placeholder, false otherwise.
402
     */
403
    public boolean isLongLiteralPlaceholder(IRI iri) {
404
        iri = transform(iri);
×
405
        return typeMap.containsKey(iri) && typeMap.get(iri).contains(NTEMPLATE.LONG_LITERAL_PLACEHOLDER);
×
406
    }
407

408
    /**
409
     * Checks if the IRI is a restricted choice placeholder.
410
     *
411
     * @param iri the IRI to check.
412
     * @return true if the IRI is a restricted choice placeholder, false otherwise.
413
     */
414
    public boolean isRestrictedChoicePlaceholder(IRI iri) {
415
        iri = transform(iri);
×
416
        return typeMap.containsKey(iri) && typeMap.get(iri).contains(NTEMPLATE.RESTRICTED_CHOICE_PLACEHOLDER);
×
417
    }
418

419
    /**
420
     * Checks if the IRI is a guided choice placeholder.
421
     *
422
     * @param iri the IRI to check.
423
     * @return true if the IRI is a guided choice placeholder, false otherwise.
424
     */
425
    public boolean isGuidedChoicePlaceholder(IRI iri) {
426
        iri = transform(iri);
×
427
        return typeMap.containsKey(iri) && typeMap.get(iri).contains(NTEMPLATE.GUIDED_CHOICE_PLACEHOLDER);
×
428
    }
429

430
    /**
431
     * Checks if the IRI is an agent placeholder.
432
     *
433
     * @param iri the IRI to check.
434
     * @return true if the IRI is an agent placeholder, false otherwise.
435
     */
436
    public boolean isAgentPlaceholder(IRI iri) {
437
        iri = transform(iri);
×
438
        return typeMap.containsKey(iri) && typeMap.get(iri).contains(NTEMPLATE.AGENT_PLACEHOLDER);
×
439
    }
440

441
    /**
442
     * Checks if the IRI is a sequence element placeholder.
443
     *
444
     * @param iri the IRI to check.
445
     * @return true if the IRI is a sequence element placeholder, false otherwise.
446
     */
447
    public boolean isSequenceElementPlaceholder(IRI iri) {
448
        iri = transform(iri);
×
449
        return typeMap.containsKey(iri) && typeMap.get(iri).contains(NTEMPLATE.SEQUENCE_ELEMENT_PLACEHOLDER);
×
450
    }
451

452
    /**
453
     * Checks if the IRI is a placeholder of any type.
454
     *
455
     * @param iri the IRI to check.
456
     * @return true if the IRI is a placeholder, false otherwise.
457
     */
458
    public boolean isPlaceholder(IRI iri) {
459
        iri = transform(iri);
×
460
        if (!typeMap.containsKey(iri)) return false;
×
461
        for (IRI t : typeMap.get(iri)) {
×
462
            if (t.equals(NTEMPLATE.VALUE_PLACEHOLDER)) return true;
×
463
            if (t.equals(NTEMPLATE.URI_PLACEHOLDER)) return true;
×
464
            if (t.equals(NTEMPLATE.EXTERNAL_URI_PLACEHOLDER)) return true;
×
465
            if (t.equals(NTEMPLATE.TRUSTY_URI_PLACEHOLDER)) return true;
×
466
            if (t.equals(NTEMPLATE.AUTO_ESCAPE_URI_PLACEHOLDER)) return true;
×
467
            if (t.equals(NTEMPLATE.RESTRICTED_CHOICE_PLACEHOLDER)) return true;
×
468
            if (t.equals(NTEMPLATE.GUIDED_CHOICE_PLACEHOLDER)) return true;
×
469
            if (t.equals(NTEMPLATE.AGENT_PLACEHOLDER)) return true;
×
470
            if (t.equals(NTEMPLATE.LITERAL_PLACEHOLDER)) return true;
×
471
            if (t.equals(NTEMPLATE.LONG_LITERAL_PLACEHOLDER)) return true;
×
472
            if (t.equals(NTEMPLATE.SEQUENCE_ELEMENT_PLACEHOLDER)) return true;
×
473
        }
×
474
        return false;
×
475
    }
476

477
    /**
478
     * Checks if the IRI is an optional statement.
479
     *
480
     * @param iri the IRI to check.
481
     * @return true if the IRI is an optional statement, false otherwise.
482
     */
483
    public boolean isOptionalStatement(IRI iri) {
484
        return typeMap.containsKey(iri) && typeMap.get(iri).contains(NTEMPLATE.OPTIONAL_STATEMENT);
×
485
    }
486

487
    /**
488
     * Checks if the IRI is a grouped statement.
489
     *
490
     * @param iri the IRI to check.
491
     * @return true if the IRI is a grouped statement, false otherwise.
492
     */
493
    public boolean isGroupedStatement(IRI iri) {
494
        return typeMap.containsKey(iri) && typeMap.get(iri).contains(NTEMPLATE.GROUPED_STATEMENT);
×
495
    }
496

497
    /**
498
     * Checks if the IRI is a repeatable statement.
499
     *
500
     * @param iri the IRI to check.
501
     * @return true if the IRI is a repeatable statement, false otherwise.
502
     */
503
    public boolean isRepeatableStatement(IRI iri) {
504
        return typeMap.containsKey(iri) && typeMap.get(iri).contains(NTEMPLATE.REPEATABLE_STATEMENT);
×
505
    }
506

507
    /**
508
     * Returns the possible values for a given IRI.
509
     *
510
     * @param iri the IRI for which to get possible values.
511
     * @return a list of possible values for the IRI. If no values are found, an empty list is returned.
512
     */
513
    public List<Value> getPossibleValues(IRI iri) {
514
        iri = transform(iri);
×
515
        List<Value> l = possibleValueMap.get(iri);
×
516
        if (l == null) {
×
517
            l = new ArrayList<>();
×
518
            possibleValueMap.put(iri, l);
×
519
        }
520
        List<IRI> nanopubList = possibleValuesToLoadMap.get(iri);
×
521
        if (nanopubList != null) {
×
522
            for (IRI npIri : new ArrayList<>(nanopubList)) {
×
523
                try {
524
                    Nanopub valuesNanopub = Utils.getNanopub(npIri.stringValue());
×
525
                    for (Statement st : valuesNanopub.getAssertion()) {
×
526
                        if (st.getPredicate().equals(RDFS.LABEL)) {
×
527
                            l.add((IRI) st.getSubject());
×
528
                        }
529
                    }
×
530
                    nanopubList.remove(npIri);
×
531
                } catch (Exception ex) {
×
532
                    ex.printStackTrace();
×
533
                }
×
534
            }
×
535
        }
536
        return l;
×
537
    }
538

539
    /**
540
     * Returns the IRI of the default provenance for the template.
541
     *
542
     * @return the IRI of the default provenance, or null if not set.
543
     */
544
    public IRI getDefaultProvenance() {
545
        return defaultProvenance;
×
546
    }
547

548
    /**
549
     * Returns the target namespace for the template.
550
     *
551
     * @return the target namespace as a string, or null if not set.
552
     */
553
    public String getTargetNamespace() {
554
        return targetNamespace;
×
555
    }
556

557
    /**
558
     * Returns the nanopub label pattern.
559
     *
560
     * @return the nanopub label pattern as a string, or null if not set.
561
     */
562
    public String getNanopubLabelPattern() {
563
        return nanopubLabelPattern;
3✔
564
    }
565

566
    /**
567
     * Returns the list of target nanopub types.
568
     *
569
     * @return a list of IRI objects representing the target nanopub types.
570
     */
571
    public List<IRI> getTargetNanopubTypes() {
572
        return targetNanopubTypes;
×
573
    }
574

575
    /**
576
     * Returns the list of the required pubinfo elements for the template.
577
     *
578
     * @return a list of IRI objects representing the required pubinfo elements.
579
     */
580
    public List<IRI> getRequiredPubinfoElements() {
581
        return requiredPubinfoElements;
×
582
    }
583

584
    /**
585
     * Returns the possible values from an API for a given IRI and search term.
586
     *
587
     * @param iri        the IRI for which to get possible values from the API.
588
     * @param searchterm the search term to filter the possible values.
589
     * @param labelMap   a map to store labels for the possible values.
590
     * @return a list of possible values from the API, filtered by the search term.
591
     */
592
    public List<String> getPossibleValuesFromApi(IRI iri, String searchterm, Map<String, String> labelMap) {
593
        iri = transform(iri);
×
594
        List<String> values = new ArrayList<>();
×
595
        List<String> apiList = apiMap.get(iri);
×
596
        if (apiList != null) {
×
597
            for (String apiString : apiList) {
×
598
                LookupApis.getPossibleValues(apiString, searchterm, labelMap, values);
×
599
            }
×
600
        }
601
        return values;
×
602
    }
603

604
    /**
605
     * Returns the tag associated with the template.
606
     *
607
     * @return the tag as a string, or null if not set.
608
     */
609
    public String getTag() {
610
        return tag;
3✔
611
    }
612

613
    private void processTemplate(Nanopub templateNp) throws MalformedTemplateException {
614
        boolean isNpTemplate = false;
2✔
615
        for (Statement st : templateNp.getAssertion()) {
11!
616
            if (st.getSubject().equals(templateNp.getAssertionUri()) && st.getPredicate().equals(RDF.TYPE)) {
11!
617
                if (st.getObject().equals(NTEMPLATE.ASSERTION_TEMPLATE) || st.getObject().equals(NTEMPLATE.PROVENANCE_TEMPLATE) || st.getObject().equals(NTEMPLATE.PUBINFO_TEMPLATE)) {
5!
618
                    isNpTemplate = true;
2✔
619
                    break;
1✔
620
                }
621
            }
622
        }
1✔
623

624
        if (isNpTemplate) {
2!
625
            processNpTemplate(templateNp);
4✔
626
        } else {
627
            // Experimental SHACL-based template:
628
            processShaclTemplate(templateNp);
×
629
        }
630
    }
1✔
631

632
    private void processNpTemplate(Nanopub templateNp) {
633
        templateIri = templateNp.getAssertionUri();
4✔
634
        for (Statement st : templateNp.getAssertion()) {
11✔
635
            final IRI subj = (IRI) st.getSubject();
4✔
636
            final IRI pred = st.getPredicate();
3✔
637
            final Value obj = st.getObject();
3✔
638
            final String objS = obj.stringValue();
3✔
639

640
            if (subj.equals(templateIri)) {
5✔
641
                if (pred.equals(RDFS.LABEL)) {
4✔
642
                    label = objS;
4✔
643
                } else if (pred.equals(DCTERMS.DESCRIPTION)) {
4✔
644
                    description = Utils.sanitizeHtml(objS);
5✔
645
                } else if (obj instanceof IRI objIri) {
6✔
646
                    if (pred.equals(NTEMPLATE.HAS_DEFAULT_PROVENANCE)) {
4!
647
                        defaultProvenance = objIri;
×
648
                    } else if (pred.equals(NTEMPLATE.HAS_REQUIRED_PUBINFO_ELEMENT)) {
4!
649
                        requiredPubinfoElements.add(objIri);
×
650
                    } else if (pred.equals(NTEMPLATE.HAS_TARGET_NAMESPACE)) {
4!
651
                        targetNamespace = objS;
×
652
                    } else if (pred.equals(NTEMPLATE.HAS_TARGET_NANOPUB_TYPE)) {
4!
653
                        targetNanopubTypes.add(objIri);
×
654
                    }
655
                } else if (obj instanceof Literal) {
3!
656
                    if (pred.equals(NTEMPLATE.HAS_TAG)) {
4✔
657
                        // TODO This should be replaced at some point with a more sophisticated mechanism based on classes.
658
                        // We are assuming that there is at most one tag.
659
                        this.tag = objS;
4✔
660
                    } else if (pred.equals(NTEMPLATE.HAS_NANOPUB_LABEL_PATTERN)) {
4!
661
                        nanopubLabelPattern = objS;
3✔
662
                    }
663
                }
664
            }
665
            if (pred.equals(RDF.TYPE) && obj instanceof IRI objIri) {
10!
666
                addType(subj, objIri);
5✔
667
            } else if (pred.equals(NTEMPLATE.HAS_STATEMENT) && obj instanceof IRI objIri) {
10!
668
                List<IRI> l = statementMap.get(subj);
6✔
669
                if (l == null) {
2✔
670
                    l = new ArrayList<>();
4✔
671
                    statementMap.put(subj, l);
6✔
672
                }
673
                l.add((IRI) objIri);
4✔
674
            } else if (pred.equals(NTEMPLATE.POSSIBLE_VALUE)) {
5!
675
                List<Value> l = possibleValueMap.get(subj);
×
676
                if (l == null) {
×
677
                    l = new ArrayList<>();
×
678
                    possibleValueMap.put(subj, l);
×
679
                }
680
                l.add(obj);
×
681
            } else if (pred.equals(NTEMPLATE.POSSIBLE_VALUES_FROM)) {
4!
682
                List<IRI> l = possibleValuesToLoadMap.get(subj);
×
683
                if (l == null) {
×
684
                    l = new ArrayList<>();
×
685
                    possibleValuesToLoadMap.put(subj, l);
×
686
                }
687
                if (obj instanceof IRI objIri) {
×
688
                    l.add(objIri);
×
689
                    Nanopub valuesNanopub = Utils.getNanopub(objS);
×
690
                    for (Statement s : valuesNanopub.getAssertion()) {
×
691
                        if (s.getPredicate().equals(RDFS.LABEL)) {
×
692
                            labelMap.put((IRI) s.getSubject(), s.getObject().stringValue());
×
693
                        }
694
                    }
×
695
                }
696
            } else if (pred.equals(NTEMPLATE.POSSIBLE_VALUES_FROM_API)) {
4✔
697
                List<String> l = apiMap.get(subj);
6✔
698
                if (l == null) {
2✔
699
                    l = new ArrayList<>();
4✔
700
                    apiMap.put(subj, l);
6✔
701
                }
702
                if (obj instanceof Literal) {
3!
703
                    l.add(objS);
4✔
704
                }
705
            } else if (pred.equals(RDFS.LABEL) && obj instanceof Literal) {
8!
706
                labelMap.put(subj, objS);
7✔
707
            } else if (pred.equals(NTEMPLATE.HAS_DATATYPE) && obj instanceof IRI objIri) {
4!
708
                datatypeMap.put(subj, objIri);
×
709
            } else if (pred.equals(NTEMPLATE.HAS_LANGUAGE_TAG) && obj instanceof Literal) {
4!
710
                languageTagMap.put(subj, Literals.normalizeLanguageTag(objS));
×
711
            } else if (pred.equals(NTEMPLATE.HAS_PREFIX) && obj instanceof Literal) {
4!
712
                prefixMap.put(subj, objS);
×
713
            } else if (pred.equals(NTEMPLATE.HAS_PREFIX_LABEL) && obj instanceof Literal) {
4!
714
                prefixLabelMap.put(subj, objS);
×
715
            } else if (pred.equals(NTEMPLATE.HAS_REGEX) && obj instanceof Literal) {
4!
716
                regexMap.put(subj, objS);
×
717
            } else if (pred.equals(RDF.SUBJECT) && obj instanceof IRI objIri) {
10!
718
                statementSubjects.put(subj, objIri);
7✔
719
            } else if (pred.equals(RDF.PREDICATE) && obj instanceof IRI objIri) {
10!
720
                statementPredicates.put(subj, objIri);
7✔
721
            } else if (pred.equals(RDF.OBJECT)) {
4✔
722
                statementObjects.put(subj, obj);
7✔
723
            } else if (pred.equals(NTEMPLATE.HAS_DEFAULT_VALUE)) {
4!
724
                defaultValues.put(subj, obj);
×
725
            } else if (pred.equals(NTEMPLATE.STATEMENT_ORDER)) {
4!
726
                if (obj instanceof Literal && objS.matches("[0-9]+")) {
×
727
                    statementOrder.put(subj, Integer.valueOf(objS));
×
728
                }
729
            }
730
        }
1✔
731
//                List<IRI> assertionTypes = typeMap.get(templateIri);
732
//                if (assertionTypes == null || (!assertionTypes.contains(NTEMPLATE.ASSERTION_TEMPLATE) &&
733
//                                !assertionTypes.contains(NTEMPLATE.PROVENANCE_TEMPLATE) && !assertionTypes.contains(PUBINFO_TEMPLATE))) {
734
//                        throw new MalformedTemplateException("Unknown template type");
735
//                }
736
        for (List<IRI> l : statementMap.values()) {
12✔
737
            l.sort(statementComparator);
4✔
738
        }
1✔
739
    }
1✔
740

741
    private void processShaclTemplate(Nanopub templateNp) throws MalformedTemplateException {
742
        templateIri = null;
×
743
        for (Statement st : templateNp.getAssertion()) {
×
744
            if (st.getPredicate().equals(SHACL.TARGET_CLASS)) {
×
745
                templateIri = (IRI) st.getSubject();
×
746
                break;
×
747
            }
748
        }
×
749
        if (templateIri == null) {
×
750
            throw new MalformedTemplateException("Base node shape not found");
×
751
        }
752

753
        IRI baseSubj = vf.createIRI(templateIri.stringValue() + "+subj");
×
754
        addType(baseSubj, NTEMPLATE.INTRODUCED_RESOURCE);
×
755

756
        List<IRI> statementList = new ArrayList<>();
×
757
        Map<IRI, Integer> minCounts = new HashMap<>();
×
758
        Map<IRI, Integer> maxCounts = new HashMap<>();
×
759

760
        for (Statement st : templateNp.getAssertion()) {
×
761
            final IRI subj = (IRI) st.getSubject();
×
762
            final IRI pred = st.getPredicate();
×
763
            final Value obj = st.getObject();
×
764
            final String objS = obj.stringValue();
×
765

766
            if (subj.equals(templateIri)) {
×
767
                if (pred.equals(RDFS.LABEL)) {
×
768
                    label = objS;
×
769
                } else if (pred.equals(DCTERMS.DESCRIPTION)) {
×
770
                    description = Utils.sanitizeHtml(objS);
×
771
                } else if (obj instanceof IRI objIri) {
×
772
                    if (pred.equals(NTEMPLATE.HAS_DEFAULT_PROVENANCE)) {
×
773
                        defaultProvenance = objIri;
×
774
                    } else if (pred.equals(NTEMPLATE.HAS_REQUIRED_PUBINFO_ELEMENT)) {
×
775
                        requiredPubinfoElements.add(objIri);
×
776
                    } else if (pred.equals(NTEMPLATE.HAS_TARGET_NAMESPACE)) {
×
777
                        targetNamespace = objS;
×
778
                    } else if (pred.equals(NTEMPLATE.HAS_TARGET_NANOPUB_TYPE)) {
×
779
                        targetNanopubTypes.add(objIri);
×
780
                    }
781
                } else if (obj instanceof Literal) {
×
782
                    if (pred.equals(NTEMPLATE.HAS_TAG)) {
×
783
                        // TODO This should be replaced at some point with a more sophisticated mechanism based on classes.
784
                        // We are assuming that there is at most one tag.
785
                        this.tag = objS;
×
786
                    } else if (pred.equals(NTEMPLATE.HAS_NANOPUB_LABEL_PATTERN)) {
×
787
                        nanopubLabelPattern = objS;
×
788
                    }
789
                }
790
            }
791
            if (pred.equals(RDF.TYPE) && obj instanceof IRI objIri) {
×
792
                addType(subj, objIri);
×
793
            } else if (pred.equals(SHACL.PROPERTY) && obj instanceof IRI objIri) {
×
794
                statementList.add(objIri);
×
795
                List<IRI> l = statementMap.get(subj);
×
796
                if (l == null) {
×
797
                    l = new ArrayList<>();
×
798
                    statementMap.put(subj, l);
×
799
                }
800
                l.add((IRI) objIri);
×
801
                IRI stSubjIri = vf.createIRI(subj.stringValue() + "+subj");
×
802
                statementSubjects.put(objIri, stSubjIri);
×
803
                addType(stSubjIri, NTEMPLATE.LOCAL_RESOURCE);
×
804
                addType(stSubjIri, NTEMPLATE.URI_PLACEHOLDER);
×
805
            } else if (pred.equals(SHACL.PATH) && obj instanceof IRI objIri) {
×
806
                statementPredicates.put(subj, objIri);
×
807
            } else if (pred.equals(SHACL.HAS_VALUE) && obj instanceof IRI objIri) {
×
808
                statementObjects.put(subj, objIri);
×
809
            } else if (pred.equals(SHACL.TARGET_CLASS) && obj instanceof IRI objIri) {
×
810
                IRI stIri = vf.createIRI(templateNp.getUri() + "/$type");
×
811
                statementList.add(stIri);
×
812
                List<IRI> l = statementMap.get(subj);
×
813
                if (l == null) {
×
814
                    l = new ArrayList<>();
×
815
                    statementMap.put(subj, l);
×
816
                }
817
                l.add((IRI) stIri);
×
818
                statementSubjects.put(stIri, baseSubj);
×
819
                statementPredicates.put(stIri, RDF.TYPE);
×
820
                statementObjects.put(stIri, objIri);
×
821
            } else if (pred.equals(NTEMPLATE.POSSIBLE_VALUE)) {
×
822
                List<Value> l = possibleValueMap.get(subj);
×
823
                if (l == null) {
×
824
                    l = new ArrayList<>();
×
825
                    possibleValueMap.put(subj, l);
×
826
                }
827
                l.add(obj);
×
828
            } else if (pred.equals(NTEMPLATE.POSSIBLE_VALUES_FROM)) {
×
829
                List<IRI> l = possibleValuesToLoadMap.get(subj);
×
830
                if (l == null) {
×
831
                    l = new ArrayList<>();
×
832
                    possibleValuesToLoadMap.put(subj, l);
×
833
                }
834
                if (obj instanceof IRI objIri) {
×
835
                    l.add(objIri);
×
836
                    Nanopub valuesNanopub = Utils.getNanopub(objS);
×
837
                    for (Statement s : valuesNanopub.getAssertion()) {
×
838
                        if (s.getPredicate().equals(RDFS.LABEL)) {
×
839
                            labelMap.put((IRI) s.getSubject(), s.getObject().stringValue());
×
840
                        }
841
                    }
×
842
                }
843
            } else if (pred.equals(NTEMPLATE.POSSIBLE_VALUES_FROM_API)) {
×
844
                List<String> l = apiMap.get(subj);
×
845
                if (l == null) {
×
846
                    l = new ArrayList<>();
×
847
                    apiMap.put(subj, l);
×
848
                }
849
                if (obj instanceof Literal) {
×
850
                    l.add(objS);
×
851
                }
852
            } else if (pred.equals(RDFS.LABEL) && obj instanceof Literal) {
×
853
                labelMap.put(subj, objS);
×
854
            } else if (pred.equals(NTEMPLATE.HAS_DATATYPE) && obj instanceof IRI objIri) {
×
855
                datatypeMap.put(subj, objIri);
×
856
            } else if (pred.equals(NTEMPLATE.HAS_LANGUAGE_TAG) && obj instanceof Literal) {
×
857
                languageTagMap.put(subj, Literals.normalizeLanguageTag(objS));
×
858
            } else if (pred.equals(NTEMPLATE.HAS_PREFIX) && obj instanceof Literal) {
×
859
                prefixMap.put(subj, objS);
×
860
            } else if (pred.equals(NTEMPLATE.HAS_PREFIX_LABEL) && obj instanceof Literal) {
×
861
                prefixLabelMap.put(subj, objS);
×
862
            } else if (pred.equals(NTEMPLATE.HAS_REGEX) && obj instanceof Literal) {
×
863
                regexMap.put(subj, objS);
×
864
//                        } else if (pred.equals(RDF.SUBJECT) && obj instanceof IRI objIri) {
865
//                                statementSubjects.put(subj, objIri);
866
//                        } else if (pred.equals(RDF.PREDICATE) && obj instanceof IRI objIri) {
867
//                                statementPredicates.put(subj, objIri);
868
//                        } else if (pred.equals(RDF.OBJECT)) {
869
//                                statementObjects.put(subj, obj);
870
            } else if (pred.equals(NTEMPLATE.HAS_DEFAULT_VALUE)) {
×
871
                defaultValues.put(subj, obj);
×
872
            } else if (pred.equals(NTEMPLATE.STATEMENT_ORDER)) {
×
873
                if (obj instanceof Literal && objS.matches("[0-9]+")) {
×
874
                    statementOrder.put(subj, Integer.valueOf(objS));
×
875
                }
876
            } else if (pred.equals(SHACL.MIN_COUNT)) {
×
877
                try {
878
                    minCounts.put(subj, Integer.parseInt(obj.stringValue()));
×
879
                } catch (NumberFormatException ex) {
×
880
                    ex.printStackTrace();
×
881
                }
×
882
            } else if (pred.equals(SHACL.MAX_COUNT)) {
×
883
                try {
884
                    maxCounts.put(subj, Integer.parseInt(obj.stringValue()));
×
885
                } catch (NumberFormatException ex) {
×
886
                    ex.printStackTrace();
×
887
                }
×
888
            }
889
        }
×
890
        for (List<IRI> l : statementMap.values()) {
×
891
            l.sort(statementComparator);
×
892
        }
×
893
        for (IRI iri : statementList) {
×
894
            if (!statementObjects.containsKey(iri)) {
×
895
                IRI stObjIri = vf.createIRI(iri.stringValue() + "+obj");
×
896
                statementObjects.put(iri, stObjIri);
×
897
                addType(stObjIri, NTEMPLATE.VALUE_PLACEHOLDER);
×
898
                if (!minCounts.containsKey(iri) || minCounts.get(iri) <= 0) {
×
899
                    addType(iri, NTEMPLATE.OPTIONAL_STATEMENT);
×
900
                }
901
                if (!maxCounts.containsKey(iri) || maxCounts.get(iri) > 1) {
×
902
                    addType(iri, NTEMPLATE.REPEATABLE_STATEMENT);
×
903
                }
904
            }
905
        }
×
906
        if (!labelMap.containsKey(baseSubj) && typeMap.get(baseSubj).contains(NTEMPLATE.URI_PLACEHOLDER) && typeMap.get(baseSubj).contains(NTEMPLATE.LOCAL_RESOURCE)) {
×
907
            labelMap.put(baseSubj, "short ID as URI suffix");
×
908
        }
909

910
        if (label == null) {
×
911
            label = NanopubUtils.getLabel(templateNp);
×
912
        }
913
    }
×
914

915
    private void addType(IRI thing, IRI type) {
916
        List<IRI> l = typeMap.get(thing);
6✔
917
        if (l == null) {
2✔
918
            l = new ArrayList<>();
4✔
919
            typeMap.put(thing, l);
6✔
920
        }
921
        l.add(type);
4✔
922
    }
1✔
923

924
    private void addStatement(IRI thing, IRI type) {
925
        List<IRI> l = typeMap.get(thing);
×
926
        if (l == null) {
×
927
            l = new ArrayList<>();
×
928
            typeMap.put(thing, l);
×
929
        }
930
        l.add(type);
×
931
    }
×
932

933
    private IRI transform(IRI iri) {
934
        if (iri.stringValue().matches(".*__[0-9]+")) {
×
935
            // TODO: Check that this double-underscore pattern isn't used otherwise:
936
            return vf.createIRI(iri.stringValue().replaceFirst("__[0-9]+$", ""));
×
937
        }
938
        return iri;
×
939
    }
940

941

942
    private StatementComparator statementComparator = new StatementComparator();
6✔
943

944
    private class StatementComparator implements Comparator<IRI>, Serializable {
6✔
945

946
        private static final long serialVersionUID = 1L;
947

948
        /**
949
         * Compares two IRIs based on their order in the template.
950
         *
951
         * @param arg0 the first object to be compared.
952
         * @param arg1 the second object to be compared.
953
         * @return a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.
954
         */
955
        @Override
956
        public int compare(IRI arg0, IRI arg1) {
957
            Integer i0 = statementOrder.get(arg0);
7✔
958
            Integer i1 = statementOrder.get(arg1);
7✔
959
            if (i0 == null && i1 == null) return arg0.stringValue().compareTo(arg1.stringValue());
10!
960
            if (i0 == null) return 1;
×
961
            if (i1 == null) return -1;
×
962
            return i0 - i1;
×
963
        }
964

965
    }
966

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