• 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

75.48
/dataverse-webapp/src/main/java/edu/harvard/iq/dataverse/settings/SettingsServiceBean.java
1
package edu.harvard.iq.dataverse.settings;
2

3
import com.google.common.cache.CacheBuilder;
4
import com.google.common.cache.CacheLoader;
5
import com.google.common.cache.LoadingCache;
6
import edu.harvard.iq.dataverse.actionlogging.ActionLogServiceBean;
7
import edu.harvard.iq.dataverse.persistence.ActionLogRecord;
8
import edu.harvard.iq.dataverse.persistence.Setting;
9
import edu.harvard.iq.dataverse.persistence.SettingDao;
10
import edu.harvard.iq.dataverse.util.StringUtil;
11
import org.apache.commons.lang3.StringUtils;
12
import org.json.JSONArray;
13
import org.json.JSONException;
14
import org.json.JSONObject;
15
import org.slf4j.Logger;
16
import org.slf4j.LoggerFactory;
17

18
import javax.ejb.EJB;
19
import javax.enterprise.context.ApplicationScoped;
20
import java.util.ArrayList;
21
import java.util.Arrays;
22
import java.util.HashMap;
23
import java.util.List;
24
import java.util.Map;
25
import java.util.Set;
26

27
import static java.util.function.Function.identity;
28
import static java.util.stream.Collectors.toMap;
29

30
/**
31
 * Service bean accessing and manipulating application settings.
32
 * Settings are resolved from database and property files (db ones takes precedence).
33
 *
34
 * @author michael
35
 * @see FileBasedSettingsFetcher
36
 */
