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

knowledgepixels / nanodash / 17424747928

03 Sep 2025 06:13AM UTC coverage: 12.048% (-0.02%) from 12.066%
17424747928

push

github

tkuhn
Update dependencies and adapt to new exceptions in nanopub-java

331 of 3866 branches covered (8.56%)

Branch coverage included in aggregate %.

967 of 6908 relevant lines covered (14.0%)

0.61 hits per line

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

0.0
src/main/java/com/knowledgepixels/nanodash/template/TemplateContext.java
1
package com.knowledgepixels.nanodash.template;
2

3
import com.knowledgepixels.nanodash.NanodashSession;
4
import com.knowledgepixels.nanodash.Utils;
5
import com.knowledgepixels.nanodash.component.PublishForm.FillMode;
6
import com.knowledgepixels.nanodash.component.StatementItem;
7
import org.apache.wicket.Component;
8
import org.apache.wicket.model.IModel;
9
import org.apache.wicket.model.Model;
10
import org.eclipse.rdf4j.model.IRI;
11
import org.eclipse.rdf4j.model.Statement;
12
import org.eclipse.rdf4j.model.Value;
13
import org.eclipse.rdf4j.model.ValueFactory;
14
import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
15
import org.eclipse.rdf4j.model.vocabulary.RDFS;
16
import org.nanopub.MalformedNanopubException;
17
import org.nanopub.Nanopub;
18
import org.nanopub.NanopubAlreadyFinalizedException;
19
import org.nanopub.NanopubCreator;
20
import org.nanopub.NanopubWithNs;
21
import org.nanopub.vocabulary.NTEMPLATE;
22

23
import java.io.Serializable;
24
import java.util.*;
25

26
/**
27
 * Context for a template, containing all necessary information to fill.
28
 */
