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

knowledgepixels / nanodash / 17380144000

01 Sep 2025 02:12PM UTC coverage: 12.03% (+0.05%) from 11.978%
17380144000

push

github

ashleycaselli
refactor: replace printStackTrace with logger.error for better error handling

330 of 3850 branches covered (8.57%)

Branch coverage included in aggregate %.

958 of 6857 relevant lines covered (13.97%)

0.62 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/AgentChoiceItem.java
1
package com.knowledgepixels.nanodash.component;
2

3
import com.knowledgepixels.nanodash.NanodashSession;
4
import com.knowledgepixels.nanodash.User;
5
import com.knowledgepixels.nanodash.Utils;
6
import com.knowledgepixels.nanodash.component.IriTextfieldItem.Validator;
7
import com.knowledgepixels.nanodash.page.ProfilePage;
8
import com.knowledgepixels.nanodash.template.Template;
9
import com.knowledgepixels.nanodash.template.TemplateContext;
10
import com.knowledgepixels.nanodash.template.UnificationException;
11
import org.apache.wicket.Component;
12
import org.apache.wicket.ajax.AjaxRequestTarget;
13
import org.apache.wicket.ajax.form.OnChangeAjaxBehavior;
14
import org.apache.wicket.behavior.AttributeAppender;
15
import org.apache.wicket.markup.html.basic.Label;
16
import org.apache.wicket.markup.html.link.ExternalLink;
17
import org.apache.wicket.markup.html.panel.Panel;
18
import org.apache.wicket.model.IModel;
19
import org.apache.wicket.model.Model;
20
import org.apache.wicket.validation.Validatable;
21
import org.eclipse.rdf4j.model.IRI;
22
import org.eclipse.rdf4j.model.Value;
23
import org.eclipse.rdf4j.model.ValueFactory;
24
import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
25
import org.nanopub.vocabulary.NTEMPLATE;
26
import org.slf4j.Logger;
27
import org.slf4j.LoggerFactory;
28
import org.wicketstuff.select2.ChoiceProvider;
29
import org.wicketstuff.select2.Response;
30
import org.wicketstuff.select2.Select2Choice;
31

32
import java.util.*;
33

34
/**
35
 * A component that allows users to select an agent (user) from a list or enter an ORCID or URL.
36
 */
