001/*- 002 * #%L 003 * HAPI FHIR JPA Model 004 * %% 005 * Copyright (C) 2014 - 2024 Smile CDR, Inc. 006 * %% 007 * Licensed under the Apache License, Version 2.0 (the "License"); 008 * you may not use this file except in compliance with the License. 009 * You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 * #L% 019 */ 020package ca.uhn.fhir.jpa.model.entity; 021 022import ca.uhn.fhir.context.ParserOptions; 023import ca.uhn.fhir.i18n.Msg; 024import ca.uhn.fhir.jpa.model.config.PartitionSettings; 025import ca.uhn.fhir.jpa.util.ISequenceValueMassager; 026import ca.uhn.fhir.model.api.TemporalPrecisionEnum; 027import ca.uhn.fhir.rest.server.interceptor.ResponseTerminologyTranslationSvc; 028import ca.uhn.fhir.util.HapiExtensions; 029import org.apache.commons.lang3.Validate; 030import org.hl7.fhir.instance.model.api.IPrimitiveType; 031import org.hl7.fhir.r4.model.DateTimeType; 032 033import java.util.Arrays; 034import java.util.Collections; 035import java.util.Date; 036import java.util.HashMap; 037import java.util.HashSet; 038import java.util.Map; 039import java.util.Set; 040 041import static org.apache.commons.lang3.ObjectUtils.defaultIfNull; 042 043/** 044 * This class contains configuration options common to all hapi-fhir-storage implementations. 045 * Ultimately it should live in that project 046 */ 047public class StorageSettings { 048 /** 049 * @since 5.6.0 050 */ 051 // Thread Pool size used by batch in bundle 052 public static final int DEFAULT_BUNDLE_BATCH_POOL_SIZE = 20; // 1 for single thread 053 054 public static final int DEFAULT_BUNDLE_BATCH_MAX_POOL_SIZE = 100; // 1 for single thread 055 /** 056 * Default {@link #getTreatReferencesAsLogical() logical URL bases}. Includes the following 057 * values: 058 * <ul> 059 * <li><code>"http://hl7.org/fhir/valueset-*"</code></li> 060 * <li><code>"http://hl7.org/fhir/codesystem-*"</code></li> 061 * <li><code>"http://hl7.org/fhir/StructureDefinition/*"</code></li> 062 * </ul> 063 */ 064 public static final Set<String> DEFAULT_LOGICAL_BASE_URLS = Collections.unmodifiableSet(new HashSet<>(Arrays.asList( 065 "http://hl7.org/fhir/ValueSet/*", 066 "http://hl7.org/fhir/CodeSystem/*", 067 "http://hl7.org/fhir/valueset-*", 068 "http://hl7.org/fhir/codesystem-*", 069 "http://hl7.org/fhir/StructureDefinition/*"))); 070 071 /* 072 * <p> 073 * Note the following database documented limitations: 074 * <ul> 075 * <li>JDBC Timestamp Datatype Low Value -4713 and High Value 9999</li> 076 * <li>MySQL 8: the range for DATETIME values is '1000-01-01 00:00:00.000000' to '9999-12-31 23:59:59.999999`</li> 077 * <li>Postgresql 12: Timestamp [without time zone] Low Value 4713 BC and High Value 294276 AD</li> 078 * <li>Oracle: Timestamp Low Value 4712 BC and High Value 9999 CE</li> 079 * <li>H2: datetime2 Low Value -4713 and High Value 9999</li> 080 * </ul> 081 * </p> 082 */ 083 protected static final String DEFAULT_PERIOD_INDEX_START_OF_TIME = "1001-01-01"; 084 protected static final String DEFAULT_PERIOD_INDEX_END_OF_TIME = "9000-01-01"; 085 private static final Integer DEFAULT_MAXIMUM_TRANSACTION_BUNDLE_SIZE = null; 086 /** 087 * update setter javadoc if default changes 088 */ 089 private boolean myAllowContainsSearches = false; 090 091 private boolean myAllowExternalReferences = false; 092 private Set<String> myTreatBaseUrlsAsLocal = new HashSet<>(); 093 private Set<String> myTreatReferencesAsLogical = new HashSet<>(DEFAULT_LOGICAL_BASE_URLS); 094 private boolean myDefaultSearchParamsCanBeOverridden = true; 095 private boolean myAutoCreatePlaceholderReferenceTargets; 096 private Integer myBundleBatchPoolSize = DEFAULT_BUNDLE_BATCH_POOL_SIZE; 097 private Integer myBundleBatchMaxPoolSize = DEFAULT_BUNDLE_BATCH_MAX_POOL_SIZE; 098 private boolean myMassIngestionMode; 099 private Integer myMaximumTransactionBundleSize = DEFAULT_MAXIMUM_TRANSACTION_BUNDLE_SIZE; 100 private boolean myNormalizeTerminologyForBulkExportJobs = false; 101 /** 102 * Update setter javadoc if default changes. 103 */ 104 private boolean myUseOrdinalDatesForDayPrecisionSearches = true; 105 106 private boolean mySuppressStringIndexingInTokens = false; 107 private Class<? extends ISequenceValueMassager> mySequenceValueMassagerClass; 108 private IPrimitiveType<Date> myPeriodIndexStartOfTime; 109 private IPrimitiveType<Date> myPeriodIndexEndOfTime; 110 private NormalizedQuantitySearchLevel myNormalizedQuantitySearchLevel; 111 private Set<String> myAutoVersionReferenceAtPaths = Collections.emptySet(); 112 private Map<String, Set<String>> myTypeToAutoVersionReferenceAtPaths = Collections.emptyMap(); 113 private boolean myRespectVersionsForSearchIncludes; 114 private boolean myIndexOnUpliftedRefchains = false; 115 private boolean myIndexOnContainedResources = false; 116 private boolean myIndexOnContainedResourcesRecursively = false; 117 private boolean myAllowMdmExpansion = false; 118 private boolean myAutoSupportDefaultSearchParams = true; 119 private boolean myIndexIdentifierOfType = false; 120 private IndexEnabledEnum myIndexMissingFieldsEnabled = IndexEnabledEnum.DISABLED; 121 122 /** 123 * Should the {@literal _lamguage} SearchParameter be supported 124 * on this server? 125 * 126 * @since 7.0.0 127 */ 128 private boolean myLanguageSearchParameterEnabled = false; 129 130 /** 131 * If set to false, all resource types will be installed via package installer, regardless of their status. 132 * Otherwise, resources will be filtered based on status according to some criteria which can be found in 133 * <code>PackageInstallerSvcImpl#isValidResourceStatusForPackageUpload<code> 134 * @since 7.0.0 135 */ 136 private boolean myValidateResourceStatusForPackageUpload = true; 137 138 /** 139 * If set to <code>true</code>, the server will not write data to the <code>SP_NAME, RES_TYPE, SP_UPDATED</code> 140 * columns for all HFJ_SPIDX tables. 141 * 142 * @since 7.4.0 143 */ 144 private boolean myIndexStorageOptimized = false; 145 146 /** 147 * Constructor 148 */ 149 public StorageSettings() { 150 setSequenceValueMassagerClass(ISequenceValueMassager.NoopSequenceValueMassager.class); 151 setPeriodIndexStartOfTime(new DateTimeType(DEFAULT_PERIOD_INDEX_START_OF_TIME)); 152 setPeriodIndexEndOfTime(new DateTimeType(DEFAULT_PERIOD_INDEX_END_OF_TIME)); 153 setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_NOT_SUPPORTED); 154 } 155 156 /** 157 * When creating or updating a resource: If this property is set to <code>true</code> 158 * (default is <code>false</code>), if the resource has a reference to another resource 159 * on the local server but that reference does not exist, a placeholder resource will be 160 * created. 161 * <p> 162 * In other words, if an observation with subject <code>Patient/FOO</code> is created, but 163 * there is no resource called <code>Patient/FOO</code> on the server, this property causes 164 * an empty patient with ID "FOO" to be created in order to prevent this operation 165 * from failing. 166 * </p> 167 * <p> 168 * This property can be useful in cases where replication between two servers is wanted. 169 * Note however that references containing purely numeric IDs will not be auto-created 170 * as they are never allowed to be client supplied in HAPI FHIR JPA. 171 * <p> 172 * All placeholder resources created in this way have an extension 173 * with the URL {@link HapiExtensions#EXT_RESOURCE_PLACEHOLDER} and the value "true". 174 * </p> 175 */ 176 public boolean isAutoCreatePlaceholderReferenceTargets() { 177 return myAutoCreatePlaceholderReferenceTargets; 178 } 179 180 /** 181 * When creating or updating a resource: If this property is set to <code>true</code> 182 * (default is <code>false</code>), if the resource has a reference to another resource 183 * on the local server but that reference does not exist, a placeholder resource will be 184 * created. 185 * <p> 186 * In other words, if an observation with subject <code>Patient/FOO</code> is created, but 187 * there is no resource called <code>Patient/FOO</code> on the server, this property causes 188 * an empty patient with ID "FOO" to be created in order to prevent this operation 189 * from failing. 190 * </p> 191 * <p> 192 * This property can be useful in cases where replication between two servers is wanted. 193 * Note however that references containing purely numeric IDs will not be auto-created 194 * as they are never allowed to be client supplied in HAPI FHIR JPA. 195 * <p> 196 * All placeholder resources created in this way have an extension 197 * with the URL {@link HapiExtensions#EXT_RESOURCE_PLACEHOLDER} and the value "true". 198 * </p> 199 */ 200 public void setAutoCreatePlaceholderReferenceTargets(boolean theAutoCreatePlaceholderReferenceTargets) { 201 myAutoCreatePlaceholderReferenceTargets = theAutoCreatePlaceholderReferenceTargets; 202 } 203 204 /** 205 * Get the batch transaction thread pool size. 206 * 207 * @since 5.6.0 208 */ 209 public Integer getBundleBatchPoolSize() { 210 return myBundleBatchPoolSize; 211 } 212 213 /** 214 * Set the batch transaction thread pool size. The default is @see {@link #DEFAULT_BUNDLE_BATCH_POOL_SIZE} 215 * set pool size to 1 for single thread 216 * 217 * @since 5.6.0 218 */ 219 public void setBundleBatchPoolSize(Integer theBundleBatchPoolSize) { 220 this.myBundleBatchPoolSize = theBundleBatchPoolSize; 221 } 222 223 /** 224 * Get the batch transaction thread max pool size. 225 * set max pool size to 1 for single thread 226 * 227 * @since 5.6.0 228 */ 229 public Integer getBundleBatchMaxPoolSize() { 230 return myBundleBatchMaxPoolSize; 231 } 232 233 /** 234 * Set the batch transaction thread pool size. The default is @see {@link #DEFAULT_BUNDLE_BATCH_MAX_POOL_SIZE} 235 * 236 * @since 5.6.0 237 */ 238 public void setBundleBatchMaxPoolSize(Integer theBundleBatchMaxPoolSize) { 239 this.myBundleBatchMaxPoolSize = theBundleBatchMaxPoolSize; 240 } 241 242 /** 243 * If set to {@link IndexEnabledEnum#DISABLED} (default is {@link IndexEnabledEnum#DISABLED}) 244 * the server will not create search indexes for search parameters with no values in resources. 245 * <p> 246 * Disabling this feature means that the <code>:missing</code> search modifier will not be 247 * supported on the server, but also means that storage and indexing (i.e. writes to the 248 * database) may be much faster on servers which have lots of search parameters and need 249 * to write quickly. 250 * </p> 251 * <p> 252 * This feature may be enabled on servers where supporting the use of the :missing parameter is 253 * of higher importance than raw write performance 254 * </p> 255 */ 256 public IndexEnabledEnum getIndexMissingFields() { 257 return myIndexMissingFieldsEnabled; 258 } 259 260 /** 261 * If set to {@link IndexEnabledEnum#DISABLED} (default is {@link IndexEnabledEnum#DISABLED}) 262 * the server will not create search indexes for search parameters with no values in resources. 263 * <p> 264 * Disabling this feature means that the <code>:missing</code> search modifier will not be 265 * supported on the server, but also means that storage and indexing (i.e. writes to the 266 * database) may be much faster on servers which have lots of search parameters and need 267 * to write quickly. 268 * </p> 269 * <p> 270 * This feature may be enabled on servers where supporting the use of the :missing parameter is 271 * of higher importance than raw write performance 272 * </p> 273 * <p> 274 * Note that this setting also has an impact on sorting (i.e. using the 275 * <code>_sort</code> parameter on searches): If the server is configured 276 * to not index missing field. 277 * </p> 278 * <p> 279 * The following index may need to be added into the indexed tables such as <code>HFJ_SPIDX_TOKEN</code> 280 * to improve the search performance while <code>:missing</code> is enabled. 281 * <code>RES_TYPE, SP_NAME, SP_MISSING</code> 282 * </p> 283 */ 284 public void setIndexMissingFields(IndexEnabledEnum theIndexMissingFields) { 285 Validate.notNull(theIndexMissingFields, "theIndexMissingFields must not be null"); 286 myIndexMissingFieldsEnabled = theIndexMissingFields; 287 } 288 289 /** 290 * If set to <code>true</code> (default is false), the server will not write data 291 * to the <code>SP_NAME, RES_TYPE, SP_UPDATED</code> columns for all HFJ_SPIDX tables. 292 * <p> 293 * This feature may be enabled on servers where HFJ_SPIDX tables are expected 294 * to have a large amount of data (millions of rows) in order to reduce overall storage size. 295 * </p> 296 * <p> 297 * Note that this setting only applies to newly inserted and updated rows in HFJ_SPIDX tables. 298 * In order to apply this optimization setting to existing HFJ_SPIDX index rows, 299 * <code>$reindex</code> operation should be executed at the instance or server level. 300 * <p> 301 * <p> 302 * If this setting is enabled, {@link PartitionSettings#isIncludePartitionInSearchHashes()} should be disabled. 303 * </p> 304 * <p> 305 * If {@link StorageSettings#getIndexMissingFields()} is enabled, the following index may need to be added 306 * into the HFJ_SPIDX tables to improve the search performance: <code>HASH_IDENTITY, SP_MISSING, RES_ID, PARTITION_ID</code> 307 * </p> 308 * 309 * @since 7.4.0 310 */ 311 public boolean isIndexStorageOptimized() { 312 return myIndexStorageOptimized; 313 } 314 315 /** 316 * If set to <code>true</code> (default is false), the server will not write data 317 * to the <code>SP_NAME, RES_TYPE, SP_UPDATED</code> columns for all HFJ_SPIDX tables. 318 * <p> 319 * This feature may be enabled on servers where HFJ_SPIDX tables are expected 320 * to have a large amount of data (millions of rows) in order to reduce overall storage size. 321 * </p> 322 * <p> 323 * Note that this setting only applies to newly inserted and updated rows in HFJ_SPIDX tables. 324 * In order to apply this optimization setting to existing HFJ_SPIDX index rows, 325 * <code>$reindex</code> operation should be executed at the instance or server level. 326 * <p> 327 * <p> 328 * If this setting is enabled, {@link PartitionSettings#isIncludePartitionInSearchHashes()} should be set to <code>false</code>. 329 * </p> 330 * <p> 331 * If {@link StorageSettings#getIndexMissingFields()} ()} is enabled, the following index may need to be added 332 * into the HFJ_SPIDX tables to improve the search performance: <code>HASH_IDENTITY, SP_MISSING, RES_ID, PARTITION_ID</code> 333 * </p> 334 * 335 * @since 7.4.0 336 */ 337 public void setIndexStorageOptimized(boolean theIndexStorageOptimized) { 338 myIndexStorageOptimized = theIndexStorageOptimized; 339 } 340 341 /** 342 * If this is enabled (disabled by default), Mass Ingestion Mode is enabled. In this mode, a number of 343 * runtime checks are disabled. This mode is designed for rapid backloading of data while the system is not 344 * being otherwise used. 345 * <p> 346 * In this mode: 347 * <p> 348 * - Tags/Profiles/Security Labels will not be updated on existing resources that already have them 349 * - Resources modification checks will be skipped in favour of a simple hash check 350 * - Extra resource ID caching is enabled 351 * 352 * @since 5.5.0 353 */ 354 public boolean isMassIngestionMode() { 355 return myMassIngestionMode; 356 } 357 358 /** 359 * If this is enabled (disabled by default), Mass Ingestion Mode is enabled. In this mode, a number of 360 * runtime checks are disabled. This mode is designed for rapid backloading of data while the system is not 361 * being otherwise used. 362 * <p> 363 * In this mode: 364 * <p> 365 * - Tags/Profiles/Security Labels will not be updated on existing resources that already have them 366 * - Resources modification checks will be skipped in favour of a simple hash check 367 * - Extra resource ID caching is enabled 368 * 369 * @since 5.5.0 370 */ 371 public void setMassIngestionMode(boolean theMassIngestionMode) { 372 myMassIngestionMode = theMassIngestionMode; 373 } 374 375 /** 376 * Specifies the maximum number of resources permitted within a single transaction bundle. 377 * If a transaction bundle is submitted with more than this number of resources, it will be 378 * rejected with a PayloadTooLarge exception. 379 * <p> 380 * The default value is <code>null</code>, which means that there is no limit. 381 * </p> 382 */ 383 public Integer getMaximumTransactionBundleSize() { 384 return myMaximumTransactionBundleSize; 385 } 386 387 /** 388 * Specifies the maximum number of resources permitted within a single transaction bundle. 389 * If a transaction bundle is submitted with more than this number of resources, it will be 390 * rejected with a PayloadTooLarge exception. 391 * <p> 392 * The default value is <code>null</code>, which means that there is no limit. 393 * </p> 394 */ 395 public StorageSettings setMaximumTransactionBundleSize(Integer theMaximumTransactionBundleSize) { 396 myMaximumTransactionBundleSize = theMaximumTransactionBundleSize; 397 return this; 398 } 399 400 /** 401 * If set to true, attempt to map terminology for bulk export jobs using the 402 * logic in 403 * {@link ResponseTerminologyTranslationSvc}. Default is <code>false</code>. 404 * 405 * @since 6.3.0 406 */ 407 public boolean isNormalizeTerminologyForBulkExportJobs() { 408 return myNormalizeTerminologyForBulkExportJobs; 409 } 410 411 /** 412 * If set to true, attempt to map terminology for bulk export jobs using the 413 * logic in 414 * {@link ResponseTerminologyTranslationSvc}. Default is <code>false</code>. 415 * 416 * @since 6.3.0 417 */ 418 public void setNormalizeTerminologyForBulkExportJobs(boolean theNormalizeTerminologyForBulkExportJobs) { 419 myNormalizeTerminologyForBulkExportJobs = theNormalizeTerminologyForBulkExportJobs; 420 } 421 422 /** 423 * This is an internal API and may change or disappear without notice 424 * 425 * @since 6.2.0 426 */ 427 public Class<? extends ISequenceValueMassager> getSequenceValueMassagerClass() { 428 return mySequenceValueMassagerClass; 429 } 430 431 /** 432 * This is an internal API and may change or disappear without notice 433 * 434 * @since 6.2.0 435 */ 436 public void setSequenceValueMassagerClass(Class<? extends ISequenceValueMassager> theSequenceValueMassagerClass) { 437 Validate.notNull(theSequenceValueMassagerClass, "theSequenceValueMassagerClass must not be null"); 438 mySequenceValueMassagerClass = theSequenceValueMassagerClass; 439 } 440 441 /** 442 * If set to <code>true</code> (default is <code>false</code>) the 443 * <code>:of-type</code> modifier on token search parameters for 444 * identifiers will be supported. Enabling this causes additional 445 * indexing overhead (although very minor) so it is disabled unless it is 446 * actually needed. 447 * 448 * @since 5.7.0 449 */ 450 public boolean isIndexIdentifierOfType() { 451 return myIndexIdentifierOfType; 452 } 453 454 /** 455 * If set to <code>true</code> (default is <code>false</code>) the 456 * <code>:of-type</code> modifier on token search parameters for 457 * identifiers will be supported. Enabling this causes additional 458 * indexing overhead (although very minor) so it is disabled unless it is 459 * actually needed. 460 * 461 * @since 5.7.0 462 */ 463 public void setIndexIdentifierOfType(boolean theIndexIdentifierOfType) { 464 myIndexIdentifierOfType = theIndexIdentifierOfType; 465 } 466 467 /** 468 * If set to {@code true} the default search params (i.e. the search parameters that are 469 * defined by the FHIR specification itself) may be overridden by uploading search 470 * parameters to the server with the same code as the built-in search parameter. 471 * <p> 472 * This can be useful if you want to be able to disable or alter 473 * the behaviour of the default search parameters. 474 * </p> 475 * <p> 476 * The default value for this setting is {@code true} 477 * </p> 478 */ 479 public boolean isDefaultSearchParamsCanBeOverridden() { 480 return myDefaultSearchParamsCanBeOverridden; 481 } 482 483 /** 484 * If set to {@code true} the default search params (i.e. the search parameters that are 485 * defined by the FHIR specification itself) may be overridden by uploading search 486 * parameters to the server with the same code as the built-in search parameter. 487 * <p> 488 * This can be useful if you want to be able to disable or alter 489 * the behaviour of the default search parameters. 490 * </p> 491 * <p> 492 * The default value for this setting is {@code true} 493 * </p> 494 */ 495 public void setDefaultSearchParamsCanBeOverridden(boolean theDefaultSearchParamsCanBeOverridden) { 496 myDefaultSearchParamsCanBeOverridden = theDefaultSearchParamsCanBeOverridden; 497 } 498 499 /** 500 * If enabled, the server will support the use of :contains searches, 501 * which are helpful but can have adverse effects on performance. 502 * <p> 503 * Default is <code>false</code> (Note that prior to HAPI FHIR 504 * 3.5.0 the default was <code>true</code>) 505 * </p> 506 * <p> 507 * Note: If you change this value after data already has 508 * already been stored in the database, you must for a reindexing 509 * of all data in the database or resources may not be 510 * searchable. 511 * </p> 512 */ 513 public boolean isAllowContainsSearches() { 514 return myAllowContainsSearches; 515 } 516 517 /** 518 * If enabled, the server will support the use of :contains searches, 519 * which are helpful but can have adverse effects on performance. 520 * <p> 521 * Default is <code>false</code> (Note that prior to HAPI FHIR 522 * 3.5.0 the default was <code>true</code>) 523 * </p> 524 * <p> 525 * Note: If you change this value after data already has 526 * already been stored in the database, you must for a reindexing 527 * of all data in the database or resources may not be 528 * searchable. 529 * </p> 530 */ 531 public void setAllowContainsSearches(boolean theAllowContainsSearches) { 532 this.myAllowContainsSearches = theAllowContainsSearches; 533 } 534 535 /** 536 * If enabled, the server will support the use of :mdm search parameter qualifier on Reference Search Parameters. 537 * This Parameter Qualifier is HAPI-specific, and not defined anywhere in the FHIR specification. Using this qualifier 538 * will result in an MDM expansion being done on the reference, which will expand the search scope. For example, if Patient/1 539 * is MDM-matched to Patient/2 and you execute the search: 540 * Observation?subject:mdm=Patient/1 , you will receive observations for both Patient/1 and Patient/2. 541 * <p> 542 * Default is <code>false</code> 543 * </p> 544 * 545 * @since 5.4.0 546 */ 547 public boolean isAllowMdmExpansion() { 548 return myAllowMdmExpansion; 549 } 550 551 /** 552 * If enabled, the server will support the use of :mdm search parameter qualifier on Reference Search Parameters. 553 * This Parameter Qualifier is HAPI-specific, and not defined anywhere in the FHIR specification. Using this qualifier 554 * will result in an MDM expansion being done on the reference, which will expand the search scope. For example, if Patient/1 555 * is MDM-matched to Patient/2 and you execute the search: 556 * Observation?subject:mdm=Patient/1 , you will receive observations for both Patient/1 and Patient/2. 557 * <p> 558 * Default is <code>false</code> 559 * </p> 560 * 561 * @since 5.4.0 562 */ 563 public void setAllowMdmExpansion(boolean theAllowMdmExpansion) { 564 myAllowMdmExpansion = theAllowMdmExpansion; 565 } 566 567 /** 568 * If set to <code>true</code> (default is <code>false</code>) the server will allow 569 * resources to have references to external servers. For example if this server is 570 * running at <code>http://example.com/fhir</code> and this setting is set to 571 * <code>true</code> the server will allow a Patient resource to be saved with a 572 * Patient.organization value of <code>http://foo.com/Organization/1</code>. 573 * <p> 574 * Under the default behaviour if this value has not been changed, the above 575 * resource would be rejected by the server because it requires all references 576 * to be resolvable on the local server. 577 * </p> 578 * <p> 579 * Note that external references will be indexed by the server and may be searched 580 * (e.g. <code>Patient:organization</code>), but 581 * chained searches (e.g. <code>Patient:organization.name</code>) will not work across 582 * these references. 583 * </p> 584 * <p> 585 * It is recommended to also set {@link #setTreatBaseUrlsAsLocal(Set)} if this value 586 * is set to <code>true</code> 587 * </p> 588 * 589 * @see #setTreatBaseUrlsAsLocal(Set) 590 * @see #setAllowExternalReferences(boolean) 591 */ 592 public boolean isAllowExternalReferences() { 593 return myAllowExternalReferences; 594 } 595 596 /** 597 * If set to <code>true</code> (default is <code>false</code>) the server will allow 598 * resources to have references to external servers. For example if this server is 599 * running at <code>http://example.com/fhir</code> and this setting is set to 600 * <code>true</code> the server will allow a Patient resource to be saved with a 601 * Patient.organization value of <code>http://foo.com/Organization/1</code>. 602 * <p> 603 * Under the default behaviour if this value has not been changed, the above 604 * resource would be rejected by the server because it requires all references 605 * to be resolvable on the local server. 606 * </p> 607 * <p> 608 * Note that external references will be indexed by the server and may be searched 609 * (e.g. <code>Patient:organization</code>), but 610 * chained searches (e.g. <code>Patient:organization.name</code>) will not work across 611 * these references. 612 * </p> 613 * <p> 614 * It is recommended to also set {@link #setTreatBaseUrlsAsLocal(Set)} if this value 615 * is set to <code>true</code> 616 * </p> 617 * 618 * @see #setTreatBaseUrlsAsLocal(Set) 619 * @see #setAllowExternalReferences(boolean) 620 */ 621 public void setAllowExternalReferences(boolean theAllowExternalReferences) { 622 myAllowExternalReferences = theAllowExternalReferences; 623 } 624 625 /** 626 * This setting may be used to advise the server that any references found in 627 * resources that have any of the base URLs given here will be replaced with 628 * simple local references. 629 * <p> 630 * For example, if the set contains the value <code>http://example.com/base/</code> 631 * and a resource is submitted to the server that contains a reference to 632 * <code>http://example.com/base/Patient/1</code>, the server will automatically 633 * convert this reference to <code>Patient/1</code> 634 * </p> 635 * <p> 636 * Note that this property has different behaviour from {@link StorageSettings#getTreatReferencesAsLogical()} 637 * </p> 638 * 639 * @see #getTreatReferencesAsLogical() 640 */ 641 public Set<String> getTreatBaseUrlsAsLocal() { 642 return myTreatBaseUrlsAsLocal; 643 } 644 645 /** 646 * This setting may be used to advise the server that any references found in 647 * resources that have any of the base URLs given here will be replaced with 648 * simple local references. 649 * <p> 650 * For example, if the set contains the value <code>http://example.com/base/</code> 651 * and a resource is submitted to the server that contains a reference to 652 * <code>http://example.com/base/Patient/1</code>, the server will automatically 653 * convert this reference to <code>Patient/1</code> 654 * </p> 655 * 656 * @param theTreatBaseUrlsAsLocal The set of base URLs. May be <code>null</code>, which 657 * means no references will be treated as external 658 */ 659 public void setTreatBaseUrlsAsLocal(Set<String> theTreatBaseUrlsAsLocal) { 660 if (theTreatBaseUrlsAsLocal != null) { 661 for (String next : theTreatBaseUrlsAsLocal) { 662 validateTreatBaseUrlsAsLocal(next); 663 } 664 } 665 666 HashSet<String> treatBaseUrlsAsLocal = new HashSet<>(); 667 for (String next : defaultIfNull(theTreatBaseUrlsAsLocal, new HashSet<String>())) { 668 while (next.endsWith("/")) { 669 next = next.substring(0, next.length() - 1); 670 } 671 treatBaseUrlsAsLocal.add(next); 672 } 673 myTreatBaseUrlsAsLocal = treatBaseUrlsAsLocal; 674 } 675 676 /** 677 * Add a value to the {@link #setTreatReferencesAsLogical(Set) logical references list}. 678 * 679 * @see #setTreatReferencesAsLogical(Set) 680 */ 681 public void addTreatReferencesAsLogical(String theTreatReferencesAsLogical) { 682 validateTreatBaseUrlsAsLocal(theTreatReferencesAsLogical); 683 684 if (myTreatReferencesAsLogical == null) { 685 myTreatReferencesAsLogical = new HashSet<>(); 686 } 687 myTreatReferencesAsLogical.add(theTreatReferencesAsLogical); 688 } 689 690 /** 691 * This setting may be used to advise the server that any references found in 692 * resources that have any of the base URLs given here will be treated as logical 693 * references instead of being treated as real references. 694 * <p> 695 * A logical reference is a reference which is treated as an identifier, and 696 * does not neccesarily resolve. See <a href="http://hl7.org/fhir/references.html">references</a> for 697 * a description of logical references. For example, the valueset 698 * <a href="http://hl7.org/fhir/valueset-quantity-comparator.html">valueset-quantity-comparator</a> is a logical 699 * reference. 700 * </p> 701 * <p> 702 * Values for this field may take either of the following forms: 703 * </p> 704 * <ul> 705 * <li><code>http://example.com/some-url</code> <b>(will be matched exactly)</b></li> 706 * <li><code>http://example.com/some-base*</code> <b>(will match anything beginning with the part before the *)</b></li> 707 * </ul> 708 * 709 * @see #DEFAULT_LOGICAL_BASE_URLS Default values for this property 710 */ 711 public Set<String> getTreatReferencesAsLogical() { 712 return myTreatReferencesAsLogical; 713 } 714 715 /** 716 * This setting may be used to advise the server that any references found in 717 * resources that have any of the base URLs given here will be treated as logical 718 * references instead of being treated as real references. 719 * <p> 720 * A logical reference is a reference which is treated as an identifier, and 721 * does not neccesarily resolve. See <a href="http://hl7.org/fhir/references.html">references</a> for 722 * a description of logical references. For example, the valueset 723 * <a href="http://hl7.org/fhir/valueset-quantity-comparator.html">valueset-quantity-comparator</a> is a logical 724 * reference. 725 * </p> 726 * <p> 727 * Values for this field may take either of the following forms: 728 * </p> 729 * <ul> 730 * <li><code>http://example.com/some-url</code> <b>(will be matched exactly)</b></li> 731 * <li><code>http://example.com/some-base*</code> <b>(will match anything beginning with the part before the *)</b></li> 732 * </ul> 733 * 734 * @see #DEFAULT_LOGICAL_BASE_URLS Default values for this property 735 */ 736 public StorageSettings setTreatReferencesAsLogical(Set<String> theTreatReferencesAsLogical) { 737 myTreatReferencesAsLogical = theTreatReferencesAsLogical; 738 return this; 739 } 740 741 /** 742 * <p> 743 * Should searches use the integer field {@code SP_VALUE_LOW_DATE_ORDINAL} and {@code SP_VALUE_HIGH_DATE_ORDINAL} in 744 * {@link ResourceIndexedSearchParamDate} when resolving searches where all predicates are using 745 * precision of {@link TemporalPrecisionEnum#DAY}. 746 * <p> 747 * For example, if enabled, the search of {@code Observation?date=2020-02-25} will cause the date to be collapsed down to an 748 * integer representing the ordinal date {@code 20200225}. It would then be compared against {@link ResourceIndexedSearchParamDate#getValueLowDateOrdinal()} 749 * and {@link ResourceIndexedSearchParamDate#getValueHighDateOrdinal()} 750 * </p> 751 * Default is {@literal true} beginning in HAPI FHIR 5.0.0 752 * </p> 753 * 754 * @since 5.0.0 755 */ 756 public boolean getUseOrdinalDatesForDayPrecisionSearches() { 757 return myUseOrdinalDatesForDayPrecisionSearches; 758 } 759 760 /** 761 * <p> 762 * Should searches use the integer field {@code SP_VALUE_LOW_DATE_ORDINAL} and {@code SP_VALUE_HIGH_DATE_ORDINAL} in 763 * {@link ResourceIndexedSearchParamDate} when resolving searches where all predicates are using 764 * precision of {@link TemporalPrecisionEnum#DAY}. 765 * <p> 766 * For example, if enabled, the search of {@code Observation?date=2020-02-25} will cause the date to be collapsed down to an 767 * ordinal {@code 20200225}. It would then be compared against {@link ResourceIndexedSearchParamDate#getValueLowDateOrdinal()} 768 * and {@link ResourceIndexedSearchParamDate#getValueHighDateOrdinal()} 769 * </p> 770 * Default is {@literal true} beginning in HAPI FHIR 5.0.0 771 * </p> 772 * 773 * @since 5.0.0 774 */ 775 public void setUseOrdinalDatesForDayPrecisionSearches(boolean theUseOrdinalDates) { 776 myUseOrdinalDatesForDayPrecisionSearches = theUseOrdinalDates; 777 } 778 779 /** 780 * If set to <code>true</code> (default is <code>false</code>), when indexing SearchParameter values for token SearchParameter, 781 * the string component to support the <code>:text</code> modifier will be disabled. This means that the following fields 782 * will not be indexed for tokens: 783 * <ul> 784 * <li>CodeableConcept.text</li> 785 * <li>Coding.display</li> 786 * <li>Identifier.use.text</li> 787 * </ul> 788 * 789 * @since 5.0.0 790 */ 791 public boolean isSuppressStringIndexingInTokens() { 792 return mySuppressStringIndexingInTokens; 793 } 794 795 /** 796 * If set to <code>true</code> (default is <code>false</code>), when indexing SearchParameter values for token SearchParameter, 797 * the string component to support the <code>:text</code> modifier will be disabled. This means that the following fields 798 * will not be indexed for tokens: 799 * <ul> 800 * <li>CodeableConcept.text</li> 801 * <li>Coding.display</li> 802 * <li>Identifier.use.text</li> 803 * </ul> 804 * 805 * @since 5.0.0 806 */ 807 public void setSuppressStringIndexingInTokens(boolean theSuppressStringIndexingInTokens) { 808 mySuppressStringIndexingInTokens = theSuppressStringIndexingInTokens; 809 } 810 811 /** 812 * When indexing a Period (e.g. Encounter.period) where the period has an upper bound 813 * but not a lower bound, a canned "start of time" value can be used as the lower bound 814 * in order to allow range searches to correctly identify all values in the range. 815 * <p> 816 * The default value for this is {@link #DEFAULT_PERIOD_INDEX_START_OF_TIME} which 817 * is probably good enough for almost any application, but this can be changed if 818 * needed. 819 * </p> 820 * <p> 821 * Note the following database documented limitations: 822 * <ul> 823 * <li>JDBC Timestamp Datatype Low Value -4713 and High Value 9999</li> 824 * <li>MySQL 8: the range for DATETIME values is '1000-01-01 00:00:00.000000' to '9999-12-31 23:59:59.999999`</li> 825 * <li>Postgresql 12: Timestamp [without time zone] Low Value 4713 BC and High Value 294276 AD</li> 826 * <li>Oracle: Timestamp Low Value 4712 BC and High Value 9999 CE</li> 827 * <li>H2: datetime2 Low Value -4713 and High Value 9999</li> 828 * </ul> 829 * </p> 830 * 831 * @see #getPeriodIndexEndOfTime() 832 * @since 5.1.0 833 */ 834 public IPrimitiveType<Date> getPeriodIndexStartOfTime() { 835 return myPeriodIndexStartOfTime; 836 } 837 838 /** 839 * When indexing a Period (e.g. Encounter.period) where the period has an upper bound 840 * but not a lower bound, a canned "start of time" value can be used as the lower bound 841 * in order to allow range searches to correctly identify all values in the range. 842 * <p> 843 * The default value for this is {@link #DEFAULT_PERIOD_INDEX_START_OF_TIME} which 844 * is probably good enough for almost any application, but this can be changed if 845 * needed. 846 * </p> 847 * <p> 848 * Note the following database documented limitations: 849 * <ul> 850 * <li>JDBC Timestamp Datatype Low Value -4713 and High Value 9999</li> 851 * <li>MySQL 8: the range for DATETIME values is '1000-01-01 00:00:00.000000' to '9999-12-31 23:59:59.999999`</li> 852 * <li>Postgresql 12: Timestamp [without time zone] Low Value 4713 BC and High Value 294276 AD</li> 853 * <li>Oracle: Timestamp Low Value 4712 BC and High Value 9999 CE</li> 854 * <li>H2: datetime2 Low Value -4713 and High Value 9999</li> 855 * </ul> 856 * </p> 857 * 858 * @see #getPeriodIndexEndOfTime() 859 * @since 5.1.0 860 */ 861 public void setPeriodIndexStartOfTime(IPrimitiveType<Date> thePeriodIndexStartOfTime) { 862 Validate.notNull(thePeriodIndexStartOfTime, "thePeriodIndexStartOfTime must not be null"); 863 myPeriodIndexStartOfTime = thePeriodIndexStartOfTime; 864 } 865 866 /** 867 * When indexing a Period (e.g. Encounter.period) where the period has a lower bound 868 * but not an upper bound, a canned "end of time" value can be used as the upper bound 869 * in order to allow range searches to correctly identify all values in the range. 870 * <p> 871 * The default value for this is {@link #DEFAULT_PERIOD_INDEX_START_OF_TIME} which 872 * is probably good enough for almost any application, but this can be changed if 873 * needed. 874 * </p> 875 * <p> 876 * Note the following database documented limitations: 877 * <ul> 878 * <li>JDBC Timestamp Datatype Low Value -4713 and High Value 9999</li> 879 * <li>MySQL 8: the range for DATETIME values is '1000-01-01 00:00:00.000000' to '9999-12-31 23:59:59.999999`</li> 880 * <li>Postgresql 12: Timestamp [without time zone] Low Value 4713 BC and High Value 294276 AD</li> 881 * <li>Oracle: Timestamp Low Value 4712 BC and High Value 9999 CE</li> 882 * <li>H2: datetime2 Low Value -4713 and High Value 9999</li> 883 * </ul> 884 * </p> 885 * 886 * @see #getPeriodIndexStartOfTime() 887 * @since 5.1.0 888 */ 889 public IPrimitiveType<Date> getPeriodIndexEndOfTime() { 890 return myPeriodIndexEndOfTime; 891 } 892 893 /** 894 * When indexing a Period (e.g. Encounter.period) where the period has an upper bound 895 * but not a lower bound, a canned "start of time" value can be used as the lower bound 896 * in order to allow range searches to correctly identify all values in the range. 897 * <p> 898 * The default value for this is {@link #DEFAULT_PERIOD_INDEX_START_OF_TIME} which 899 * is probably good enough for almost any application, but this can be changed if 900 * needed. 901 * </p> 902 * <p> 903 * Note the following database documented limitations: 904 * <ul> 905 * <li>JDBC Timestamp Datatype Low Value -4713 and High Value 9999</li> 906 * <li>MySQL 8: the range for DATETIME values is '1000-01-01 00:00:00.000000' to '9999-12-31 23:59:59.999999`</li> 907 * <li>Postgresql 12: Timestamp [without time zone] Low Value 4713 BC and High Value 294276 AD</li> 908 * <li>Oracle: Timestamp Low Value 4712 BC and High Value 9999 CE</li> 909 * <li>H2: datetime2 Low Value -4713 and High Value 9999</li> 910 * </ul> 911 * </p> 912 * 913 * @see #getPeriodIndexStartOfTime() 914 * @since 5.1.0 915 */ 916 public void setPeriodIndexEndOfTime(IPrimitiveType<Date> thePeriodIndexEndOfTime) { 917 Validate.notNull(thePeriodIndexEndOfTime, "thePeriodIndexEndOfTime must not be null"); 918 myPeriodIndexEndOfTime = thePeriodIndexEndOfTime; 919 } 920 921 /** 922 * Toggles whether Quantity searches support value normalization when using valid UCUM coded values. 923 * 924 * <p> 925 * The default value is {@link NormalizedQuantitySearchLevel#NORMALIZED_QUANTITY_SEARCH_NOT_SUPPORTED} which is current behavior. 926 * </p> 927 * <p> 928 * Here is the UCUM service support level 929 * <ul> 930 * <li>{@link NormalizedQuantitySearchLevel#NORMALIZED_QUANTITY_SEARCH_NOT_SUPPORTED}, default, Quantity is stored in {@link ResourceIndexedSearchParamQuantity} only and it is used by searching.</li> 931 * <li>{@link NormalizedQuantitySearchLevel#NORMALIZED_QUANTITY_STORAGE_SUPPORTED}, Quantity is stored in both {@link ResourceIndexedSearchParamQuantity} and {@link ResourceIndexedSearchParamQuantityNormalized}, but {@link ResourceIndexedSearchParamQuantity} is used by searching.</li> 932 * <li>{@link NormalizedQuantitySearchLevel#NORMALIZED_QUANTITY_SEARCH_SUPPORTED}, Quantity is stored in both {@link ResourceIndexedSearchParamQuantity} and {@link ResourceIndexedSearchParamQuantityNormalized}, {@link ResourceIndexedSearchParamQuantityNormalized} is used by searching.</li> 933 * </ul> 934 * </p> 935 * 936 * @since 5.3.0 937 */ 938 public NormalizedQuantitySearchLevel getNormalizedQuantitySearchLevel() { 939 return myNormalizedQuantitySearchLevel; 940 } 941 942 /** 943 * Toggles whether Quantity searches support value normalization when using valid UCUM coded values. 944 * 945 * <p> 946 * The default value is {@link NormalizedQuantitySearchLevel#NORMALIZED_QUANTITY_SEARCH_NOT_SUPPORTED} which is current behavior. 947 * </p> 948 * <p> 949 * Here is the UCUM service support level 950 * <ul> 951 * <li>{@link NormalizedQuantitySearchLevel#NORMALIZED_QUANTITY_SEARCH_NOT_SUPPORTED}, default, Quantity is stored in {@link ResourceIndexedSearchParamQuantity} only and it is used by searching.</li> 952 * <li>{@link NormalizedQuantitySearchLevel#NORMALIZED_QUANTITY_STORAGE_SUPPORTED}, Quantity is stored in both {@link ResourceIndexedSearchParamQuantity} and {@link ResourceIndexedSearchParamQuantityNormalized}, but {@link ResourceIndexedSearchParamQuantity} is used by searching.</li> 953 * <li>{@link NormalizedQuantitySearchLevel#NORMALIZED_QUANTITY_SEARCH_SUPPORTED}, Quantity is stored in both {@link ResourceIndexedSearchParamQuantity} and {@link ResourceIndexedSearchParamQuantityNormalized}, {@link ResourceIndexedSearchParamQuantityNormalized} is used by searching.</li> 954 * </ul> 955 * </p> 956 * 957 * @since 5.3.0 958 */ 959 public void setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel theNormalizedQuantitySearchLevel) { 960 myNormalizedQuantitySearchLevel = theNormalizedQuantitySearchLevel; 961 } 962 963 /** 964 * When set with resource paths (e.g. <code>"Observation.subject"</code>), any references found at the given paths 965 * will automatically have versions appended. The version used will be the current version of the given resource. 966 * 967 * @since 5.3.0 968 */ 969 public Set<String> getAutoVersionReferenceAtPaths() { 970 return myAutoVersionReferenceAtPaths; 971 } 972 973 /** 974 * When set with resource paths (e.g. <code>"Observation.subject"</code>), any references found at the given paths 975 * will automatically have versions appended. The version used will be the current version of the given resource. 976 * <p> 977 * Versions will only be added if the reference does not already have a version, so any versioned references 978 * supplied by the client will take precedence over the automatic current version. 979 * </p> 980 * <p> 981 * Note that for this setting to be useful, the {@link ParserOptions} 982 * {@link ParserOptions#getDontStripVersionsFromReferencesAtPaths() DontStripVersionsFromReferencesAtPaths} 983 * option must also be set. 984 * </p> 985 * 986 * @param thePaths A collection of reference paths for which the versions will be appended automatically 987 * when serializing, e.g. "Patient.managingOrganization" or "AuditEvent.object.reference". Note that 988 * only resource name and field names with dots separating is allowed here (no repetition 989 * indicators, FluentPath expressions, etc.) 990 * @since 5.3.0 991 */ 992 public void setAutoVersionReferenceAtPaths(String... thePaths) { 993 Set<String> paths = Collections.emptySet(); 994 if (thePaths != null) { 995 paths = new HashSet<>(Arrays.asList(thePaths)); 996 } 997 setAutoVersionReferenceAtPaths(paths); 998 } 999 1000 /** 1001 * When set with resource paths (e.g. <code>"Observation.subject"</code>), any references found at the given paths 1002 * will automatically have versions appended. The version used will be the current version of the given resource. 1003 * <p> 1004 * Versions will only be added if the reference does not already have a version, so any versioned references 1005 * supplied by the client will take precedence over the automatic current version. 1006 * </p> 1007 * <p> 1008 * Note that for this setting to be useful, the {@link ParserOptions} 1009 * {@link ParserOptions#getDontStripVersionsFromReferencesAtPaths() DontStripVersionsFromReferencesAtPaths} 1010 * option must also be set 1011 * </p> 1012 * 1013 * @param thePaths A collection of reference paths for which the versions will be appended automatically 1014 * when serializing, e.g. "Patient.managingOrganization" or "AuditEvent.object.reference". Note that 1015 * only resource name and field names with dots separating is allowed here (no repetition 1016 * indicators, FluentPath expressions, etc.) 1017 * @since 5.3.0 1018 */ 1019 public void setAutoVersionReferenceAtPaths(Set<String> thePaths) { 1020 Set<String> paths = defaultIfNull(thePaths, Collections.emptySet()); 1021 Map<String, Set<String>> byType = new HashMap<>(); 1022 for (String nextPath : paths) { 1023 int doxIdx = nextPath.indexOf('.'); 1024 Validate.isTrue(doxIdx > 0, "Invalid path for auto-version reference at path: %s", nextPath); 1025 String type = nextPath.substring(0, doxIdx); 1026 byType.computeIfAbsent(type, t -> new HashSet<>()).add(nextPath); 1027 } 1028 1029 myAutoVersionReferenceAtPaths = paths; 1030 myTypeToAutoVersionReferenceAtPaths = byType; 1031 } 1032 1033 /** 1034 * Returns a sub-collection of {@link #getAutoVersionReferenceAtPaths()} containing only paths 1035 * for the given resource type. 1036 * 1037 * @since 5.3.0 1038 */ 1039 public Set<String> getAutoVersionReferenceAtPathsByResourceType(String theResourceType) { 1040 Validate.notEmpty(theResourceType, "theResourceType must not be null or empty"); 1041 Set<String> retVal = myTypeToAutoVersionReferenceAtPaths.get(theResourceType); 1042 retVal = defaultIfNull(retVal, Collections.emptySet()); 1043 return retVal; 1044 } 1045 1046 /** 1047 * Should searches with <code>_include</code> respect versioned references, and pull the specific requested version. 1048 * This may have performance impacts on heavily loaded systems. 1049 * 1050 * @since 5.3.0 1051 */ 1052 public boolean isRespectVersionsForSearchIncludes() { 1053 return myRespectVersionsForSearchIncludes; 1054 } 1055 1056 /** 1057 * Should searches with <code>_include</code> respect versioned references, and pull the specific requested version. 1058 * This may have performance impacts on heavily loaded systems. 1059 * 1060 * @since 5.3.0 1061 */ 1062 public void setRespectVersionsForSearchIncludes(boolean theRespectVersionsForSearchIncludes) { 1063 myRespectVersionsForSearchIncludes = theRespectVersionsForSearchIncludes; 1064 } 1065 1066 /** 1067 * If enabled, "Uplifted Refchains" will be enabled. This feature causes 1068 * HAPI FHIR to generate indexes for stored resources that include the current 1069 * value of the target of a chained reference, such as "Encounter?subject.name". 1070 * 1071 * @since 6.6.0 1072 */ 1073 public boolean isIndexOnUpliftedRefchains() { 1074 return myIndexOnUpliftedRefchains; 1075 } 1076 1077 /** 1078 * If enabled, "Uplifted Refchains" will be enabled. This feature causes 1079 * HAPI FHIR to generate indexes for stored resources that include the current 1080 * value of the target of a chained reference, such as "Encounter?subject.name". 1081 * 1082 * @since 6.6.0 1083 */ 1084 public void setIndexOnUpliftedRefchains(boolean theIndexOnUpliftedRefchains) { 1085 myIndexOnUpliftedRefchains = theIndexOnUpliftedRefchains; 1086 } 1087 1088 /** 1089 * Should indexing and searching on contained resources be enabled on this server. 1090 * This may have performance impacts, and should be enabled only if it is needed. Default is <code>false</code>. 1091 * 1092 * @since 5.4.0 1093 */ 1094 public boolean isIndexOnContainedResources() { 1095 return myIndexOnContainedResources; 1096 } 1097 1098 /** 1099 * Should indexing and searching on contained resources be enabled on this server. 1100 * This may have performance impacts, and should be enabled only if it is needed. Default is <code>false</code>. 1101 * 1102 * @since 5.4.0 1103 */ 1104 public void setIndexOnContainedResources(boolean theIndexOnContainedResources) { 1105 myIndexOnContainedResources = theIndexOnContainedResources; 1106 } 1107 1108 /** 1109 * Should recursive indexing and searching on contained resources be enabled on this server. 1110 * This may have performance impacts, and should be enabled only if it is needed. Default is <code>false</code>. 1111 * 1112 * @since 5.6.0 1113 */ 1114 public boolean isIndexOnContainedResourcesRecursively() { 1115 return myIndexOnContainedResourcesRecursively; 1116 } 1117 1118 /** 1119 * Should recursive indexing and searching on contained resources be enabled on this server. 1120 * This may have performance impacts, and should be enabled only if it is needed. Default is <code>false</code>. 1121 * 1122 * @since 5.6.0 1123 */ 1124 public void setIndexOnContainedResourcesRecursively(boolean theIndexOnContainedResourcesRecursively) { 1125 myIndexOnContainedResourcesRecursively = theIndexOnContainedResourcesRecursively; 1126 } 1127 1128 /** 1129 * If this is disabled by setting this to {@literal false} (default is {@literal true}), 1130 * the server will not automatically implement and support search parameters that 1131 * are not explcitly created in the repository. 1132 * <p> 1133 * Disabling this can have a dramatic improvement on performance (especially write performance) 1134 * in servers that only need to support a small number of search parameters, or no search parameters at all. 1135 * Disabling this obviously reduces the options for searching however. 1136 * </p> 1137 * 1138 * @since 5.7.0 1139 */ 1140 public boolean isAutoSupportDefaultSearchParams() { 1141 return myAutoSupportDefaultSearchParams; 1142 } 1143 1144 /** 1145 * If this is disabled by setting this to {@literal false} (default is {@literal true}), 1146 * the server will not automatically implement and support search parameters that 1147 * are not explcitly created in the repository. 1148 * <p> 1149 * Disabling this can have a dramatic improvement on performance (especially write performance) 1150 * in servers that only need to support a small number of search parameters, or no search parameters at all. 1151 * Disabling this obviously reduces the options for searching however. 1152 * </p> 1153 * 1154 * @since 5.7.0 1155 */ 1156 public void setAutoSupportDefaultSearchParams(boolean theAutoSupportDefaultSearchParams) { 1157 myAutoSupportDefaultSearchParams = theAutoSupportDefaultSearchParams; 1158 } 1159 1160 /** 1161 * @return Should the {@literal _lamguage} SearchParameter be supported on this server? Defaults to {@literal false}. 1162 * @since 7.0.0 1163 */ 1164 public boolean isLanguageSearchParameterEnabled() { 1165 return myLanguageSearchParameterEnabled; 1166 } 1167 1168 /** 1169 * Should the {@literal _lamguage} SearchParameter be supported on this server? Defaults to {@literal false}. 1170 * 1171 * @since 7.0.0 1172 */ 1173 public void setLanguageSearchParameterEnabled(boolean theLanguageSearchParameterEnabled) { 1174 myLanguageSearchParameterEnabled = theLanguageSearchParameterEnabled; 1175 } 1176 1177 /** 1178 * @return true if the filter is enabled for resources installed via package installer, false otherwise 1179 * @since 7.0.0 1180 */ 1181 public boolean isValidateResourceStatusForPackageUpload() { 1182 return myValidateResourceStatusForPackageUpload; 1183 } 1184 1185 /** 1186 * Should resources being installed via package installer be filtered. 1187 * @since 7.0.0 1188 */ 1189 public void setValidateResourceStatusForPackageUpload(boolean theValidateResourceStatusForPackageUpload) { 1190 myValidateResourceStatusForPackageUpload = theValidateResourceStatusForPackageUpload; 1191 } 1192 1193 private static void validateTreatBaseUrlsAsLocal(String theUrl) { 1194 Validate.notBlank(theUrl, "Base URL must not be null or empty"); 1195 1196 int starIdx = theUrl.indexOf('*'); 1197 if (starIdx != -1) { 1198 if (starIdx != theUrl.length() - 1) { 1199 throw new IllegalArgumentException(Msg.code(1525) 1200 + "Base URL wildcard character (*) can only appear at the end of the string: " + theUrl); 1201 } 1202 } 1203 } 1204 1205 public enum IndexEnabledEnum { 1206 ENABLED, 1207 DISABLED 1208 } 1209}