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

IQSS / dataverse / #23566

25 Oct 2024 02:19PM UTC coverage: 20.892% (+0.02%) from 20.87%
#23566

Pull #10790

github

web-flow
Merge a5534586d into 03538f0dd
Pull Request #10790: fix: issues in exporters and citations for PermaLink/non-DOI PIDs

48 of 69 new or added lines in 7 files covered. (69.57%)

574 existing lines in 5 files now uncovered.

17994 of 86128 relevant lines covered (20.89%)

0.21 hits per line

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

0.0
/src/main/java/edu/harvard/iq/dataverse/search/SearchServiceBean.java
1
package edu.harvard.iq.dataverse.search;
2

3
import edu.harvard.iq.dataverse.*;
4
import edu.harvard.iq.dataverse.authorization.groups.Group;
5
import edu.harvard.iq.dataverse.authorization.groups.GroupServiceBean;
6
import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser;
7
import edu.harvard.iq.dataverse.authorization.users.GuestUser;
8
import edu.harvard.iq.dataverse.authorization.users.PrivateUrlUser;
9
import edu.harvard.iq.dataverse.authorization.users.User;
10
import edu.harvard.iq.dataverse.engine.command.DataverseRequest;
11
import edu.harvard.iq.dataverse.settings.FeatureFlags;
12
import edu.harvard.iq.dataverse.util.BundleUtil;
13
import edu.harvard.iq.dataverse.util.SystemConfig;
14
import java.io.IOException;
15
import java.lang.reflect.Field;
16
import java.util.ArrayList;
17
import java.util.Arrays;
18
import java.util.Calendar;
19
import java.util.Collections;
20
import java.util.Date;
21
import java.util.HashMap;
22
import java.util.LinkedList;
23
import java.util.List;
24
import java.util.ListIterator;
25
import java.util.Map;
26
import java.util.Optional;
27
import java.util.Set;
28
import java.util.MissingResourceException;
29
import java.util.logging.Level;
30
import java.util.logging.Logger;
31
import jakarta.ejb.EJB;
32
import jakarta.ejb.EJBTransactionRolledbackException;
33
import jakarta.ejb.Stateless;
34
import jakarta.ejb.TransactionRolledbackLocalException;
35
import jakarta.inject.Inject;
36
import jakarta.inject.Named;
37
import jakarta.persistence.NoResultException;
38

39
import org.apache.commons.lang3.StringUtils;
40
import org.apache.solr.client.solrj.SolrQuery;
41
import org.apache.solr.client.solrj.SolrQuery.SortClause;
42
import org.apache.solr.client.solrj.SolrServerException;
43
import org.apache.solr.client.solrj.impl.BaseHttpSolrClient.RemoteSolrException;
44
import org.apache.solr.client.solrj.response.FacetField;
45
import org.apache.solr.client.solrj.response.QueryResponse;
46
import org.apache.solr.client.solrj.response.RangeFacet;
47
import org.apache.solr.client.solrj.response.SpellCheckResponse;
48
import org.apache.solr.common.SolrDocument;
49
import org.apache.solr.common.SolrDocumentList;
50