37
@ApplicationScoped
38
public class SettingsServiceBean {
1✔
39

40
    private static final String KEY_AND_POSTFIX_SEPARATOR = ".";
41

42
    /**
43
     * Some convenient keys for the settings. Note that the setting's
44
     * name is really a {@code String}, but it's good to have the compiler look
45
     * over your shoulder when typing strings in various places of a large app.
46
     * So there.
47
     */
48
    public enum Key {
1✔
49
        AllowApiTokenLookupViaApi,
1✔
50
        /**
51
         * Ordered, comma-separated list of custom fields to show above the fold
52
         * on dataset page such as "data_type,sample,pdb"
53
         */
54
        CustomDatasetSummaryFields,
1✔
55
        /**
56
         * Defines a public installation -- all datafiles are unrestricted
57
         */
58
        PublicInstall,
1✔
59
        /**
60
         * Enables the provenance collection popup.
61
         * Allows users to store their provenance json and description
62
         */
63
        ProvCollectionEnabled,
1✔
64
        /**
65
         * For example, https://datacapture.example.org
66
         */
67
        DataCaptureModuleUrl,
1✔
68
        RepositoryStorageAbstractionLayerUrl,
1✔
69
        UploadMethods,
1✔
70
        DownloadMethods,
1✔
71
        /**
72
         * If the data replicated around the world using RSAL (Repository
73
         * Storage Abstraction Layer) is locally available, this is its file
74
         * path, such as "/programs/datagrid".
75
         * <p>
76
         * TODO: Think about if it makes sense to make this a column in the
77
         * StorageSite database table.
78
         */
79
        LocalDataAccessPath,
1✔
80
        IdentifierGenerationStyle,
1✔
81
        OAuth2CallbackUrl,
1✔
82
        DefaultAuthProvider,
1✔
83
        FooterCopyright,
1✔
84
        FileFixityChecksumAlgorithm,
1✔
85
        MinutesUntilConfirmEmailTokenExpires,
1✔
86
        /**
87
         * Override Solr highlighting "fragsize"
88
         * https://wiki.apache.org/solr/HighlightingParameters#hl.fragsize
89
         */
90
        SearchHighlightFragmentSize,
1✔
91
        /**
92
         * Experimental: Allow non-public search with a key/token using the
93
         * Search API. See also https://github.com/IQSS/dataverse/issues/1299
94
         */
95
        SearchApiNonPublicAllowed,
1✔
96
        /**
97
         * In Dataverse 4.7 and earlier, an API token was required to use the
98
         * Search API. Tokens are no longer required but you can revert to the
99
         * old behavior by setting this to false.
100
         */
101
        SearchApiRequiresToken,
1✔
102

103
        /**
104
         * API endpoints that are not accessible. Comma separated list.
105
         */
106
        BlockedApiEndpoints,
1✔
107

108
        /**
109
         * A key that, with the right {@link ApiBlockingFilter.BlockPolicy},
110
         * allows calling blocked APIs.
111
         */
112
        BlockedApiKey,
1✔
113

114

115
        /**
116
         * How to treat blocked APIs. One of drop, localhost-only, unblock-key
117
         */
118
        BlockedApiPolicy,
1✔
119

120
        /**
121
         * For development only (see dev guide for details). Backed by an enum
122
         * of possible account types.
123
         */
124
        DebugShibAccountType,
1✔
125
        DebugOAuthAccountType,
1✔
126
        /**
127
         * Application-wide Terms of Use per installation.
128
         * Setting can be postfixed with language code to
129
         * obtain translated versions of terms of use.
130
         * It is assumed that not postfixed setting is
131
         * the default one (used in case if language specific
132
         * version is not present).
133
         */
134
        ApplicationTermsOfUse,
1✔
135
        /**
136
         * Terms of Use specific to API per installation.
137
         */
138
        ApiTermsOfUse,
1✔
139
        /**
140
         * URL for the application-wide Privacy Policy per installation, linked
141
         * to from the footer.
142
         */
143
        ApplicationPrivacyPolicyUrl,
1✔
144
        /**
145
         * Solr hostname and port, such as "localhost:8983".
146
         */
147
        SolrHostColonPort,
1✔
148
        /**
149
         * Enable full-text indexing in solr
150
         * Defaults to false
151
         **/
152
        SolrFullTextIndexing,
1✔
153
        /**
154
         * If file size of indexed file is greater than this value
155
         * then full text indexing will not take place
156
         * If set to 0 then no limit
157
         * Defaults to 0
158
         */
159
        SolrMaxFileSizeForFullTextIndexing, //
1✔
160
        /**
161
         * Key for limiting the number of bytes uploaded via the Data Deposit API, UI
162
         * If not set then not limit
163
         **/
164
        MaxFileUploadSizeInBytes,
1✔
165
        /**
166
         * Key for if ScrubMigrationData is enabled or disabled.
167
         */
168
        ScrubMigrationData,
1✔
169
        /**
170
         * Key for the url to send users who want to sign up to.
171
         */
172
        SignUpUrl,
1✔
173
        /**
174
         * Key for whether we allow users to sign up
175
         */
176
        AllowSignUp,
1✔
177
        /**
178
         * protocol for global id
179
         */
180
        Protocol,
1✔
181
        /**
182
         * authority for global id
183
         */
184
        Authority,
1✔
185
        /**
186
         * DoiProvider for global id
187
         */
188
        DoiProvider,
1✔
189
        /**
190
         * Period in ms after which the service will try to reserve yet unreserved DOI's
191
         */
192
        DoiBackgroundReservationInterval,
1✔
193
        /**
194
         * Shoulder for global id - used to create a common prefix on identifiers
195
         */
196
        Shoulder,
1✔
197

198
        /**
199
         * Optionally override http://guides.dataverse.org .
200
         */
201
        GuidesBaseUrl,
1✔
202

203
        /**
204
         * A link to an installation of https://github.com/IQSS/miniverse or
205
         * some other metrics app.
206
         */
207
        MetricsUrl,
1✔
208

209
        /**
210
         * Number of minutes before a metrics query can be rerun. Otherwise a cached value is returned.
211
         * Previous month dates always return cache. Only applies to new internal caching system (not miniverse).
212
         */
213
        MetricsCacheTimeoutMinutes,
1✔
214
        /* zip download size limit */
215
        /**
216
         * Optionally override version number in guides.
217
         */
218
        GuidesVersion,
1✔
219
        /**
220
         * Download-as-zip size limit.
221
         * If set to 0 then no limit.
222
         * If set to -1 then zip downloads are disabled
223
         */
224
        ZipDownloadLimit,
1✔
225
        /**
226
         * Number of datafiles that we allow to be created through
227
         * zip file upload.
228
         */
229
        ZipUploadFilesLimit,
1✔
230
        /**
231
         * the number of files the GUI user is allowed to upload in one batch,
232
         * via drag-and-drop, or through the file select dialog
233
         */
234
        MultipleUploadFilesLimit,
1✔
235

236
        /**
237
         * status message that will appear on the home page
238
         */
239
        StatusMessageHeader,
1✔
240
        /**
241
         * full text of status message, to appear in popup
242
         */
243
        StatusMessageText,
1✔
244
        /**
245
         * return email address for system emails such as notifications
246
         */
247
        SystemEmail,
1✔
248
        /**
249
         * size limit for Tabular data file ingests <br/>
250
         * (can be set separately for specific ingestable formats; in which
251
         * case the actual stored option will be TabularIngestSizeLimit:{FORMAT_NAME}
252
         * where {FORMAT_NAME} is the format identification tag returned by the
253
         * getFormatName() method in the format-specific plugin; "sav" for the
254
         * SPSS/sav format, "RData" for R, etc.
255
         * for example: :TabularIngestSizeLimit:RData <br/>
256
         * -1 means no limit is set;
257
         * 0 on the other hand would mean that ingest is fully disabled for tabular data.
258
         */
259
        TabularIngestSizeLimit,
1✔
260
        /**
261
         * Files with the number of cells (ie. cases times variables) above
262
         * that number will be ingested using different method of reading
263
         * and storing intermediate data (with the same final result), which
264
         * may be more time-consuming but less resource-consuming.
265
         * Those with number of cells below or equal to that number will
266
         * be processed in-memory.
267
         */
268
        IngestMethodChangeThreshold,
1✔
269
        /**
270
         * If the number of variables of ingested file exceeds that limit,
271
         * the ingest will fail.
272
         */
273
        IngestedVariablesLimit,
1✔
274
        /**
275
         * Whether to allow user to create GeoConnect Maps
276
         * This boolean effects whether the user sees the map button on
277
         * the dataset page and if the ingest will create a shape file
278
         * Default is false
279
         */
280
        GeoconnectCreateEditMaps,
1✔
281
        /**
282
         * Whether to allow a user to view existing maps
283
         * This boolean effects whether a user may see the
284
         * Explore World Map Button
285
         * Default is false;
286
         */
287
        GeoconnectViewMaps,
1✔
288
        /**
289
         * The message added to a popup upon dataset publish
290
         */
291
        DatasetPublishPopupCustomText,
1✔
292
        /**
293
         * Whether to display the publish text for every published version
294
         */
295
        DatasetPublishPopupCustomTextOnAllVersions,
1✔
296
        /**
297
         * Whether Harvesting (OAI) service is enabled
298
         */
299
        OAIServerEnabled,
1✔
300

301
        /**
302
         * Whether Shibboleth passive authentication mode is enabled
303
         */
304
        ShibPassiveLoginEnabled,
1✔
305
        /**
306
         * Convert Shibboleth AJP attributes from ISO-8859-1 to UTF-8
307
         */
308
        ShibAttributeCharacterSetConversionEnabled,
1✔
309
        /**
310
         * Whether Export should exclude FieldType.EMAIL
311
         */
312
        ExcludeEmailFromExport,
1✔
313
        /**
314
         * Location and name of HomePage customization file
315
         */
316
        HomePageCustomizationFile,
1✔
317
        /**
318
         * Location and name of Header customization file
319
         */
320
        HeaderCustomizationFile,
1✔
321
        /**
322
         * Location and name of Footer customization file
323
         */
324
        FooterCustomizationFile,
1✔
325
        /**
326
         * Location and name of CSS customization file (it will be used as an inline style)
327
         */
328
        StyleCustomizationFile,
1✔
329
        /**
330
         * Location and name of analytics code file
331
         */
332
        WebAnalyticsCode,
1✔
333
        /**
334
         * Location and name of installation logo customization file
335
         */
336
        LogoCustomizationFile,
1✔
337

338
        // Option to override the navbar url underlying the "About" link
339
        NavbarAboutUrl,
1✔
340

341
        // Option to override multiple guides with a single url
342
        NavbarGuidesUrl,
1✔
343

344
        // Option to overide the feedback dialog display with a link to an external page via its url
345
        NavbarSupportUrl,
1✔
346

347
        /**
348
         * The theme for the root dataverse can get in the way when you try make
349
         * use of HeaderCustomizationFile and LogoCustomizationFile so this is a
350
         * way to disable it.
351
         */
352
        DisableRootDataverseTheme,
1✔
353
        // Limit on how many guestbook entries to display on the guestbook-responses page:
354
        GuestbookResponsesPageDisplayLimit,
1✔
355

356
        /**
357
         * The dictionary filepaths separated by a pipe (|)
358
         */
359
        PVDictionaries,
1✔
360

361
        /**
362
         * The minimum length of a good, long, strong password.
363
         * Defaults to 20.
364
         */
365
        PVGoodStrength,
1✔
366

367
        /**
368
         * A password minimum length
369
         * Defaults to 6
370
         */
371
        PVMinLength,
1✔
372
        /**
373
         * A password maximum length
374
         * If set to 0 then maximum length is disabled
375
         */
376
        PVMaxLength,
1✔
377

378
        /**
379
         * One letter, 2 special characters, etc. (string in form Alphabetical:1,Digit:1)
380
         * Defaults to (string in form Alphabetical:1,Digit:1):
381
         * - one alphabetical
382
         * - one digit
383
         */
384
        PVCharacterRules,
1✔
385

386
        /**
387
         * The number of M characteristics.
388
         * Defaults to 2.
389
         */
390
        PVNumberOfCharacteristics,
1✔
391

392
        /**
393
         * The number of consecutive digits allowed for a password.
394
         * Defaults to highest int
395
         */
396
        PVNumberOfConsecutiveDigitsAllowed,
1✔
397
        /**
398
         * Configurable text for alert/info message on passwordreset.xhtml when users are required to update their password.
399
         */
400
        PVCustomPasswordResetAlertMessage,
1✔
401
        /**
402
         * String to describe DOI format for data files. Default is DEPENDENT.
403
         * 'DEPENEDENT' means the DOI will be the Dataset DOI plus a file DOI with a slash in between.
404
         * 'INDEPENDENT' means a new global id, completely independent from the dataset-level global id.
405
         */
406
        DataFilePIDFormat,
1✔
407
        /**
408
         * Json array of supported languages
409
         */
410
        Languages,
1✔
411
        /**
412
         * Number for the minimum number of files to send PID registration to asynchronous workflow
413
         */
414
        PIDAsynchRegFileCount,
1✔
415
        /**
416
         *
417
         */
418
        FilePIDsEnabled,
1✔
419

420
        /**
421
         * Indicates if the Handle service is setup to work 'independently' (No communication with the Global Handle Registry)
422
         */
423
        IndependentHandleService,
1✔
424

425
        /**
426
         * Archiving can be configured by providing an Archiver class name (class must extend AstractSubmitToArchiverCommand)
427
         * and a list of settings that should be passed to the Archiver.
428
         * Note:
429
         * Configuration may also require adding Archiver-specific jvm-options (i.e. for username and password) in glassfish.
430
         * <p>
431
         * To automate the submission of an archival copy step as part of publication, a post-publication workflow must also be configured.
432
         * <p>
433
         * For example:
434
         * ArchiverClassName - "edu.harvard.iq.dataverse.engine.command.impl.DPNSubmitToArchiveCommand"
435
         * ArchiverSettings - "DuraCloudHost, DuraCloudPort, DuraCloudContext"
436
         * <p>
437
         * Note: Dataverse must be configured with values for these dynamically defined settings as well, e.g.
438
         * <p>
439
         * DuraCloudHost , eg. "qdr.duracloud.org", a non-null value enables submission
440
         * DuraCloudPort, default is 443
441
         * DuraCloudContext, default is "durastore"
442
         */
443

444
        ArchiverClassName,
1✔
445
        ArchiverSettings,
1✔
446
        /**
447
         * A comma-separated list of roles for which new dataverses should inherit the
448
         * corresponding role assignments from the parent dataverse. Also affects
449
         * /api/admin/dataverse/{alias}/addRolesToChildren. Default is "", no
450
         * inheritance. "*" means inherit assignments for all roles
451
         */
452
        InheritParentRoleAssignments,
1✔
453

454
        /**
455
         * Indicates if other terms of use are active or not.
456
         */
457
        AllRightsReservedTermsOfUseActive,
1✔
458
        RestrictedAccessTermsOfUseActive,
1✔
459

460
        /**
461
         * Size limits for generating thumbnails on the fly
462
         * (i.e., we'll attempt to generate a thumbnail on the fly if the
463
         * size of the file is less than this)
464
         */
465
        ThumbnailImageSizeLimit,
1✔
466
        ThumbnailPDFSizeLimit,
1✔
467

468
        DropboxKey,
1✔
469
        DoiDataCiteCitationsPageUrl,
1✔
470
        DoiDataCiteRestApiUrl,
1✔
471
        DoiBaseUrlString,
1✔
472
        DoiUsername,
1✔
473
        DoiPassword,
1✔
474

475
        HandleNetAdmCredFile,
1✔
476
        HandleNetAdmPrivPhrase,
1✔
477
        HandleNetIndex,
1✔
478

479
        TimerServer,
1✔
480

481
        MinutesUntilPasswordResetTokenExpires,
1✔
482

483
        /**
484
         * Indicates if rserve is properly configured in this dataverse installation.
485
         * If not, then any functionality using rserve should be switched off
486
         */
487
        RserveConfigured,
1✔
488
        RserveHost,
1✔
489
        RservePort,
1✔
490
        RserveUser,
1✔
491
        RservePassword,
1✔
492
        RserveTempDir,
1✔
493

494
        /**
495
         * Some installations may not want download URLs to their files to be
496
         * available in Schema.org JSON-LD output.
497
         */
498
        HideSchemaDotOrgDownloadUrls,
1✔
499

500
        /**
501
         * A JVM option for specifying the "official" URL of the site.
502
         * Unlike the FQDN option above, this would be a complete URL,
503
         * with the protocol, port number etc.
504
         */
505
        SiteUrl,
1✔
506

507
        /**
508
         * Text with privacy policy content.
509
         * Setting can be postfixed with language code to
510
         * obtain translated versions of terms of use.
511
         * It is assumed that not postfixed setting is
512
         * the default one (used in case if language specific
513
         * version is not present).
514
         */
515
        PrivacyPolicy,
1✔
516

517
        /**
518
         * Text with accessibility statement.
519
         * Setting can be postfixed with language code to
520
         * obtain translated versions of the statement.
521
         * It is assumed that not postfixed setting is
522
         * the default one (used in case if language specific
523
         * version is not present).
524
         */
525
        AccessibilityStatement,
1✔
526

527
        /**
528
         * Dataverse admin can configure application-wide maximum length for embargo.
529
         * @value number of months
530
         * For any given date, maximum embargo for that date is: [date] + [MaximumEmbargoLength]
531
         * Example: for setting value = 3 and date 12DEC2019, effective maximum embargo date for user
532
         * trying to set embargo for his dataset is 12MAR2020 (3 months from [date])
533
         */
534
        MaximumEmbargoLength,
1✔
535

536
        /**
537
         * Application wide format for dates.
538
         * Use this whenever you want to print date on GUI.
539
         */
540
        DefaultDateFormat,
1✔
541

542
        /**
543
         * Email of mail overseer: if present, a copy of every mail sent by the application
544
         * will be sent to that address.
545
         *
546
         * By default it is not set, so the feature is turned off.
547
         */
548
        MailOverseerAddress,
1✔
549

550
        /**
551
         * Show link to Privacy Policy page in the footer (if set to 'true').
552
         * By default is set to 'false', so link won't be shown.
553
         */
554
        ShowPrivacyPolicyFooterLink,
1✔
555

556
        /**
557
         * Show link to Terms of Use page in the footer (if set to 'true').
558
         * By default is set to 'false', so link won't be shown.
559
         */
560
        ShowTermsOfUseFooterLink,
1✔
561

562
        /**
563
         * Show link to Accesibility Statement page in the footer (if set to 'true').
564
         * By default is set to 'false', so link won't be shown.
565
         */
566
        ShowAccessibilityStatementFooterLink,
1✔
567

568
        /**
569
         * Name of the site that will be presented in the header.
570
         * Setting can be postfixed with language code to
571
         * obtain translated versions.
572
         */
573
        SiteName,
1✔
574

575
        /**
576
         * Full name of the site that will be presented in the header
577
         * below {@link Key#SiteName}.
578
         * Setting can be postfixed with language code to
579
         * obtain translated versions.
580
         */
581
        SiteFullName,
1✔
582

583
        /**
584
         * Target link for the "superior logo".
585
         * Setting can be postfixed with language code to
586
         * obtain path a language-specific link.
587
         */
588
        SuperiorLogoLink,
1✔
589

590
        /**
591
         * Path to a "superior logo" to be presented in the header.
592
         * Setting can be postfixed with language code to
593
         * obtain path to a translated logo.
594
         */
595
        SuperiorLogoPath,
1✔
596

597
        /**
598
         * Path to a compact "superior logo" to be presented in the header.
599
         * Setting can be postfixed with language code to
600
         * obtain the path to a translated logo.
601
         */
602
        SuperiorLogoResponsivePath,
1✔
603

604
        /**
605
         * Path to a "superior logo" (high contrast version) to be presented in the header.
606
         * Setting can be postfixed with language code to
607
         * obtain path to a translated logo.
608
         */
609
        SuperiorLogoContrastPath,
1✔
610

611
        /**
612
         * Path to a compact "superior logo" (high contrast version) to be presented in the header.
613
         * Setting can be postfixed with language code to
614
         * obtain the path to a translated logo.
615
         */
616
        SuperiorLogoContrastResponsivePath,
1✔
617

618
        /**
619
         * Description (alt text) for the "superior logo".
620
         * Setting can be postfixed with language code to
621
         * obtain translated versions.
622
         */
623
        SuperiorLogoAlt,
1✔
624

625
        /**
626
         * Indicates if antivirus scanner is enabled
627
         */
628
        AntivirusScannerEnabled,
1✔
629
        /**
630
         * Maximum size of files that will be scanned
631
         * by antivirus
632
         */
633
        AntivirusScannerMaxFileSize,
1✔
634
        AntivirusScannerMaxFileSizeForExecutables,
1✔
635
        /**
636
         * Antivirus scanner engine settings
637
         */
638
        AntivirusScannerSocketAddress,
1✔
639
        AntivirusScannerSocketPort,
1✔
640
        AntivirusScannerSocketTimeout,
1✔
641

642
        FilesIntegrityCheckTimerExpression,
1✔
643

644
        /**
645
         * If set to true, the set of actions that could be performed by the
646
         * users with unconfirmed emails will be severely limited.
647
         */
648
        UnconfirmedMailRestrictionModeEnabled,
1✔
649

650
        /**
651
         * Command or path for external utility for RAR5 size checking
652
         */
653
        RarDataUtilCommand,
1✔
654
        /**
655
         * Additional options for rar utility
656
         */
657
        RarDataUtilOpts,
1✔
658
        /**
659
         * Character starting the line before the result (total size). The
660
         * line must be the last in the output that starts with the chosen
661
         * character. The next line has to start with result (with optional
662
         * spaces before).
663
         */
664
        RarDataLineBeforeResultDelimiter,
1✔
665

666
        /**
667
         * Sets the maximal size of gzip file (in bytes) that would be
668
         * subject to checking of uncompressed content size.
669
         */
670
        GzipMaxInputFileSizeInBytes,
1✔
671

672
        /**
673
         * Sets the maximal size of output file (in bytes) that could be
674
         * unpacked from gzip file in order to check its uncompressed size.
675
         */
676
        GzipMaxOutputFileSizeInBytes,
1✔
677

678
        /**
679
         * Cron expression that indicates how often
680
         * updating of citation counts should take place.
681
         * Note that current implementation is heavily based
682
         * on DataCite api. If your installation uses some
683
         * other global id provider then this process will
684
         * not work as expected.
685
         * If empty then updating of citation counts will be skipped.
686
         * Default value: empty.
687
         */
688
        CitationCountUpdateTimerExpression,
1✔
689

690
        /**
691
         * Cron expression that indicates how often
692
         * updating of featured dataverses automatic sorting
693
         * should take place.
694
         * If empty then updating of sorting will be skipped.
695
         * Default value: empty.
696
         */
697
        FeaturedDataversesSortingUpdateTimerExpression,
1✔
698

699
        /**
700
         * If true then instance will run in readonly mode.
701
         * Installation in readonly mode will have functionality
702
         * limited to operations that will not modify database and
703
         * storage state.
704
         */
705
        ReadonlyMode,
1✔
706

707
        /**
708
         * Maximal size (in bytes) of files that can be uploaded in a single
709
         * batch. If set to 0 then there's no limit.
710
         */
711
        SingleUploadBatchMaxSize,
1✔
712

713
        /**
714
         * Cron expression that indicates how often
715
         * checking of datasets after embargo for reindex should take place.
716
         * If empty then check will be skipped.
717
         * Default value: empty.
718
         */
719

720
        ReindexAfterEmbargoTimerExpression,
1✔
721

722
        /**
723
         * Wrap http requests with url from SiteUrl property
724
         * It is needed when glassfish is behind reverse proxy
725
         * for matching url in saml assertions with the server
726
         * url
727
         */
728
        SamlWrapHttpRequestUrl,
1✔
729

730
        /**
731
         * Additional (localized) text to show at the top
732
         * of the login page.
733
         */
734
        LoginInfo,
1✔
735

736
        /**
737
         * Additional (localized) text to show at the top
738
         * of the "Add dataset" modal window.
739
         */
740
        SelectDataverseInfo
1✔
741
        ;
742

743

744
        @Override
745
        public String toString() {
746
            return ":" + name();
1✔
747
        }
748
    }
749

750
    private static final Logger log = LoggerFactory.getLogger(SettingsServiceBean.class);
1✔
751

752
    @EJB
753
    private SettingDao settingDao;
754

755
    @EJB
756
    private ActionLogServiceBean actionLogSvc;
757

758
    @EJB
759
    private FileBasedSettingsFetcher fileBasedSettingsFetcher;
760

761
    private final CacheLoader<String, String> settingCacheLoader = new CacheLoader<String, String>() {
1✔
762
        @Override
763
        public String load(String key) {
UNCOV
764
            Setting s = settingDao.find(key);
×
UNCOV
765
            return (s != null) ? s.getContent() : fileBasedSettingsFetcher.getSetting(key);
×
766
        }
767
    };
768

769
    private final LoadingCache<String, String> settingCache = CacheBuilder.newBuilder()
1✔
770
            .build(settingCacheLoader);
1✔
771

772
    // -------------------- LOGIC --------------------
773

774
    /**
775
     * Basic functionality - get the name, return the setting from db if present or from properties file if not.
776
     *
777
     * @param name of the setting
778
     * @return the actual setting or empty string.
779
     */
780
    public String get(String name) {
UNCOV
781
        return settingCache.getUnchecked(name);
×
782
    }
783

784
    /**
785
     * Same as {@link #get(java.lang.String)}, but with static checking.
786
     *
787
     * @param key Enum value of the name.
788
     * @return The setting, or  empty string.
789
     */
790
    public String getValueForKey(Key key) {
791
        return get(key.toString());
1✔
792
    }
793

794
    /**
795
     * Returns value of setting with key that is postfixed.
796
     * It can be used if setting has static base key part and dynamic
797
     * postfix.
798
     * <p>
799
     * Example of such setting is {@link Key#ApplicationTermsOfUse}.
800
     * It can be posfixed with language code to obtain translated
801
     * values:
802
     * <code>
803
     * getValueForKeyWithPostfix(Key.ApplicationTermsOfUse, "de")
804
     * getValueForKeyWithPostfix(Key.ApplicationTermsOfUse, "fr")
805
     * </code>
806
     *
807
     * @param key
808
     * @param postfix
809
     * @return setting value or empty string if setting not present
810
     */
811
    public String getValueForKeyWithPostfix(Key key, String postfix) {
UNCOV
812
        return get(key.toString() + KEY_AND_POSTFIX_SEPARATOR + postfix);
×
813
    }
814

815
    /**
816
     * Attempt to convert the value to an integer
817
     * - Applicable for keys such as MaxFileUploadSizeInBytes
818
     * <p>
819
     * On failure (key not found or string not convertible to a long), returns null
820
     *
821
     * @param key
822
     * @return
823
     */
824
    public Long getValueForKeyAsLong(Key key) {
825

826
        String val = this.getValueForKey(key);
1✔
827

828
        if (StringUtils.isEmpty(val)) {
1✔
829
            return null;
1✔
830
        }
831

832
        try {
833
            return Long.parseLong(val);
×
834
        } catch (NumberFormatException ex) {
×
835
            log.warn("Incorrect setting. Could not convert \"{}\" from setting {} to long.", val, key.toString());
×
UNCOV
836
            return null;
×
837
        }
838

839
    }
840

841
    public Integer getValueForKeyAsInt(Key key) {
UNCOV
842
        Long value = getValueForKeyAsLong(key);
×
UNCOV
843
        if (value == null) {
×
UNCOV
844
            return null;
×
845
        }
UNCOV
846
        return value.intValue();
×
847
    }
848

849
    public List<String> getValueForKeyAsList(Key key) {
850
        return Arrays.asList(StringUtils.split(getValueForKey(key), ","));
×
851
    }
852

853
    public List<Map<String, String>> getValueForKeyAsListOfMaps(Key key) {
854
        List<Map<String, String>> list = new ArrayList<>();
×
855
        try {
856
            JSONArray entries = new JSONArray(getValueForKey(key));
×
UNCOV
857
            for (Object obj : entries) {
×
UNCOV
858
                JSONObject entry = (JSONObject) obj;
×
UNCOV
859
                list.add(entry.keySet().stream()
×
860
                        .collect(toMap(identity(), entry::getString)));
×
861
            }
×
862
        } catch (JSONException e) {
×
863
            log.warn("Error parsing setting " + key + " as JSON", e);
×
864
        }
×
UNCOV
865
        return list;
×
866
    }
867

868
    public Setting set(String name, String content) {
UNCOV
869
        settingCache.invalidate(name);
×
UNCOV
870
        Setting s = settingDao.save(new Setting(name, content));
×
UNCOV
871
        actionLogSvc.log(new ActionLogRecord(ActionLogRecord.ActionType.Setting, "set")
×
UNCOV
872
                                 .setInfo(name + ": " + content));
×
UNCOV
873
        return s;
×
874
    }
875

876
    public Setting setValueForKey(Key key, String content) {
UNCOV
877
        return set(key.toString(), content);
×
878
    }
879

880
    /**
881
     * The correct way to decide whether a string value in the
882
     * settings table should be considered as {@code true}.
883
     *
884
     * @param name name of the setting.
885
     * @return boolean value of the setting.
886
     */
887
    public boolean isTrue(String name) {
888
        String val = get(name);
×
889
        return StringUtil.isTrue(val);
×
890
    }
891

892
    public boolean isTrueForKey(Key key) {
893
        return isTrue(key.toString());
×
894
    }
895

896
    public void deleteValueForKey(Key name) {
UNCOV
897
        delete(name.toString());
×
UNCOV
898
    }
×
899

900
    public void delete(String name) {
901
        settingCache.invalidate(name);
×
902
        actionLogSvc.log(new ActionLogRecord(ActionLogRecord.ActionType.Setting, "delete")
×
UNCOV
903
                                 .setInfo(name));
×
904
        settingDao.delete(name);
×
905
    }
×
906

907
    public Map<String, String> listAll() {
UNCOV
908
        Map<String, String> mergedSettings = new HashMap<>();
×
909

UNCOV
910
        Map<String, String> fileSettings = fileBasedSettingsFetcher.getAllSettings();
×
911
        mergedSettings.putAll(fileSettings);
×
912

913
        List<Setting> dbSettings = settingDao.findAll();
×
914
        dbSettings.forEach(s -> mergedSettings.put(s.getName(), s.getContent()));
×
915

UNCOV
916
        return mergedSettings;
×
917
    }
918

919
    public Map<String, String> getFileBasedSettingsForPrefix(String prefix) {
UNCOV
920
        Map<String, String> settings = fileBasedSettingsFetcher.getAllSettings();
×
UNCOV
921
        Set<String> keys = settings.keySet();
×
UNCOV
922
        return keys.stream()
×
UNCOV
923
                .filter(k -> k.startsWith(prefix))
×
UNCOV
924
                .collect(HashMap::new, (m, k) -> m.put(k, settings.get(k)), Map::putAll);
×
925
    }
926
}
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