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

knowledgepixels / nanodash / 29395622307

15 Jul 2026 06:54AM UTC coverage: 30.168% (+0.8%) from 29.361%
29395622307

Pull #559

github

web-flow
Merge f07c8a0b6 into 809bff55b
Pull Request #559: feat: language-tag picker for literal placeholders

2086 of 7605 branches covered (27.43%)

Branch coverage included in aggregate %.

4020 of 12635 relevant lines covered (31.82%)

4.8 hits per line

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

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

44
import java.net.URISyntaxException;
45
import java.net.URLEncoder;
46
import java.util.HashMap;
47
import java.util.List;
48
import java.util.Map;
49

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

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

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

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

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

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

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

129
        }));
130

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

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

158
        }, new Model<String>() {
27✔
159

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

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

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

237
        }));
238
        Model<String> uriModel = new Model<String>() {
33✔
239

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

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

270
        showMoreLabelLiteral = new Label("show-more-literal", "");
21✔
271
        add(showMoreLabelLiteral);
30✔
272
        showMoreLabelLiteral.setVisible(false);
15✔
273

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

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

299
    /**
300
     * {@inheritDoc}
301
     */
302
    @Override
303
    public void finalizeValues() {
304
    }
3✔
305

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

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

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

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

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

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

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

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

379
    /**
380
     * {@inheritDoc}
381
     */
382
    @Override
383
    public boolean isUnifiableWith(Value v) {
384
        if (v == null) return true;
6!
385
        if (v instanceof IRI) {
9✔
386
            String vs = v.stringValue();
9✔
387
            if (vs.equals(LocalUri.of("nanopub").stringValue())) {
18!
388
                vs = getNanopubValue();
×
389
            } else if (vs.equals(LocalUri.of("assertion").stringValue())) {
18!
390
                vs = getAssertionValue();
×
391
            }
392
            if (vs.startsWith(prefix)) vs = vs.substring(prefix.length());
33!
393
//                        if (Utils.isLocalURI(vs)) vs = vs.replaceFirst("^" + LocalUri.PREFIX, "");
394
            if (template.isAutoEscapePlaceholder(iri)) {
18!
395
                vs = Utils.urlDecode(vs);
×
396
            }
397
            Validatable<String> validatable = new Validatable<>(vs);
15✔
398
//                        if (template.isLocalResource(iri) && !Utils.isUriPostfix(vs)) {
399
//                                vs = Utils.getUriPostfix(vs);
400
//                        }
401
            new Validator().validate(validatable);
18✔
402
            if (!validatable.isValid()) {
9✔
403
                return false;
6✔
404
            }
405
            if (model.getObject().isEmpty()) {
18✔
406
                return true;
6✔
407
            }
408
            return vs.equals(model.getObject());
18✔
409
        } else if (v instanceof Literal vL) {
18!
410
            if (template.getRegex(iri) != null && !v.stringValue().matches(template.getRegex(iri))) {
18!
411
                return false;
×
412
            }
413
            String languagetag = template.getLanguageTag(iri);
18✔
414
            IRI datatype = template.getDatatype(iri);
18✔
415
            if (template.isLanguageTagSelectable(iri)) {
18✔
416
                // Any tag from the allowed set unifies (any tag at all if unrestricted);
417
                // a declared nt:hasLanguageTag is only the picker's default.
418
                if (vL.getLanguage().isEmpty()) {
12✔
419
                    return false;
6✔
420
                }
421
                List<String> possibleTags = template.getPossibleLanguageTags(iri);
18✔
422
                if (possibleTags != null && !possibleTags.contains(Literals.normalizeLanguageTag(vL.getLanguage().get()))) {
30✔
423
                    return false;
6✔
424
                }
425
            } else if (languagetag != null) {
9✔
426
                if (vL.getLanguage().isEmpty() || !Literals.normalizeLanguageTag(vL.getLanguage().get()).equals(languagetag)) {
36!
427
                    return false;
6✔
428
                }
429
            } else if (datatype != null) {
6!
430
                if (!vL.getDatatype().equals(datatype)) {
×
431
                    return false;
×
432
                }
433
            }
434
            if (linkComp.getDefaultModelObject() == null || linkComp.getDefaultModelObject().toString().isEmpty()) {
30!
435
                return true;
6✔
436
            }
437
            return linkComp.getDefaultModelObject().equals("\"" + v.stringValue() + "\"");
×
438
        }
439
        return false;
×
440
    }
441

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

498
    /**
499
     * Validator class for validating the input.
500
     */
501
    protected class Validator extends InvalidityHighlighting implements IValidator<String> {
502

503
        /**
504
         * Default constructor for Validator.
505
         */
506
        public Validator() {
15✔
507
        }
3✔
508

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

573
    }
574

575
    /**
576
     * <p>toString.</p>
577
     *
578
     * @return a {@link java.lang.String} object
579
     */
580
    public String toString() {
581
        return "[read-only IRI item: " + iri + "]";
×
582
    }
583

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