37
public class AgentChoiceItem extends Panel implements ContextComponent {
38

39
    private static final long serialVersionUID = 1L;
40
    private TemplateContext context;
41
    private Select2Choice<String> textfield;
42
    private ExternalLink tooltipLink;
43
    private Label tooltipDescription;
44
    private IRI iri;
45
    private IModel<String> model;
46
    private static final Logger logger = LoggerFactory.getLogger(AgentChoiceItem.class);
×
47

48
    private String getChoiceLabel(String choiceId) {
49
        IRI iri = vf.createIRI(choiceId);
×
50
        String name = User.getName(iri);
×
51
        if (name != null) return name;
×
52
        return choiceId;
×
53
    }
54

55
    /**
56
     * Constructor for AgentChoiceItem.
57
     *
58
     * @param id       the component ID
59
     * @param parentId the parent component ID
60
     * @param iriP     the IRI of the agent choice item
61
     * @param optional whether the choice is optional
62
     * @param context  the template context
63
     */
64
    public AgentChoiceItem(String id, String parentId, final IRI iriP, boolean optional, final TemplateContext context) {
65
        super(id);
×
66
        this.context = context;
×
67
        this.iri = iriP;
×
68
        final Template template = context.getTemplate();
×
69
        model = context.getComponentModels().get(iri);
×
70
        if (model == null) {
×
71
            model = Model.of("");
×
72
            context.getComponentModels().put(iri, model);
×
73
        }
74
        String postfix = Utils.getUriPostfix(iri);
×
75
        if (context.hasParam(postfix)) {
×
76
            model.setObject(context.getParam(postfix));
×
77
        }
78
        final List<String> possibleValues = new ArrayList<>();
×
79
        for (Value v : template.getPossibleValues(iri)) {
×
80
            possibleValues.add(v.toString());
×
81
        }
×
82

83
        ChoiceProvider<String> choiceProvider = new ChoiceProvider<String>() {
×
84

85
            private static final long serialVersionUID = 1L;
86

87
            @Override
88
            public String getDisplayValue(String choiceId) {
89
                if (choiceId == null || choiceId.isEmpty()) return "";
×
90
                String label = getChoiceLabel(choiceId);
×
91
                if (label == null || label.isBlank()) {
×
92
                    return choiceId;
×
93
                }
94
                return label + " (" + choiceId + ")";
×
95
            }
96

97
            @Override
98
            public String getIdValue(String object) {
99
                return object;
×
100
            }
101

102
            // Getting strange errors with Tomcat if this method is not overridden:
103
            @Override
104
            public void detach() {
105
            }
×
106

107
            @Override
108
            public void query(String term, int page, Response<String> response) {
109
                if (term == null) {
×
110
                    if (possibleValues.isEmpty()) {
×
111
                        if (NanodashSession.get().getUserIri() != null) {
×
112
                            response.add(NanodashSession.get().getUserIri().stringValue());
×
113
                        }
114
                    } else {
115
                        response.addAll(possibleValues);
×
116
                    }
117
                    return;
×
118
                }
119
                if (term.startsWith("https://") || term.startsWith("http://")) {
×
120
                    response.add(term);
×
121
                } else if (term.matches(ProfilePage.ORCID_PATTERN)) {
×
122
                    response.add("https://orcid.org/" + term);
×
123
                }
124
                Map<String, Boolean> alreadyAddedMap = new HashMap<>();
×
125
                term = term.toLowerCase();
×
126
                for (String s : possibleValues) {
×
127
                    if (s.toLowerCase().contains(term) || getDisplayValue(s).toLowerCase().contains(term)) {
×
128
                        response.add(s);
×
129
                        alreadyAddedMap.put(s, true);
×
130
                    }
131
                }
×
132

133
                // TODO: We'll need some indexing to perform this more efficiently at some point:
134
                for (IRI iri : User.getUsers(true)) {
×
135
                    // Collect approved users
136
                    if (response.size() > 9) break;
×
137
                    if (response.getResults().contains(iri.stringValue())) continue;
×
138
                    String name = User.getName(iri);
×
139
                    if (iri.stringValue().contains(term)) {
×
140
                        response.add(iri.stringValue());
×
141
                    } else if (name != null && name.toLowerCase().contains(term)) {
×
142
                        response.add(iri.stringValue());
×
143
                    }
144
                }
×
145
                for (IRI iri : User.getUsers(false)) {
×
146
                    // Collect non-approved users
147
                    if (response.size() > 9) break;
×
148
                    if (response.getResults().contains(iri.stringValue())) continue;
×
149
                    String name = User.getName(iri);
×
150
                    if (iri.stringValue().contains(term)) {
×
151
                        response.add(iri.stringValue());
×
152
                    } else if (name != null && name.toLowerCase().contains(term)) {
×
153
                        response.add(iri.stringValue());
×
154
                    }
155
                }
×
156
            }
×
157

158
            @Override
159
            public Collection<String> toChoices(Collection<String> ids) {
160
                return ids;
×
161
            }
162

163
        };
164
        textfield = new Select2Choice<String>("textfield", model, choiceProvider);
×
165
        textfield.getSettings().getAjax(true).setDelay(500);
×
166
        textfield.getSettings().setCloseOnSelect(true);
×
167
        String placeholder = template.getLabel(iri);
×
168
        if (placeholder == null) placeholder = "select user or paste ORCID/URL";
×
169
        textfield.getSettings().setPlaceholder(placeholder);
×
170
        Utils.setSelect2ChoiceMinimalEscapeMarkup(textfield);
×
171
        textfield.getSettings().setAllowClear(true);
×
172

173
        if (!optional) textfield.setRequired(true);
×
174
        textfield.add(new AttributeAppender("class", " wide"));
×
175
        textfield.add(new Validator(iri, template, "", context));
×
176
        context.getComponents().add(textfield);
×
177

178
        tooltipDescription = new Label("description", new IModel<String>() {
×
179

180
            private static final long serialVersionUID = 1L;
181

182
            @Override
183
            public String getObject() {
184
                String obj = AgentChoiceItem.this.getModel().getObject();
×
185
                if (obj == null || obj.isEmpty()) return "choose a value";
×
186
                String label = getChoiceLabel(AgentChoiceItem.this.getModel().getObject());
×
187
                if (label == null || !label.contains(" - ")) return "";
×
188
                return label.substring(label.indexOf(" - ") + 3);
×
189
            }
190

191
        });
192
        tooltipDescription.setOutputMarkupId(true);
×
193
        add(tooltipDescription);
×
194

195
        tooltipLink = Utils.getUriLink("uri", model);
×
196
        tooltipLink.setOutputMarkupId(true);
×
197
        add(tooltipLink);
×
198

199
        textfield.add(new OnChangeAjaxBehavior() {
×
200

201
            private static final long serialVersionUID = 1L;
202

203
            @Override
204
            protected void onUpdate(AjaxRequestTarget target) {
205
                for (Component c : context.getComponents()) {
×
206
                    if (c == textfield) continue;
×
207
                    if (c.getDefaultModel() == textfield.getModel()) {
×
208
                        c.modelChanged();
×
209
                        target.add(c);
×
210
                    }
211
                }
×
212
                target.add(tooltipLink);
×
213
                target.add(tooltipDescription);
×
214
            }
×
215

216
        });
217
        add(textfield);
×
218
    }
×
219

220
    /**
221
     * Returns the IRI of the agent choice item.
222
     *
223
     * @return the IRI of the agent choice item
224
     */
225
    public IModel<String> getModel() {
226
        return model;
×
227
    }
228

229
    /**
230
     * {@inheritDoc}
231
     */
232
    @Override
233
    public void removeFromContext() {
234
        context.getComponents().remove(textfield);
×
235
    }
×
236

237
    /**
238
     * {@inheritDoc}
239
     */
240
    @Override
241
    public boolean isUnifiableWith(Value v) {
242
        if (v == null) return true;
×
243
        if (v instanceof IRI) {
×
244
            String vs = v.stringValue();
×
245
            if (vs.startsWith("local:")) vs = vs.replaceFirst("^local:", "");
×
246
            Validatable<String> validatable = new Validatable<>(vs);
×
247
            if (context.getTemplate().isLocalResource(iri) && !Utils.isUriPostfix(vs)) {
×
248
                vs = Utils.getUriPostfix(vs);
×
249
            }
250
            new Validator(iri, context.getTemplate(), "", context).validate(validatable);
×
251
            if (!validatable.isValid()) {
×
252
                return false;
×
253
            }
254
            if (textfield.getModelObject().isEmpty()) {
×
255
                return true;
×
256
            }
257
            return vs.equals(textfield.getModelObject());
×
258
        }
259
        return false;
×
260
    }
261

262
    /**
263
     * {@inheritDoc}
264
     */
265
    @Override
266
    public void unifyWith(Value v) throws UnificationException {
267
        if (v == null) return;
×
268
        if (!isUnifiableWith(v)) throw new UnificationException(v.stringValue());
×
269
        String vs = v.stringValue();
×
270
        if (vs.startsWith("local:")) {
×
271
            vs = vs.replaceFirst("^local:", "");
×
272
        }
273
        textfield.setModelObject(vs);
×
274
    }
×
275

276
    /**
277
     * {@inheritDoc}
278
     */
279
    @Override
280
    public void fillFinished() {
281
    }
×
282

283
    /**
284
     * {@inheritDoc}
285
     */
286
    @Override
287
    public void finalizeValues() {
288
        Value defaultValue = context.getTemplate().getDefault(iri);
×
289
        if (NTEMPLATE.CREATOR_PLACEHOLDER.equals(defaultValue)) {
×
290
            defaultValue = NanodashSession.get().getUserIri();
×
291
        }
292
        if (isUnifiableWith(defaultValue)) {
×
293
            try {
294
                unifyWith(defaultValue);
×
295
            } catch (UnificationException ex) {
×
296
                logger.error("Could not unify default value: {}", defaultValue, ex);
×
297
            }
×
298
        }
299
    }
×
300

301
    private static ValueFactory vf = SimpleValueFactory.getInstance();
×
302

303
    /**
304
     * <p>toString.</p>
305
     *
306
     * @return a {@link java.lang.String} object
307
     */
308
    public String toString() {
309
        return "[Agent choiced item: " + iri + "]";
×
310
    }
311

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