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