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

knowledgepixels / nanodash / 28574924141

02 Jul 2026 08:02AM UTC coverage: 28.037% (-0.02%) from 28.06%
28574924141

push

github

web-flow
Merge pull request #528 from knowledgepixels/fix/derive-root-definition-527

fix: reset root definition when deriving; add override fill mode

1736 of 7061 branches covered (24.59%)

Branch coverage included in aggregate %.

3625 of 12060 relevant lines covered (30.06%)

4.45 hits per line

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

41.2
src/main/java/com/knowledgepixels/nanodash/component/ReadonlyItem.java
1
package com.knowledgepixels.nanodash.component;
2

3
import com.knowledgepixels.nanodash.LocalUri;
4
import com.knowledgepixels.nanodash.RestrictedChoice;
5
import com.knowledgepixels.nanodash.domain.User;
6
import com.knowledgepixels.nanodash.Utils;
7
import com.knowledgepixels.nanodash.component.StatementItem.RepetitionGroup;
8
import com.knowledgepixels.nanodash.domain.IndividualAgent;
9
import com.knowledgepixels.nanodash.domain.MaintainedResource;
10
import com.knowledgepixels.nanodash.domain.Space;
11
import com.knowledgepixels.nanodash.page.ExplorePage;
12
import com.knowledgepixels.nanodash.repository.MaintainedResourceRepository;
13
import com.knowledgepixels.nanodash.repository.SpaceRepository;
14
import com.knowledgepixels.nanodash.template.ContextType;
15
import com.knowledgepixels.nanodash.template.Template;
16
import com.knowledgepixels.nanodash.template.UnificationException;
17
import net.trustyuri.TrustyUriUtils;
18
import org.apache.commons.codec.Charsets;
19
import org.apache.wicket.behavior.AttributeAppender;
20
import org.apache.wicket.markup.html.basic.Label;
21
import org.apache.wicket.markup.html.link.ExternalLink;
22
import org.apache.wicket.model.IModel;
23
import org.apache.wicket.model.Model;
24
import org.apache.wicket.validation.IValidatable;
25
import org.apache.wicket.validation.IValidator;
26
import org.apache.wicket.validation.Validatable;
27
import org.apache.wicket.validation.ValidationError;
28
import org.eclipse.rdf4j.common.net.ParsedIRI;
29
import org.eclipse.rdf4j.model.IRI;
30
import org.eclipse.rdf4j.model.Literal;
31
import org.eclipse.rdf4j.model.Value;
32
import org.eclipse.rdf4j.model.ValueFactory;
33
import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
34
import org.eclipse.rdf4j.model.util.Literals;
35
import org.eclipse.rdf4j.model.vocabulary.XSD;
36
import org.nanopub.Nanopub;
37
import org.nanopub.NanopubUtils;
38
import org.nanopub.SimpleCreatorPattern;
39
import org.nanopub.vocabulary.NTEMPLATE;
40
import org.slf4j.Logger;
41
import org.slf4j.LoggerFactory;
42

43
import java.net.URISyntaxException;
44
import java.net.URLEncoder;
45
import java.util.HashMap;
46
import java.util.Map;
47

48
/**
49
 * ReadonlyItem is a component that displays a read-only item in the form.
50
 */
