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

knowledgepixels / nanodash / 19291868322

12 Nov 2025 09:00AM UTC coverage: 14.211% (+0.3%) from 13.89%
19291868322

push

github

tkuhn
feat(PublishForm): Support for loading values from query result

537 of 4736 branches covered (11.34%)

Branch coverage included in aggregate %.

1377 of 8732 relevant lines covered (15.77%)

0.71 hits per line

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

0.0
src/main/java/com/knowledgepixels/nanodash/component/PublishForm.java
1
package com.knowledgepixels.nanodash.component;
2

3
import com.github.jsonldjava.shaded.com.google.common.base.Charsets;
4
import com.knowledgepixels.nanodash.*;
5
import com.knowledgepixels.nanodash.page.ExplorePage;
6
import com.knowledgepixels.nanodash.page.NanodashPage;
7
import com.knowledgepixels.nanodash.template.*;
8
import org.apache.commons.lang3.Strings;
9
import org.apache.http.NameValuePair;
10
import org.apache.http.client.utils.URLEncodedUtils;
11
import org.apache.wicket.Component;
12
import org.apache.wicket.RestartResponseException;
13
import org.apache.wicket.ajax.AjaxEventBehavior;
14
import org.apache.wicket.ajax.AjaxRequestTarget;
15
import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
16
import org.apache.wicket.feedback.FeedbackMessage;
17
import org.apache.wicket.markup.html.WebMarkupContainer;
18
import org.apache.wicket.markup.html.WebPage;
19
import org.apache.wicket.markup.html.basic.Label;
20
import org.apache.wicket.markup.html.form.CheckBox;
21
import org.apache.wicket.markup.html.form.Form;
22
import org.apache.wicket.markup.html.form.FormComponent;
23
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
24
import org.apache.wicket.markup.html.list.ListItem;
25
import org.apache.wicket.markup.html.list.ListView;
26
import org.apache.wicket.markup.html.panel.FeedbackPanel;
27
import org.apache.wicket.markup.html.panel.Panel;
28
import org.apache.wicket.markup.repeater.Item;
29
import org.apache.wicket.markup.repeater.data.DataView;
30
import org.apache.wicket.markup.repeater.data.ListDataProvider;
31
import org.apache.wicket.model.IModel;
32
import org.apache.wicket.model.Model;
33
import org.apache.wicket.request.mapper.parameter.PageParameters;
34
import org.apache.wicket.validation.IValidatable;
35
import org.apache.wicket.validation.IValidator;
36
import org.apache.wicket.validation.ValidationError;
37
import org.eclipse.rdf4j.model.IRI;
38
import org.eclipse.rdf4j.model.Literal;
39
import org.eclipse.rdf4j.model.Statement;
40
import org.eclipse.rdf4j.model.ValueFactory;
41
import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
42
import org.eclipse.rdf4j.model.vocabulary.FOAF;
43
import org.eclipse.rdf4j.model.vocabulary.RDFS;
44
import org.nanopub.MalformedNanopubException;
45
import org.nanopub.Nanopub;
46
import org.nanopub.NanopubAlreadyFinalizedException;
47
import org.nanopub.NanopubCreator;
48
import org.nanopub.extra.security.SignNanopub;
49
import org.nanopub.extra.security.SignatureAlgorithm;
50
import org.nanopub.extra.security.TransformContext;
51
import org.nanopub.extra.server.PublishNanopub;
52
import org.nanopub.extra.services.APINotReachableException;
53
import org.nanopub.extra.services.ApiResponse;
54
import org.nanopub.extra.services.ApiResponseEntry;
55
import org.nanopub.extra.services.FailedApiCallException;
56
import org.nanopub.extra.services.NotEnoughAPIInstancesException;
57
import org.nanopub.extra.services.QueryRef;
58
import org.nanopub.vocabulary.NPX;
59
import org.nanopub.vocabulary.NTEMPLATE;
60
import org.slf4j.Logger;
61
import org.slf4j.LoggerFactory;
62
import org.wicketstuff.select2.ChoiceProvider;
63
import org.wicketstuff.select2.Response;
64
import org.wicketstuff.select2.Select2Choice;
65

66
import java.lang.reflect.InvocationTargetException;
67
import java.net.URI;
68
import java.nio.charset.Charset;
69
import java.util.*;
70

71
/**
72
 * Form for publishing a nanopublication.
73
 */
