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

CeON / dataverse / 1371

28 Jun 2024 05:54AM UTC coverage: 25.453% (-0.05%) from 25.503%
1371

push

jenkins

web-flow
Closes #2474: Store the entity id in saml session once user logs in with the identity provider (#2486)

49 of 54 new or added lines in 4 files covered. (90.74%)

860 existing lines in 14 files now uncovered.

17805 of 69953 relevant lines covered (25.45%)

0.25 hits per line

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

2.34
/dataverse-webapp/src/main/java/edu/harvard/iq/dataverse/search/SearchServiceBean.java
1
package edu.harvard.iq.dataverse.search;
2

3
import com.google.common.collect.Lists;
4
import edu.harvard.iq.dataverse.DatasetFieldServiceBean;
5
import edu.harvard.iq.dataverse.DataverseDao;
6
import edu.harvard.iq.dataverse.DvObjectServiceBean;
7
import edu.harvard.iq.dataverse.common.BundleUtil;
8
import edu.harvard.iq.dataverse.common.DatasetFieldConstant;
9
import edu.harvard.iq.dataverse.common.FriendlyFileTypeUtil;
10
import edu.harvard.iq.dataverse.engine.command.DataverseRequest;
11
import edu.harvard.iq.dataverse.persistence.datafile.DataFile;
12
import edu.harvard.iq.dataverse.persistence.datafile.license.LicenseRepository;
13
import edu.harvard.iq.dataverse.persistence.dataset.DatasetFieldType;
14
import edu.harvard.iq.dataverse.persistence.dataverse.Dataverse;
15
import edu.harvard.iq.dataverse.persistence.dataverse.DataverseFacet;
16
import edu.harvard.iq.dataverse.search.index.IndexServiceBean;
17
import edu.harvard.iq.dataverse.search.index.IndexedTermOfUse;
18
import edu.harvard.iq.dataverse.search.query.PermissionFilterQueryBuilder;
19
import edu.harvard.iq.dataverse.search.query.SearchForTypes;
20
import edu.harvard.iq.dataverse.search.query.SearchObjectType;
21
import edu.harvard.iq.dataverse.search.query.SearchPublicationStatus;
22
import edu.harvard.iq.dataverse.search.query.SolrQuerySanitizer;
23
import edu.harvard.iq.dataverse.search.response.DvObjectCounts;
24
import edu.harvard.iq.dataverse.search.response.FacetCategory;
25
import edu.harvard.iq.dataverse.search.response.FacetLabel;
26
import edu.harvard.iq.dataverse.search.response.FilterQuery;
27
import edu.harvard.iq.dataverse.search.response.Highlight;
28
import edu.harvard.iq.dataverse.search.response.PublicationStatusCounts;
29
import edu.harvard.iq.dataverse.search.response.SearchParentInfo;
30
import edu.harvard.iq.dataverse.search.response.SolrQueryResponse;
31
import edu.harvard.iq.dataverse.search.response.SolrSearchResult;
32
import edu.harvard.iq.dataverse.settings.SettingsServiceBean;
33
import edu.harvard.iq.dataverse.util.SystemConfig;
34
import io.vavr.control.Try;
35
import org.apache.commons.lang3.StringUtils;
36
import org.apache.solr.client.solrj.SolrClient;
37
import org.apache.solr.client.solrj.SolrQuery;
38
import org.apache.solr.client.solrj.SolrQuery.ORDER;
39
import org.apache.solr.client.solrj.SolrQuery.SortClause;
40
import org.apache.solr.client.solrj.SolrServerException;
41
import org.apache.solr.client.solrj.impl.HttpSolrClient.RemoteSolrException;
42
import org.apache.solr.client.solrj.response.FacetField;
43
import org.apache.solr.client.solrj.response.FacetField.Count;
44
import org.apache.solr.client.solrj.response.QueryResponse;
45
import org.apache.solr.client.solrj.response.SpellCheckResponse;
46
import org.apache.solr.common.SolrDocument;
47
import org.apache.solr.common.SolrDocumentList;
48

49
import javax.ejb.Stateless;
50
import javax.inject.Inject;
51
import java.io.IOException;
52
import java.util.ArrayList;
53
import java.util.Arrays;
54
import java.util.Collections;
55
import java.util.Date;
56
import java.util.HashMap;
57
import java.util.HashSet;
58
import java.util.List;
59
import java.util.Map;
60
import java.util.Optional;
61
import java.util.Set;
62
import java.util.function.Function;
63
import java.util.logging.Logger;
64
import java.util.stream.Collectors;
65

66
import static java.lang.String.format;
67

