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

knowledgepixels / nanodash / 17302137193

28 Aug 2025 04:35PM UTC coverage: 11.965% (-0.4%) from 12.355%
17302137193

Pull #244

github

web-flow
Merge 4e969b0ee into 3323a35f1
Pull Request #244: Use vocabularies with latest version of `nanopub-java`

331 of 3840 branches covered (8.62%)

Branch coverage included in aggregate %.

943 of 6808 relevant lines covered (13.85%)

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.NanopubCreator;
19
import org.nanopub.NanopubWithNs;
20
import org.nanopub.vocabulary.NTEMPLATE;
21

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

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

30
    private static final long serialVersionUID = 1L;
31

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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