74
public class PublishForm extends Panel {
75

76
    private static final Logger logger = LoggerFactory.getLogger(PublishForm.class);
×
77

78
    private static final ValueFactory vf = SimpleValueFactory.getInstance();
×
79

80
    private static String creatorPubinfoTemplateId = "https://w3id.org/np/RAukAcWHRDlkqxk7H2XNSegc1WnHI569INvNr-xdptDGI";
×
81
    private static String licensePubinfoTempalteId = "https://w3id.org/np/RA0J4vUn_dekg-U1kK3AOEt02p9mT2WO03uGxLDec1jLw";
×
82
    private static String defaultProvTemplateId = "https://w3id.org/np/RA7lSq6MuK_TIC6JMSHvLtee3lpLoZDOqLJCLXevnrPoU";
×
83
    private static String supersedesPubinfoTemplateId = "https://w3id.org/np/RAoTD7udB2KtUuOuAe74tJi1t3VzK0DyWS7rYVAq1GRvw";
×
84
    private static String derivesFromPubinfoTemplateId = "https://w3id.org/np/RARW4MsFkHuwjycNElvEVtuMjpf4yWDL10-0C5l2MqqRQ";
×
85

86
    private static String[] fixedPubInfoTemplates = new String[]{creatorPubinfoTemplateId, licensePubinfoTempalteId};
×
87

88
    /**
89
     * Fill modes for the nanopublication to be created.
90
     */
91
    public enum FillMode {
×
92
        /**
93
         * Use fill mode
94
         */
95
        USE,
×
96
        /**
97
         * Supersede fill mode
98
         */
99
        SUPERSEDE,
×
100
        /**
101
         * Derive fill mode
102
         */
103
        DERIVE
×
104
    }
105

106
    protected Form<?> form;
107
    protected FeedbackPanel feedbackPanel;
108
    private final TemplateContext assertionContext;
109
    private TemplateContext provenanceContext;
110
    private List<TemplateContext> pubInfoContexts = new ArrayList<>();
×
111
    private Map<String, TemplateContext> pubInfoContextMap = new HashMap<>();
×
112
    private List<TemplateContext> requiredPubInfoContexts = new ArrayList<>();
×
113
    private String targetNamespace;
114
    private Class<? extends WebPage> confirmPageClass;
115

116
    /**
117
     * Constructor for the PublishForm.
118
     *
119
     * @param id               the Wicket component ID
120
     * @param pageParams       the parameters for the page, which may include information on how to fill the form
121
     * @param publishPageClass the class of the page to redirect to after successful publication
122
     * @param confirmPageClass the class of the confirmation page to show after publication
123
     */
124
    public PublishForm(String id, final PageParameters pageParams, Class<? extends WebPage> publishPageClass, Class<? extends WebPage> confirmPageClass) {
125
        super(id);
×
126
        setOutputMarkupId(true);
×
127
        this.confirmPageClass = confirmPageClass;
×
128

129
        WebMarkupContainer linkMessageItem = new WebMarkupContainer("link-message-item");
×
130
        if (pageParams.get("link-message").isNull()) {
×
131
            linkMessageItem.add(new Label("link-message", ""));
×
132
            linkMessageItem.setVisible(false);
×
133
        } else {
134
            linkMessageItem.add(new Label("link-message", Utils.sanitizeHtml(pageParams.get("link-message").toString())).setEscapeModelStrings(false));
×
135
        }
136
        add(linkMessageItem);
×
137

138
        final Nanopub fillNp;
139
        final FillMode fillMode;
140
        boolean fillOnlyAssertion = false;
×
141
        if (!pageParams.get("use").isNull()) {
×
142
            fillNp = Utils.getNanopub(pageParams.get("use").toString());
×
143
            fillMode = FillMode.USE;
×
144
        } else if (!pageParams.get("use-a").isNull()) {
×
145
            fillNp = Utils.getNanopub(pageParams.get("use-a").toString());
×
146
            fillMode = FillMode.USE;
×
147
            fillOnlyAssertion = true;
×
148
        } else if (!pageParams.get("supersede").isNull()) {
×
149
            fillNp = Utils.getNanopub(pageParams.get("supersede").toString());
×
150
            fillMode = FillMode.SUPERSEDE;
×
151
            targetNamespace = pageParams.get("supersede").toString().replaceFirst("RA[A-Za-z0-9-_]{43}$", "");
×
152
        } else if (!pageParams.get("supersede-a").isNull()) {
×
153
            fillNp = Utils.getNanopub(pageParams.get("supersede-a").toString());
×
154
            fillMode = FillMode.SUPERSEDE;
×
155
            fillOnlyAssertion = true;
×
156
        } else if (!pageParams.get("derive").isNull()) {
×
157
            fillNp = Utils.getNanopub(pageParams.get("derive").toString());
×
158
            fillMode = FillMode.DERIVE;
×
159
        } else if (!pageParams.get("derive-a").isNull()) {
×
160
            fillNp = Utils.getNanopub(pageParams.get("derive-a").toString());
×
161
            fillMode = FillMode.DERIVE;
×
162
            fillOnlyAssertion = true;
×
163
        } else if (!pageParams.get("fill-all").isNull()) {
×
164
            // TODO: This is deprecated and should be removed at some point
165
            fillNp = Utils.getNanopub(pageParams.get("fill-all").toString());
×
166
            fillMode = FillMode.USE;
×
167
        } else if (!pageParams.get("fill").isNull()) {
×
168
            // TODO: This is deprecated and should be removed at some point
169
            fillNp = Utils.getNanopub(pageParams.get("fill").toString());
×
170
            fillMode = FillMode.SUPERSEDE;
×
171
        } else {
172
            fillNp = null;
×
173
            fillMode = null;
×
174
        }
175

176
        final TemplateData td = TemplateData.get();
×
177

178
        // TODO Properly integrate this namespace feature:
179
        String templateId = pageParams.get("template").toString();
×
180
        if (td.getTemplate(templateId).getTargetNamespace() != null) {
×
181
            targetNamespace = td.getTemplate(templateId).getTargetNamespace();
×
182
        }
183
        if (!pageParams.get("target-namespace").isNull()) {
×
184
            targetNamespace = pageParams.get("target-namespace").toString();
×
185
        }
186
        if (targetNamespace == null) {
×
187
            targetNamespace = Template.DEFAULT_TARGET_NAMESPACE;
×
188
        }
189
        String targetNamespaceLabel = targetNamespace + "...";
×
190
        targetNamespace = targetNamespace + "~~~ARTIFACTCODE~~~/";
×
191

192
        assertionContext = new TemplateContext(ContextType.ASSERTION, templateId, "statement", targetNamespace);
×
193
        assertionContext.setFillMode(fillMode);
×
194
        final String prTemplateId;
195
        if (pageParams.get("prtemplate").toString() != null) {
×
196
            prTemplateId = pageParams.get("prtemplate").toString();
×
197
        } else {
198
            if (fillNp != null && !fillOnlyAssertion) {
×
199
                if (td.getProvenanceTemplateId(fillNp) != null) {
×
200
                    prTemplateId = td.getProvenanceTemplateId(fillNp).stringValue();
×
201
                } else {
202
                    prTemplateId = "http://purl.org/np/RAcm8OurwUk15WOgBM9wySo-T3a5h6as4K8YR5MBrrxUc";
×
203
                }
204
            } else if (assertionContext.getTemplate().getDefaultProvenance() != null) {
×
205
                prTemplateId = assertionContext.getTemplate().getDefaultProvenance().stringValue();
×
206
            } else {
207
                prTemplateId = defaultProvTemplateId;
×
208
            }
209
        }
210
        provenanceContext = new TemplateContext(ContextType.PROVENANCE, prTemplateId, "pr-statement", targetNamespace);
×
211
        for (String t : fixedPubInfoTemplates) {
×
212
            // TODO consistently check for latest versions of templates here and below:
213
            TemplateContext c = new TemplateContext(ContextType.PUBINFO, t, "pi-statement", targetNamespace);
×
214
            pubInfoContexts.add(c);
×
215
            pubInfoContextMap.put(c.getTemplate().getId(), c);
×
216
            requiredPubInfoContexts.add(c);
×
217
        }
218
        if (fillMode == FillMode.SUPERSEDE) {
×
219
            TemplateContext c = new TemplateContext(ContextType.PUBINFO, supersedesPubinfoTemplateId, "pi-statement", targetNamespace);
×
220
            pubInfoContexts.add(c);
×
221
            pubInfoContextMap.put(supersedesPubinfoTemplateId, c);
×
222
            //requiredPubInfoContexts.add(c);
223
            c.setParam("np", fillNp.getUri().stringValue());
×
224
        } else if (fillMode == FillMode.DERIVE) {
×
225
            TemplateContext c = new TemplateContext(ContextType.PUBINFO, derivesFromPubinfoTemplateId, "pi-statement", targetNamespace);
×
226
            pubInfoContexts.add(c);
×
227
            pubInfoContextMap.put(derivesFromPubinfoTemplateId, c);
×
228
            c.setParam("np", fillNp.getUri().stringValue());
×
229
        }
230
        for (IRI r : assertionContext.getTemplate().getRequiredPubinfoElements()) {
×
231
            String latestId = QueryApiAccess.getLatestVersionId(r.stringValue());
×
232
            if (pubInfoContextMap.containsKey(r.stringValue()) || pubInfoContextMap.containsKey(latestId)) continue;
×
233
            TemplateContext c = new TemplateContext(ContextType.PUBINFO, r.stringValue(), "pi-statement", targetNamespace);
×
234
            pubInfoContexts.add(c);
×
235
            pubInfoContextMap.put(c.getTemplateId(), c);
×
236
            requiredPubInfoContexts.add(c);
×
237
        }
×
238
        Map<Integer, TemplateContext> piParamIdMap = new HashMap<>();
×
239
        for (String k : pageParams.getNamedKeys()) {
×
240
            if (!k.matches("pitemplate[1-9][0-9]*")) continue;
×
241
            Integer i = Integer.parseInt(k.replaceFirst("^pitemplate([1-9][0-9]*)$", "$1"));
×
242
            String tid = pageParams.get(k).toString();
×
243
            // TODO Allow for automatically using latest template version:
244
            //String piTempalteIdLatest = QueryApiAccess.getLatestVersionId(tid);
245
            TemplateContext c = createPubinfoContext(tid);
×
246
            if (piParamIdMap.containsKey(i)) {
×
247
                // TODO: handle this error better
248
                logger.error("ERROR: pitemplate param identifier assigned multiple times: {}", i);
×
249
            }
250
            piParamIdMap.put(i, c);
×
251
        }
×
252
        if (fillNp != null && !fillOnlyAssertion) {
×
253
            for (IRI piTemplateId : td.getPubinfoTemplateIds(fillNp)) {
×
254
                String piTempalteIdLatest = QueryApiAccess.getLatestVersionId(piTemplateId.stringValue());
×
255
                if (piTempalteIdLatest.equals(supersedesPubinfoTemplateId)) continue;
×
256
                if (!pubInfoContextMap.containsKey(piTempalteIdLatest)) {
×
257
                    // TODO Allow for automatically using latest template version
258
                    createPubinfoContext(piTemplateId.stringValue());
×
259
                }
260
            }
×
261
        }
262
        if (!pageParams.get("values-from-query").isEmpty() && !pageParams.get("values-from-query-mapping").isEmpty()) {
×
263
            String querySpec = pageParams.get("values-from-query").toString();
×
264

265
            String mapping = pageParams.get("values-from-query-mapping").toString();
×
266
            String mapsFrom, mapsTo;
267
            if (mapping.contains(":")) {
×
268
                mapsFrom = mapping.split(":")[0];
×
269
                mapsTo = mapping.split(":")[1];
×
270
            } else {
271
                mapsFrom = mapping;
×
272
                mapsTo = mapping;
×
273
            }
274
            try {
275
                ApiResponse resp = QueryApiAccess.get(Utils.parseQueryRef(querySpec));
×
276
                int i = 0;
×
277
                for (ApiResponseEntry e : resp.getData()) {
×
278
                    String mapsToSuffix = "";
×
279
                    if (i > 0) mapsToSuffix = "__" + i;
×
280
                    assertionContext.setParam(mapsTo + mapsToSuffix, e.get(mapsFrom));
×
281
                    i++;
×
282
                }
×
283
            } catch (FailedApiCallException | APINotReachableException | NotEnoughAPIInstancesException | NullPointerException ex) {
×
284
                ex.printStackTrace();
×
285
            }
×
286
        }
287
        for (String k : pageParams.getNamedKeys()) {
×
288
            if (k.startsWith("param_")) assertionContext.setParam(k.substring(6), pageParams.get(k).toString());
×
289
            if (k.startsWith("prparam_")) provenanceContext.setParam(k.substring(8), pageParams.get(k).toString());
×
290
            if (k.matches("piparam[1-9][0-9]*_.*")) {
×
291
                Integer i = Integer.parseInt(k.replaceFirst("^piparam([1-9][0-9]*)_.*$", "$1"));
×
292
                if (!piParamIdMap.containsKey(i)) {
×
293
                    // TODO: handle this error better
294
                    logger.error("ERROR: pitemplate param identifier not found: {}", i);
×
295
                    continue;
×
296
                }
297
                String n = k.replaceFirst("^piparam[1-9][0-9]*_(.*)$", "$1");
×
298
                logger.info(n);
×
299
                piParamIdMap.get(i).setParam(n, pageParams.get(k).toString());
×
300
            }
301
        }
×
302

303
        // Init statements only now, in order to pick up parameter values:
304
        assertionContext.initStatements();
×
305
        provenanceContext.initStatements();
×
306
        for (TemplateContext c : pubInfoContexts) {
×
307
            c.initStatements();
×
308
        }
×
309

310
        String latestAssertionId = QueryApiAccess.getLatestVersionId(assertionContext.getTemplateId());
×
311
        if (!assertionContext.getTemplateId().equals(latestAssertionId)) {
×
312
            add(new Label("newversion", "There is a new version of this assertion template:"));
×
313
            PageParameters params = new PageParameters(pageParams);
×
314
            params.set("template", latestAssertionId).remove("formobj");
×
315
            add(new BookmarkablePageLink<Void>("newversionlink", publishPageClass, params));
×
316
            if ("latest".equals(pageParams.get("template-version").toString())) {
×
317
                throw new RestartResponseException(publishPageClass, params);
×
318
            }
319
        } else {
×
320
            add(new Label("newversion", "").setVisible(false));
×
321
            add(new Label("newversionlink", "").setVisible(false));
×
322
        }
323

324
        final Nanopub improveNp;
325
        if (!pageParams.get("improve").isNull()) {
×
326
            improveNp = Utils.getNanopub(pageParams.get("improve").toString());
×
327
        } else {
328
            improveNp = null;
×
329
        }
330

331
        final List<Statement> unusedStatementList = new ArrayList<>();
×
332
        final List<Statement> unusedPrStatementList = new ArrayList<>();
×
333
        final List<Statement> unusedPiStatementList = new ArrayList<>();
×
334
        if (fillNp != null) {
×
335
            ValueFiller filler = new ValueFiller(fillNp, ContextType.ASSERTION, true, fillMode);
×
336
            filler.fill(assertionContext);
×
337
            unusedStatementList.addAll(filler.getUnusedStatements());
×
338

339
            if (!fillOnlyAssertion) {
×
340
                ValueFiller prFiller = new ValueFiller(fillNp, ContextType.PROVENANCE, true);
×
341
                prFiller.fill(provenanceContext);
×
342
                unusedPrStatementList.addAll(prFiller.getUnusedStatements());
×
343

344
                ValueFiller piFiller = new ValueFiller(fillNp, ContextType.PUBINFO, true);
×
345
                if (!assertionContext.getTemplate().getTargetNanopubTypes().isEmpty()) {
×
346
                    for (Statement st : new ArrayList<>(piFiller.getUnusedStatements())) {
×
347
                        if (st.getSubject().stringValue().equals(LocalUri.of("nanopub").stringValue()) && st.getPredicate().equals(NPX.HAS_NANOPUB_TYPE)) {
×
348
                            if (assertionContext.getTemplate().getTargetNanopubTypes().contains(st.getObject())) {
×
349
                                piFiller.removeUnusedStatement(st);
×
350
                            }
351
                        }
352
                    }
×
353
                }
354
                for (TemplateContext c : pubInfoContexts) {
×
355
                    piFiller.fill(c);
×
356
                }
×
357
                piFiller.removeUnusedStatements(NanodashSession.get().getUserIri(), FOAF.NAME, null);
×
358
                if (piFiller.hasUnusedStatements()) {
×
359
                    final String handcodedStatementsTemplateId = "https://w3id.org/np/RAMEgudZsQ1bh1fZhfYnkthqH6YSXpghSE_DEN1I-6eAI";
×
360
                    if (!pubInfoContextMap.containsKey(handcodedStatementsTemplateId)) {
×
361
                        TemplateContext c = createPubinfoContext(handcodedStatementsTemplateId);
×
362
                        c.initStatements();
×
363
                        piFiller.fill(c);
×
364
                    }
365
                }
366
                unusedPiStatementList.addAll(piFiller.getUnusedStatements());
×
367
                // TODO: Also use pubinfo templates stated in nanopub to be filled in?
368
//                                Set<IRI> pubinfoTemplateIds = Template.getPubinfoTemplateIds(fillNp);
369
//                                if (!pubinfoTemplateIds.isEmpty()) {
370
//                                        ValueFiller piFiller = new ValueFiller(fillNp, ContextType.PUBINFO);
371
//                                        for (IRI pubinfoTemplateId : pubinfoTemplateIds) {
372
//                                                // TODO: Make smart choice on the ordering in trying to fill in all pubinfo elements
373
//                                                piFiller.fill(pubInfoContextMap.get(pubinfoTemplateId.stringValue()));
374
//                                        }
375
//                                        warningMessage += (piFiller.getWarningMessage() == null ? "" : "Publication info: " + piFiller.getWarningMessage() + " ");
376
//                                }
377
            }
378
        } else if (improveNp != null) {
×
379
            ValueFiller filler = new ValueFiller(improveNp, ContextType.ASSERTION, true);
×
380
            filler.fill(assertionContext);
×
381
            unusedStatementList.addAll(filler.getUnusedStatements());
×
382
        }
383
        if (!unusedStatementList.isEmpty()) {
×
384
            add(new Label("warnings", "Some content from the existing nanopublication could not be filled in:"));
×
385
        } else {
386
            add(new Label("warnings", "").setVisible(false));
×
387
        }
388
        add(new DataView<Statement>("unused-statements", new ListDataProvider<Statement>(unusedStatementList)) {
×
389

390
            @Override
391
            protected void populateItem(Item<Statement> item) {
392
                item.add(new TripleItem("unused-statement", item.getModelObject(), (fillNp != null ? fillNp : improveNp), null));
×
393
            }
×
394

395
        });
396
        add(new DataView<Statement>("unused-prstatements", new ListDataProvider<Statement>(unusedPrStatementList)) {
×
397

398
            @Override
399
            protected void populateItem(Item<Statement> item) {
400
                item.add(new TripleItem("unused-prstatement", item.getModelObject(), (fillNp != null ? fillNp : improveNp), null));
×
401
            }
×
402

403
        });
404
        add(new DataView<Statement>("unused-pistatements", new ListDataProvider<Statement>(unusedPiStatementList)) {
×
405

406
            @Override
407
            protected void populateItem(Item<Statement> item) {
408
                item.add(new TripleItem("unused-pistatement", item.getModelObject(), (fillNp != null ? fillNp : improveNp), null));
×
409
            }
×
410

411
        });
412

413
        // Finalize statements, which picks up parameter values in repetitions:
414
        assertionContext.finalizeStatements();
×
415
        provenanceContext.finalizeStatements();
×
416
        for (TemplateContext c : pubInfoContexts) {
×
417
            c.finalizeStatements();
×
418
        }
×
419

420
        final CheckBox consentCheck = new CheckBox("consentcheck", new Model<>(false));
×
421
        consentCheck.setRequired(true);
×
422
        consentCheck.add(new InvalidityHighlighting());
×
423
        consentCheck.add(new IValidator<Boolean>() {
×
424

425
            @Override
426
            public void validate(IValidatable<Boolean> validatable) {
427
                if (!Boolean.TRUE.equals(validatable.getValue())) {
×
428
                    validatable.error(new ValidationError("You need to check the checkbox that you understand the consequences."));
×
429
                }
430
            }
×
431

432
        });
433

434
        form = new Form<Void>("form") {
×
435

436
            @Override
437
            protected void onConfigure() {
438
                super.onConfigure();
×
439
                form.getFeedbackMessages().clear();
×
440
//                                formComponents.clear();
441
            }
×
442

443
            protected void onSubmit() {
444
                logger.info("Publish form submitted");
×
445
                Nanopub signedNp = null;
×
446
                try {
447
                    Nanopub np = createNanopub();
×
448
                    logger.info("Nanopublication created: {}", np.getUri());
×
449
                    TransformContext tc = new TransformContext(SignatureAlgorithm.RSA, NanodashSession.get().getKeyPair(), NanodashSession.get().getUserIri(), false, false, false);
×
450
                    signedNp = SignNanopub.signAndTransform(np, tc);
×
451
                    logger.info("Nanopublication signed: {}", signedNp.getUri());
×
452
                    String npUrl = PublishNanopub.publish(signedNp);
×
453
                    logger.info("Nanopublication published: {}", npUrl);
×
454
                } catch (Exception ex) {
×
455
                    signedNp = null;
×
456
                    logger.error("Nanopublication publishing failed: {}", ex);
×
457
                    String message = ex.getClass().getName();
×
458
                    if (ex.getMessage() != null) {
×
459
                        message = ex.getMessage();
×
460
                    }
461
                    feedbackPanel.error(message);
×
462
                }
×
463
                if (signedNp != null) {
×
464
                    throw new RestartResponseException(getConfirmPage(signedNp, pageParams));
×
465
                } else {
466
                    logger.error("Nanopublication publishing failed");
×
467
                }
468
            }
×
469

470
            @Override
471
            protected void onValidate() {
472
                super.onValidate();
×
473
                for (Component fc : assertionContext.getComponents()) {
×
474
                    processFeedback(fc);
×
475
                }
×
476
                for (Component fc : provenanceContext.getComponents()) {
×
477
                    processFeedback(fc);
×
478
                }
×
479
                for (TemplateContext c : pubInfoContexts) {
×
480
                    for (Component fc : c.getComponents()) {
×
481
                        processFeedback(fc);
×
482
                    }
×
483
                }
×
484
            }
×
485

486
            private void processFeedback(Component c) {
487
                if (c instanceof FormComponent) {
×
488
                    ((FormComponent<?>) c).processInput();
×
489
                }
490
                for (FeedbackMessage fm : c.getFeedbackMessages()) {
×
491
                    form.getFeedbackMessages().add(fm);
×
492
                }
×
493
            }
×
494

495
        };
496
        form.setOutputMarkupId(true);
×
497

498
        form.add(new Label("nanopub-namespace", targetNamespaceLabel));
×
499

500
        form.add(new BookmarkablePageLink<Void>("templatelink", ExplorePage.class, new PageParameters().set("id", assertionContext.getTemplate().getId())));
×
501
        form.add(new Label("templatename", assertionContext.getTemplate().getLabel()));
×
502
        String description = assertionContext.getTemplate().getLabel();
×
503
        if (description == null) description = "";
×
504
        form.add(new Label("templatedesc", assertionContext.getTemplate().getDescription()).setEscapeModelStrings(false));
×
505

506
        form.add(new ListView<StatementItem>("statements", assertionContext.getStatementItems()) {
×
507

508
            protected void populateItem(ListItem<StatementItem> item) {
509
                item.add(item.getModelObject());
×
510
            }
×
511

512
        });
513

514
        final Map<String, Boolean> handledProvTemplates = new HashMap<>();
×
515
        final String defaultProvTemplateId;
516
        if (assertionContext.getTemplate().getDefaultProvenance() != null) {
×
517
            defaultProvTemplateId = assertionContext.getTemplate().getDefaultProvenance().stringValue();
×
518
            handledProvTemplates.put(defaultProvTemplateId, true);
×
519
        } else {
520
            defaultProvTemplateId = null;
×
521
        }
522
        final List<String> recommendedProvTemplateOptionIds = new ArrayList<>();
×
523
        final List<String> provTemplateOptionIds = new ArrayList<>();
×
524
        if (pageParams.get("prtemplate-options").isNull()) {
×
525
            // TODO Make this dynamic and consider updated templates:
526
            recommendedProvTemplateOptionIds.add("https://w3id.org/np/RA7lSq6MuK_TIC6JMSHvLtee3lpLoZDOqLJCLXevnrPoU");
×
527
            recommendedProvTemplateOptionIds.add("http://purl.org/np/RAcTpoh5Ra0ssqmcpOgWdaZ_YiPE6demO6cpw-2RvSNs8");
×
528
            recommendedProvTemplateOptionIds.add("http://purl.org/np/RA4LGtuOqTIMqVAkjnfBXk1YDcAPNadP5CGiaJiBkdHCQ");
×
529
            recommendedProvTemplateOptionIds.add("http://purl.org/np/RAl_-VTw9Re_uRF8r8y0rjlfnu7FlhTa8xg_8xkcweqiE");
×
530
            recommendedProvTemplateOptionIds.add("https://w3id.org/np/RASORV2mMEVpS4lWh2bwUTEcV-RWjbD9RPbN7J0PIeYAU");
×
531
            recommendedProvTemplateOptionIds.add("http://purl.org/np/RAjkBbM5yQm7hKH1l_Jk3HAUqWi3Bd57TPmAOZCsZmi_M");
×
532
            recommendedProvTemplateOptionIds.add("http://purl.org/np/RAGXx_k9eQMnXaCbsXMsJbGClwZtQEGNg0GVJu6amdAVw");
×
533
            recommendedProvTemplateOptionIds.add("http://purl.org/np/RA1fnITI3Pu1UQ0CHghNpys3JwQrM32LBnjmDLoayp9-4");
×
534
            recommendedProvTemplateOptionIds.add("http://purl.org/np/RAJgbsGeGdTG-zq_gU0TLw4s3raMgoRk-mPlc2DSLXvE0");
×
535
            recommendedProvTemplateOptionIds.add("http://purl.org/np/RA6SXfhUY-xeblZU8HhPddw6tsu-C5NXevG6C_zv4bMxU");
×
536
            for (String s : recommendedProvTemplateOptionIds) {
×
537
                handledProvTemplates.put(s, true);
×
538
            }
×
539

540
            for (ApiResponseEntry t : td.getProvenanceTemplates()) {
×
541
                String tid = t.get("np");
×
542
                if (handledProvTemplates.containsKey(tid)) continue;
×
543
                provTemplateOptionIds.add(tid);
×
544
                handledProvTemplates.put(tid, true);
×
545
            }
×
546
        } else {
547
            for (String s : pageParams.get("prtemplate-options").toString().split(" ")) {
×
548
                if (handledProvTemplates.containsKey(s)) continue;
×
549
                recommendedProvTemplateOptionIds.add(s);
×
550
                handledProvTemplates.put(s, true);
×
551
            }
552
        }
553

554
        ChoiceProvider<String> prTemplateChoiceProvider = new ChoiceProvider<String>() {
×
555

556
            @Override
557
            public String getDisplayValue(String object) {
558
                if (object == null || object.isEmpty()) return "";
×
559
                Template t = td.getTemplate(object);
×
560
                if (t != null) return t.getLabel();
×
561
                return object;
×
562
            }
563

564
            @Override
565
            public String getIdValue(String object) {
566
                return object;
×
567
            }
568

569
            // Getting strange errors with Tomcat if this method is not overridden:
570
            @Override
571
            public void detach() {
572
            }
×
573

574
            @Override
575
            public void query(String term, int page, Response<String> response) {
576
                if (term == null) term = "";
×
577
                term = term.toLowerCase();
×
578
                if (pageParams.get("prtemplate").toString() != null) {
×
579
                    // Using this work-around with "——" because 'optgroup' is not available through Wicket's Select2 classes
580
                    response.add("—— default for this link ——");
×
581
                    response.add(prTemplateId);
×
582
                }
583
                if (defaultProvTemplateId != null) {
×
584
                    response.add("—— default for this template ——");
×
585
                    response.add(defaultProvTemplateId);
×
586
                }
587
                if (!recommendedProvTemplateOptionIds.isEmpty()) {
×
588
                    if (pageParams.get("prtemplate-options").isNull()) {
×
589
                        response.add("—— recommended ——");
×
590
                    }
591
                    for (String s : recommendedProvTemplateOptionIds) {
×
592
                        if (s.toLowerCase().contains(term) || getDisplayValue(s).toLowerCase().contains(term)) {
×
593
                            response.add(s);
×
594
                        }
595
                    }
×
596
                }
597
                if (!provTemplateOptionIds.isEmpty()) {
×
598
                    response.add("—— others ——");
×
599
                    for (String s : provTemplateOptionIds) {
×
600
                        if (s.toLowerCase().contains(term) || getDisplayValue(s).toLowerCase().contains(term)) {
×
601
                            response.add(s);
×
602
                        }
603
                    }
×
604
                }
605
            }
×
606

607
            @Override
608
            public Collection<String> toChoices(Collection<String> ids) {
609
                return ids;
×
610
            }
611

612
        };
613
        final IModel<String> prTemplateModel = Model.of(provenanceContext.getTemplate().getId());
×
614
        Select2Choice<String> prTemplateChoice = new Select2Choice<String>("prtemplate", prTemplateModel, prTemplateChoiceProvider);
×
615
        prTemplateChoice.setRequired(true);
×
616
        prTemplateChoice.getSettings().setCloseOnSelect(true);
×
617
        prTemplateChoice.add(new AjaxFormComponentUpdatingBehavior("change") {
×
618

619
            @Override
620
            protected void onUpdate(AjaxRequestTarget target) {
621
                String o = prTemplateModel.getObject();
×
622
                if (o.startsWith("——")) {
×
623
                    o = provenanceContext.getTemplate().getId();
×
624
                    prTemplateModel.setObject(o);
×
625
                }
626
                provenanceContext = new TemplateContext(ContextType.PROVENANCE, prTemplateModel.getObject(), "pr-statement", targetNamespace);
×
627
                provenanceContext.initStatements();
×
628
                refreshProvenance(target);
×
629
                provenanceContext.finalizeStatements();
×
630
            }
×
631

632
        });
633
        form.add(prTemplateChoice);
×
634
        refreshProvenance(null);
×
635

636
        final Map<String, Boolean> handledPiTemplates = new HashMap<>();
×
637
        final List<String> recommendedPiTemplateOptionIds = new ArrayList<>();
×
638
        final List<String> piTemplateOptionIds = new ArrayList<>();
×
639
        // TODO Make this dynamic and consider updated templates:
640
        recommendedPiTemplateOptionIds.add("http://purl.org/np/RAXflINqt3smqxV5Aq7E9lzje4uLdkKIOefa6Bp8oJ8CY");
×
641
        recommendedPiTemplateOptionIds.add("https://w3id.org/np/RARW4MsFkHuwjycNElvEVtuMjpf4yWDL10-0C5l2MqqRQ");
×
642
        recommendedPiTemplateOptionIds.add("https://w3id.org/np/RA16U9Wo30ObhrK1NzH7EsmVRiRtvEuEA_Dfc-u8WkUCA");
×
643
        recommendedPiTemplateOptionIds.add("http://purl.org/np/RAdyqI6k07V5nAS82C6hvIDtNWk179EIV4DV-sLbOFKg4");
×
644
        recommendedPiTemplateOptionIds.add("https://w3id.org/np/RAjvEpLZUE7rMoa8q6mWSsN6utJDp-5FmgO47YGsbgw3w");
×
645
        recommendedPiTemplateOptionIds.add("http://purl.org/np/RAxuGRKID6yNg63V5Mf0ot2NjncOnodh-mkN3qT_1txGI");
×
646
        for (TemplateContext c : pubInfoContexts) {
×
647
            String s = c.getTemplate().getId();
×
648
            handledPiTemplates.put(s, true);
×
649
        }
×
650
        for (String s : recommendedPiTemplateOptionIds) {
×
651
            handledPiTemplates.put(s, true);
×
652
        }
×
653

654
        for (ApiResponseEntry entry : td.getPubInfoTemplates()) {
×
655
            String tid = entry.get("np");
×
656
            if (handledPiTemplates.containsKey(tid)) continue;
×
657
            piTemplateOptionIds.add(tid);
×
658
            handledPiTemplates.put(tid, true);
×
659
        }
×
660

661
        ChoiceProvider<String> piTemplateChoiceProvider = new ChoiceProvider<String>() {
×
662

663
            @Override
664
            public String getDisplayValue(String object) {
665
                if (object == null || object.isEmpty()) return "";
×
666
                Template t = td.getTemplate(object);
×
667
                if (t != null) return t.getLabel();
×
668
                return object;
×
669
            }
670

671
            @Override
672
            public String getIdValue(String object) {
673
                return object;
×
674
            }
675

676
            // Getting strange errors with Tomcat if this method is not overridden:
677
            @Override
678
            public void detach() {
679
            }
×
680

681
            @Override
682
            public void query(String term, int page, Response<String> response) {
683
                if (term == null) term = "";
×
684
                term = term.toLowerCase();
×
685
                if (!recommendedPiTemplateOptionIds.isEmpty()) {
×
686
                    response.add("—— recommended ——");
×
687
                    for (String s : recommendedPiTemplateOptionIds) {
×
688
                        boolean isAlreadyUsed = false;
×
689
                        for (TemplateContext c : pubInfoContexts) {
×
690
                            // TODO: make this more efficient/nicer
691
                            if (c.getTemplate().getId().equals(s)) {
×
692
                                isAlreadyUsed = true;
×
693
                                break;
×
694
                            }
695
                        }
×
696
                        if (isAlreadyUsed) continue;
×
697
                        if (s.toLowerCase().contains(term) || getDisplayValue(s).toLowerCase().contains(term)) {
×
698
                            response.add(s);
×
699
                        }
700
                    }
×
701
                }
702
                if (!piTemplateOptionIds.isEmpty()) {
×
703
                    response.add("—— others ——");
×
704
                    for (String s : piTemplateOptionIds) {
×
705
                        boolean isAlreadyUsed = false;
×
706
                        for (TemplateContext c : pubInfoContexts) {
×
707
                            // TODO: make this more efficient/nicer
708
                            if (c.getTemplate().getId().equals(s)) {
×
709
                                isAlreadyUsed = true;
×
710
                                break;
×
711
                            }
712
                        }
×
713
                        if (isAlreadyUsed) continue;
×
714
                        if (s.toLowerCase().contains(term) || getDisplayValue(s).toLowerCase().contains(term)) {
×
715
                            response.add(s);
×
716
                        }
717
                    }
×
718
                }
719
            }
×
720

721
            @Override
722
            public Collection<String> toChoices(Collection<String> ids) {
723
                return ids;
×
724
            }
725

726
        };
727
        final IModel<String> newPiTemplateModel = Model.of();
×
728
        Select2Choice<String> piTemplateChoice = new Select2Choice<String>("pitemplate", newPiTemplateModel, piTemplateChoiceProvider);
×
729
        piTemplateChoice.getSettings().setCloseOnSelect(true);
×
730
        piTemplateChoice.getSettings().setPlaceholder("add element...");
×
731
        piTemplateChoice.add(new AjaxFormComponentUpdatingBehavior("change") {
×
732

733
            @Override
734
            protected void onUpdate(AjaxRequestTarget target) {
735
                if (newPiTemplateModel.getObject().startsWith("——")) {
×
736
                    newPiTemplateModel.setObject(null);
×
737
                    refreshPubInfo(target);
×
738
                    return;
×
739
                }
740
                String id = newPiTemplateModel.getObject();
×
741
                TemplateContext c = new TemplateContext(ContextType.PUBINFO, id, "pi-statement", targetNamespace);
×
742
                c.initStatements();
×
743
                pubInfoContexts.add(c);
×
744
                newPiTemplateModel.setObject(null);
×
745
                refreshPubInfo(target);
×
746
                c.finalizeStatements();
×
747
            }
×
748

749
        });
750
        form.add(piTemplateChoice);
×
751
        refreshPubInfo(null);
×
752

753
        form.add(consentCheck);
×
754
        add(form);
×
755

756
        feedbackPanel = new FeedbackPanel("feedback");
×
757
        feedbackPanel.setOutputMarkupId(true);
×
758
        add(feedbackPanel);
×
759
    }
×
760

761
    private void refreshProvenance(AjaxRequestTarget target) {
762
        if (target != null) {
×
763
            form.remove("prtemplatelink");
×
764
            form.remove("pr-statements");
×
765
            target.add(form);
×
766
            target.appendJavaScript("updateElements();");
×
767
        }
768
        form.add(new BookmarkablePageLink<Void>("prtemplatelink", ExplorePage.class, new PageParameters().set("id", provenanceContext.getTemplate().getId())));
×
769
        ListView<StatementItem> list = new ListView<StatementItem>("pr-statements", provenanceContext.getStatementItems()) {
×
770

771
            protected void populateItem(ListItem<StatementItem> item) {
772
                item.add(item.getModelObject());
×
773
            }
×
774

775
        };
776
        list.setOutputMarkupId(true);
×
777
        form.add(list);
×
778
    }
×
779

780
    private void refreshPubInfo(AjaxRequestTarget target) {
781
        ListView<TemplateContext> list = new ListView<TemplateContext>("pis", pubInfoContexts) {
×
782

783
            protected void populateItem(ListItem<TemplateContext> item) {
784
                final TemplateContext pic = item.getModelObject();
×
785
                item.add(new Label("pitemplatename", pic.getTemplate().getLabel()));
×
786
                item.add(new BookmarkablePageLink<Void>("pitemplatelink", ExplorePage.class, new PageParameters().set("id", pic.getTemplate().getId())));
×
787
                Label remove = new Label("piremove", "×");
×
788
                item.add(remove);
×
789
                remove.add(new AjaxEventBehavior("click") {
×
790

791
                    @Override
792
                    protected void onEvent(AjaxRequestTarget target) {
793
                        pubInfoContexts.remove(pic);
×
794
                        target.add(PublishForm.this);
×
795
                        target.appendJavaScript("updateElements();");
×
796
                    }
×
797

798
                });
799
                if (requiredPubInfoContexts.contains(pic)) remove.setVisible(false);
×
800
                item.add(new ListView<StatementItem>("pi-statements", pic.getStatementItems()) {
×
801

802
                    protected void populateItem(ListItem<StatementItem> item) {
803
                        item.add(item.getModelObject());
×
804
                    }
×
805

806
                });
807
            }
×
808

809
        };
810
        list.setOutputMarkupId(true);
×
811
        if (target == null) {
×
812
            form.add(list);
×
813
        } else {
814
            form.remove("pis");
×
815
            form.add(list);
×
816
            target.add(form);
×
817
            target.appendJavaScript("updateElements();");
×
818
        }
819
    }
×
820

821
    private TemplateContext createPubinfoContext(String piTemplateId) {
822
        TemplateContext c;
823
        if (pubInfoContextMap.containsKey(piTemplateId)) {
×
824
            c = pubInfoContextMap.get(piTemplateId);
×
825
        } else {
826
            c = new TemplateContext(ContextType.PUBINFO, piTemplateId, "pi-statement", targetNamespace);
×
827
            pubInfoContextMap.put(piTemplateId, c);
×
828
            pubInfoContexts.add(c);
×
829
        }
830
        return c;
×
831
    }
832

833
    private synchronized Nanopub createNanopub() throws MalformedNanopubException, NanopubAlreadyFinalizedException {
834
        assertionContext.getIntroducedIris().clear();
×
835
        NanopubCreator npCreator = new NanopubCreator(targetNamespace);
×
836
        npCreator.setAssertionUri(vf.createIRI(targetNamespace + "assertion"));
×
837
        assertionContext.propagateStatements(npCreator);
×
838
        provenanceContext.propagateStatements(npCreator);
×
839
        for (TemplateContext c : pubInfoContexts) {
×
840
            c.propagateStatements(npCreator);
×
841
        }
×
842
        for (IRI introducedIri : assertionContext.getIntroducedIris()) {
×
843
            npCreator.addPubinfoStatement(NPX.INTRODUCES, introducedIri);
×
844
        }
×
845
        for (IRI embeddedIri : assertionContext.getEmbeddedIris()) {
×
846
            npCreator.addPubinfoStatement(NPX.EMBEDS, embeddedIri);
×
847
        }
×
848
        npCreator.addNamespace("this", targetNamespace);
×
849
        npCreator.addNamespace("sub", targetNamespace + "/");
×
850
        npCreator.addTimestampNow();
×
851
        IRI templateUri = assertionContext.getTemplate().getNanopub().getUri();
×
852
        npCreator.addPubinfoStatement(NTEMPLATE.WAS_CREATED_FROM_TEMPLATE, templateUri);
×
853
        IRI prTemplateUri = provenanceContext.getTemplate().getNanopub().getUri();
×
854
        npCreator.addPubinfoStatement(NTEMPLATE.WAS_CREATED_FROM_PROVENANCE_TEMPLATE, prTemplateUri);
×
855
        for (TemplateContext c : pubInfoContexts) {
×
856
            IRI piTemplateUri = c.getTemplate().getNanopub().getUri();
×
857
            npCreator.addPubinfoStatement(NTEMPLATE.WAS_CREATED_FROM_PUBINFO_TEMPLATE, piTemplateUri);
×
858
        }
×
859
        String nanopubLabel = getNanopubLabel(npCreator);
×
860
        if (nanopubLabel != null) {
×
861
            npCreator.addPubinfoStatement(RDFS.LABEL, vf.createLiteral(nanopubLabel));
×
862
        }
863
        for (IRI type : assertionContext.getTemplate().getTargetNanopubTypes()) {
×
864
            npCreator.addPubinfoStatement(NPX.HAS_NANOPUB_TYPE, type);
×
865
        }
×
866
        IRI userIri = NanodashSession.get().getUserIri();
×
867
        if (User.getName(userIri) != null) {
×
868
            npCreator.addPubinfoStatement(userIri, FOAF.NAME, vf.createLiteral(User.getName(userIri)));
×
869
            npCreator.addNamespace("foaf", FOAF.NAMESPACE);
×
870
        }
871
        String websiteUrl = NanodashPreferences.get().getWebsiteUrl();
×
872
        if (websiteUrl != null) {
×
873
            npCreator.addPubinfoStatement(NPX.WAS_CREATED_AT, vf.createIRI(websiteUrl));
×
874
        }
875
        return npCreator.finalizeNanopub();
×
876
    }
877

878
    private String getNanopubLabel(NanopubCreator npCreator) {
879
        if (assertionContext.getTemplate().getNanopubLabelPattern() == null) return null;
×
880

881
        Map<IRI, String> labelMap = new HashMap<>();
×
882
        for (Statement st : npCreator.getCurrentPubinfoStatements()) {
×
883
            if (st.getPredicate().equals(RDFS.LABEL) && st.getObject() instanceof Literal objL) {
×
884
                labelMap.put((IRI) st.getSubject(), objL.stringValue());
×
885
            }
886
        }
×
887

888
        String nanopubLabel = assertionContext.getTemplate().getNanopubLabelPattern();
×
889
        while (nanopubLabel.matches(".*\\$\\{[_a-zA-Z0-9-]+\\}.*")) {
×
890
            String placeholderPostfix = nanopubLabel.replaceFirst("^.*\\$\\{([_a-zA-Z0-9-]+)\\}.*$", "$1");
×
891
            IRI placeholderIriHash = vf.createIRI(assertionContext.getTemplateId() + "#" + placeholderPostfix);
×
892
            IRI placeholderIriSlash = vf.createIRI(assertionContext.getTemplateId() + "/" + placeholderPostfix);
×
893
            IRI placeholderIri = null;
×
894
            String placeholderValue = "";
×
895
            if (assertionContext.getComponentModels().get(placeholderIriSlash) != null) {
×
896
                placeholderIri = placeholderIriSlash;
×
897
            } else {
898
                placeholderIri = placeholderIriHash;
×
899
            }
900
            IModel<String> m = (IModel<String>) assertionContext.getComponentModels().get(placeholderIri);
×
901
            if (m != null) placeholderValue = m.orElse("").getObject();
×
902
            if (placeholderValue == null) placeholderValue = "";
×
903
            String placeholderLabel = placeholderValue;
×
904
            if (assertionContext.getTemplate().isUriPlaceholder(placeholderIri)) {
×
905
                try {
906
                    // TODO Fix this. It doesn't work for placeholders with auto-encode placeholders, etc.
907
                    //      Not sure we need labels for these, but this code should be improved anyway.
908
                    String prefix = assertionContext.getTemplate().getPrefix(placeholderIri);
×
909
                    if (prefix != null) placeholderValue = prefix + placeholderValue;
×
910
                    IRI placeholderValueIri = vf.createIRI(placeholderValue);
×
911
                    String l = assertionContext.getTemplate().getLabel(placeholderValueIri);
×
912
                    if (labelMap.containsKey(placeholderValueIri)) {
×
913
                        l = labelMap.get(placeholderValueIri);
×
914
                    }
915
                    if (l == null) l = GuidedChoiceItem.getLabel(placeholderValue);
×
916
                    if (assertionContext.getTemplate().isAgentPlaceholder(placeholderIri) && !placeholderValue.isEmpty()) {
×
917
                        l = User.getName(vf.createIRI(placeholderValue));
×
918
                    }
919
                    if (l != null && !l.isEmpty()) {
×
920
                        placeholderLabel = l.replaceFirst(" - .*$", "");
×
921
                    } else {
922
                        placeholderLabel = Utils.getShortNameFromURI(placeholderValueIri);
×
923
                    }
924
                } catch (Exception ex) {
×
925
                    logger.error("Nanopub label placeholder IRI error: {}", ex.getMessage());
×
926
                }
×
927
            }
928
            placeholderLabel = placeholderLabel.replaceAll("\\s+", " ");
×
929
            if (placeholderLabel.length() > 100) placeholderLabel = placeholderLabel.substring(0, 97) + "...";
×
930
            nanopubLabel = Strings.CS.replace(nanopubLabel, "${" + placeholderPostfix + "}", placeholderLabel);
×
931
        }
×
932
        return nanopubLabel;
×
933
    }
934

935
    private NanodashPage getConfirmPage(Nanopub signedNp, PageParameters pageParams) {
936
        try {
937
            return (NanodashPage) confirmPageClass.getConstructor(Nanopub.class, PageParameters.class).newInstance(signedNp, pageParams);
×
938
        } catch (InstantiationException | IllegalAccessException | IllegalArgumentException |
×
939
                 InvocationTargetException | NoSuchMethodException | SecurityException ex) {
940
            logger.error("Could not create instance of confirmation page: {}", ex.getMessage());
×
941
        }
942
        return null;
×
943
    }
944

945
    /**
946
     * Returns a hint whether the form is stateless or not.
947
     *
948
     * @return false if the form is stateful, true if it is stateless.
949
     */
950
    // This is supposed to solve the problem that sometimes (but only sometimes) form content is reset
951
    // if the user browses other pages in parallel:
952
    protected boolean getStatelessHint() {
953
        return false;
×
954
    }
955

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