68
@Stateless
69
public class SearchServiceBean {
70

71
    private static final Logger logger = Logger.getLogger(SearchServiceBean.class.getCanonicalName());
1✔
72

73
    public static final String FACETBUNDLE_MASK_GROUP_AND_VALUE = "facets.search.fieldtype.%s.%s.label";
74
    public static final String FACETBUNDLE_MASK_VALUE = "facets.search.fieldtype.%s.label";
75
    private static final String FACETBUNDLE_MASK_DVCATEGORY_VALUE = "dataverse.type.selectTab.%s";
76

77
    public enum SortOrder {
1✔
78
        asc,
1✔
79
        desc;
1✔
80

81
        public static Optional<SortOrder> fromString(String sortOrderString) {
82
            return Try.of(() -> SortOrder.valueOf(sortOrderString))
1✔
83
                    .toJavaOptional();
1✔
84

85
        }
86

87
        public static List<String> allowedOrderStrings() {
88
            return Lists.newArrayList(SortOrder.values()).stream()
1✔
89
                    .map(Enum::name)
1✔
90
                    .collect(Collectors.toList());
1✔
91
        }
92
    }
93

94
    private DvObjectServiceBean dvObjectService;
95
    private DatasetFieldServiceBean datasetFieldService;
96
    private SettingsServiceBean settingsService;
97
    private SystemConfig systemConfig;
98
    private PermissionFilterQueryBuilder permissionQueryBuilder;
99
    private SolrClient solrServer;
100
    private SolrQuerySanitizer querySanitizer;
101
    private LicenseRepository licenseRepository;
102
    private DataverseDao dataverseDao;
103

104
    private Long rootDataverseId;
105

106
    // -------------------- CONSTRUCTORS --------------------
107

108
    public SearchServiceBean() { }
×
109

110
    @Inject
111
    public SearchServiceBean(DvObjectServiceBean dvObjectService, DatasetFieldServiceBean datasetFieldService,
112
                             SettingsServiceBean settingsService, SystemConfig systemConfig,
113
                             PermissionFilterQueryBuilder permissionQueryBuilder, SolrClient solrServer,
114
                             SolrQuerySanitizer querySanitizer, LicenseRepository licenseRepository,
115
                             DataverseDao dataverseDao) {
×
116
        this.dvObjectService = dvObjectService;
×
117
        this.datasetFieldService = datasetFieldService;
×
118
        this.settingsService = settingsService;
×
119
        this.systemConfig = systemConfig;
×
120
        this.permissionQueryBuilder = permissionQueryBuilder;
×
121
        this.solrServer = solrServer;
×
122
        this.querySanitizer = querySanitizer;
×
123
        this.licenseRepository = licenseRepository;
×
124
        this.dataverseDao = dataverseDao;
×
125
    }
×
126

127

128
    // -------------------- LOGIC --------------------
129

130
    /**
131
     * @param countsOnly after executing solr query only found object counts
132
     *                   (ie. datasets, dataverses & files) would be filled in
133
     *                   returned object, so it is unsuitable for other uses.
134
     */
135
    public SolrQueryResponse search(DataverseRequest dataverseRequest, List<Dataverse> dataverses, String query, SearchForTypes typesToSearch,
136
                                    List<String> filterQueries, String sortField, SortOrder sortOrder, int paginationStart,
137
                                    int numResultsPerPage, boolean countsOnly)
138
            throws SearchException {
139
        if (paginationStart < 0) {
×
140
            throw new IllegalArgumentException("paginationStart must be 0 or greater");
×
141
        }
142
        if (numResultsPerPage < 1) {
×
143
            throw new IllegalArgumentException("numResultsPerPage must be 1 or greater");
×
144
        }
145

146
        SolrQuery solrQuery = new SolrQuery();
×
147

148
        List<DatasetFieldType> datasetFields = datasetFieldService.findAllOrderedById();
×
149
        Map<String, DatasetFieldType> fieldIndex = datasetFields.stream()
×
150
                .collect(Collectors.toMap(DatasetFieldType::getName, Function.identity()));
×
151

152
        query = querySanitizer.sanitizeQuery(query, datasetFields);
×
153
        solrQuery.setQuery(query);
×
154

155
        solrQuery.setSort(new SortClause(sortField, sortOrder == SortOrder.asc ? ORDER.asc : ORDER.desc));
×
156
        solrQuery.setHighlight(true).setHighlightSnippets(1);
×
157
        Integer fragSize = settingsService.getValueForKeyAsInt(SettingsServiceBean.Key.SearchHighlightFragmentSize);
×
158
        if (fragSize != null) {
×
159
            solrQuery.setHighlightFragsize(fragSize);
×
160
        }
161
        solrQuery.setHighlightSimplePre("<span class=\"search-term-match\">");
×
162
        solrQuery.setHighlightSimplePost("</span>");
×
163
        Map<String, String> solrFieldsToHightlightOnMap = new HashMap<>();
×
164
        solrFieldsToHightlightOnMap.put(SearchFields.NAME, BundleUtil.getStringFromBundle("name"));
×
165
        solrFieldsToHightlightOnMap.put(SearchFields.AFFILIATION, BundleUtil.getStringFromBundle("affiliation"));
×
166
        solrFieldsToHightlightOnMap.put(SearchFields.FILE_TYPE_FRIENDLY, BundleUtil.getStringFromBundle("advanced.search.files.fileType"));
×
167
        solrFieldsToHightlightOnMap.put(SearchFields.DESCRIPTION, BundleUtil.getStringFromBundle("description"));
×
168
        solrFieldsToHightlightOnMap.put(SearchFields.VARIABLE_NAME, BundleUtil.getStringFromBundle("advanced.search.files.variableName"));
×
169
        solrFieldsToHightlightOnMap.put(SearchFields.VARIABLE_LABEL, BundleUtil.getStringFromBundle("advanced.search.files.variableLabel"));
×
170
        solrFieldsToHightlightOnMap.put(SearchFields.FILE_TYPE_SEARCHABLE, BundleUtil.getStringFromBundle("advanced.search.files.fileType"));
×
171
        solrFieldsToHightlightOnMap.put(SearchFields.DATASET_PUBLICATION_DATE, BundleUtil.getStringFromBundle("dataset.metadata.publicationYear"));
×
172
        solrFieldsToHightlightOnMap.put(SearchFields.DATASET_PERSISTENT_ID, BundleUtil.getStringFromBundle("advanced.search.datasets.persistentId"));
×
173
        solrFieldsToHightlightOnMap.put(SearchFields.FILE_PERSISTENT_ID, BundleUtil.getStringFromBundle("advanced.search.files.persistentId"));
×
174
        /*
175
          @todo Dataverse subject and affiliation should be highlighted but
176
         * this is commented out right now because the "friendly" names are not
177
         * being shown on the dataverse cards. See also
178
         * https://github.com/IQSS/dataverse/issues/1431
179
         */
180
//        solrFieldsToHightlightOnMap.put(SearchFields.DATAVERSE_SUBJECT, "Subject");
181
//        solrFieldsToHightlightOnMap.put(SearchFields.DATAVERSE_AFFILIATION, "Affiliation");
182
        /*
183
          @todo: show highlight on file card?
184
         * https://redmine.hmdc.harvard.edu/issues/3848
185
         */
186
        solrFieldsToHightlightOnMap.put(SearchFields.FILENAME_WITHOUT_EXTENSION, BundleUtil.getStringFromBundle("facets.search.fieldtype.fileNameWithoutExtension.label"));
×
187
        solrFieldsToHightlightOnMap.put(SearchFields.FILE_EXTENSION, BundleUtil.getStringFromBundle("advanced.search.files.fileExtension"));
×
188
        solrFieldsToHightlightOnMap.put(SearchFields.FILE_TAG_SEARCHABLE, BundleUtil.getStringFromBundle("facets.search.fieldtype.fileTag.label"));
×
189
        for (DatasetFieldType datasetFieldType : datasetFields) {
×
190

191
            SolrField dsfSolrField = SolrField.of(datasetFieldType);
×
192

193
            String solrField = dsfSolrField.getNameSearchable();
×
194
            String displayName = datasetFieldType.getDisplayName();
×
195
            solrFieldsToHightlightOnMap.put(solrField, displayName);
×
196
        }
×
197

198
        solrQuery = addHighlightFields(solrQuery, solrFieldsToHightlightOnMap);
×
199

200
        solrQuery.setHighlightRequireFieldMatch(true);
×
201
        solrQuery.setParam("fl", "*,score");
×
202
        solrQuery.setParam("qt", "/select");
×
203
        solrQuery.setParam("facet", "true");
×
204
        solrQuery.setParam("facet.mincount", "1");
×
205
        //  @todo: do we need facet.query?
206
        solrQuery.setParam("facet.query", "*");
×
207

208

209
        for (String filterQuery : filterQueries) {
×
210
            solrQuery.addFilterQuery(filterQuery);
×
211
        }
×
212
        // Remove root dataverse from search results
213
        solrQuery.addFilterQuery(String.format("-%s:%d", SearchFields.ENTITY_ID, getRootDataverseId()));
×
214

215
        addDvObjectTypeFilterQuery(solrQuery, typesToSearch);
×
216

217
        String permissionFilterQuery = permissionQueryBuilder.buildPermissionFilterQuery(dataverseRequest);
×
218
        if (!permissionFilterQuery.isEmpty()) {
×
219
            solrQuery.addFilterQuery(permissionFilterQuery);
×
220
        }
221

222
        // -----------------------------------
223
        // Facets to Retrieve
224
        // -----------------------------------
225
        solrQuery.addFacetField(SearchFields.DATAVERSE_CATEGORY);
×
226
        solrQuery.addFacetField(SearchFields.METADATA_SOURCE);
×
227
        solrQuery.addFacetField(SearchFields.PUBLICATION_YEAR);
×
228
        /*
229
          @todo when a new method on datasetFieldService is available
230
         * (retrieveFacetsByDataverse?) only show the facets that the dataverse
231
         * in question wants to show (and in the right order):
232
         * https://redmine.hmdc.harvard.edu/issues/3490
233
         *
234
         * also, findAll only returns advancedSearchField = true... we should
235
         * probably introduce the "isFacetable" boolean rather than caring about
236
         * if advancedSearchField is true or false
237

238
         */
239

240
        if (dataverseRequest.getUser().isAuthenticated()) {
×
241
            solrQuery.addFacetField(SearchFields.PUBLICATION_STATUS);
×
242
        }
243

244
        if (dataverses != null) {
×
245
            for (Dataverse dataverse : dataverses) {
×
246
                for (DataverseFacet dataverseFacet : dataverse.getDataverseFacets()) {
×
247
                    SolrField dsfSolrField = SolrField.of(dataverseFacet.getDatasetFieldType());
×
248
                    solrQuery.addFacetField(dsfSolrField.getNameFacetable());
×
249
                }
×
250
            };
×
251
        }
252

253
        solrQuery.addFacetField(SearchFields.LICENSE);
×
254

255
        solrQuery.addFacetField(SearchFields.FILE_TYPE);
×
256
        // @todo: hide the extra line this shows in the GUI... at least it's
257
        solrQuery.addFacetField(SearchFields.TYPE);
×
258
        solrQuery.addFacetField(SearchFields.FILE_TAG);
×
259
        if (!settingsService.isTrueForKey(SettingsServiceBean.Key.PublicInstall)) {
×
260
            solrQuery.addFacetField(SearchFields.ACCESS);
×
261
        }
262
        // @todo: do sanity checking... throw error if negative
263
        solrQuery.setStart(paginationStart);
×
264
        solrQuery.setRows(numResultsPerPage);
×
265
        logger.fine("Solr query:" + solrQuery);
×
266

267
        // -----------------------------------
268
        // Make the solr query
269
        // -----------------------------------
270
        QueryResponse queryResponse = null;
×
271
        try {
272
            queryResponse = solrServer.query(solrQuery);
×
273
        } catch (RemoteSolrException | SolrServerException | IOException ex) {
×
274
            throw new SearchException("Internal Dataverse Search Engine Error", ex);
×
275
        }
×
276
        SolrDocumentList docs = queryResponse.getResults();
×
277
        List<SolrSearchResult> solrSearchResults = new ArrayList<>();
×
278

279
        SolrQueryResponse solrQueryResponse = new SolrQueryResponse(solrQuery);
×
280
        solrQueryResponse.setDvObjectCounts(convertFacetToDvObjectCounts(queryResponse.getFacetField(SearchFields.TYPE)));
×
281
        if (countsOnly) {
×
282
            return solrQueryResponse;
×
283
        }
284

285
        String titleSolrField = null;
×
286
        if (fieldIndex.containsKey(DatasetFieldConstant.title)) {
×
287
            titleSolrField = SolrField.of(fieldIndex.get(DatasetFieldConstant.title)).getNameSearchable();
×
288
        } else {
289
            logger.info("Couldn't find " + DatasetFieldConstant.title);
×
290
        }
291
        String baseUrl = systemConfig.getDataverseSiteUrl();
×
292

293
        //Going through the results
294
        for (SolrDocument solrDocument : docs) {
×
295
            String id = (String) solrDocument.getFieldValue(SearchFields.ID);
×
296
            Long entityId = (Long) solrDocument.getFieldValue(SearchFields.ENTITY_ID);
×
297
            String solrType = (String) solrDocument.getFieldValue(SearchFields.TYPE);
×
298
            SearchObjectType type = SearchObjectType.fromSolrValue(solrType);
×
299

300
            float score = (Float) solrDocument.getFieldValue(SearchFields.RELEVANCE);
×
301
            logger.fine("score for " + id + ": " + score);
×
302
            String identifier = (String) solrDocument.getFieldValue(SearchFields.IDENTIFIER);
×
303
            String citation = getLocalizedValueWithFallback(solrDocument, SearchFields.DATASET_CITATION);
×
304
            String citationPlainHtml = getLocalizedValueWithFallback(solrDocument, SearchFields.DATASET_CITATION_HTML);
×
305
            String persistentUrl = (String) solrDocument.getFieldValue(SearchFields.PERSISTENT_URL);
×
306
            String name = (String) solrDocument.getFieldValue(SearchFields.NAME);
×
307
            String nameSort = (String) solrDocument.getFieldValue(SearchFields.NAME_SORT);
×
308
            String title = (String) solrDocument.getFirstValue(titleSolrField);
×
309
            Long datasetVersionId = (Long) solrDocument.getFieldValue(SearchFields.DATASET_VERSION_ID);
×
310
            String deaccessionReason = (String) solrDocument.getFieldValue(SearchFields.DATASET_DEACCESSION_REASON);
×
311
            String fileContentType = (String) solrDocument.getFieldValue(SearchFields.FILE_CONTENT_TYPE);
×
312
            Date release_or_create_date = (Date) solrDocument.getFieldValue(SearchFields.RELEASE_OR_CREATE_DATE);
×
313
            String dvTree = (String) solrDocument.getFirstValue(SearchFields.SUBTREE);
×
314
            String identifierOfDataverse = (String) solrDocument.getFieldValue(SearchFields.IDENTIFIER_OF_DATAVERSE);
×
315
            String nameOfDataverse = (String) solrDocument.getFieldValue(SearchFields.DATAVERSE_NAME);
×
UNCOV
316
            Date embargoUntil = (Date) solrDocument.getFieldValue(SearchFields.EMBARGO_UNTIL);
×
317

318
            List<String> matchedFields = new ArrayList<>();
×
319
            List<Highlight> highlights = new ArrayList<>();
×
320
            Map<SolrField, Highlight> highlightsMap = new HashMap<>();
×
321
            Map<SolrField, List<String>> highlightsMap2 = new HashMap<>();
×
322
            Map<String, Highlight> highlightsMap3 = new HashMap<>();
×
323
            if (queryResponse.getHighlighting().get(id) != null) {
×
324
                for (Map.Entry<String, String> entry : solrFieldsToHightlightOnMap.entrySet()) {
×
325
                    String field = entry.getKey();
×
UNCOV
326
                    String displayName = entry.getValue();
×
327

328
                    List<String> highlightSnippets = queryResponse.getHighlighting().get(id).get(field);
×
329
                    if (highlightSnippets != null) {
×
UNCOV
330
                        matchedFields.add(field);
×
331
                        /*
332
                          @todo only SolrField.SolrType.STRING? that's not
333
                         * right... knit the SolrField object more into the
334
                         * highlighting stuff
335
                         */
336
                        SolrField solrField = new SolrField(field, SolrField.SolrType.STRING, true, true, false);
×
337
                        Highlight highlight = new Highlight(solrField, highlightSnippets, displayName);
×
338
                        highlights.add(highlight);
×
339
                        highlightsMap.put(solrField, highlight);
×
340
                        highlightsMap2.put(solrField, highlightSnippets);
×
UNCOV
341
                        highlightsMap3.put(field, highlight);
×
342
                    }
UNCOV
343
                }
×
344

345
            }
UNCOV
346
            SolrSearchResult solrSearchResult = new SolrSearchResult();
×
347
            // @todo put all this in the constructor?
348
            List<String> states = (List<String>) solrDocument.getFieldValue(SearchFields.PUBLICATION_STATUS);
×
UNCOV
349
            if (states != null) {
×
350
                // set list of all statuses
351
                // this method also sets booleans for individual statuses
352
                List<SearchPublicationStatus> publicationStates = states.stream()
×
353
                        .map(solrStatus -> SearchPublicationStatus.fromSolrValue(solrStatus))
×
354
                        .collect(Collectors.toList());
×
UNCOV
355
                solrSearchResult.setPublicationStatuses(publicationStates);
×
356
            }
357
            solrSearchResult.setId(id);
×
358
            solrSearchResult.setEntityId(entityId);
×
359
            solrSearchResult.setIdentifier(identifier);
×
360
            solrSearchResult.setPersistentUrl(persistentUrl);
×
361
            solrSearchResult.setType(type);
×
362
            solrSearchResult.setScore(score);
×
363
            solrSearchResult.setNameSort(nameSort);
×
364
            solrSearchResult.setReleaseOrCreateDate(release_or_create_date);
×
365
            solrSearchResult.setMatchedFields(matchedFields);
×
366
            solrSearchResult.setHighlightsAsList(highlights);
×
367
            solrSearchResult.setHighlightsMap(highlightsMap);
×
368
            solrSearchResult.setHighlightsAsMap(highlightsMap3);
×
369
            SearchParentInfo parent = new SearchParentInfo();
×
370
            String description = (String) solrDocument.getFieldValue(SearchFields.DESCRIPTION);
×
371
            solrSearchResult.setDescriptionNoSnippet(description);
×
UNCOV
372
            solrSearchResult.setDeaccessionReason(deaccessionReason);
×
373
            solrSearchResult.setEmbargoUntil(embargoUntil);
×
374

375
            String originSource = (String) solrDocument.getFieldValue(SearchFields.METADATA_SOURCE);
×
UNCOV
376
            if (IndexServiceBean.HARVESTED.equals(originSource)) {
×
UNCOV
377
                solrSearchResult.setHarvested(true);
×
378
            }
379

380
            if (type == SearchObjectType.DATAVERSES) {
×
UNCOV
381
                solrSearchResult.setName(name);
×
UNCOV
382
                solrSearchResult.setHtmlUrl(baseUrl + SystemConfig.DATAVERSE_PATH + identifier);
×
383
                // Do not set the ImageUrl, let the search include fragment fill in
384
                // the thumbnail, similarly to how the dataset and datafile cards
385
                // are handled.
386
                //solrSearchResult.setImageUrl(baseUrl + "/api/access/dvCardImage/" + entityid);
387
                /*
388
                  @todo Expose this API URL after "dvs" is changed to
389
                 * "dataverses". Also, is an API token required for published
390
                 * dataverses? Michael: url changed.
391
                 */
392
//                solrSearchResult.setApiUrl(baseUrl + "/api/dataverses/" + entityid);
393
            } else if (type == SearchObjectType.DATASETS) {
×
UNCOV
394
                solrSearchResult.setHtmlUrl(baseUrl + "/dataset.xhtml?globalId=" + identifier);
×
UNCOV
395
                solrSearchResult.setApiUrl(baseUrl + "/api/datasets/" + entityId);
×
396
                //Image url now set via thumbnail api
397
                //solrSearchResult.setImageUrl(baseUrl + "/api/access/dsCardImage/" + datasetVersionId);
398
                // No, we don't want to set the base64 thumbnails here.
399
                // We want to do it inside SearchIncludeFragment, AND ONLY once the rest of the
400
                // page has already loaded.
401
                //DatasetVersion datasetVersion = datasetVersionService.find(datasetVersionId);
402
                //if (datasetVersion != null){
403
                //    solrSearchResult.setDatasetThumbnail(datasetVersion.getDataset().getDatasetThumbnail(datasetVersion));
404
                //}
405

406
                // @todo Could use getFieldValues (plural) here.
UNCOV
407
                String firstDatasetDescription = (String) solrDocument.getFirstValue(SearchFields.DATASET_DESCRIPTION);
×
408
                solrSearchResult.setDescriptionNoSnippet(firstDatasetDescription);
×
409

410
                solrSearchResult.setDatasetVersionId(datasetVersionId);
×
411

UNCOV
412
                solrSearchResult.setCitation(citation);
×
413
                solrSearchResult.setCitationHtml(citationPlainHtml);
×
414

UNCOV
415
                solrSearchResult.setIdentifierOfDataverse(identifierOfDataverse);
×
416
                solrSearchResult.setNameOfDataverse(nameOfDataverse);
×
417

UNCOV
418
                if (title != null) {
×
419
                    solrSearchResult.setTitle(title);
×
420
                } else {
UNCOV
421
                    logger.fine("No title indexed. Setting to empty string to prevent NPE. Dataset id " + entityId + " and version id " + datasetVersionId);
×
422
                    solrSearchResult.setTitle("");
×
423
                }
424
                List<String> authors = (List) solrDocument.getFieldValues("dsf_txt_" + DatasetFieldConstant.authorName);
×
UNCOV
425
                if (authors != null) {
×
426
                    solrSearchResult.setDatasetAuthors(authors);
×
427
                }
428
            } else if (type == SearchObjectType.FILES) {
×
429
                String parentGlobalId = null;
×
430
                Object parentGlobalIdObject = solrDocument.getFieldValue(SearchFields.PARENT_IDENTIFIER);
×
431
                if (parentGlobalIdObject != null) {
×
UNCOV
432
                    parentGlobalId = (String) parentGlobalIdObject;
×
433
                    parent.setParentIdentifier(parentGlobalId);
×
434
                }
UNCOV
435
                solrSearchResult.setHtmlUrl(baseUrl + "/dataset.xhtml?persistentId=" + parentGlobalId);
×
UNCOV
436
                solrSearchResult.setDownloadUrl(baseUrl + "/api/access/datafile/" + entityId);
×
437
                /*
438
                  @todo We are not yet setting the API URL for files because
439
                 * not all files have metadata. Only subsettable files (those
440
                 * with a datatable) seem to have metadata. Furthermore, the
441
                 * response is in XML whereas the rest of the Search API returns
442
                 * JSON.
443
                 */
444
//                solrSearchResult.setApiUrl(baseUrl + "/api/meta/datafile/" + entityid);
445
                //solrSearchResult.setImageUrl(baseUrl + "/api/access/fileCardImage/" + entityid);
446
                solrSearchResult.setName(name);
×
447
                solrSearchResult.setFiletype(FriendlyFileTypeUtil.getUserFriendlyFileTypeForDisplay(fileContentType));
×
448
                solrSearchResult.setFileContentType(fileContentType);
×
UNCOV
449
                Object fileSizeInBytesObject = solrDocument.getFieldValue(SearchFields.FILE_SIZE_IN_BYTES);
×
450
                if (fileSizeInBytesObject != null) {
×
451
                    try {
452
                        long fileSizeInBytesLong = (long) fileSizeInBytesObject;
×
453
                        solrSearchResult.setFileSizeInBytes(fileSizeInBytesLong);
×
454
                    } catch (ClassCastException ex) {
×
UNCOV
455
                        logger.info("Could not cast file " + entityId + " to long for " + SearchFields.FILE_SIZE_IN_BYTES + ": " + ex.getLocalizedMessage());
×
456
                    }
×
457
                }
458
                solrSearchResult.setFileMd5((String) solrDocument.getFieldValue(SearchFields.FILE_MD5));
×
459
                try {
460
                    solrSearchResult.setFileChecksumType(DataFile.ChecksumType.fromString((String) solrDocument.getFieldValue(SearchFields.FILE_CHECKSUM_TYPE)));
×
461
                } catch (IllegalArgumentException ex) {
×
462
                    logger.info("Exception setting setFileChecksumType: " + ex);
×
463
                }
×
464
                solrSearchResult.setFileChecksumValue((String) solrDocument.getFieldValue(SearchFields.FILE_CHECKSUM_VALUE));
×
465
                solrSearchResult.setUnf((String) solrDocument.getFieldValue(SearchFields.UNF));
×
466
                solrSearchResult.setDatasetVersionId(datasetVersionId);
×
467
                List<String> fileCategories = (List) solrDocument.getFieldValues(SearchFields.FILE_TAG);
×
UNCOV
468
                if (fileCategories != null) {
×
469
                    solrSearchResult.setFileCategories(fileCategories);
×
470
                }
471
                List<String> tabularDataTags = (List) solrDocument.getFieldValues(SearchFields.TABDATA_TAG);
×
472
                if (tabularDataTags != null) {
×
UNCOV
473
                    Collections.sort(tabularDataTags);
×
474
                    solrSearchResult.setTabularDataTags(tabularDataTags);
×
475
                }
476
                String filePID = (String) solrDocument.getFieldValue(SearchFields.FILE_PERSISTENT_ID);
×
UNCOV
477
                if (null != filePID && !"".equals(filePID)) {
×
UNCOV
478
                    solrSearchResult.setFilePersistentId(filePID);
×
479
                }
480

UNCOV
481
                String fileAccess = (String) solrDocument.getFirstValue(SearchFields.ACCESS);
×
UNCOV
482
                solrSearchResult.setFileAccess(fileAccess);
×
483
            }
484
            // @todo store PARENT_ID as a long instead and cast as such
485
            parent.setId((String) solrDocument.getFieldValue(SearchFields.PARENT_ID))
×
486
                  .setName((String) solrDocument.getFieldValue(SearchFields.PARENT_NAME))
×
487
                  .setCitation(getLocalizedValueWithFallback(solrDocument, SearchFields.PARENT_CITATION));
×
488
            solrSearchResult.setParent(parent);
×
UNCOV
489
            solrSearchResults.add(solrSearchResult);
×
490
        }
×
491

492
        Map<String, List<String>> spellingSuggestionsByToken = new HashMap<>();
×
493
        SpellCheckResponse spellCheckResponse = queryResponse.getSpellCheckResponse();
×
494
        if (spellCheckResponse != null) {
×
495
            List<SpellCheckResponse.Suggestion> suggestions = spellCheckResponse.getSuggestions();
×
496
            for (SpellCheckResponse.Suggestion suggestion : suggestions) {
×
UNCOV
497
                spellingSuggestionsByToken.put(suggestion.getToken(), suggestion.getAlternatives());
×
UNCOV
498
            }
×
499
        }
500

501
        List<FacetCategory> facetCategoryList = new ArrayList<>();
×
502

503
        for (FacetField facetField : queryResponse.getFacetFields()) {
×
UNCOV
504
            if (!shouldIncludeFacetInResults(facetField)) {
×
UNCOV
505
                continue;
×
506
            }
507

508
            FacetCategory facetCategory = new FacetCategory();
×
UNCOV
509
            facetCategory.setName(facetField.getName());
×
510
            facetCategory.setFriendlyName(getLocaleFacetCategoryName(facetField.getName(), fieldIndex));
×
511

512
            List<FacetLabel> facetLabelList = new ArrayList<>();
×
513

514
            for (FacetField.Count facetFieldCount : facetField.getValues()) {
×
515
                // @todo we do want to show the count for each facet
516
                FacetLabel facetLabel = new FacetLabel(facetFieldCount.getName(),
×
UNCOV
517
                        getLocaleFacetLabelName(facetFieldCount.getName(), facetField.getName(), fieldIndex),
×
518
                        facetFieldCount.getCount());
×
519
                // quote field facets
520
                facetLabel.setFilterQuery(facetField.getName() + ":\"" + facetFieldCount.getName() + "\"");
×
UNCOV
521
                facetLabelList.add(facetLabel);
×
522
            }
×
523

524
            facetCategory.setFacetLabels(facetLabelList);
×
525

UNCOV
526
            if (!facetLabelList.isEmpty()) {
×
527
                facetCategoryList.add(facetCategory);
×
528
            }
529
        }
×
530

531
        solrQueryResponse.setSolrSearchResults(solrSearchResults);
×
532
        solrQueryResponse.setSpellingSuggestionsByToken(spellingSuggestionsByToken);
×
533
        solrQueryResponse.setFacetCategoryList(facetCategoryList);
×
534
        solrQueryResponse.setNumResultsFound(queryResponse.getResults().getNumFound());
×
535
        solrQueryResponse.setResultsStart(queryResponse.getResults().getStart());
×
UNCOV
536
        String[] filterQueriesArray = solrQuery.getFilterQueries();
×
537
        if (filterQueriesArray != null) {
×
538
            // null check added because these tests were failing: mvn test -Dtest=SearchIT
539
            List<String> actualFilterQueries = Arrays.asList(filterQueriesArray);
×
540
            logger.fine("actual filter queries: " + actualFilterQueries);
×
UNCOV
541
            solrQueryResponse.setFilterQueriesActual(actualFilterQueries);
×
542
        } else {
×
543
            // how often is this null?
UNCOV
544
            logger.info("solrQuery.getFilterQueries() was null");
×
545
        }
546

547
        for (String filterQuery: filterQueries) {
×
548

549
            String[] parts = filterQuery.split(":");
×
UNCOV
550
            if (parts.length != 2) {
×
551
                solrQueryResponse.addFilterQuery(new FilterQuery(filterQuery));
×
552
            } else {
UNCOV
553
                String key = parts[0];
×
554
                String value = parts[1].replaceAll("^\"", "").replaceAll("\"$", "");
×
555

556
                solrQueryResponse.addFilterQuery(new FilterQuery(
×
557
                        filterQuery,
UNCOV
558
                        getLocaleFacetCategoryName(key, fieldIndex),
×
UNCOV
559
                        getLocaleFacetLabelName(value, key, fieldIndex)));
×
560
            }
561

562
        }
×
563

564
        solrQueryResponse.setPublicationStatusCounts(convertFacetToPublicationStatusCounts(queryResponse.getFacetField(SearchFields.PUBLICATION_STATUS)));
×
565

UNCOV
566
        return solrQueryResponse;
×
567
    }
568

569
    // -------------------- PRIVATE --------------------
570

571
    private Long getRootDataverseId() {
UNCOV
572
        if (rootDataverseId == null) {
×
573
            rootDataverseId = dataverseDao.findRootDataverse().getId();
×
574
        }
UNCOV
575
        return rootDataverseId;
×
576
    }
577

578
    private String getLocaleFacetCategoryName(String facetCategoryName, Map<String, DatasetFieldType> index) {
579
        final String formattedFacetFieldName = removeSolrFieldSuffix(facetCategoryName);
×
580

UNCOV
581
        if (index.containsKey(formattedFacetFieldName)) {
×
582
            return getDatasetFieldFacetCategoryName(index.get(formattedFacetFieldName));
×
583
        } else {
UNCOV
584
            return getNonDatasetFieldFacetCategoryName(facetCategoryName);
×
585
        }
586
    }
587

588
    private String getLocaleFacetLabelName(String facetLabelName, String facetCategoryName,
589
                                          Map<String, DatasetFieldType> index) {
UNCOV
590
        String formattedFacetCategoryName = removeSolrFieldSuffix(facetCategoryName);
×
591
        String formattedFacetLabelName = toBundleNameFormat(facetLabelName);
×
592

UNCOV
593
        if (index.containsKey(formattedFacetCategoryName)) {
×
UNCOV
594
            return getDatasetFieldFacetLabelName(facetLabelName, formattedFacetLabelName, index.get(formattedFacetCategoryName));
×
595

596
        } else {
UNCOV
597
            return getNonDatasetFieldFacetLabelName(facetLabelName, formattedFacetCategoryName);
×
598
        }
599
    }
600

601
    private String getDatasetFieldFacetCategoryName(DatasetFieldType matchedDatasetField) {
602
        if (matchedDatasetField.isFacetable() && !matchedDatasetField.isHasParent()) {
×
603
            String key = format(FACETBUNDLE_MASK_VALUE, matchedDatasetField.getName());
×
604
            return Optional.ofNullable(BundleUtil.getStringFromBundle(key))
×
UNCOV
605
                    .filter(name -> !name.isEmpty())
×
606
                    .orElse(matchedDatasetField.getDisplayName());
×
607
        }
UNCOV
608
        return matchedDatasetField.getDisplayName();
×
609
    }
610

611
    private String getNonDatasetFieldFacetCategoryName(String facetCategoryName) {
UNCOV
612
        if(facetCategoryName.equals(SearchFields.TYPE)) {
×
613
            return facetCategoryName;
×
614
        }
UNCOV
615
        String key = format(FACETBUNDLE_MASK_VALUE, facetCategoryName);
×
UNCOV
616
        return BundleUtil.getStringFromBundle(key);
×
617
    }
618

619
    private String getDatasetFieldFacetLabelName(String facetLabelName, String formattedFacetLabelName,
620
                                                 DatasetFieldType matchedDatasetField) {
621
        if (matchedDatasetField.isControlledVocabulary()) {
×
622
            String key = "controlledvocabulary." + matchedDatasetField.getName() + "." + formattedFacetLabelName;
×
UNCOV
623
            String bundleName = matchedDatasetField.getMetadataBlock().getName().toLowerCase();
×
624
            return BundleUtil.getStringFromNonDefaultBundle(key, bundleName);
×
625
        }
UNCOV
626
        return facetLabelName;
×
627
    }
628

629
    private String getNonDatasetFieldFacetLabelName(String facetLabelName, String formattedFacetCategoryName) {
UNCOV
630
        String formattedFacetLabelName = toBundleNameFormat(facetLabelName);
×
UNCOV
631
        List<String> translatableNonDictionaryFacets = Lists.newArrayList(SearchFields.PUBLICATION_STATUS,
×
632
                SearchFields.DATAVERSE_CATEGORY, SearchFields.FILE_TYPE, SearchFields.ACCESS);
633

634
        if(translatableNonDictionaryFacets.contains(formattedFacetCategoryName)) {
×
635
            if(formattedFacetCategoryName.equals(SearchFields.DATAVERSE_CATEGORY)) {
×
UNCOV
636
                String key = format(FACETBUNDLE_MASK_DVCATEGORY_VALUE, formattedFacetLabelName);
×
637
                return BundleUtil.getStringFromBundle(key);
×
638
            }
UNCOV
639
            String key = format(FACETBUNDLE_MASK_GROUP_AND_VALUE, formattedFacetCategoryName, formattedFacetLabelName);
×
UNCOV
640
            return BundleUtil.getStringFromBundle(key);
×
641
        }
642

UNCOV
643
        if(formattedFacetCategoryName.equals(SearchFields.METADATA_SOURCE) && formattedFacetLabelName.equals("harvested")) {
×
UNCOV
644
            return BundleUtil.getStringFromBundle(formattedFacetLabelName);
×
645
        }
646

647
        if(formattedFacetCategoryName.equals(SearchFields.LICENSE)) {
×
648
            return licenseRepository.findLicenseByName(facetLabelName)
×
649
                .map(l -> l.getLocalizedName(BundleUtil.getCurrentLocale()))
×
650
                .orElseGet(() -> {
×
UNCOV
651
                    String label = BundleUtil.getStringFromBundle(IndexedTermOfUse.getLabelFromName(facetLabelName));
×
UNCOV
652
                    return StringUtils.isBlank(label)?facetLabelName:label;
×
653
                });
654
        }
655

UNCOV
656
        return facetLabelName;
×
657
    }
658

659
    private SolrQuery addHighlightFields(SolrQuery solrQuery, Map<String, String> solrFieldsToHightlightOnMap) {
660
        Set<String> dynamicDatasetFieldsPrefixes = new HashSet<>();
×
661

662
        for(String field : solrFieldsToHightlightOnMap.keySet()) {
×
UNCOV
663
            if(isFieldDynamic(field)) {
×
664
                dynamicDatasetFieldsPrefixes.add(field.substring(0, 8));
×
665
            } else {
666
                solrQuery.addHighlightField(field);
×
667
            }
668
        }
×
669

670
        for (String dynamicFieldPrefix : dynamicDatasetFieldsPrefixes) {
×
UNCOV
671
            solrQuery.addHighlightField(dynamicFieldPrefix + "*");
×
672
        }
×
673

UNCOV
674
        return solrQuery;
×
675
    }
676

677
    private boolean isFieldDynamic(String field) {
UNCOV
678
        return field.length() > 8 && SearchDynamicFieldPrefix.contains(field.substring(0, 8));
×
679
    }
680

681
    private String removeSolrFieldSuffix(String name) {
682
        if(name.endsWith("_ss")) {
×
683
            name = name.substring(0, name.length() - 3);
×
UNCOV
684
        } else if (name.endsWith("_s")) {
×
685
            name = name.substring(0, name.length() - 2);
×
686
        }
UNCOV
687
        return name;
×
688
    }
689

690
    /**
691
     * if exist, multi word bundle names are connected with underscores and formatted toLowerCase
692
     * @param name text for which we want to create its bundle name
693
     * @return text with replaced spaces with underscores, and leading/trailing whitespaces removed, toLowerCased
694
     */
695
    private String toBundleNameFormat(String name) {
UNCOV
696
        return StringUtils.stripAccents(name.toLowerCase().replace(" ", "_"));
×
697
    }
698

699
    private DvObjectCounts convertFacetToDvObjectCounts(FacetField dvObjectFacetField) {
700

701
        DvObjectCounts dvObjectCounts = DvObjectCounts.emptyDvObjectCounts();
×
UNCOV
702
        if (dvObjectFacetField == null) {
×
UNCOV
703
            return dvObjectCounts;
×
704
        }
705

706
        for (Count count: dvObjectFacetField.getValues()) {
×
707
            SearchObjectType dvType = SearchObjectType.fromSolrValue(count.getName());
×
708
            dvObjectCounts.setCountByObjectType(dvType, count.getCount());
×
UNCOV
709
        }
×
UNCOV
710
        return dvObjectCounts;
×
711
    }
712

713
    private PublicationStatusCounts convertFacetToPublicationStatusCounts(FacetField publicationStatusFacetField) {
714

715
        PublicationStatusCounts publicationStatusCounts = PublicationStatusCounts.emptyPublicationStatusCounts();
×
UNCOV
716
        if (publicationStatusFacetField == null) {
×
UNCOV
717
            return publicationStatusCounts;
×
718
        }
719

720
        for (Count count: publicationStatusFacetField.getValues()) {
×
721
            SearchPublicationStatus status = SearchPublicationStatus.fromSolrValue(count.getName());
×
722
            publicationStatusCounts.setCountByPublicationStatus(status, count.getCount());
×
UNCOV
723
        }
×
UNCOV
724
        return publicationStatusCounts;
×
725
    }
726

727
    private void addDvObjectTypeFilterQuery(SolrQuery query, SearchForTypes typesToSearch) {
728
        String filterValue = typesToSearch.getTypes().stream()
×
729
                .sorted()
×
UNCOV
730
                .map(SearchObjectType::getSolrValue)
×
731
                .collect(Collectors.joining(" OR "));
×
732

UNCOV
733
        query.addFilterQuery(SearchFields.TYPE + ":(" + filterValue + ")");
×
UNCOV
734
    }
×
735

736
    private String getLocalizedValueWithFallback(SolrDocument document, String fieldName) {
737
        String suffix = "_" + BundleUtil.getCurrentLocale().getLanguage();
×
738
        return (String) (document.containsKey(fieldName + suffix)
×
UNCOV
739
                ? document.getFieldValue(fieldName + suffix)
×
UNCOV
740
                : document.getFieldValue(fieldName + "_en"));
×
741
    }
742

743
    private boolean shouldIncludeFacetInResults(FacetField facetField) {
744
        if (facetField.getName().equals(SearchFields.TYPE)) {
×
745
            // the "type" facet is special
746
            return false;
×
747
        }
UNCOV
748
        if (facetField.getName().equals(SearchFields.METADATA_SOURCE) && facetField.getValueCount() < 2) {
×
749
            return false;
×
750
        }
UNCOV
751
        return true;
×
752
    }
753
}
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