29
public class TemplateContext implements Serializable {
30

31
    private static final long serialVersionUID = 1L;
32

33
    private static ValueFactory vf = SimpleValueFactory.getInstance();
×
34

35
    private final ContextType contextType;
36
    private final Template template;
37
    private final String componentId;
38
    private final Map<String, String> params = new HashMap<>();
×
39
    private List<Component> components = new ArrayList<>();
×
40
    private Map<IRI, IModel<String>> componentModels = new HashMap<>();
×
41
    private Set<IRI> introducedIris = new HashSet<>();
×
42
    private Set<IRI> embeddedIris = new HashSet<>();
×
43
    private List<StatementItem> statementItems;
44
    private Set<IRI> iriSet = new HashSet<>();
×
45
    private Map<IRI, StatementItem> narrowScopeMap = new HashMap<>();
×
46
    private String targetNamespace = Template.DEFAULT_TARGET_NAMESPACE;
×
47
    private Nanopub existingNanopub;
48
    private Map<IRI, String> labels;
49
    private FillMode fillMode = null;
×
50

51
    /**
52
     * Constructor for creating a new template context for filling a template.
53
     *
54
     * @param contextType     the type of context
55
     * @param templateId      the ID of the template to fill
56
     * @param componentId     the ID of the component that will use this context
57
     * @param targetNamespace the target namespace for the template, can be null to use the default namespace
58
     */
59
    public TemplateContext(ContextType contextType, String templateId, String componentId, String targetNamespace) {
60
        this(contextType, templateId, componentId, targetNamespace, null);
×
61
    }
×
62

63
    /**
64
     * Constructor for creating a new template context for filling a template.
65
     *
66
     * @param contextType     the type of context
67
     * @param templateId      the ID of the template to fill
68
     * @param componentId     the ID of the component that will use this context
69
     * @param existingNanopub an existing nanopub to fill, can be null if creating a new nanopub
70
     */
71
    public TemplateContext(ContextType contextType, String templateId, String componentId, Nanopub existingNanopub) {
72
        this(contextType, templateId, componentId, null, existingNanopub);
×
73
    }
×
74

75
    private TemplateContext(ContextType contextType, String templateId, String componentId, String targetNamespace, Nanopub existingNanopub) {
×
76
        this.contextType = contextType;
×
77
        // TODO: check whether template is of correct type:
78
        this.template = TemplateData.get().getTemplate(templateId);
×
79
        this.componentId = componentId;
×
80
        if (targetNamespace != null) {
×
81
            this.targetNamespace = targetNamespace;
×
82
        }
83
        this.existingNanopub = existingNanopub;
×
84
        if (existingNanopub == null && NanodashSession.get().getUserIri() != null) {
×
85
            componentModels.put(NTEMPLATE.CREATOR_PLACEHOLDER, Model.of(NanodashSession.get().getUserIri().stringValue()));
×
86
        }
87
    }
×
88

89
    /**
90
     * Initializes the statements for this context.
91
     */
92
    public void initStatements() {
93
        if (statementItems != null) return;
×
94
        statementItems = new ArrayList<>();
×
95
        for (IRI st : template.getStatementIris()) {
×
96
            StatementItem si = new StatementItem(componentId, st, this);
×
97
            statementItems.add(si);
×
98
            for (IRI i : si.getIriSet()) {
×
99
                if (iriSet.contains(i)) {
×
100
                    narrowScopeMap.remove(i);
×
101
                } else {
102
                    iriSet.add(i);
×
103
                    narrowScopeMap.put(i, si);
×
104
                }
105
            }
×
106
        }
×
107
    }
×
108

109
    /**
110
     * Finalizes the statements by processing all parameters and setting the repetition counts.
111
     */
112
    public void finalizeStatements() {
113
        Map<StatementItem, Integer> finalRepetitionCount = new HashMap<>();
×
114
        for (IRI ni : narrowScopeMap.keySet()) {
×
115
            // TODO: Move all occurrences of this to utility function:
116
            String postfix = Utils.getUriPostfix(ni);
×
117
            StatementItem si = narrowScopeMap.get(ni);
×
118
            int i = si.getRepetitionCount();
×
119
            while (true) {
120
                String p = postfix + "__" + i;
×
121
                if (hasParam(p)) {
×
122
                    si.addRepetitionGroup();
×
123
                } else {
124
                    break;
125
                }
126
                i++;
×
127
            }
×
128
            i = 1;
×
129
            int corr = 0;
×
130
            if (si.isEmpty()) corr = 1;
×
131
            while (true) {
132
                String p = postfix + "__." + i;
×
133
                if (hasParam(p)) {
×
134
                    int absPos = si.getRepetitionCount() + i - 1 - corr;
×
135
                    String param = postfix + "__" + absPos;
×
136
                    if (i - corr == 0) param = postfix;
×
137
                    setParam(param, getParam(p));
×
138
                    finalRepetitionCount.put(si, i - corr);
×
139
                } else {
140
                    break;
141
                }
142
                i++;
×
143
            }
×
144
        }
×
145
        for (StatementItem si : finalRepetitionCount.keySet()) {
×
146
            for (int i = 0; i < finalRepetitionCount.get(si); i++) {
×
147
                si.addRepetitionGroup();
×
148
            }
149
        }
×
150
        for (StatementItem si : statementItems) {
×
151
            si.finalizeValues();
×
152
        }
×
153
    }
×
154

155
    /**
156
     * Sets the fill mode for this context.
157
     *
158
     * @param fillMode the fill mode to set
159
     */
160
    public void setFillMode(FillMode fillMode) {
161
        this.fillMode = fillMode;
×
162
    }
×
163

164
    /**
165
     * Gets the fill mode for this context.
166
     *
167
     * @return the fill mode, or null if not set
168
     */
169
    public FillMode getFillMode() {
170
        return fillMode;
×
171
    }
172

173
    /**
174
     * Returns the type of context.
175
     *
176
     * @return the context type
177
     */
178
    public ContextType getType() {
179
        return contextType;
×
180
    }
181

182
    /**
183
     * Returns the template associated with this context.
184
     *
185
     * @return the template
186
     */
187
    public Template getTemplate() {
188
        return template;
×
189
    }
190

191
    /**
192
     * Returns the ID of the template associated with this context.
193
     *
194
     * @return the template ID
195
     */
196
    public String getTemplateId() {
197
        return template.getId();
×
198
    }
199

200
    /**
201
     * Sets a parameter for this context.
202
     *
203
     * @param name  the name of the parameter
204
     * @param value the value of the parameter
205
     */
206
    public void setParam(String name, String value) {
207
        params.put(name, value);
×
208
    }
×
209

210
    /**
211
     * Gets a parameter value by its name.
212
     *
213
     * @param name the name of the parameter
214
     * @return the value of the parameter, or null if not set
215
     */
216
    public String getParam(String name) {
217
        return params.get(name);
×
218
    }
219

220
    /**
221
     * Checks if a parameter with the given name exists.
222
     *
223
     * @param name the name of the parameter
224
     * @return true if the parameter exists, false otherwise
225
     */
226
    public boolean hasParam(String name) {
227
        return params.containsKey(name);
×
228
    }
229

230
    /**
231
     * Returns the components associated with this context.
232
     *
233
     * @return a list of components
234
     */
235
    public List<Component> getComponents() {
236
        return components;
×
237
    }
238

239
    /**
240
     * Returns the component models associated with this context.
241
     *
242
     * @return a map of IRI to model of strings
243
     */
244
    public Map<IRI, IModel<String>> getComponentModels() {
245
        return componentModels;
×
246
    }
247

248
    /**
249
     * Returns the introduced IRIs in this context.
250
     *
251
     * @return a set of introduced IRIs
252
     */
253
    public Set<IRI> getIntroducedIris() {
254
        return introducedIris;
×
255
    }
256

257
    /**
258
     * Returns the embedded IRIs in this context.
259
     *
260
     * @return a set of embedded IRIs
261
     */
262
    public Set<IRI> getEmbeddedIris() {
263
        return embeddedIris;
×
264
    }
265

266
    /**
267
     * Processes an IRI by applying the template's processing rules.
268
     *
269
     * @param iri the IRI to process
270
     * @return the processed IRI, or null if the processing results in no value
271
     */
272
    public IRI processIri(IRI iri) {
273
        Value v = processValue(iri);
×
274
        if (v == null) return null;
×
275
        if (v instanceof IRI) return (IRI) v;
×
276
        return iri;
×
277
    }
278

279
    /**
280
     * Processes a Value according to the template's rules.
281
     *
282
     * @param value the Value to process
283
     * @return the processed Value, or the original Value if no processing is applicable
284
     */
285
    public Value processValue(Value value) {
286
        if (!(value instanceof IRI)) return value;
×
287
        IRI iri = (IRI) value;
×
288
        if (iri.equals(NTEMPLATE.CREATOR_PLACEHOLDER)) {
×
289
            iri = NanodashSession.get().getUserIri();
×
290
        }
291
        if (iri.equals(NTEMPLATE.ASSERTION_PLACEHOLDER)) {
×
292
            iri = vf.createIRI(targetNamespace + "assertion");
×
293
        } else if (iri.equals(NTEMPLATE.NANOPUB_PLACEHOLDER)) {
×
294
            iri = vf.createIRI(targetNamespace);
×
295
        }
296
        // TODO: Move this code below to the respective placeholder classes:
297
        IModel<String> tf = componentModels.get(iri);
×
298
        Value processedValue = null;
×
299
        if (template.isRestrictedChoicePlaceholder(iri)) {
×
300
            if (tf != null && tf.getObject() != null && !tf.getObject().isEmpty()) {
×
301
                String prefix = template.getPrefix(iri);
×
302
                if (prefix == null) prefix = "";
×
303
                if (template.isLocalResource(iri)) prefix = targetNamespace;
×
304
                if (tf.getObject().matches("https?://.+")) prefix = "";
×
305
                String v = prefix + tf.getObject();
×
306
                if (v.matches("[^:# ]+")) v = targetNamespace + v;
×
307
                if (v.matches("https?://.*")) {
×
308
                    processedValue = vf.createIRI(v);
×
309
                } else {
310
                    processedValue = vf.createLiteral(tf.getObject());
×
311
                }
312
            }
×
313
        } else if (template.isUriPlaceholder(iri)) {
×
314
            if (tf != null && tf.getObject() != null && !tf.getObject().isEmpty()) {
×
315
                String prefix = template.getPrefix(iri);
×
316
                if (prefix == null) prefix = "";
×
317
                if (template.isLocalResource(iri)) prefix = targetNamespace;
×
318
                String v;
319
                if (template.isAutoEscapePlaceholder(iri)) {
×
320
                    v = prefix + Utils.urlEncode(tf.getObject());
×
321
                } else {
322
                    if (tf.getObject().matches("https?://.+")) prefix = "";
×
323
                    v = prefix + tf.getObject();
×
324
                }
325
                if (v.matches("[^:# ]+")) v = targetNamespace + v;
×
326
                processedValue = vf.createIRI(v);
×
327
            }
×
328
        } else if (template.isLocalResource(iri)) {
×
329
            String prefix = Utils.getUriPrefix(iri);
×
330
            processedValue = vf.createIRI(iri.stringValue().replace(prefix, targetNamespace));
×
331
        } else if (template.isLiteralPlaceholder(iri)) {
×
332
            IRI datatype = template.getDatatype(iri);
×
333
            String languagetag = template.getLanguageTag(iri);
×
334
            if (tf != null && tf.getObject() != null && !tf.getObject().isEmpty()) {
×
335
                if (datatype != null) {
×
336
                    processedValue = vf.createLiteral(tf.getObject(), datatype);
×
337
                } else if (languagetag != null) {
×
338
                    processedValue = vf.createLiteral(tf.getObject(), languagetag);
×
339
                } else {
340
                    processedValue = vf.createLiteral(tf.getObject());
×
341
                }
342
            }
343

344
        } else if (template.isValuePlaceholder(iri)) {
×
345
            if (tf != null && tf.getObject() != null && !tf.getObject().isEmpty()) {
×
346
                if (Utils.isValidLiteralSerialization(tf.getObject())) {
×
347
                    processedValue = Utils.getParsedLiteral(tf.getObject());
×
348
                } else {
349
                    String v = tf.getObject();
×
350
                    if (v.matches("[^:# ]+")) v = targetNamespace + v;
×
351
                    processedValue = vf.createIRI(v);
×
352
                }
×
353
            }
354
        } else if (template.isSequenceElementPlaceholder(iri)) {
×
355
            if (tf != null && tf.getObject() != null && !tf.getObject().isEmpty()) {
×
356
                processedValue = vf.createIRI(tf.getObject());
×
357
            }
358
        } else {
359
            processedValue = iri;
×
360
        }
361
        if (processedValue instanceof IRI pvIri && template.isIntroducedResource(iri)) {
×
362
            introducedIris.add(pvIri);
×
363
        }
364
        if (processedValue instanceof IRI pvIri && template.isEmbeddedResource(iri)) {
×
365
            embeddedIris.add(pvIri);
×
366
        }
367
        return processedValue;
×
368
    }
369

370
    /**
371
     * Returns the statement items associated with this context.
372
     *
373
     * @return a list of StatementItem objects
374
     */
375
    public List<StatementItem> getStatementItems() {
376
        return statementItems;
×
377
    }
378

379
    /**
380
     * Propagates the statements from this context to a NanopubCreator.
381
     *
382
     * @param npCreator the NanopubCreator to which the statements will be added
383
     * @throws org.nanopub.MalformedNanopubException if there is an error in the nanopub structure
384
     */
385
    public void propagateStatements(NanopubCreator npCreator) throws MalformedNanopubException, NanopubAlreadyFinalizedException {
386
        if (template.getNanopub() instanceof NanopubWithNs) {
×
387
            NanopubWithNs np = (NanopubWithNs) template.getNanopub();
×
388
            for (String p : np.getNsPrefixes()) {
×
389
                npCreator.addNamespace(p, np.getNamespace(p));
×
390
            }
×
391
        }
392
        for (StatementItem si : statementItems) {
×
393
            si.addTriplesTo(npCreator);
×
394
        }
×
395
    }
×
396

397
    /**
398
     * Checks if the context has a narrow scope for the given IRI.
399
     *
400
     * @param iri the IRI to check
401
     * @return true if there is a narrow scope for the IRI, false otherwise
402
     */
403
    public boolean hasNarrowScope(IRI iri) {
404
        return narrowScopeMap.containsKey(iri);
×
405
    }
406

407
    /**
408
     * Checks if any of the statement items in this context will match any triple.
409
     *
410
     * @return true if any statement item will match any triple, false otherwise
411
     */
412
    public boolean willMatchAnyTriple() {
413
        initStatements();
×
414
        for (StatementItem si : statementItems) {
×
415
            if (si.willMatchAnyTriple()) return true;
×
416
        }
×
417
        return false;
×
418
    }
419

420
    /**
421
     * Fills the context with statements, processing each StatementItem.
422
     *
423
     * @param statements the list of statements to fill
424
     * @throws com.knowledgepixels.nanodash.template.UnificationException if there is an error during unification of statements
425
     */
426
    public void fill(List<Statement> statements) throws UnificationException {
427
        for (StatementItem si : statementItems) {
×
428
            si.fill(statements);
×
429
        }
×
430
        for (StatementItem si : statementItems) {
×
431
            si.fillFinished();
×
432
        }
×
433
    }
×
434

435
    /**
436
     * Returns the existing Nanopub associated with this context, if any.
437
     *
438
     * @return the existing Nanopub, or null if this context is for a new Nanopub
439
     */
440
    public Nanopub getExistingNanopub() {
441
        return existingNanopub;
×
442
    }
443

444
    /**
445
     * Checks if this context is read-only.
446
     *
447
     * @return true if the context is read-only, false otherwise
448
     */
449
    public boolean isReadOnly() {
450
        return existingNanopub != null;
×
451
    }
452

453
    /**
454
     * Returns the label for a given IRI, if available.
455
     *
456
     * @param iri the IRI for which to get the label
457
     * @return the label as a String, or null if no label is found
458
     */
459
    public String getLabel(IRI iri) {
460
        if (existingNanopub == null) return null;
×
461
        if (labels == null) {
×
462
            labels = new HashMap<>();
×
463
            for (Statement st : existingNanopub.getPubinfo()) {
×
464
                if (st.getPredicate().equals(NTEMPLATE.HAS_LABEL_FROM_API) || st.getPredicate().equals(RDFS.LABEL)) {
×
465
                    String label = st.getObject().stringValue();
×
466
                    labels.put((IRI) st.getSubject(), label);
×
467
                }
468
            }
×
469
        }
470
        return labels.get(iri);
×
471
    }
472

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