51
public class ReadonlyItem extends AbstractContextComponent {
52

53
    private static final int LONG_LITERAL_LENGTH = 100;
54
    private static final Logger logger = LoggerFactory.getLogger(ReadonlyItem.class);
9✔
55
    private static final ValueFactory vf = SimpleValueFactory.getInstance();
9✔
56

57
    private IModel<String> model;
58
    private String prefix;
59
    private ExternalLink linkComp;
60
    private Label extraComp, languageComp, datatypeComp;
61
    private IModel<String> extraModel, languageModel, datatypeModel;
62
    private IRI iri;
63
    private RestrictedChoice restrictedChoice;
64
    private Label showMoreLabelLiteral, showMoreLabelHTML;
65
    private final Template template;
66

67
    /**
68
     * Constructor for ReadonlyItem.
69
     *
70
     * @param id              the component id
71
     * @param parentId        the parent id (e.g., "subj", "obj")
72
     * @param iriP            the IRI of the item
73
     * @param statementPartId the statement part ID
74
     * @param rg              the repetition group
75
     */
76
    public ReadonlyItem(String id, String parentId, final IRI iriP, IRI statementPartId, final RepetitionGroup rg) {
77
        super(id, rg.getContext());
15✔
78
        this.iri = iriP;
9✔
79
        template = context.getTemplate();
15✔
80
        model = (IModel<String>) context.getComponentModels().get(iri);
27✔
81
        boolean modelIsNew = false;
6✔
82
        if (model == null) {
9✔
83
            model = Model.of("");
12✔
84
            context.getComponentModels().put(iri, model);
27✔
85
            modelIsNew = true;
6✔
86
        }
87
        String postfix = Utils.getUriPostfix(iri);
12✔
88
        if (modelIsNew && context.hasParam(postfix)) {
21!
89
            model.setObject(context.getParam(postfix));
×
90
        }
91
        if (model.getObject().isEmpty() && template.isRootNanopubPlaceholder(iri) && context.getReferenceNanopub() == null) {
36!
92
            model.setObject(LocalUri.of("nanopub").stringValue());
×
93
        }
94

95
        final Map<String, String> foafNameMap;
96
        if (context.getExistingNanopub() == null) {
12✔
97
            foafNameMap = new HashMap<>();
15✔
98
        } else {
99
            foafNameMap = Utils.getFoafNameMap(context.getExistingNanopub());
15✔
100
        }
101

102
        prefix = template.getPrefix(iri);
21✔
103
        if (prefix == null) prefix = "";
18!
104
        if (template.isRestrictedChoicePlaceholder(iri)) {
18✔
105
            restrictedChoice = new RestrictedChoice(iri, context);
27✔
106
        }
107
        add(new Label("prefix", new Model<String>() {
90✔
108

109
            @Override
110
            public String getObject() {
111
                String prefixLabel = template.getPrefixLabel(iri);
×
112
                String v = getFullValue();
×
113
                if (prefixLabel == null || IndividualAgent.isUser(v) || foafNameMap.containsKey(v)) {
×
114
                    return "";
×
115
                } else if (prefixLabel.matches("https?://.*")) {
×
116
                    // Hide prefix label that leaks through as a raw URL.
117
                    return "";
×
118
                } else {
119
                    if (!prefixLabel.isEmpty() && parentId.equals("subj")) {
×
120
                        // Capitalize first letter of label if at subject position:
121
                        prefixLabel = prefixLabel.substring(0, 1).toUpperCase() + prefixLabel.substring(1);
×
122
                    }
123
                    return prefixLabel;
×
124
                }
125
            }
126

127
        }));
128

129
        linkComp = new ExternalLink("link", new Model<String>() {
63✔
130

131
            @Override
132
            public String getObject() {
133
                String obj = getFullValue();
12✔
134
                if (obj == null) return "";
6!
135
                if (obj.equals(LocalUri.of("nanopub").stringValue())) {
18!
136
                    if (context.getExistingNanopub() != null) {
×
137
                        obj = context.getExistingNanopub().getUri().stringValue();
×
138
                        return ExplorePage.MOUNT_PATH + "?id=" + URLEncoder.encode(obj, Charsets.UTF_8);
×
139
                    } else {
140
                        return "";
×
141
                    }
142
                } else if (obj.equals(LocalUri.of("assertion").stringValue())) {
18!
143
                    if (context.getExistingNanopub() != null) {
×
144
                        obj = context.getExistingNanopub().getAssertionUri().stringValue();
×
145
                        return ExplorePage.MOUNT_PATH + "?id=" + URLEncoder.encode(obj, Charsets.UTF_8);
×
146
                    } else {
147
                        return "";
×
148
                    }
149
                } else if (obj.matches("https?://.+")) {
12!
150
                    return NanodashLink.getPageUrl(obj);
×
151
                } else {
152
                    return "";
6✔
153
                }
154
            }
155

156
        }, new Model<String>() {
27✔
157

158
            @Override
159
            public String getObject() {
160
                String obj = getFullValue();
×
161
                if (rootResolvesToThisNanopub()) {
×
162
                    // No prior value migrated (e.g. supersede with a newer template that added this slot),
163
                    // or we are deriving. Either way the root resolves to the new nanopub in
164
                    // TemplateContext.processValue, so surface that to the user in the form.
165
                    return "this nanopublication";
×
166
                }
167
                if (obj != null && obj.equals(LocalUri.of("nanopub").stringValue())) {
×
168
                    return "this nanopublication";
×
169
                }
170
                if (obj != null && obj.equals(LocalUri.of("assertion").stringValue())) {
×
171
                    return context.getType() == ContextType.ASSERTION ? "this assertion" : "the assertion above";
×
172
                }
173
                if (obj != null && obj.matches("https?://.+")) {
×
174
                    IRI objIri = vf.createIRI(obj);
×
175
                    if (iri.equals(NTEMPLATE.CREATOR_PLACEHOLDER)) {
×
176
                        // TODO We might want to introduce a "(you)" flag here at some point
177
                        return User.getShortDisplayName(objIri);
×
178
                    } else if (isAssertionValue(objIri)) {
×
179
                        if (context.getType() == ContextType.ASSERTION) {
×
180
                            return "this assertion";
×
181
                        } else {
182
                            return "the assertion above";
×
183
                        }
184
                    } else if (isNanopubValue(objIri)) {
×
185
                        return "this nanopublication";
×
186
                    } else if (IndividualAgent.isUser(obj)) {
×
187
                        return User.getShortDisplayName(objIri);
×
188
                    } else if (foafNameMap.containsKey(obj)) {
×
189
                        return foafNameMap.get(obj);
×
190
                    }
191
                    Space space = SpaceRepository.get().findById(obj);
×
192
                    if (space != null) return Utils.truncateLinkLabel(space.getLabel());
×
193
                    space = SpaceRepository.get().findByAltId(obj);
×
194
                    if (space != null) return Utils.truncateLinkLabel(space.getLabel());
×
195
                    MaintainedResource mr = MaintainedResourceRepository.get().findById(obj);
×
196
                    if (mr != null) return Utils.truncateLinkLabel(mr.getLabel());
×
197
                    return Utils.truncateLinkLabel(getLabelString(objIri));
×
198
                }
199
                return obj;
×
200
            }
201

202
        });
203
        if (template.isIntroducedResource(iri) || template.isEmbeddedResource(iri)) {
36!
204
            linkComp.add(AttributeAppender.append("class", "introduced"));
×
205
        }
206
        add(linkComp);
30✔
207
        add(new Label("description", new Model<String>() {
66✔
208

209
            @Override
210
            public String getObject() {
211
                String obj = getFullValue();
×
212
                if (rootResolvesToThisNanopub()) {
×
213
                    return "This is the identifier for this whole nanopublication.";
×
214
                }
215
                if (obj != null && obj.matches("https?://.+")) {
×
216
                    IRI objIri = vf.createIRI(obj);
×
217
                    if (isAssertionValue(objIri)) {
×
218
                        return "This is the identifier for the assertion of this nanopublication.";
×
219
                    } else if (isNanopubValue(objIri)) {
×
220
                        return "This is the identifier for this whole nanopublication.";
×
221
                    } else if (context.isReadOnly() && obj.startsWith(context.getExistingNanopub().getUri().stringValue())) {
×
222
                        return "This is a local identifier minted within the nanopublication.";
×
223
                    }
224
                    String labelString = getLabelString(objIri);
×
225
                    String description = "";
×
226
                    if (labelString.contains(" - ")) description = labelString.replaceFirst("^.* - ", "");
×
227
                    return description;
×
228
                } else if (obj != null && obj.startsWith("\"")) {
×
229
                    return "(this is a literal)";
×
230
                }
231
                return "";
×
232
            }
233

234
        }));
235
        Model<String> uriModel = new Model<String>() {
33✔
236

237
            @Override
238
            public String getObject() {
239
                String obj = getFullValue();
×
240
                if (rootResolvesToThisNanopub()) {
×
241
                    return LocalUri.of("nanopub").stringValue();
×
242
                }
243
                if (obj != null && obj.startsWith("\"")) return "";
×
244
                if (isAssertionValue(obj)) {
×
245
                    return getAssertionValue();
×
246
                } else if (isNanopubValue(obj)) {
×
247
                    return getNanopubValue();
×
248
                }
249
                return obj;
×
250
            }
251

252
        };
253
        add(Utils.getUriLink("uri", uriModel));
33✔
254
        extraModel = Model.of("");
12✔
255
        extraComp = new Label("extra", extraModel);
24✔
256
        extraComp.setVisible(false);
15✔
257
        add(extraComp);
30✔
258
        languageModel = Model.of("");
12✔
259
        languageComp = new Label("language", languageModel);
24✔
260
        languageComp.setVisible(false);
15✔
261
        add(languageComp);
30✔
262
        datatypeModel = Model.of("");
12✔
263
        datatypeComp = new Label("datatype", datatypeModel);
24✔
264
        datatypeComp.setVisible(false);
15✔
265
        add(datatypeComp);
30✔
266

267
        showMoreLabelLiteral = new Label("show-more-literal", "");
21✔
268
        add(showMoreLabelLiteral);
30✔
269
        showMoreLabelLiteral.setVisible(false);
15✔
270

271
        showMoreLabelHTML = new Label("show-more-html", "");
21✔
272
        add(showMoreLabelHTML);
30✔
273
        showMoreLabelHTML.setVisible(false);
15✔
274
    }
3✔
275

276
    /**
277
     * {@inheritDoc}
278
     */
279
    @Override
280
    public void fillFinished() {
281
        String obj = getFullValue();
9✔
282
        if (obj != null) {
6!
283
            if (isAssertionValue(obj)) {
12!
284
                linkComp.add(new AttributeAppender("class", "this-assertion"));
×
285
            } else if (isNanopubValue(obj)) {
12!
286
                linkComp.add(new AttributeAppender("class", "this-nanopub"));
×
287
            } else if (context.getExistingNanopub() != null) {
12!
288
                Nanopub np = context.getExistingNanopub();
12✔
289
                if (NanopubUtils.getIntroducedIriIds(np).contains(obj) || NanopubUtils.getEmbeddedIriIds(np).contains(obj)) {
30!
290
                    linkComp.add(AttributeAppender.append("class", "introduced"));
×
291
                }
292
            }
293
        }
294
    }
3✔
295

296
    /**
297
     * {@inheritDoc}
298
     */
299
    @Override
300
    public void finalizeValues() {
301
    }
3✔
302

303
    private String getLabelString(IRI iri) {
304
        if (template.getLabel(iri) != null) {
×
305
            return template.getLabel(iri).replaceFirst(" - .*$", "");
×
306
        } else if (context.getLabel(iri) != null) {
×
307
            return context.getLabel(iri).replaceFirst(" - .*$", "");
×
308
        } else {
309
            return Utils.getShortNameFromURI(iri.stringValue());
×
310
        }
311
    }
312

313
    /**
314
     * {@inheritDoc}
315
     */
316
    @Override
317
    public void removeFromContext() {
318
        // Nothing to be done here.
319
    }
3✔
320

321
    private String getFullValue() {
322
        String s = model.getObject();
15✔
323
        if (s == null) return null;
6!
324
        if (template.isAutoEscapePlaceholder(iri)) {
18!
325
            s = Utils.urlEncode(s);
×
326
        }
327
        if (!prefix.isEmpty()) {
12!
328
            s = prefix + s;
×
329
        }
330
        return s;
6✔
331
    }
332

333
    // True when the root-nanopub placeholder will resolve to the new nanopub itself:
334
    // either no prior root value was migrated, or we are deriving (which resets the root
335
    // to the new nanopub, see TemplateContext.processValue / issue #527).
336
    private boolean rootResolvesToThisNanopub() {
337
        if (!template.isRootNanopubPlaceholder(iri)) return false;
×
338
        String obj = getFullValue();
×
339
        return obj == null || obj.isEmpty() || context.getFillMode() == PublishForm.FillMode.DERIVE;
×
340
    }
341

342
    private boolean isNanopubValue(Object obj) {
343
        if (obj == null) return false;
6!
344
        if (obj.toString().equals(LocalUri.of("nanopub").stringValue())) return true;
21!
345
        // A fillSource match means a *prior* nanopub (supersede/derive), not "this" one — don't label it as such.
346
        if (context.getExistingNanopub() == null) return false;
12!
347
        return obj.toString().equals(context.getExistingNanopub().getUri().stringValue());
27✔
348
    }
349

350
    private String getNanopubValue() {
351
        Nanopub ref = context.getReferenceNanopub();
×
352
        if (ref != null) {
×
353
            return ref.getUri().stringValue();
×
354
        } else {
355
            return LocalUri.of("nanopub").stringValue();
×
356
        }
357
    }
358

359
    private boolean isAssertionValue(Object obj) {
360
        if (obj == null) return false;
6!
361
        if (obj.toString().equals(LocalUri.of("assertion").stringValue())) return true;
21!
362
        // A fillSource match means a *prior* assertion (supersede/derive), not "this" one.
363
        if (context.getExistingNanopub() == null) return false;
12!
364
        return obj.toString().equals(context.getExistingNanopub().getAssertionUri().stringValue());
27✔
365
    }
366

367
    private String getAssertionValue() {
368
        Nanopub ref = context.getReferenceNanopub();
×
369
        if (ref != null) {
×
370
            return ref.getAssertionUri().stringValue();
×
371
        } else {
372
            return LocalUri.of("assertion").stringValue();
×
373
        }
374
    }
375

376
    /**
377
     * {@inheritDoc}
378
     */
379
    @Override
380
    public boolean isUnifiableWith(Value v) {
381
        if (v == null) return true;
6!
382
        if (v instanceof IRI) {
9✔
383
            String vs = v.stringValue();
9✔
384
            if (vs.equals(LocalUri.of("nanopub").stringValue())) {
18!
385
                vs = getNanopubValue();
×
386
            } else if (vs.equals(LocalUri.of("assertion").stringValue())) {
18!
387
                vs = getAssertionValue();
×
388
            }
389
            if (vs.startsWith(prefix)) vs = vs.substring(prefix.length());
33!
390
//                        if (Utils.isLocalURI(vs)) vs = vs.replaceFirst("^" + LocalUri.PREFIX, "");
391
            if (template.isAutoEscapePlaceholder(iri)) {
18!
392
                vs = Utils.urlDecode(vs);
×
393
            }
394
            Validatable<String> validatable = new Validatable<>(vs);
15✔
395
//                        if (template.isLocalResource(iri) && !Utils.isUriPostfix(vs)) {
396
//                                vs = Utils.getUriPostfix(vs);
397
//                        }
398
            new Validator().validate(validatable);
18✔
399
            if (!validatable.isValid()) {
9✔
400
                return false;
6✔
401
            }
402
            if (model.getObject().isEmpty()) {
18✔
403
                return true;
6✔
404
            }
405
            return vs.equals(model.getObject());
18✔
406
        } else if (v instanceof Literal vL) {
18!
407
            if (template.getRegex(iri) != null && !v.stringValue().matches(template.getRegex(iri))) {
18!
408
                return false;
×
409
            }
410
            String languagetag = template.getLanguageTag(iri);
18✔
411
            IRI datatype = template.getDatatype(iri);
18✔
412
            if (languagetag != null) {
6!
413
                if (vL.getLanguage().isEmpty() || !Literals.normalizeLanguageTag(vL.getLanguage().get()).equals(languagetag)) {
×
414
                    return false;
×
415
                }
416
            } else if (datatype != null) {
6!
417
                if (!vL.getDatatype().equals(datatype)) {
×
418
                    return false;
×
419
                }
420
            }
421
            if (linkComp.getDefaultModelObject() == null || linkComp.getDefaultModelObject().toString().isEmpty()) {
30!
422
                return true;
6✔
423
            }
424
            return linkComp.getDefaultModelObject().equals("\"" + v.stringValue() + "\"");
×
425
        }
426
        return false;
×
427
    }
428

429
    /**
430
     * {@inheritDoc}
431
     */
432
    @Override
433
    public void unifyWith(Value v) throws UnificationException {
434
        if (v == null) return;
6!
435
        String vs = v.stringValue();
9✔
436
        if (!isUnifiableWith(v)) {
12!
437
            logger.error("Cannot unify {}", v);
×
438
            throw new UnificationException(vs);
×
439
        }
440
        if (v instanceof IRI) {
9✔
441
            if (vs.equals(LocalUri.of("nanopub").stringValue())) {
18!
442
                vs = getNanopubValue();
×
443
            } else if (vs.equals(LocalUri.of("assertion").stringValue())) {
18!
444
                vs = getAssertionValue();
×
445
            }
446
            if (!prefix.isEmpty() && vs.startsWith(prefix)) {
12!
447
                vs = vs.substring(prefix.length());
×
448
                // With read-only items, we don't need preliminary local identifiers:
449
//                        } else if (Utils.isLocalURI(vs)) {
450
//                                vs = vs.replaceFirst("^" + LocalUri.PREFIX, "");
451
//                        } else if (template.isLocalResource(iri) && !Utils.isUriPostfix(vs)) {
452
//                                vs = Utils.getUriPostfix(vs);
453
            }
454
            if (template.isAutoEscapePlaceholder(iri)) {
18!
455
                vs = Utils.urlDecode(vs);
×
456
            }
457
            model.setObject(vs);
15✔
458
        } else if (v instanceof Literal vL) {
18!
459
            if (vs.length() >= LONG_LITERAL_LENGTH) {
12✔
460
                linkComp.add(AttributeAppender.append("class", "long-literal collapsed"));
36✔
461
                showMoreLabelLiteral.setVisible(true);
15✔
462
            }
463
            if (vL.getLanguage().isPresent()) {
12!
464
                model.setObject("\"" + vs + "\"");
×
465
                languageModel.setObject("(" + Literals.normalizeLanguageTag(vL.getLanguage().get()) + ")");
×
466
                languageComp.setVisible(true);
×
467
            } else if (!vL.getDatatype().equals(XSD.STRING)) {
15!
468
                model.setObject("\"" + vs + "\"");
×
469
                datatypeModel.setObject("(" + vL.getDatatype().stringValue().replace(XSD.NAMESPACE, "xsd:") + ")");
×
470
                datatypeComp.setVisible(true);
×
471
            } else {
472
                model.setObject("\"" + vs + "\"");
15✔
473
            }
474
            if (Utils.looksLikeHtml(vs)) {
9✔
475
                linkComp.setVisible(false);
15✔
476
                extraModel.setObject(Utils.sanitizeHtml(vs));
15✔
477
                extraComp.setEscapeModelStrings(false);
15✔
478
                extraComp.setVisible(true);
15✔
479
                showMoreLabelLiteral.setVisible(false);
15✔
480
                showMoreLabelHTML.setVisible(true);
15✔
481
            }
482
        }
483
    }
3✔
484

485
    /**
486
     * Validator class for validating the input.
487
     */
488
    protected class Validator extends InvalidityHighlighting implements IValidator<String> {
489

490
        /**
491
         * Default constructor for Validator.
492
         */
493
        public Validator() {
15✔
494
        }
3✔
495

496
        @Override
497
        public void validate(IValidatable<String> s) {
498
            String sv = s.getValue();
12✔
499
            String p = prefix;
12✔
500
            if (template.isAutoEscapePlaceholder(iri)) {
24!
501
                sv = Utils.urlEncode(sv);
×
502
            }
503
            if (sv.matches("https?://.+")) {
12!
504
                p = "";
9✔
505
            } else if (sv.contains(":")) {
×
506
                s.error(new ValidationError("Colon character is not allowed in postfix"));
×
507
            }
508
            String iriString = p + sv;
12✔
509
            if (iriString.matches("[^:# ]+")) {
12!
510
                p = LocalUri.PREFIX;
×
511
                iriString = p + sv;
×
512
            }
513
            try {
514
                ParsedIRI piri = new ParsedIRI(iriString);
15✔
515
                if (!piri.isAbsolute()) {
9!
516
                    s.error(new ValidationError("IRI not well-formed"));
×
517
                }
518
                if (p.isEmpty() && !Utils.isLocalURI(sv) && !sv.matches("https?://.+")) {
30!
519
                    s.error(new ValidationError("Only http(s):// IRIs are allowed here"));
×
520
                }
521
            } catch (URISyntaxException ex) {
×
522
                s.error(new ValidationError("IRI not well-formed"));
×
523
            }
3✔
524
            String regex = template.getRegex(iri);
24✔
525
            if (regex != null) {
6!
526
                if (!sv.matches(regex)) {
×
527
                    s.error(new ValidationError("Value '" + sv + "' doesn't match the pattern '" + regex + "'"));
×
528
                }
529
            }
530
            if (template.isRestrictedChoicePlaceholder(iri)) {
24✔
531
                if (!restrictedChoice.getPossibleValues().contains(iriString) && !restrictedChoice.hasPossibleRefValues()) {
36✔
532
                    // not checking the possible ref values can overgenerate, but normally works
533
                    s.error(new ValidationError("Invalid choice"));
18✔
534
                }
535
            }
536
            if (template.isExternalUriPlaceholder(iri)) {
24!
537
                if (!iriString.matches("https?://.+")) {
×
538
                    s.error(new ValidationError("Not an external IRI"));
×
539
                }
540
            }
541
            if (template.isTrustyUriPlaceholder(iri)) {
24!
542
                if (!TrustyUriUtils.isPotentialTrustyUri(iriString)) {
×
543
                    s.error(new ValidationError("Not a trusty URI"));
×
544
                }
545
            }
546
            if (iri.equals(NTEMPLATE.CREATOR_PLACEHOLDER) && context.getExistingNanopub() != null) {
18!
547
                boolean found = false;
×
548
                for (IRI creator : SimpleCreatorPattern.getCreators(context.getExistingNanopub())) {
×
549
                    if (creator.stringValue().equals(iriString)) {
×
550
                        found = true;
×
551
                        break;
×
552
                    }
553
                }
×
554
                if (!found) {
×
555
                    s.error(new ValidationError("Not a creator of nanopub"));
×
556
                }
557
            }
558
        }
3✔
559

560
    }
561

562
    /**
563
     * <p>toString.</p>
564
     *
565
     * @return a {@link java.lang.String} object
566
     */
567
    public String toString() {
568
        return "[read-only IRI item: " + iri + "]";
×
569
    }
570

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