51
@Stateless
52
@Named
53
public class SearchServiceBean {
×
54

UNCOV
55
    private static final Logger logger = Logger.getLogger(SearchServiceBean.class.getCanonicalName());
×
56

57
    private static final String ALL_GROUPS = "*";
58

59
    /**
60
     * We're trying to make the SearchServiceBean lean, mean, and fast, with as
61
     * few injections of EJBs as possible.
62
     */
63
    /**
64
     * @todo Can we do without the DatasetFieldServiceBean?
65
     */
66
    @EJB
67
    DvObjectServiceBean dvObjectService;
68
    @EJB
69
    DatasetVersionServiceBean datasetVersionService;
70
    @EJB
71
    DatasetFieldServiceBean datasetFieldService;
72
    @EJB
73
    GroupServiceBean groupService;
74
    @EJB
75
    SystemConfig systemConfig;
76
    @EJB
77
    SolrClientService solrClientService;
78
    @Inject
79
    ThumbnailServiceWrapper thumbnailServiceWrapper;
80
    
81
    /**
82
     * Import note: "onlyDatatRelatedToMe" relies on filterQueries for providing
83
     * access to Private Data for the correct user
84
     *
85
     * In other words "onlyDatatRelatedToMe", negates other filter Queries
86
     * related to permissions
87
     *
88
     *
89
     * @param dataverseRequest
90
     * @param dataverses
91
     * @param query
92
     * @param filterQueries
93
     * @param sortField
94
     * @param sortOrder
95
     * @param paginationStart
96
     * @param onlyDatatRelatedToMe
97
     * @param numResultsPerPage
98
     * @return
99
     * @throws SearchException
100
     */
101
    public SolrQueryResponse search(DataverseRequest dataverseRequest, List<Dataverse> dataverses, String query, List<String> filterQueries, String sortField, String sortOrder, int paginationStart, boolean onlyDatatRelatedToMe, int numResultsPerPage) throws SearchException {
UNCOV
102
        return search(dataverseRequest, dataverses, query, filterQueries, sortField, sortOrder, paginationStart, onlyDatatRelatedToMe, numResultsPerPage, true, null, null);
×
103
    }
104
    
105
    /**
106
     * Import note: "onlyDatatRelatedToMe" relies on filterQueries for providing
107
     * access to Private Data for the correct user
108
     *
109
     * In other words "onlyDatatRelatedToMe", negates other filter Queries
110
     * related to permissions
111
     *
112
     *
113
     * @param dataverseRequest
114
     * @param dataverses
115
     * @param query
116
     * @param filterQueries
117
     * @param sortField
118
     * @param sortOrder
119
     * @param paginationStart
120
     * @param onlyDatatRelatedToMe
121
     * @param numResultsPerPage
122
     * @param retrieveEntities - look up dvobject entities with .find() (potentially expensive!)
123
     * @param geoPoint e.g. "35,15"
124
     * @param geoRadius e.g. "5"
125

126
     * @return
127
     * @throws SearchException
128
     */
129
    public SolrQueryResponse search(
130
            DataverseRequest dataverseRequest, 
131
            List<Dataverse> dataverses, 
132
            String query, 
133
            List<String> filterQueries, 
134
            String sortField, 
135
            String sortOrder, 
136
            int paginationStart, 
137
            boolean onlyDatatRelatedToMe, 
138
            int numResultsPerPage,
139
            boolean retrieveEntities,
140
            String geoPoint,
141
            String geoRadius) throws SearchException {
UNCOV
142
        return search(dataverseRequest, dataverses, query, filterQueries, sortField, sortOrder, paginationStart, onlyDatatRelatedToMe, numResultsPerPage, true, null, null, true, true);
×
143
    }
144

145
    /**
146
     * @param dataverseRequest
147
     * @param dataverses
148
     * @param query
149
     * @param filterQueries
150
     * @param sortField
151
     * @param sortOrder
152
     * @param paginationStart
153
     * @param onlyDatatRelatedToMe
154
     * @param numResultsPerPage
155
     * @param retrieveEntities - look up dvobject entities with .find() (potentially expensive!)
156
     * @param geoPoint e.g. "35,15"
157
     * @param geoRadius e.g. "5"
158
     * @param addFacets boolean
159
     * @param addHighlights boolean
160
     * @return
161
     * @throws SearchException
162
     */
163
    public SolrQueryResponse search(
164
            DataverseRequest dataverseRequest,
165
            List<Dataverse> dataverses,
166
            String query,
167
            List<String> filterQueries,
168
            String sortField, 
169
            String sortOrder,
170
            int paginationStart,
171
            boolean onlyDatatRelatedToMe,
172
            int numResultsPerPage,
173
            boolean retrieveEntities,
174
            String geoPoint,
175
            String geoRadius,
176
            boolean addFacets,
177
            boolean addHighlights
178
    ) throws SearchException {
179

180
        if (paginationStart < 0) {
×
UNCOV
181
            throw new IllegalArgumentException("paginationStart must be 0 or greater");
×
182
        }
183
        if (numResultsPerPage < 1) {
×
184
            throw new IllegalArgumentException("numResultsPerPage must be 1 or greater");
×
185
        }
186

UNCOV
187
        SolrQuery solrQuery = new SolrQuery();
×
UNCOV
188
        query = SearchUtil.sanitizeQuery(query);
×
189

UNCOV
190
        solrQuery.setQuery(query);
×
UNCOV
191
        if (sortField != null) {
×
192
            // is it ok not to specify any sort? - there are cases where we 
193
            // don't care, and it must cost some extra cycles -- L.A.
194
            solrQuery.setSort(new SortClause(sortField, sortOrder));
×
195
        }
196
        
UNCOV
197
        solrQuery.setParam("fl", "*,score");
×
UNCOV
198
        solrQuery.setParam("qt", "/select");
×
199
        solrQuery.setParam("facet", "true");
×
200
        
201
        /**
202
         * @todo: do we need facet.query?
203
         */
204
        solrQuery.setParam("facet.query", "*");
×
205
        solrQuery.addFacetField(SearchFields.TYPE); // this one is always performed
×
206

207
        for (String filterQuery : filterQueries) {
×
UNCOV
208
            solrQuery.addFilterQuery(filterQuery);
×
209
        }
×
UNCOV
210
        if (geoPoint != null && !geoPoint.isBlank() && geoRadius != null && !geoRadius.isBlank()) {
×
UNCOV
211
            solrQuery.setParam("pt", geoPoint);
×
212
            solrQuery.setParam("d", geoRadius);
×
213
            // See https://solr.apache.org/guide/8_11/spatial-search.html#bbox
214
            solrQuery.addFilterQuery("{!bbox sfield=" + SearchFields.GEOLOCATION + "}");
×
215
        }
216
        
UNCOV
217
        List<DataverseMetadataBlockFacet> metadataBlockFacets = new LinkedList<>();
×
218

UNCOV
219
        if (addFacets) {
×
220

221
            
222

223
            // -----------------------------------
224
            // Facets to Retrieve
225
            // -----------------------------------
UNCOV
226
            solrQuery.addFacetField(SearchFields.METADATA_TYPES);
×
UNCOV
227
            solrQuery.addFacetField(SearchFields.DATASET_TYPE);
×
UNCOV
228
            solrQuery.addFacetField(SearchFields.DATAVERSE_CATEGORY);
×
UNCOV
229
            solrQuery.addFacetField(SearchFields.METADATA_SOURCE);
×
UNCOV
230
            solrQuery.addFacetField(SearchFields.PUBLICATION_YEAR);
×
231
            /*
232
            * We talked about this in slack on 2021-09-14, Users can see objects on draft/unpublished 
233
            *  if the owner gives permissions to all users so it makes sense to expose this facet 
234
            *  to all users. The request of this change started because the order of the facets were 
235
            *  changed with the PR #9635 and this was unintended.
236
            */
UNCOV
237
            solrQuery.addFacetField(SearchFields.PUBLICATION_STATUS);
×
UNCOV
238
            solrQuery.addFacetField(SearchFields.DATASET_LICENSE);
×
239
            /**
240
             * @todo when a new method on datasetFieldService is available
241
             * (retrieveFacetsByDataverse?) only show the facets that the
242
             * dataverse in question wants to show (and in the right order):
243
             * https://redmine.hmdc.harvard.edu/issues/3490
244
             *
245
             * also, findAll only returns advancedSearchField = true... we
246
             * should probably introduce the "isFacetable" boolean rather than
247
             * caring about if advancedSearchField is true or false
248
             *
249
             */
250

251
            if (dataverses != null) {
×
252
                for (Dataverse dataverse : dataverses) {
×
UNCOV
253
                    if (dataverse != null) {
×
UNCOV
254
                        for (DataverseFacet dataverseFacet : dataverse.getDataverseFacets()) {
×
255
                            DatasetFieldType datasetField = dataverseFacet.getDatasetFieldType();
×
UNCOV
256
                            solrQuery.addFacetField(datasetField.getSolrField().getNameFacetable());
×
257
                        }
×
258

259
                        // Get all metadata block facets configured to be displayed
260
                        metadataBlockFacets.addAll(dataverse.getMetadataBlockFacets());
×
261
                    }
UNCOV
262
                }
×
263
            }
264
            
265
            solrQuery.addFacetField(SearchFields.FILE_TYPE);
×
266
            /**
267
            * @todo: hide the extra line this shows in the GUI... at least it's
268
            * last...
269
            */
UNCOV
270
            solrQuery.addFacetField(SearchFields.FILE_TAG);
×
271
            if (!systemConfig.isPublicInstall()) {
×
272
                solrQuery.addFacetField(SearchFields.ACCESS);
×
273
            }
274
        }
275

276
        List<DatasetFieldType> datasetFields = datasetFieldService.findAllOrderedById();
×
277
        Map<String, String> solrFieldsToHightlightOnMap = new HashMap<>();
×
UNCOV
278
        if (addHighlights) {
×
279
            solrQuery.setHighlight(true).setHighlightSnippets(1);
×
280
            Integer fragSize = systemConfig.getSearchHighlightFragmentSize();
×
UNCOV
281
            if (fragSize != null) {
×
UNCOV
282
                solrQuery.setHighlightFragsize(fragSize);
×
283
            }
284
            solrQuery.setHighlightSimplePre("<span class=\"search-term-match\">");
×
285
            solrQuery.setHighlightSimplePost("</span>");
×
286

287
            // TODO: Do not hard code "Name" etc as English here.
288
            solrFieldsToHightlightOnMap.put(SearchFields.NAME, "Name");
×
289
            solrFieldsToHightlightOnMap.put(SearchFields.AFFILIATION, "Affiliation");
×
290
            solrFieldsToHightlightOnMap.put(SearchFields.FILE_TYPE_FRIENDLY, "File Type");
×
291
            solrFieldsToHightlightOnMap.put(SearchFields.DESCRIPTION, "Description");
×
292
            solrFieldsToHightlightOnMap.put(SearchFields.VARIABLE_NAME, "Variable Name");
×
293
            solrFieldsToHightlightOnMap.put(SearchFields.VARIABLE_LABEL, "Variable Label");
×
UNCOV
294
            solrFieldsToHightlightOnMap.put(SearchFields.LITERAL_QUESTION, BundleUtil.getStringFromBundle("search.datasets.literalquestion"));
×
295
            solrFieldsToHightlightOnMap.put(SearchFields.INTERVIEW_INSTRUCTIONS, BundleUtil.getStringFromBundle("search.datasets.interviewinstructions"));
×
296
            solrFieldsToHightlightOnMap.put(SearchFields.POST_QUESTION, BundleUtil.getStringFromBundle("search.datasets.postquestion"));
×
297
            solrFieldsToHightlightOnMap.put(SearchFields.VARIABLE_UNIVERSE, BundleUtil.getStringFromBundle("search.datasets.variableuniverse"));
×
298
            solrFieldsToHightlightOnMap.put(SearchFields.VARIABLE_NOTES, BundleUtil.getStringFromBundle("search.datasets.variableNotes"));
×
299

UNCOV
300
            solrFieldsToHightlightOnMap.put(SearchFields.FILE_TYPE_SEARCHABLE, "File Type");
×
UNCOV
301
            solrFieldsToHightlightOnMap.put(SearchFields.DATASET_PUBLICATION_DATE, "Publication Year");
×
UNCOV
302
            solrFieldsToHightlightOnMap.put(SearchFields.DATASET_PERSISTENT_ID, BundleUtil.getStringFromBundle("advanced.search.datasets.persistentId"));
×
UNCOV
303
            solrFieldsToHightlightOnMap.put(SearchFields.FILE_PERSISTENT_ID, BundleUtil.getStringFromBundle("advanced.search.files.persistentId"));
×
304
            /**
305
             * @todo Dataverse subject and affiliation should be highlighted but
306
             * this is commented out right now because the "friendly" names are
307
             * not being shown on the dataverse cards. See also
308
             * https://github.com/IQSS/dataverse/issues/1431
309
             */
310
//        solrFieldsToHightlightOnMap.put(SearchFields.DATAVERSE_SUBJECT, "Subject");
311
//        solrFieldsToHightlightOnMap.put(SearchFields.DATAVERSE_AFFILIATION, "Affiliation");
312
            /**
313
             * @todo: show highlight on file card?
314
             * https://redmine.hmdc.harvard.edu/issues/3848
315
             */
316
            solrFieldsToHightlightOnMap.put(SearchFields.FILENAME_WITHOUT_EXTENSION, "Filename Without Extension");
×
317
            solrFieldsToHightlightOnMap.put(SearchFields.FILE_TAG_SEARCHABLE, "File Tag");
×
318

319
            for (DatasetFieldType datasetFieldType : datasetFields) {
×
320
                String solrField = datasetFieldType.getSolrField().getNameSearchable();
×
UNCOV
321
                String displayName = datasetFieldType.getDisplayName();
×
322
                solrFieldsToHightlightOnMap.put(solrField, displayName);
×
323
            }
×
UNCOV
324
            for (Map.Entry<String, String> entry : solrFieldsToHightlightOnMap.entrySet()) {
×
UNCOV
325
                String solrField = entry.getKey();
×
326
                // String displayName = entry.getValue();
327
                solrQuery.addHighlightField(solrField);
×
328
            }
×
329
        }
330

331
        // -----------------------------------
332
        // PERMISSION FILTER QUERY
333
        // -----------------------------------
334
        String permissionFilterQuery = this.getPermissionFilterQuery(dataverseRequest, solrQuery, onlyDatatRelatedToMe, addFacets);
×
UNCOV
335
        if (permissionFilterQuery != null) {
×
336
            solrQuery.addFilterQuery(permissionFilterQuery);
×
337
        }
338
        
339
        /**
340
         * @todo: do sanity checking... throw error if negative
341
         */
UNCOV
342
        solrQuery.setStart(paginationStart);
×
343
        /**
344
         * @todo: decide if year CITATION_YEAR is good enough or if we should
345
         * support CITATION_DATE
346
         */
347
//        Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"), Locale.UK);
348
//        calendar.set(2010, 1, 1);
349
//        Date start = calendar.getTime();
350
//        calendar.set(2013, 1, 1);
351
//        Date end = calendar.getTime();
352
//        solrQuery.addDateRangeFacet(SearchFields.CITATION_DATE, start, end, "+1MONTH");
353
        /**
354
         * @todo make this configurable
355
         */
UNCOV
356
        int thisYear = Calendar.getInstance().get(Calendar.YEAR);
×
357
        /**
358
         * @todo: odd or even makes a difference. Couldn't find value of 2014
359
         * when this was set to 2000
360
         */
UNCOV
361
        final int citationYearRangeStart = 1901;
×
362
        final int citationYearRangeEnd = thisYear;
×
UNCOV
363
        final int citationYearRangeSpan = 2;
×
364
        /**
365
         * @todo: these are dates and should be "range facets" not "field
366
         * facets"
367
         *
368
         * right now they are lumped in with the datasetFieldService.findAll()
369
         * above
370
         */
371
//        solrQuery.addNumericRangeFacet(SearchFields.PRODUCTION_DATE_YEAR_ONLY, citationYearRangeStart, citationYearRangeEnd, citationYearRangeSpan);
372
//        solrQuery.addNumericRangeFacet(SearchFields.DISTRIBUTION_DATE_YEAR_ONLY, citationYearRangeStart, citationYearRangeEnd, citationYearRangeSpan);
UNCOV
373
        solrQuery.setRows(numResultsPerPage);
×
UNCOV
374
        logger.fine("Solr query:" + solrQuery);
×
375

376
        // -----------------------------------
377
        // Make the solr query
378
        // -----------------------------------
379
        QueryResponse queryResponse = null;
×
380
        
381
        try {
UNCOV
382
            queryResponse = solrClientService.getSolrClient().query(solrQuery);
×
383

UNCOV
384
        } catch (RemoteSolrException ex) {
×
385
            String messageFromSolr = ex.getLocalizedMessage();
×
386
            
UNCOV
387
            logger.fine("message from the solr exception: "+messageFromSolr+"; code: "+ex.code());
×
388
            
UNCOV
389
            SolrQueryResponse exceptionSolrQueryResponse = new SolrQueryResponse(solrQuery);
×
390

391
            // We probably shouldn't be assuming that this is necessarily a 
392
            // "search syntax error", as the code below implies - could be 
393
            // something else too - ? 
394
            
395
            // Specifically, we now rely on the Solr "circuit breaker" mechanism
396
            // to start dropping requests with 503, when the service is 
397
            // overwhelmed with requests load (with the assumption that this is
398
            // a transient condition): 
399
            
UNCOV
400
            if (ex.code() == 503) {
×
401
                // actual logic for communicating this state back to the local 
402
                // client code TBD (@todo)
UNCOV
403
                exceptionSolrQueryResponse.setSolrTemporarilyUnavailable(true);
×
404
            }
405
            
406
            String error = "Search Syntax Error: ";
×
UNCOV
407
            String stringToHide = "org.apache.solr.search.SyntaxError: ";
×
UNCOV
408
            if (messageFromSolr.startsWith(stringToHide)) {
×
409
                // hide "org.apache.solr..."
UNCOV
410
                error += messageFromSolr.substring(stringToHide.length());
×
411
            } else {
412
                error += messageFromSolr;
×
413
            }
414
            logger.info(error);
×
UNCOV
415
            exceptionSolrQueryResponse.setError(error);
×
416

417
            // we can't show anything because of the search syntax error
418
                        
UNCOV
419
            long zeroNumResultsFound = 0;
×
420
            long zeroGetResultsStart = 0;
×
421
            List<SolrSearchResult> emptySolrSearchResults = new ArrayList<>();
×
UNCOV
422
            List<FacetCategory> exceptionFacetCategoryList = new ArrayList<>();
×
UNCOV
423
            Map<String, List<String>> emptySpellingSuggestion = new HashMap<>();
×
UNCOV
424
            exceptionSolrQueryResponse.setNumResultsFound(zeroNumResultsFound);
×
425
            exceptionSolrQueryResponse.setResultsStart(zeroGetResultsStart);
×
426
            exceptionSolrQueryResponse.setSolrSearchResults(emptySolrSearchResults);
×
427
            exceptionSolrQueryResponse.setFacetCategoryList(exceptionFacetCategoryList);
×
428
            exceptionSolrQueryResponse.setTypeFacetCategories(exceptionFacetCategoryList);
×
429
            exceptionSolrQueryResponse.setSpellingSuggestionsByToken(emptySpellingSuggestion);
×
430
            return exceptionSolrQueryResponse;
×
431
        } catch (SolrServerException | IOException ex) {
×
432
            throw new SearchException("Internal Dataverse Search Engine Error", ex);
×
433
        }
×
434
        
435
        int statusCode = queryResponse.getStatus();
×
436
        
437
        logger.fine("status code of the query response: "+statusCode);
×
438
        logger.fine("_size from query response: "+queryResponse._size());
×
439
        logger.fine("qtime: "+queryResponse.getQTime());
×
440

441
        SolrDocumentList docs = queryResponse.getResults();
×
UNCOV
442
        List<SolrSearchResult> solrSearchResults = new ArrayList<>();
×
443

444
        /**
445
         * @todo refactor SearchFields to a hashmap (or something? put in
446
         * database? internationalize?) to avoid the crazy reflection and string
447
         * manipulation below
448
         */
UNCOV
449
        Object searchFieldsObject = new SearchFields();
×
UNCOV
450
        Field[] staticSearchFields = searchFieldsObject.getClass().getDeclaredFields();
×
UNCOV
451
        String titleSolrField = null;
×
452
        try {
UNCOV
453
            DatasetFieldType titleDatasetField = datasetFieldService.findByName(DatasetFieldConstant.title);
×
UNCOV
454
            titleSolrField = titleDatasetField.getSolrField().getNameSearchable();
×
455
        } catch (EJBTransactionRolledbackException ex) {
×
456
            logger.info("Couldn't find " + DatasetFieldConstant.title);
×
457
            if (ex.getCause() instanceof TransactionRolledbackLocalException) {
×
UNCOV
458
                if (ex.getCause().getCause() instanceof NoResultException) {
×
459
                    logger.info("Caught NoResultException");
×
460
                }
461
            }
462
        }
×
463
        Map<String, String> datasetfieldFriendlyNamesBySolrField = new HashMap<>();
×
464
        Map<String, String> staticSolrFieldFriendlyNamesBySolrField = new HashMap<>();
×
465
        String baseUrl = systemConfig.getDataverseSiteUrl();
×
466

467
        //Going through the results
468
        for (SolrDocument solrDocument : docs) {
×
469
            String id = (String) solrDocument.getFieldValue(SearchFields.ID);
×
470
            Long entityid = (Long) solrDocument.getFieldValue(SearchFields.ENTITY_ID);
×
471
            String type = (String) solrDocument.getFieldValue(SearchFields.TYPE);
×
UNCOV
472
            float score = (Float) solrDocument.getFieldValue(SearchFields.RELEVANCE);
×
UNCOV
473
            logger.fine("score for " + id + ": " + score);
×
474
            String identifier = (String) solrDocument.getFieldValue(SearchFields.IDENTIFIER);
×
475
            String citation = (String) solrDocument.getFieldValue(SearchFields.DATASET_CITATION);
×
476
            String citationPlainHtml = (String) solrDocument.getFieldValue(SearchFields.DATASET_CITATION_HTML);
×
477
            String datasetType = (String) solrDocument.getFieldValue(SearchFields.DATASET_TYPE);
×
478
            String persistentUrl = (String) solrDocument.getFieldValue(SearchFields.PERSISTENT_URL);
×
479
            String name = (String) solrDocument.getFieldValue(SearchFields.NAME);
×
480
            String nameSort = (String) solrDocument.getFieldValue(SearchFields.NAME_SORT);
×
481
//            ArrayList titles = (ArrayList) solrDocument.getFieldValues(SearchFields.TITLE);
482
            String title = (String) solrDocument.getFieldValue(titleSolrField);
×
483
            Long datasetVersionId = (Long) solrDocument.getFieldValue(SearchFields.DATASET_VERSION_ID);
×
484
            String deaccessionReason = (String) solrDocument.getFieldValue(SearchFields.DATASET_DEACCESSION_REASON);
×
485
//            logger.info("titleSolrField: " + titleSolrField);
486
//            logger.info("title: " + title);
UNCOV
487
            String filetype = (String) solrDocument.getFieldValue(SearchFields.FILE_TYPE_FRIENDLY);
×
488
            String fileContentType = (String) solrDocument.getFieldValue(SearchFields.FILE_CONTENT_TYPE);
×
489
            Date release_or_create_date = (Date) solrDocument.getFieldValue(SearchFields.RELEASE_OR_CREATE_DATE);
×
490
            String dvTree = (String) solrDocument.getFirstValue(SearchFields.SUBTREE);
×
UNCOV
491
            String identifierOfDataverse = (String) solrDocument.getFieldValue(SearchFields.IDENTIFIER_OF_DATAVERSE);
×
UNCOV
492
            String nameOfDataverse = (String) solrDocument.getFieldValue(SearchFields.DATAVERSE_NAME);
×
493
            String dataverseAffiliation = (String) solrDocument.getFieldValue(SearchFields.DATAVERSE_AFFILIATION);
×
494
            String dataverseParentAlias = (String) solrDocument.getFieldValue(SearchFields.DATAVERSE_PARENT_ALIAS);
×
495
            String dataverseParentName = (String) solrDocument.getFieldValue(SearchFields.PARENT_NAME);
×
496
            Long embargoEndDate = (Long) solrDocument.getFieldValue(SearchFields.EMBARGO_END_DATE);
×
497
            Long retentionEndDate = (Long) solrDocument.getFieldValue(SearchFields.RETENTION_END_DATE);
×
498
            //
499
            Boolean datasetValid = (Boolean) solrDocument.getFieldValue(SearchFields.DATASET_VALID);
×
500

501
            List<String> matchedFields = new ArrayList<>();
×
502
            
503
            SolrSearchResult solrSearchResult = new SolrSearchResult(query, name);
×
504
            
505
            if (addHighlights) {
×
UNCOV
506
                List<Highlight> highlights = new ArrayList<>();
×
507
                Map<SolrField, Highlight> highlightsMap = new HashMap<>();
×
UNCOV
508
                Map<SolrField, List<String>> highlightsMap2 = new HashMap<>();
×
509
                Map<String, Highlight> highlightsMap3 = new HashMap<>();
×
UNCOV
510
                if (queryResponse.getHighlighting().get(id) != null) {
×
511
                    for (Map.Entry<String, String> entry : solrFieldsToHightlightOnMap.entrySet()) {
×
512
                        String field = entry.getKey();
×
513
                        String displayName = entry.getValue();
×
514

515
                        List<String> highlightSnippets = queryResponse.getHighlighting().get(id).get(field);
×
516
                        if (highlightSnippets != null) {
×
517
                            matchedFields.add(field);
×
518
                            /**
519
                             * @todo only SolrField.SolrType.STRING? that's not
520
                             * right... knit the SolrField object more into the
521
                             * highlighting stuff
522
                             */
523
                            SolrField solrField = new SolrField(field, SolrField.SolrType.STRING, true, true);
×
UNCOV
524
                            Highlight highlight = new Highlight(solrField, highlightSnippets, displayName);
×
UNCOV
525
                            highlights.add(highlight);
×
UNCOV
526
                            highlightsMap.put(solrField, highlight);
×
UNCOV
527
                            highlightsMap2.put(solrField, highlightSnippets);
×
UNCOV
528
                            highlightsMap3.put(field, highlight);
×
529
                        }
530
                    }
×
531

532
                }
533

534
                solrSearchResult.setHighlightsAsList(highlights);
×
UNCOV
535
                solrSearchResult.setHighlightsMap(highlightsMap);
×
536
                solrSearchResult.setHighlightsAsMap(highlightsMap3);
×
537
            }
538
            
539
            
540
            /**
541
             * @todo put all this in the constructor?
542
             */
UNCOV
543
            List<String> states = (List<String>) solrDocument.getFieldValue(SearchFields.PUBLICATION_STATUS);
×
UNCOV
544
            if (states != null) {
×
545
                // set list of all statuses
546
                // this method also sets booleans for individual statuses
UNCOV
547
                solrSearchResult.setPublicationStatuses(states);
×
548
            }
549
            String externalStatus = (String) solrDocument.getFieldValue(SearchFields.EXTERNAL_STATUS);
×
550
            if (externalStatus != null) {
×
UNCOV
551
                solrSearchResult.setExternalStatus(externalStatus);
×
552
            }
553
//            logger.info(id + ": " + description);
UNCOV
554
            solrSearchResult.setId(id);
×
555
            solrSearchResult.setEntityId(entityid);
×
556
            if (retrieveEntities) {
×
557
                solrSearchResult.setEntity(dvObjectService.findDvObject(entityid));
×
558
            }
UNCOV
559
            solrSearchResult.setIdentifier(identifier);
×
560
            solrSearchResult.setPersistentUrl(persistentUrl);
×
561
            solrSearchResult.setType(type);
×
562
            solrSearchResult.setScore(score);
×
563
            solrSearchResult.setNameSort(nameSort);
×
UNCOV
564
            solrSearchResult.setReleaseOrCreateDate(release_or_create_date);
×
565
            solrSearchResult.setMatchedFields(matchedFields);
×
566
            
567
            Map<String, String> parent = new HashMap<>();
×
568
            String description = (String) solrDocument.getFieldValue(SearchFields.DESCRIPTION);
×
569
            solrSearchResult.setDescriptionNoSnippet(description);
×
570
            solrSearchResult.setDeaccessionReason(deaccessionReason);
×
571
            solrSearchResult.setDvTree(dvTree);
×
UNCOV
572
            solrSearchResult.setDatasetValid(datasetValid);
×
573

574
            if (Boolean.TRUE.equals((Boolean) solrDocument.getFieldValue(SearchFields.IS_HARVESTED))) {
×
575
                solrSearchResult.setHarvested(true);
×
576
            }
577

578
            solrSearchResult.setEmbargoEndDate(embargoEndDate);
×
UNCOV
579
            solrSearchResult.setRetentionEndDate(retentionEndDate);
×
580

581
            /**
582
             * @todo start using SearchConstants class here
583
             */
584
            if (type.equals("dataverses")) {
×
585
                solrSearchResult.setName(name);
×
UNCOV
586
                solrSearchResult.setHtmlUrl(baseUrl + SystemConfig.DATAVERSE_PATH + identifier);
×
UNCOV
587
                solrSearchResult.setDataverseAffiliation(dataverseAffiliation);
×
UNCOV
588
                solrSearchResult.setDataverseParentAlias(dataverseParentAlias);
×
UNCOV
589
                solrSearchResult.setDataverseParentName(dataverseParentName);
×
590
                solrSearchResult.setImageUrl(thumbnailServiceWrapper.getDataverseCardImageAsUrl(solrSearchResult));
×
591
                /**
592
                 * @todo Expose this API URL after "dvs" is changed to
593
                 * "dataverses". Also, is an API token required for published
594
                 * dataverses? Michael: url changed.
595
                 */
596
//                solrSearchResult.setApiUrl(baseUrl + "/api/dataverses/" + entityid);
UNCOV
597
            } else if (type.equals("datasets")) {
×
UNCOV
598
                solrSearchResult.setHtmlUrl(baseUrl + "/dataset.xhtml?globalId=" + identifier);
×
UNCOV
599
                solrSearchResult.setApiUrl(baseUrl + "/api/datasets/" + entityid);
×
UNCOV
600
                solrSearchResult.setImageUrl(thumbnailServiceWrapper.getDatasetCardImageAsUrl(solrSearchResult));
×
601
                //Image url now set via thumbnail api
602
                //solrSearchResult.setImageUrl(baseUrl + "/api/access/dsCardImage/" + datasetVersionId);
603
                // No, we don't want to set the base64 thumbnails here.
604
                // We want to do it inside SearchIncludeFragment, AND ONLY once the rest of the
605
                // page has already loaded.
606
                //DatasetVersion datasetVersion = datasetVersionService.find(datasetVersionId);
607
                //if (datasetVersion != null){
608
                //    solrSearchResult.setDatasetThumbnail(datasetVersion.getDataset().getDatasetThumbnail(datasetVersion));
609
                //}
610
                /**
611
                 * @todo Could use getFieldValues (plural) here.
612
                 */
UNCOV
613
                List<String> datasetDescriptions = (List<String>) solrDocument.getFieldValue(SearchFields.DATASET_DESCRIPTION);
×
UNCOV
614
                if (datasetDescriptions != null) {
×
UNCOV
615
                    String firstDatasetDescription = datasetDescriptions.get(0);
×
UNCOV
616
                    if (firstDatasetDescription != null) {
×
UNCOV
617
                        solrSearchResult.setDescriptionNoSnippet(firstDatasetDescription);
×
618
                    }
619
                }
620
                solrSearchResult.setDatasetVersionId(datasetVersionId);
×
621

622
                solrSearchResult.setCitation(citation);
×
623
                solrSearchResult.setCitationHtml(citationPlainHtml);
×
624

UNCOV
625
                solrSearchResult.setIdentifierOfDataverse(identifierOfDataverse);
×
626
                solrSearchResult.setNameOfDataverse(nameOfDataverse);
×
627

628
                if (title != null) {
×
629
//                    solrSearchResult.setTitle((String) titles.get(0));
UNCOV
630
                    solrSearchResult.setTitle(title);
×
631
                } else {
632
                    logger.fine("No title indexed. Setting to empty string to prevent NPE. Dataset id " + entityid + " and version id " + datasetVersionId);
×
UNCOV
633
                    solrSearchResult.setTitle("");
×
634
                }
UNCOV
635
                List<String> authors = (List) solrDocument.getFieldValues(DatasetFieldConstant.authorName);
×
636
                if (authors != null) {
×
UNCOV
637
                    solrSearchResult.setDatasetAuthors(authors);
×
638
                }
639
                solrSearchResult.setDatasetType(datasetType);
×
UNCOV
640
            } else if (type.equals("files")) {
×
641
                String parentGlobalId = null;
×
642
                Object parentGlobalIdObject = solrDocument.getFieldValue(SearchFields.PARENT_IDENTIFIER);
×
643
                if (parentGlobalIdObject != null) {
×
UNCOV
644
                    parentGlobalId = (String) parentGlobalIdObject;
×
645
                    parent.put(SolrSearchResult.PARENT_IDENTIFIER, parentGlobalId);
×
646
                }
647
                solrSearchResult.setHtmlUrl(baseUrl + "/dataset.xhtml?persistentId=" + parentGlobalId);
×
648
                solrSearchResult.setDownloadUrl(baseUrl + "/api/access/datafile/" + entityid);
×
649
                solrSearchResult.setImageUrl(thumbnailServiceWrapper.getFileCardImageAsUrl(solrSearchResult));
×
650
                /**
651
                 * @todo We are not yet setting the API URL for files because
652
                 * not all files have metadata. Only subsettable files (those
653
                 * with a datatable) seem to have metadata. Furthermore, the
654
                 * response is in XML whereas the rest of the Search API returns
655
                 * JSON.
656
                 */
657
//                solrSearchResult.setApiUrl(baseUrl + "/api/meta/datafile/" + entityid);
658
                //solrSearchResult.setImageUrl(baseUrl + "/api/access/fileCardImage/" + entityid);
UNCOV
659
                solrSearchResult.setName(name);
×
UNCOV
660
                solrSearchResult.setFiletype(filetype);
×
UNCOV
661
                solrSearchResult.setFileContentType(fileContentType);
×
UNCOV
662
                Object fileSizeInBytesObject = solrDocument.getFieldValue(SearchFields.FILE_SIZE_IN_BYTES);
×
UNCOV
663
                if (fileSizeInBytesObject != null) {
×
664
                    try {
665
                        long fileSizeInBytesLong = (long) fileSizeInBytesObject;
×
666
                        solrSearchResult.setFileSizeInBytes(fileSizeInBytesLong);
×
667
                    } catch (ClassCastException ex) {
×
668
                        logger.info("Could not cast file " + entityid + " to long for " + SearchFields.FILE_SIZE_IN_BYTES + ": " + ex.getLocalizedMessage());
×
669
                    }
×
670
                }
671
                solrSearchResult.setFileMd5((String) solrDocument.getFieldValue(SearchFields.FILE_MD5));
×
672
                try {
673
                    solrSearchResult.setFileChecksumType(DataFile.ChecksumType.fromString((String) solrDocument.getFieldValue(SearchFields.FILE_CHECKSUM_TYPE)));
×
674
                } catch (IllegalArgumentException ex) {
×
675
                    logger.info("Exception setting setFileChecksumType: " + ex);
×
UNCOV
676
                }
×
677
                solrSearchResult.setFileChecksumValue((String) solrDocument.getFieldValue(SearchFields.FILE_CHECKSUM_VALUE));
×
UNCOV
678
                solrSearchResult.setUnf((String) solrDocument.getFieldValue(SearchFields.UNF));
×
679
                solrSearchResult.setDatasetVersionId(datasetVersionId);
×
680
                List<String> fileCategories = (List) solrDocument.getFieldValues(SearchFields.FILE_TAG);
×
681
                if (fileCategories != null) {
×
682
                    solrSearchResult.setFileCategories(fileCategories);
×
683
                }
684
                List<String> tabularDataTags = (List) solrDocument.getFieldValues(SearchFields.TABDATA_TAG);
×
685
                if (tabularDataTags != null) {
×
686
                    Collections.sort(tabularDataTags);
×
687
                    solrSearchResult.setTabularDataTags(tabularDataTags);
×
688
                }
UNCOV
689
                String filePID = (String) solrDocument.getFieldValue(SearchFields.FILE_PERSISTENT_ID);
×
690
                if(null != filePID && !"".equals(filePID) && !"".equals("null")) {
×
691
                    solrSearchResult.setFilePersistentId(filePID);
×
692
                }
693
            }
694
            /**
695
             * @todo store PARENT_ID as a long instead and cast as such
696
             */
697
            parent.put("id", (String) solrDocument.getFieldValue(SearchFields.PARENT_ID));
×
UNCOV
698
            parent.put("name", (String) solrDocument.getFieldValue(SearchFields.PARENT_NAME));
×
UNCOV
699
            parent.put("citation", (String) solrDocument.getFieldValue(SearchFields.PARENT_CITATION));
×
UNCOV
700
            solrSearchResult.setParent(parent);
×
UNCOV
701
            solrSearchResults.add(solrSearchResult);
×
UNCOV
702
        }
×
703
        Map<String, List<String>> spellingSuggestionsByToken = new HashMap<>();
×
704
        SpellCheckResponse spellCheckResponse = queryResponse.getSpellCheckResponse();
×
705
        if (spellCheckResponse != null) {
×
706
            List<SpellCheckResponse.Suggestion> suggestions = spellCheckResponse.getSuggestions();
×
707
            for (SpellCheckResponse.Suggestion suggestion : suggestions) {
×
708
                spellingSuggestionsByToken.put(suggestion.getToken(), suggestion.getAlternatives());
×
709
            }
×
710
        }
711

712
        List<FacetCategory> facetCategoryList = new ArrayList<>();
×
713
        List<FacetCategory> typeFacetCategories = new ArrayList<>();
×
714
        boolean hidePublicationStatusFacet = true;
×
715
        boolean draftsAvailable = false;
×
UNCOV
716
        boolean unpublishedAvailable = false;
×
UNCOV
717
        boolean deaccessionedAvailable = false;
×
718
        boolean hideMetadataSourceFacet = true;
×
719
        boolean hideLicenseFacet = true;
×
720
        boolean hideDatasetTypeFacet = true;
×
721
        for (FacetField facetField : queryResponse.getFacetFields()) {
×
722
            FacetCategory facetCategory = new FacetCategory();
×
723
            List<FacetLabel> facetLabelList = new ArrayList<>();
×
724
            int numMetadataSources = 0;
×
725
            int numLicenses = 0;
×
726
            int numDatasetTypes = 0;
×
727
            String metadataBlockName = "";
×
728
            String datasetFieldName = "";
×
729
            /**
730
             * To find the metadata block name to which the facetField belongs to
731
             * ===facetField: authorName_ss   metadatablockname : citation
732
             * ===facetField: dvCategory  metadatablockname : ""
733
             */
734
            for (DatasetFieldType datasetField : datasetFields) {
×
UNCOV
735
                String solrFieldNameForDataset = datasetField.getSolrField().getNameFacetable();
×
UNCOV
736
                if (solrFieldNameForDataset != null && facetField.getName().equals(solrFieldNameForDataset)) {
×
UNCOV
737
                    metadataBlockName = datasetField.getMetadataBlock().getName() ;
×
UNCOV
738
                    datasetFieldName = datasetField.getName();
×
UNCOV
739
                    facetCategory.setDatasetFieldTypeId(datasetField.getId());
×
740
                    break;
×
741
                }
742
            }
×
743

744

745
            for (FacetField.Count facetFieldCount : facetField.getValues()) {
×
746
                /**
747
                 * @todo we do want to show the count for each facet
748
                 */
749
//                logger.info("field: " + facetField.getName() + " " + facetFieldCount.getName() + " (" + facetFieldCount.getCount() + ")");
UNCOV
750
                String localefriendlyName = null;
×
751
                if (facetFieldCount.getCount() > 0) {
×
UNCOV
752
                    if(metadataBlockName.length() > 0 ) {
×
UNCOV
753
                        localefriendlyName = getLocaleTitle(datasetFieldName,facetFieldCount.getName(), metadataBlockName);
×
UNCOV
754
                    } else if (facetField.getName().equals(SearchFields.METADATA_TYPES)) {
×
UNCOV
755
                        Optional<DataverseMetadataBlockFacet> metadataBlockFacet = metadataBlockFacets.stream().filter(blockFacet -> blockFacet.getMetadataBlock().getName().equals(facetFieldCount.getName())).findFirst();
×
756
                        if (metadataBlockFacet.isEmpty()) {
×
757
                           // metadata block facet is not configured to be displayed => ignore
758
                           continue;
×
759
                        }
760

761
                        localefriendlyName = metadataBlockFacet.get().getMetadataBlock().getLocaleDisplayFacet();
×
762
                    } else if (facetField.getName().equals(SearchFields.DATASET_LICENSE)) {
×
763
                        try {
764
                            localefriendlyName = BundleUtil.getStringFromPropertyFile("license." + facetFieldCount.getName().toLowerCase().replace(" ","_") + ".name", "License");
×
UNCOV
765
                        } catch (Exception e) {
×
UNCOV
766
                            localefriendlyName = facetFieldCount.getName();
×
767
                        }
×
768
                    } else {
769
                        try {
770
                            // This is where facets are capitalized.
771
                            // This will be a problem for the API clients because they get back a string like this from the Search API...
772
                            // {"datasetType":{"friendly":"Dataset Type","labels":[{"Dataset":1},{"Software":1}]}
773
                            // ... but they will need to use the lower case version (e.g. "software") to narrow results.
UNCOV
774
                           localefriendlyName = BundleUtil.getStringFromPropertyFile(facetFieldCount.getName(), "Bundle");
×
UNCOV
775
                        } catch (Exception e) {
×
UNCOV
776
                           localefriendlyName = facetFieldCount.getName();
×
UNCOV
777
                        }
×
778
                    }
UNCOV
779
                    FacetLabel facetLabel = new FacetLabel(localefriendlyName, facetFieldCount.getCount());
×
780
                    // quote field facets
781
                    facetLabel.setFilterQuery(facetField.getName() + ":\"" + facetFieldCount.getName() + "\"");
×
782
                    facetLabelList.add(facetLabel);
×
783
                    if (facetField.getName().equals(SearchFields.PUBLICATION_STATUS)) {
×
UNCOV
784
                        if (facetFieldCount.getName().equals(IndexServiceBean.getUNPUBLISHED_STRING())) {
×
785
                            unpublishedAvailable = true;
×
UNCOV
786
                        } else if (facetFieldCount.getName().equals(IndexServiceBean.getDRAFT_STRING())) {
×
787
                            draftsAvailable = true;
×
788
                        } else if (facetFieldCount.getName().equals(IndexServiceBean.getDEACCESSIONED_STRING())) {
×
789
                            deaccessionedAvailable = true;
×
790
                        }
791
                    } else if (facetField.getName().equals(SearchFields.METADATA_SOURCE)) {
×
792
                        numMetadataSources++;
×
793
                    } else if (facetField.getName().equals(SearchFields.DATASET_LICENSE)) {
×
794
                        numLicenses++;
×
795
                    } else if (facetField.getName().equals(SearchFields.DATASET_TYPE)) {
×
UNCOV
796
                        numDatasetTypes++;
×
797
                    }
798
                }
799
            }
×
800
            if (numMetadataSources > 1) {
×
801
                hideMetadataSourceFacet = false;
×
802
            }
UNCOV
803
            if (numLicenses > 1) {
×
UNCOV
804
                hideLicenseFacet = false;
×
805
            }
806
            if (numDatasetTypes > 1 ) {
×
807
                hideDatasetTypeFacet = false;
×
808
            }
809
            facetCategory.setName(facetField.getName());
×
810
            // hopefully people will never see the raw facetField.getName() because it may well have an _s at the end
UNCOV
811
            facetCategory.setFriendlyName(facetField.getName());
×
812
            // try to find a friendlier name to display as a facet
813
            /**
814
             * @todo hmm, we thought we wanted the datasetFields array to go
815
             * away once we have more granularity than findAll() available per
816
             * the todo above but we need a way to lookup by Solr field, so
817
             * we'll build a hashmap
818
             */
UNCOV
819
            for (DatasetFieldType datasetField : datasetFields) {
×
UNCOV
820
                String solrFieldNameForDataset = datasetField.getSolrField().getNameFacetable();
×
UNCOV
821
                String friendlyName = datasetField.getDisplayName();
×
UNCOV
822
                if (solrFieldNameForDataset != null && facetField.getName().endsWith(datasetField.getTmpNullFieldTypeIdentifier())) {
×
823
                    // give it the non-friendly name so we remember to update the reference data script for datasets
UNCOV
824
                    facetCategory.setName(facetField.getName());
×
825
                } else if (solrFieldNameForDataset != null && facetField.getName().equals(solrFieldNameForDataset)) {
×
826
                    if (friendlyName != null && !friendlyName.isEmpty()) {
×
827
                        facetCategory.setFriendlyName(friendlyName);
×
828
                        // stop examining available dataset fields. we found a match
UNCOV
829
                        break;
×
830
                    }
831
                }
832
                datasetfieldFriendlyNamesBySolrField.put(datasetField.getSolrField().getNameFacetable(), friendlyName);
×
833
            }
×
834
            /**
835
             * @todo get rid of this crazy reflection, per todo above... or
836
             * should we... let's put into a hash the friendly names of facet
837
             * categories, indexed by Solr field
838
             */
839
            for (Field fieldObject : staticSearchFields) {
×
UNCOV
840
                String name = fieldObject.getName();
×
UNCOV
841
                String staticSearchField = null;
×
842
                try {
UNCOV
843
                    staticSearchField = (String) fieldObject.get(searchFieldsObject);
×
UNCOV
844
                } catch (IllegalArgumentException | IllegalAccessException ex) {
×
845
                    Logger.getLogger(SearchServiceBean.class.getName()).log(Level.SEVERE, null, ex);
×
846
                }
×
847
                if (staticSearchField != null && facetField.getName().equals(staticSearchField)) {
×
UNCOV
848
                    String friendlyName = BundleUtil.getStringFromPropertyFile("staticSearchFields."+staticSearchField, "staticSearchFields");
×
849
                    if(friendlyName != null && friendlyName.length() > 0) {
×
850
                        facetCategory.setFriendlyName(friendlyName);
×
851
                    } else {
852
                        String[] parts = name.split("_");
×
853
                        StringBuilder stringBuilder = new StringBuilder();
×
854
                        for (String part : parts) {
×
855
                            stringBuilder.append(getCapitalizedName(part.toLowerCase()) + " ");
×
856
                        }
UNCOV
857
                        String friendlyNameWithTrailingSpace = stringBuilder.toString();
×
858
                        friendlyName = friendlyNameWithTrailingSpace.replaceAll(" $", "");
×
859
                        facetCategory.setFriendlyName(friendlyName);
×
860
                    }
861

862
//                    logger.info("adding <<<" + staticSearchField + ":" + friendlyName + ">>>");
863
                    staticSolrFieldFriendlyNamesBySolrField.put(staticSearchField, friendlyName);
×
864
                    // stop examining the declared/static fields in the SearchFields object. we found a match
865
                    break;
×
866
                }
867
            }
868

869
            facetCategory.setFacetLabel(facetLabelList);
×
UNCOV
870
            if (!facetLabelList.isEmpty()) {
×
871
                if (facetCategory.getName().equals(SearchFields.TYPE)) {
×
872
                    // the "type" facet is special, these are not
UNCOV
873
                    typeFacetCategories.add(facetCategory);
×
UNCOV
874
                } else if (facetCategory.getName().equals(SearchFields.PUBLICATION_STATUS)) {
×
875
                    if (unpublishedAvailable || draftsAvailable || deaccessionedAvailable) {
×
876
                        hidePublicationStatusFacet = false;
×
877
                    }
UNCOV
878
                    if (!hidePublicationStatusFacet) {
×
879
                        facetCategoryList.add(facetCategory);
×
880
                    }
881
                } else if (facetCategory.getName().equals(SearchFields.METADATA_SOURCE)) {
×
882
                    if (!hideMetadataSourceFacet) {
×
UNCOV
883
                        facetCategoryList.add(facetCategory);
×
884
                    }
885
                } else if (facetCategory.getName().equals(SearchFields.DATASET_LICENSE)) {
×
UNCOV
886
                    if (!hideLicenseFacet) {
×
887
                        facetCategoryList.add(facetCategory);
×
888
                    }
889
                } else if (facetCategory.getName().equals(SearchFields.DATASET_TYPE)) {
×
UNCOV
890
                    if (!hideDatasetTypeFacet) {
×
891
                        facetCategoryList.add(facetCategory);
×
892
                    }
893
                } else {
UNCOV
894
                    facetCategoryList.add(facetCategory);
×
895
                }
896
            }
897
        }
×
898

899
        // for now the only range facet is citation year
900
        for (RangeFacet<String, String> rangeFacet : queryResponse.getFacetRanges()) {
×
UNCOV
901
            FacetCategory facetCategory = new FacetCategory();
×
UNCOV
902
            List<FacetLabel> facetLabelList = new ArrayList<>();
×
903
            for (Object rfObj : rangeFacet.getCounts()) {
×
UNCOV
904
                RangeFacet.Count rangeFacetCount = (RangeFacet.Count) rfObj;
×
UNCOV
905
                String valueString = rangeFacetCount.getValue();
×
906
                Integer start = Integer.parseInt(valueString);
×
907
                Integer end = start + Integer.parseInt(rangeFacet.getGap().toString());
×
908
                // to avoid overlapping dates
909
                end = end - 1;
×
910
                if (rangeFacetCount.getCount() > 0) {
×
911
                    FacetLabel facetLabel = new FacetLabel(start + "-" + end, Long.valueOf(rangeFacetCount.getCount()));
×
912
                    // special [12 TO 34] syntax for range facets
913
                    facetLabel.setFilterQuery(rangeFacet.getName() + ":" + "[" + start + " TO " + end + "]");
×
UNCOV
914
                    facetLabelList.add(facetLabel);
×
915
                }
916
            }
×
917
            facetCategory.setName(rangeFacet.getName());
×
UNCOV
918
            facetCategory.setFacetLabel(facetLabelList);
×
919
            // reverse to show the newest citation year range at the top
920
            List<FacetLabel> facetLabelListReversed = new ArrayList<>();
×
UNCOV
921
            ListIterator<FacetLabel> li = facetLabelList.listIterator(facetLabelList.size());
×
922
            while (li.hasPrevious()) {
×
923
                facetLabelListReversed.add(li.previous());
×
924
            }
UNCOV
925
            facetCategory.setFacetLabel(facetLabelListReversed);
×
926
            if (!facetLabelList.isEmpty()) {
×
927
                facetCategoryList.add(facetCategory);
×
928
            }
929
        }
×
930

931
        SolrQueryResponse solrQueryResponse = new SolrQueryResponse(solrQuery);
×
932
        solrQueryResponse.setSolrSearchResults(solrSearchResults);
×
933
        solrQueryResponse.setSpellingSuggestionsByToken(spellingSuggestionsByToken);
×
UNCOV
934
        solrQueryResponse.setFacetCategoryList(facetCategoryList);
×
935
        solrQueryResponse.setTypeFacetCategories(typeFacetCategories);
×
UNCOV
936
        solrQueryResponse.setNumResultsFound(queryResponse.getResults().getNumFound());
×
937
        solrQueryResponse.setResultsStart(queryResponse.getResults().getStart());
×
938
        solrQueryResponse.setDatasetfieldFriendlyNamesBySolrField(datasetfieldFriendlyNamesBySolrField);
×
939
        solrQueryResponse.setStaticSolrFieldFriendlyNamesBySolrField(staticSolrFieldFriendlyNamesBySolrField);
×
940
        String[] filterQueriesArray = solrQuery.getFilterQueries();
×
941
        if (filterQueriesArray != null) {
×
942
            // null check added because these tests were failing: mvn test -Dtest=SearchIT
943
            List<String> actualFilterQueries = Arrays.asList(filterQueriesArray);
×
944
            logger.fine("actual filter queries: " + actualFilterQueries);
×
945
            solrQueryResponse.setFilterQueriesActual(actualFilterQueries);
×
946
        } else {
×
947
            // how often is this null?
UNCOV
948
            logger.info("solrQuery.getFilterQueries() was null");
×
949
        }
950

951
        solrQueryResponse.setDvObjectCounts(queryResponse.getFacetField("dvObjectType"));
×
952
        solrQueryResponse.setPublicationStatusCounts(queryResponse.getFacetField("publicationStatus"));
×
953

954
        return solrQueryResponse;
×
955
    }
956

957
    public String getLocaleTitle(String title,  String controlledvoc , String propertyfile) {
958

UNCOV
959
        String output = "";
×
960
        try {
UNCOV
961
            if(controlledvoc != "" ) {
×
UNCOV
962
                output =  BundleUtil.getStringFromPropertyFile("controlledvocabulary." + title +"."+ controlledvoc.toLowerCase().replace(" ","_")  , propertyfile);
×
963
            } else {
UNCOV
964
                output = BundleUtil.getStringFromPropertyFile("datasetfieldtype." + title + ".title", propertyfile);
×
965
            }
UNCOV
966
        } catch (MissingResourceException e1) {
×
967
            if(controlledvoc != "" ) {
×
968
                return controlledvoc;
×
969
            } else {
970
                return title;
×
971
            }
972
        }
×
973

974
        if(output != null && output.length() >0) {
×
UNCOV
975
            return output;
×
976
        }
977
        else
978
            return title;
×
979
    }
980

981

982
    public String getCapitalizedName(String name) {
UNCOV
983
        return Character.toUpperCase(name.charAt(0)) + name.substring(1);
×
984
    }
985

986
    /**
987
     * Moved this logic out of the "search" function
988
     *
989
     * @return
990
     */
991
    private String getPermissionFilterQuery(DataverseRequest dataverseRequest, SolrQuery solrQuery, boolean onlyDatatRelatedToMe, boolean addFacets) {
992

UNCOV
993
        User user = dataverseRequest.getUser();
×
UNCOV
994
        if (user == null) {
×
UNCOV
995
            throw new NullPointerException("user cannot be null");
×
996
        }
UNCOV
997
        if (solrQuery == null) {
×
UNCOV
998
            throw new NullPointerException("solrQuery cannot be null");
×
999
        }
1000
        
1001
        if (user instanceof PrivateUrlUser) {
×
UNCOV
1002
            user = GuestUser.get();
×
1003
        }
1004

UNCOV
1005
        ArrayList<String> groupList = new ArrayList<String>();
×
UNCOV
1006
        AuthenticatedUser au = null;
×
1007
        Set<Group> groups;
1008

UNCOV
1009
        boolean avoidJoin = FeatureFlags.AVOID_EXPENSIVE_SOLR_JOIN.enabled();
×
1010

UNCOV
1011
        if (user instanceof AuthenticatedUser) {
×
UNCOV
1012
            au = (AuthenticatedUser) user;
×
1013

1014
            // ----------------------------------------------------
1015
            // Is this a Super User?
1016
            // If so, they can see everything
1017
            // ----------------------------------------------------
1018
            if (au.isSuperuser()) {
×
1019
                // Somewhat dangerous because this user (a superuser) will be able
1020
                // to see everything in Solr with no regard to permissions. But it's
1021
                // been this way since Dataverse 4.0. So relax. :)
1022

UNCOV
1023
                return buildPermissionFilterQuery(avoidJoin, ALL_GROUPS);
×
1024
            }
1025

1026
            // ----------------------------------------------------
1027
            // User is logged in AND onlyDatatRelatedToMe == true
1028
            // Yes, give back everything -> the settings will be in
1029
            // the filterqueries given to search
1030
            // ----------------------------------------------------
1031
            if (onlyDatatRelatedToMe == true) {
×
UNCOV
1032
                if (systemConfig.myDataDoesNotUsePermissionDocs()) {
×
UNCOV
1033
                    logger.fine("old 4.2 behavior: MyData is not using Solr permission docs");
×
1034
                    return buildPermissionFilterQuery(avoidJoin, ALL_GROUPS);
×
1035
                } else {
1036
                    // fall-through
UNCOV
1037
                    logger.fine("new post-4.2 behavior: MyData is using Solr permission docs");
×
1038
                }
1039
            }
1040
            // ----------------------------------------------------
1041
            // Work with Authenticated User who is not a Superuser
1042
            // ----------------------------------------------------
UNCOV
1043
            groupList.add(IndexServiceBean.getGroupPerUserPrefix() + au.getId());
×
1044
        }
1045
        
1046
        // In addition to the user referenced directly, we will also
1047
        // add joins on all the non-public groups that may exist for the
1048
        // user:
1049

1050
        // Authenticated users and GuestUser may be part of one or more groups; such
1051
        // as IP Groups.
UNCOV
1052
        groups = groupService.collectAncestors(groupService.groupsFor(dataverseRequest));
×
1053

1054
        for (Group group : groups) {
×
1055
            String groupAlias = group.getAlias();
×
1056
            if (groupAlias != null && !groupAlias.isEmpty() && (!avoidJoin || !groupAlias.startsWith("builtIn"))) {
×
UNCOV
1057
                groupList.add(IndexServiceBean.getGroupPrefix() + groupAlias);
×
1058
            }
1059
        }
×
1060

UNCOV
1061
        if (!avoidJoin) {
×
1062
            // Add the public group
UNCOV
1063
            groupList.add(0, IndexServiceBean.getPublicGroupString());
×
1064
        } 
1065
        
UNCOV
1066
        String groupString = null;
×
1067
        //If we have additional groups, format them correctly into a search string, with parens if there is more than one
UNCOV
1068
        if (groupList.size() > 1) {
×
UNCOV
1069
            groupString = "(" + StringUtils.join(groupList, " OR ") + ")";
×
1070
        } else if (groupList.size() == 1) {
×
UNCOV
1071
            groupString = groupList.get(0);
×
1072
        }
UNCOV
1073
        logger.fine("Groups: " + groupString);
×
UNCOV
1074
        String permissionQuery = buildPermissionFilterQuery(avoidJoin, groupString);
×
UNCOV
1075
        logger.fine("Permission Query: " + permissionQuery);
×
UNCOV
1076
        return permissionQuery;
×
1077
    }
1078

1079
    private String buildPermissionFilterQuery(boolean avoidJoin, String permissionFilterGroups) {
1080
        String query = (avoidJoin&& !isAllGroups(permissionFilterGroups)) ? SearchFields.PUBLIC_OBJECT + ":" + true : "";
×
UNCOV
1081
        if (permissionFilterGroups != null && !isAllGroups(permissionFilterGroups)) {
×
UNCOV
1082
            if (!query.isEmpty()) {
×
UNCOV
1083
                query = "(" + query + " OR " + "{!join from=" + SearchFields.DEFINITION_POINT + " to=id}" + SearchFields.DISCOVERABLE_BY + ":" + permissionFilterGroups + ")";
×
1084
            } else {
UNCOV
1085
                query = "{!join from=" + SearchFields.DEFINITION_POINT + " to=id}" + SearchFields.DISCOVERABLE_BY + ":" + permissionFilterGroups;
×
1086
            }
1087
        }
UNCOV
1088
        return query;
×
1089
    }
1090
    
1091
    private boolean isAllGroups(String groups) {
UNCOV
1092
        return (groups!=null &&groups.equals(ALL_GROUPS));
×
1093
    }
1094
}
1095

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

© 2025 Coveralls, Inc