View Javadoc
1   package ca.uhn.fhir.jpa.dao;
2   
3   import ca.uhn.fhir.jpa.entity.ResourceEncodingEnum;
4   import ca.uhn.fhir.jpa.search.warm.WarmCacheEntry;
5   import ca.uhn.fhir.jpa.util.JpaConstants;
6   import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
7   import com.google.common.collect.Sets;
8   import org.apache.commons.lang3.ObjectUtils;
9   import org.apache.commons.lang3.Validate;
10  import org.apache.commons.lang3.time.DateUtils;
11  import org.hl7.fhir.r4.model.Bundle;
12  import org.slf4j.Logger;
13  import org.slf4j.LoggerFactory;
14  
15  import java.util.*;
16  
17  /*
18   * #%L
19   * HAPI FHIR JPA Server
20   * %%
21   * Copyright (C) 2014 - 2018 University Health Network
22   * %%
23   * Licensed under the Apache License, Version 2.0 (the "License");
24   * you may not use this file except in compliance with the License.
25   * You may obtain a copy of the License at
26   * 
27   * http://www.apache.org/licenses/LICENSE-2.0
28   * 
29   * Unless required by applicable law or agreed to in writing, software
30   * distributed under the License is distributed on an "AS IS" BASIS,
31   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
32   * See the License for the specific language governing permissions and
33   * limitations under the License.
34   * #L%
35   */
36  
37  public class DaoConfig {
38  
39  	/**
40  	 * Default {@link #getTreatReferencesAsLogical() logical URL bases}. Includes the following
41  	 * values:
42  	 * <ul>
43  	 * <li><code>"http://hl7.org/fhir/valueset-*"</code></li>
44  	 * <li><code>"http://hl7.org/fhir/codesystem-*"</code></li>
45  	 * <li><code>"http://hl7.org/fhir/StructureDefinition/*"</code></li>
46  	 * </ul>
47  	 */
48  	public static final Set<String> DEFAULT_LOGICAL_BASE_URLS = Collections.unmodifiableSet(new HashSet<String>(Arrays.asList(
49  		"http://hl7.org/fhir/ValueSet/*",
50  		"http://hl7.org/fhir/CodeSystem/*",
51  		"http://hl7.org/fhir/valueset-*",
52  		"http://hl7.org/fhir/codesystem-*",
53  		"http://hl7.org/fhir/StructureDefinition/*")));
54  	/**
55  	 * Default value for {@link #setReuseCachedSearchResultsForMillis(Long)}: 60000ms (one minute)
56  	 */
57  	public static final Long DEFAULT_REUSE_CACHED_SEARCH_RESULTS_FOR_MILLIS = DateUtils.MILLIS_PER_MINUTE;
58  	/**
59  	 * Default value for {@link #setTranslationCachesExpireAfterWriteInMinutes(Long)}: 60 minutes
60  	 *
61  	 * @see #setTranslationCachesExpireAfterWriteInMinutes(Long)
62  	 */
63  	public static final Long DEFAULT_TRANSLATION_CACHES_EXPIRE_AFTER_WRITE_IN_MINUTES = 60L;
64  	/**
65  	 * See {@link #setStatusBasedReindexingDisabled(boolean)}
66  	 */
67  	public static final String DISABLE_STATUS_BASED_REINDEX = "disable_status_based_reindex";
68  	/**
69  	 * Default value for {@link #setMaximumSearchResultCountInTransaction(Integer)}
70  	 *
71  	 * @see #setMaximumSearchResultCountInTransaction(Integer)
72  	 */
73  	private static final Integer DEFAULT_MAXIMUM_SEARCH_RESULT_COUNT_IN_TRANSACTION = null;
74  	/**
75  	 * Default {@link #setBundleTypesAllowedForStorage(Set)} value:
76  	 * <ul>
77  	 * <li>collection</li>
78  	 * <li>document</li>
79  	 * <li>message</li>
80  	 * </ul>
81  	 */
82  	private static final Set<String> DEFAULT_BUNDLE_TYPES_ALLOWED_FOR_STORAGE = Collections.unmodifiableSet(new TreeSet<>(Sets.newHashSet(
83  		Bundle.BundleType.COLLECTION.toCode(),
84  		Bundle.BundleType.DOCUMENT.toCode(),
85  		Bundle.BundleType.MESSAGE.toCode()
86  	)));
87  	private static final Logger ourLog = LoggerFactory.getLogger(DaoConfig.class);
88  	private IndexEnabledEnum myIndexMissingFieldsEnabled = IndexEnabledEnum.DISABLED;
89  	/**
90  	 * update setter javadoc if default changes
91  	 */
92  	private Long myTranslationCachesExpireAfterWriteInMinutes = DEFAULT_TRANSLATION_CACHES_EXPIRE_AFTER_WRITE_IN_MINUTES;
93  	/**
94  	 * update setter javadoc if default changes
95  	 */
96  	private boolean myAllowExternalReferences = false;
97  	/**
98  	 * update setter javadoc if default changes
99  	 */
100 	private boolean myAllowContainsSearches = false;
101 	/**
102 	 * update setter javadoc if default changes
103 	 */
104 	private boolean myAllowInlineMatchUrlReferences = true;
105 	private boolean myAllowMultipleDelete;
106 	private boolean myDefaultSearchParamsCanBeOverridden = false;
107 	/**
108 	 * update setter javadoc if default changes
109 	 */
110 	private int myDeferIndexingForCodesystemsOfSize = 2000;
111 	private boolean myDeleteStaleSearches = true;
112 	private boolean myEnforceReferentialIntegrityOnDelete = true;
113 	private boolean myUniqueIndexesEnabled = true;
114 	private boolean myUniqueIndexesCheckedBeforeSave = true;
115 	private boolean myEnforceReferentialIntegrityOnWrite = true;
116 	private int myEverythingIncludesFetchPageSize = 50;
117 	/**
118 	 * update setter javadoc if default changes
119 	 */
120 	private long myExpireSearchResultsAfterMillis = DateUtils.MILLIS_PER_HOUR;
121 	/**
122 	 * update setter javadoc if default changes
123 	 */
124 	private Integer myFetchSizeDefaultMaximum = null;
125 	private int myHardTagListLimit = 1000;
126 	/**
127 	 * update setter javadoc if default changes
128 	 */
129 	private boolean myIndexContainedResources = true;
130 	private List<IServerInterceptor> myInterceptors;
131 	/**
132 	 * update setter javadoc if default changes
133 	 */
134 	private int myMaximumExpansionSize = 5000;
135 	private Integer myMaximumSearchResultCountInTransaction = DEFAULT_MAXIMUM_SEARCH_RESULT_COUNT_IN_TRANSACTION;
136 	private ResourceEncodingEnum myResourceEncoding = ResourceEncodingEnum.JSONC;
137 	/**
138 	 * update setter javadoc if default changes
139 	 */
140 	private Integer myResourceMetaCountHardLimit = 1000;
141 	private Long myReuseCachedSearchResultsForMillis = DEFAULT_REUSE_CACHED_SEARCH_RESULTS_FOR_MILLIS;
142 	private boolean mySchedulingDisabled;
143 	private boolean mySuppressUpdatesWithNoChange = true;
144 	private Set<String> myTreatBaseUrlsAsLocal = new HashSet<>();
145 	private Set<String> myTreatReferencesAsLogical = new HashSet<>(DEFAULT_LOGICAL_BASE_URLS);
146 	private boolean myAutoCreatePlaceholderReferenceTargets;
147 	private Integer myCacheControlNoStoreMaxResultsUpperLimit = 1000;
148 	private Integer myCountSearchResultsUpTo = null;
149 	private boolean myStatusBasedReindexingDisabled;
150 	private IdStrategyEnum myResourceServerIdStrategy = IdStrategyEnum.SEQUENTIAL_NUMERIC;
151 	private boolean myMarkResourcesForReindexingUponSearchParameterChange;
152 	private boolean myExpungeEnabled;
153 	private int myReindexThreadCount;
154 	private Set<String> myBundleTypesAllowedForStorage;
155 	private boolean myValidateSearchParameterExpressionsOnSave = true;
156 	private List<Integer> mySearchPreFetchThresholds = Arrays.asList(500, 2000, -1);
157 	private List<WarmCacheEntry> myWarmCacheEntries = new ArrayList<>();
158 	private boolean myDisableHashBasedSearches;
159 	private ClientIdStrategyEnum myResourceClientIdStrategy = ClientIdStrategyEnum.ALPHANUMERIC;
160 
161 	/**
162 	 * Constructor
163 	 */
164 	public DaoConfig() {
165 		setSubscriptionEnabled(true);
166 		setSubscriptionPollDelay(0);
167 		setSubscriptionPurgeInactiveAfterMillis(Long.MAX_VALUE);
168 		setMarkResourcesForReindexingUponSearchParameterChange(true);
169 		setReindexThreadCount(Runtime.getRuntime().availableProcessors());
170 		setBundleTypesAllowedForStorage(DEFAULT_BUNDLE_TYPES_ALLOWED_FOR_STORAGE);
171 
172 		if ("true".equalsIgnoreCase(System.getProperty(DISABLE_STATUS_BASED_REINDEX))) {
173 			ourLog.info("Status based reindexing is DISABLED");
174 			setStatusBasedReindexingDisabled(true);
175 		}
176 	}
177 
178 	/**
179 	 * Returns a set of searches that should be kept "warm", meaning that
180 	 * searches will periodically be performed in the background to
181 	 * keep results ready for this search
182 	 */
183 	public List<WarmCacheEntry> getWarmCacheEntries() {
184 		if (myWarmCacheEntries == null) {
185 			myWarmCacheEntries = new ArrayList<>();
186 		}
187 		return myWarmCacheEntries;
188 	}
189 
190 	public void setWarmCacheEntries(List<WarmCacheEntry> theWarmCacheEntries) {
191 		myWarmCacheEntries = theWarmCacheEntries;
192 	}
193 
194 	/**
195 	 * If set to <code>true</code> (default is false), the reindexing of search parameters
196 	 * using a query on the HFJ_RESOURCE.SP_INDEX_STATUS column will be disabled completely.
197 	 * This query is just not efficient on Oracle and bogs the system down when there are
198 	 * a lot of resources. A more efficient way of doing this will be introduced
199 	 * in the next release of HAPI FHIR.
200 	 *
201 	 * @since 3.5.0
202 	 */
203 	public boolean isStatusBasedReindexingDisabled() {
204 		return myStatusBasedReindexingDisabled;
205 	}
206 
207 	/**
208 	 * If set to <code>true</code> (default is false), the reindexing of search parameters
209 	 * using a query on the HFJ_RESOURCE.SP_INDEX_STATUS column will be disabled completely.
210 	 * This query is just not efficient on Oracle and bogs the system down when there are
211 	 * a lot of resources. A more efficient way of doing this will be introduced
212 	 * in the next release of HAPI FHIR.
213 	 *
214 	 * @since 3.5.0
215 	 */
216 	public void setStatusBasedReindexingDisabled(boolean theStatusBasedReindexingDisabled) {
217 		myStatusBasedReindexingDisabled = theStatusBasedReindexingDisabled;
218 	}
219 
220 	/**
221 	 * Add a value to the {@link #setTreatReferencesAsLogical(Set) logical references list}.
222 	 *
223 	 * @see #setTreatReferencesAsLogical(Set)
224 	 */
225 	public void addTreatReferencesAsLogical(String theTreatReferencesAsLogical) {
226 		validateTreatBaseUrlsAsLocal(theTreatReferencesAsLogical);
227 
228 		if (myTreatReferencesAsLogical == null) {
229 			myTreatReferencesAsLogical = new HashSet<>();
230 		}
231 		myTreatReferencesAsLogical.add(theTreatReferencesAsLogical);
232 	}
233 
234 	/**
235 	 * This setting specifies the bundle types (<code>Bundle.type</code>) that
236 	 * are allowed to be stored as-is on the /Bundle endpoint.
237 	 *
238 	 * @see #DEFAULT_BUNDLE_TYPES_ALLOWED_FOR_STORAGE
239 	 */
240 	public Set<String> getBundleTypesAllowedForStorage() {
241 		return myBundleTypesAllowedForStorage;
242 	}
243 
244 	/**
245 	 * This setting specifies the bundle types (<code>Bundle.type</code>) that
246 	 * are allowed to be stored as-is on the /Bundle endpoint.
247 	 *
248 	 * @see #DEFAULT_BUNDLE_TYPES_ALLOWED_FOR_STORAGE
249 	 */
250 	public void setBundleTypesAllowedForStorage(Set<String> theBundleTypesAllowedForStorage) {
251 		Validate.notNull(theBundleTypesAllowedForStorage, "theBundleTypesAllowedForStorage must not be null");
252 		myBundleTypesAllowedForStorage = theBundleTypesAllowedForStorage;
253 	}
254 
255 	/**
256 	 * Specifies the highest number that a client is permitted to use in a
257 	 * <code>Cache-Control: nostore, max-results=NNN</code>
258 	 * directive. If the client tries to exceed this limit, the
259 	 * request will be denied. Defaults to 1000.
260 	 */
261 	public Integer getCacheControlNoStoreMaxResultsUpperLimit() {
262 		return myCacheControlNoStoreMaxResultsUpperLimit;
263 	}
264 
265 	/**
266 	 * Specifies the highest number that a client is permitted to use in a
267 	 * <code>Cache-Control: nostore, max-results=NNN</code>
268 	 * directive. If the client tries to exceed this limit, the
269 	 * request will be denied. Defaults to 1000.
270 	 */
271 	public void setCacheControlNoStoreMaxResultsUpperLimit(Integer theCacheControlNoStoreMaxResults) {
272 		myCacheControlNoStoreMaxResultsUpperLimit = theCacheControlNoStoreMaxResults;
273 	}
274 
275 	/**
276 	 * When searching, if set to a non-null value (default is <code>null</code>) the
277 	 * search coordinator will attempt to find at least this many results
278 	 * before returning a response to the client. This parameter mainly affects
279 	 * whether a "total count" is included in the response bundle for searches that
280 	 * return large amounts of data.
281 	 * <p>
282 	 * For a search that returns 10000 results, if this value is set to
283 	 * 10000 the search coordinator will find all 10000 results
284 	 * prior to returning, so the initial response bundle will have the
285 	 * total set to 10000. If this value is null (or less than 10000)
286 	 * the response bundle will likely return slightly faster, but will
287 	 * not include the total. Subsequent page requests will likely
288 	 * include the total however, if they are performed after the
289 	 * search coordinator has found all results.
290 	 * </p>
291 	 * <p>
292 	 * Set this value to <code>0</code> to always load all
293 	 * results before returning.
294 	 * </p>
295 	 */
296 	public Integer getCountSearchResultsUpTo() {
297 		return myCountSearchResultsUpTo;
298 	}
299 
300 	/**
301 	 * When searching, if set to a non-null value (default is <code>null</code>) the
302 	 * search coordinator will attempt to find at least this many results
303 	 * before returning a response to the client. This parameter mainly affects
304 	 * whether a "total count" is included in the response bundle for searches that
305 	 * return large amounts of data.
306 	 * <p>
307 	 * For a search that returns 10000 results, if this value is set to
308 	 * 10000 the search coordinator will find all 10000 results
309 	 * prior to returning, so the initial response bundle will have the
310 	 * total set to 10000. If this value is null (or less than 10000)
311 	 * the response bundle will likely return slightly faster, but will
312 	 * not include the total. Subsequent page requests will likely
313 	 * include the total however, if they are performed after the
314 	 * search coordinator has found all results.
315 	 * </p>
316 	 * <p>
317 	 * Set this value to <code>0</code> to always load all
318 	 * results before returning.
319 	 * </p>
320 	 */
321 	public void setCountSearchResultsUpTo(Integer theCountSearchResultsUpTo) {
322 		myCountSearchResultsUpTo = theCountSearchResultsUpTo;
323 	}
324 
325 	/**
326 	 * When a code system is added that contains more than this number of codes,
327 	 * the code system will be indexed later in an incremental process in order to
328 	 * avoid overwhelming Lucene with a huge number of codes in a single operation.
329 	 * <p>
330 	 * Defaults to 2000
331 	 * </p>
332 	 */
333 	public int getDeferIndexingForCodesystemsOfSize() {
334 		return myDeferIndexingForCodesystemsOfSize;
335 	}
336 
337 	/**
338 	 * When a code system is added that contains more than this number of codes,
339 	 * the code system will be indexed later in an incremental process in order to
340 	 * avoid overwhelming Lucene with a huge number of codes in a single operation.
341 	 * <p>
342 	 * Defaults to 2000
343 	 * </p>
344 	 */
345 	public void setDeferIndexingForCodesystemsOfSize(int theDeferIndexingForCodesystemsOfSize) {
346 		myDeferIndexingForCodesystemsOfSize = theDeferIndexingForCodesystemsOfSize;
347 	}
348 
349 	/**
350 	 * Unlike with normal search queries, $everything queries have their _includes loaded by the main search thread and these included results
351 	 * are added to the normal search results instead of being added on as extras in a page. This means that they will not appear multiple times
352 	 * as the search results are paged over.
353 	 * <p>
354 	 * In order to recursively load _includes, we process the original results in batches of this size. Adjust with caution, increasing this
355 	 * value may improve performance but may also cause memory issues.
356 	 * </p>
357 	 * <p>
358 	 * The default value is 50
359 	 * </p>
360 	 */
361 	public int getEverythingIncludesFetchPageSize() {
362 		return myEverythingIncludesFetchPageSize;
363 	}
364 
365 	/**
366 	 * Unlike with normal search queries, $everything queries have their _includes loaded by the main search thread and these included results
367 	 * are added to the normal search results instead of being added on as extras in a page. This means that they will not appear multiple times
368 	 * as the search results are paged over.
369 	 * <p>
370 	 * In order to recursively load _includes, we process the original results in batches of this size. Adjust with caution, increasing this
371 	 * value may improve performance but may also cause memory issues.
372 	 * </p>
373 	 * <p>
374 	 * The default value is 50
375 	 * </p>
376 	 */
377 	public void setEverythingIncludesFetchPageSize(int theEverythingIncludesFetchPageSize) {
378 		Validate.inclusiveBetween(1, Integer.MAX_VALUE, theEverythingIncludesFetchPageSize);
379 		myEverythingIncludesFetchPageSize = theEverythingIncludesFetchPageSize;
380 	}
381 
382 	/**
383 	 * Sets the number of milliseconds that search results for a given client search
384 	 * should be preserved before being purged from the database.
385 	 * <p>
386 	 * Search results are stored in the database so that they can be paged over multiple
387 	 * requests. After this
388 	 * number of milliseconds, they will be deleted from the database, and any paging links
389 	 * (next/prev links in search response bundles) will become invalid. Defaults to 1 hour.
390 	 * </p>
391 	 * <p>
392 	 * To disable this feature entirely, see {@link #setExpireSearchResults(boolean)}
393 	 * </p>
394 	 *
395 	 * @since 1.5
396 	 */
397 	public long getExpireSearchResultsAfterMillis() {
398 		return myExpireSearchResultsAfterMillis;
399 	}
400 
401 	/**
402 	 * Sets the number of milliseconds that search results for a given client search
403 	 * should be preserved before being purged from the database.
404 	 * <p>
405 	 * Search results are stored in the database so that they can be paged over multiple
406 	 * requests. After this
407 	 * number of milliseconds, they will be deleted from the database, and any paging links
408 	 * (next/prev links in search response bundles) will become invalid. Defaults to 1 hour.
409 	 * </p>
410 	 * <p>
411 	 * To disable this feature entirely, see {@link #setExpireSearchResults(boolean)}
412 	 * </p>
413 	 *
414 	 * @since 1.5
415 	 */
416 	public void setExpireSearchResultsAfterMillis(long theExpireSearchResultsAfterMillis) {
417 		myExpireSearchResultsAfterMillis = theExpireSearchResultsAfterMillis;
418 	}
419 
420 	/**
421 	 * Gets the default maximum number of results to load in a query.
422 	 * <p>
423 	 * For example, if the database has a million Patient resources in it, and
424 	 * the client requests <code>GET /Patient</code>, if this value is set
425 	 * to a non-null value (default is <code>null</code>) only this number
426 	 * of results will be fetched. Setting this value appropriately
427 	 * can be useful to improve performance in some situations.
428 	 * </p>
429 	 */
430 	public Integer getFetchSizeDefaultMaximum() {
431 		return myFetchSizeDefaultMaximum;
432 	}
433 
434 	/**
435 	 * Gets the default maximum number of results to load in a query.
436 	 * <p>
437 	 * For example, if the database has a million Patient resources in it, and
438 	 * the client requests <code>GET /Patient</code>, if this value is set
439 	 * to a non-null value (default is <code>null</code>) only this number
440 	 * of results will be fetched. Setting this value appropriately
441 	 * can be useful to improve performance in some situations.
442 	 * </p>
443 	 */
444 	public void setFetchSizeDefaultMaximum(Integer theFetchSizeDefaultMaximum) {
445 		myFetchSizeDefaultMaximum = theFetchSizeDefaultMaximum;
446 	}
447 
448 	/**
449 	 * Gets the maximum number of results to return in a GetTags query (DSTU1 only)
450 	 */
451 	public int getHardTagListLimit() {
452 		return myHardTagListLimit;
453 	}
454 
455 	/**
456 	 * Gets the maximum number of results to return in a GetTags query (DSTU1 only)
457 	 */
458 	public void setHardTagListLimit(int theHardTagListLimit) {
459 		myHardTagListLimit = theHardTagListLimit;
460 	}
461 
462 	/**
463 	 * If set to {@link IndexEnabledEnum#DISABLED} (default is {@link IndexEnabledEnum#DISABLED})
464 	 * the server will not create search indexes for search parameters with no values in resources.
465 	 * <p>
466 	 * Disabling this feature means that the <code>:missing</code> search modifier will not be
467 	 * supported on the server, but also means that storage and indexing (i.e. writes to the
468 	 * database) may be much faster on servers which have lots of search parameters and need
469 	 * to write quickly.
470 	 * </p>
471 	 * <p>
472 	 * This feature may be enabled on servers where supporting the use of the :missing parameter is
473 	 * of higher importance than raw write performance
474 	 * </p>
475 	 */
476 	public IndexEnabledEnum getIndexMissingFields() {
477 		return myIndexMissingFieldsEnabled;
478 	}
479 
480 	/**
481 	 * If set to {@link IndexEnabledEnum#DISABLED} (default is {@link IndexEnabledEnum#DISABLED})
482 	 * the server will not create search indexes for search parameters with no values in resources.
483 	 * <p>
484 	 * Disabling this feature means that the <code>:missing</code> search modifier will not be
485 	 * supported on the server, but also means that storage and indexing (i.e. writes to the
486 	 * database) may be much faster on servers which have lots of search parameters and need
487 	 * to write quickly.
488 	 * </p>
489 	 * <p>
490 	 * This feature may be enabled on servers where supporting the use of the :missing parameter is
491 	 * of higher importance than raw write performance
492 	 * </p>
493 	 * <p>
494 	 * Note that this setting also has an impact on sorting (i.e. using the
495 	 * <code>_sort</code> parameter on searches): If the server is configured
496 	 * to not index missing field.
497 	 * </p>
498 	 */
499 	public void setIndexMissingFields(IndexEnabledEnum theIndexMissingFields) {
500 		Validate.notNull(theIndexMissingFields, "theIndexMissingFields must not be null");
501 		myIndexMissingFieldsEnabled = theIndexMissingFields;
502 	}
503 
504 	/**
505 	 * Returns the interceptors which will be notified of operations.
506 	 *
507 	 * @see #setInterceptors(List)
508 	 */
509 	public List<IServerInterceptor> getInterceptors() {
510 		if (myInterceptors == null) {
511 			myInterceptors = new ArrayList<>();
512 		}
513 		return myInterceptors;
514 	}
515 
516 	/**
517 	 * This may be used to optionally register server interceptors directly against the DAOs.
518 	 */
519 	public void setInterceptors(List<IServerInterceptor> theInterceptors) {
520 		myInterceptors = theInterceptors;
521 	}
522 
523 	/**
524 	 * This may be used to optionally register server interceptors directly against the DAOs.
525 	 */
526 	public void setInterceptors(IServerInterceptor... theInterceptor) {
527 		setInterceptors(new ArrayList<IServerInterceptor>());
528 		if (theInterceptor != null && theInterceptor.length != 0) {
529 			getInterceptors().addAll(Arrays.asList(theInterceptor));
530 		}
531 	}
532 
533 	/**
534 	 * See {@link #setMaximumExpansionSize(int)}
535 	 */
536 	public int getMaximumExpansionSize() {
537 		return myMaximumExpansionSize;
538 	}
539 
540 	/**
541 	 * Sets the maximum number of codes that will be added to a valueset expansion before
542 	 * the operation will be failed as too costly
543 	 */
544 	public void setMaximumExpansionSize(int theMaximumExpansionSize) {
545 		Validate.isTrue(theMaximumExpansionSize > 0, "theMaximumExpansionSize must be > 0");
546 		myMaximumExpansionSize = theMaximumExpansionSize;
547 	}
548 
549 	/**
550 	 * Provides the maximum number of results which may be returned by a search (HTTP GET) which
551 	 * is executed as a sub-operation within within a FHIR <code>transaction</code> or
552 	 * <code>batch</code> operation. For example, if this value is set to <code>100</code> and
553 	 * a FHIR transaction is processed with a sub-request for <code>Patient?gender=male</code>,
554 	 * the server will throw an error (and the transaction will fail) if there are more than
555 	 * 100 resources on the server which match this query.
556 	 * <p>
557 	 * The default value is <code>null</code>, which means that there is no limit.
558 	 * </p>
559 	 */
560 	public Integer getMaximumSearchResultCountInTransaction() {
561 		return myMaximumSearchResultCountInTransaction;
562 	}
563 
564 	/**
565 	 * Provides the maximum number of results which may be returned by a search (HTTP GET) which
566 	 * is executed as a sub-operation within within a FHIR <code>transaction</code> or
567 	 * <code>batch</code> operation. For example, if this value is set to <code>100</code> and
568 	 * a FHIR transaction is processed with a sub-request for <code>Patient?gender=male</code>,
569 	 * the server will throw an error (and the transaction will fail) if there are more than
570 	 * 100 resources on the server which match this query.
571 	 * <p>
572 	 * The default value is <code>null</code>, which means that there is no limit.
573 	 * </p>
574 	 */
575 	public void setMaximumSearchResultCountInTransaction(Integer theMaximumSearchResultCountInTransaction) {
576 		myMaximumSearchResultCountInTransaction = theMaximumSearchResultCountInTransaction;
577 	}
578 
579 	/**
580 	 * This setting controls the number of threads allocated to resource reindexing
581 	 * (which is only ever used if SearchParameters change, or a manual reindex is
582 	 * triggered due to a HAPI FHIR upgrade or some other reason).
583 	 * <p>
584 	 * The default value is set to the number of available processors
585 	 * (via <code>Runtime.getRuntime().availableProcessors()</code>). Value
586 	 * for this setting must be a positive integer.
587 	 * </p>
588 	 */
589 	public int getReindexThreadCount() {
590 		return myReindexThreadCount;
591 	}
592 
593 	/**
594 	 * This setting controls the number of threads allocated to resource reindexing
595 	 * (which is only ever used if SearchParameters change, or a manual reindex is
596 	 * triggered due to a HAPI FHIR upgrade or some other reason).
597 	 * <p>
598 	 * The default value is set to the number of available processors
599 	 * (via <code>Runtime.getRuntime().availableProcessors()</code>). Value
600 	 * for this setting must be a positive integer.
601 	 * </p>
602 	 */
603 	public void setReindexThreadCount(int theReindexThreadCount) {
604 		myReindexThreadCount = theReindexThreadCount;
605 		myReindexThreadCount = Math.max(myReindexThreadCount, 1); // Minimum of 1
606 	}
607 
608 	public ResourceEncodingEnum getResourceEncoding() {
609 		return myResourceEncoding;
610 	}
611 
612 	public void setResourceEncoding(ResourceEncodingEnum theResourceEncoding) {
613 		myResourceEncoding = theResourceEncoding;
614 	}
615 
616 	/**
617 	 * If set, an individual resource will not be allowed to have more than the
618 	 * given number of tags, profiles, and security labels (the limit is for the combined
619 	 * total for all of these things on an individual resource).
620 	 * <p>
621 	 * If set to <code>null</code>, no limit will be applied.
622 	 * </p>
623 	 * <p>
624 	 * The default value for this setting is 1000.
625 	 * </p>
626 	 */
627 	public Integer getResourceMetaCountHardLimit() {
628 		return myResourceMetaCountHardLimit;
629 	}
630 
631 	/**
632 	 * If set, an individual resource will not be allowed to have more than the
633 	 * given number of tags, profiles, and security labels (the limit is for the combined
634 	 * total for all of these things on an individual resource).
635 	 * <p>
636 	 * If set to <code>null</code>, no limit will be applied.
637 	 * </p>
638 	 * <p>
639 	 * The default value for this setting is 1000.
640 	 * </p>
641 	 */
642 	public void setResourceMetaCountHardLimit(Integer theResourceMetaCountHardLimit) {
643 		myResourceMetaCountHardLimit = theResourceMetaCountHardLimit;
644 	}
645 
646 	/**
647 	 * Controls the behaviour when a client-assigned ID is encountered, i.e. an HTTP PUT
648 	 * on a resource ID that does not already exist in the database.
649 	 * <p>
650 	 * Default is {@link ClientIdStrategyEnum#ALPHANUMERIC}
651 	 * </p>
652 	 */
653 	public ClientIdStrategyEnum getResourceClientIdStrategy() {
654 		return myResourceClientIdStrategy;
655 	}
656 
657 	/**
658 	 * Controls the behaviour when a client-assigned ID is encountered, i.e. an HTTP PUT
659 	 * on a resource ID that does not already exist in the database.
660 	 * <p>
661 	 * Default is {@link ClientIdStrategyEnum#ALPHANUMERIC}
662 	 * </p>
663 	 *
664 	 * @param theResourceClientIdStrategy Must not be <code>null</code>
665 	 */
666 	public void setResourceClientIdStrategy(ClientIdStrategyEnum theResourceClientIdStrategy) {
667 		Validate.notNull(theResourceClientIdStrategy, "theClientIdStrategy must not be null");
668 		myResourceClientIdStrategy = theResourceClientIdStrategy;
669 	}
670 
671 	/**
672 	 * This setting configures the strategy to use in generating IDs for newly
673 	 * created resources on the server. The default is {@link IdStrategyEnum#SEQUENTIAL_NUMERIC}.
674 	 * <p>
675 	 * This strategy is only used for server-assigned IDs, i.e. for HTTP POST
676 	 * where the client is requesing that the server store a new resource and give
677 	 * it an ID.
678 	 * </p>
679 	 */
680 	public IdStrategyEnum getResourceServerIdStrategy() {
681 		return myResourceServerIdStrategy;
682 	}
683 
684 	/**
685 	 * This setting configures the strategy to use in generating IDs for newly
686 	 * created resources on the server. The default is {@link IdStrategyEnum#SEQUENTIAL_NUMERIC}.
687 	 * <p>
688 	 * This strategy is only used for server-assigned IDs, i.e. for HTTP POST
689 	 * where the client is requesing that the server store a new resource and give
690 	 * it an ID.
691 	 * </p>
692 	 *
693 	 * @param theResourceIdStrategy The strategy. Must not be <code>null</code>.
694 	 */
695 	public void setResourceServerIdStrategy(IdStrategyEnum theResourceIdStrategy) {
696 		Validate.notNull(theResourceIdStrategy, "theResourceIdStrategy must not be null");
697 		myResourceServerIdStrategy = theResourceIdStrategy;
698 	}
699 
700 	/**
701 	 * If set to a non {@literal null} value (default is {@link #DEFAULT_REUSE_CACHED_SEARCH_RESULTS_FOR_MILLIS non null})
702 	 * if an identical search is requested multiple times within this window, the same results will be returned
703 	 * to multiple queries. For example, if this value is set to 1 minute and a client searches for all
704 	 * patients named "smith", and then a second client also performs the same search within 1 minute,
705 	 * the same cached results will be returned.
706 	 * <p>
707 	 * This approach can improve performance, especially under heavy load, but can also mean that
708 	 * searches may potentially return slightly out-of-date results.
709 	 * </p>
710 	 * <p>
711 	 * Note that if this is set to a non-null value, clients may override this setting by using
712 	 * the <code>Cache-Control</code> header. If this is set to <code>null</code>, the Cache-Control
713 	 * header will be ignored.
714 	 * </p>
715 	 */
716 	public Long getReuseCachedSearchResultsForMillis() {
717 		return myReuseCachedSearchResultsForMillis;
718 	}
719 
720 	/**
721 	 * If set to a non {@literal null} value (default is {@link #DEFAULT_REUSE_CACHED_SEARCH_RESULTS_FOR_MILLIS non null})
722 	 * if an identical search is requested multiple times within this window, the same results will be returned
723 	 * to multiple queries. For example, if this value is set to 1 minute and a client searches for all
724 	 * patients named "smith", and then a second client also performs the same search within 1 minute,
725 	 * the same cached results will be returned.
726 	 * <p>
727 	 * This approach can improve performance, especially under heavy load, but can also mean that
728 	 * searches may potentially return slightly out-of-date results.
729 	 * </p>
730 	 * <p>
731 	 * Note that if this is set to a non-null value, clients may override this setting by using
732 	 * the <code>Cache-Control</code> header. If this is set to <code>null</code>, the Cache-Control
733 	 * header will be ignored.
734 	 * </p>
735 	 */
736 	public void setReuseCachedSearchResultsForMillis(Long theReuseCachedSearchResultsForMillis) {
737 		myReuseCachedSearchResultsForMillis = theReuseCachedSearchResultsForMillis;
738 	}
739 
740 	/**
741 	 * Specifies the duration in minutes for which values will be retained after being
742 	 * written to the terminology translation cache. Defaults to 60.
743 	 */
744 	public Long getTranslationCachesExpireAfterWriteInMinutes() {
745 		return myTranslationCachesExpireAfterWriteInMinutes;
746 	}
747 
748 	/**
749 	 * Specifies the duration in minutes for which values will be retained after being
750 	 * written to the terminology translation cache. Defaults to 60.
751 	 */
752 	public void setTranslationCachesExpireAfterWriteInMinutes(Long translationCachesExpireAfterWriteInMinutes) {
753 		myTranslationCachesExpireAfterWriteInMinutes = translationCachesExpireAfterWriteInMinutes;
754 	}
755 
756 	/**
757 	 * This setting may be used to advise the server that any references found in
758 	 * resources that have any of the base URLs given here will be replaced with
759 	 * simple local references.
760 	 * <p>
761 	 * For example, if the set contains the value <code>http://example.com/base/</code>;
762 	 * and a resource is submitted to the server that contains a reference to
763 	 * <code>http://example.com/base/Patient/1</code>, the server will automatically
764 	 * convert this reference to <code>Patient/1</code>
765 	 * </p>
766 	 * <p>
767 	 * Note that this property has different behaviour from {@link DaoConfig#getTreatReferencesAsLogical()}
768 	 * </p>
769 	 *
770 	 * @see #getTreatReferencesAsLogical()
771 	 */
772 	public Set<String> getTreatBaseUrlsAsLocal() {
773 		return myTreatBaseUrlsAsLocal;
774 	}
775 
776 	/**
777 	 * This setting may be used to advise the server that any references found in
778 	 * resources that have any of the base URLs given here will be replaced with
779 	 * simple local references.
780 	 * <p>
781 	 * For example, if the set contains the value <code>http://example.com/base/</code>;
782 	 * and a resource is submitted to the server that contains a reference to
783 	 * <code>http://example.com/base/Patient/1</code>, the server will automatically
784 	 * convert this reference to <code>Patient/1</code>
785 	 * </p>
786 	 *
787 	 * @param theTreatBaseUrlsAsLocal The set of base URLs. May be <code>null</code>, which
788 	 *                                means no references will be treated as external
789 	 */
790 	public void setTreatBaseUrlsAsLocal(Set<String> theTreatBaseUrlsAsLocal) {
791 		if (theTreatBaseUrlsAsLocal != null) {
792 			for (String next : theTreatBaseUrlsAsLocal) {
793 				validateTreatBaseUrlsAsLocal(next);
794 			}
795 		}
796 
797 		HashSet<String> treatBaseUrlsAsLocal = new HashSet<String>();
798 		for (String next : ObjectUtils.defaultIfNull(theTreatBaseUrlsAsLocal, new HashSet<String>())) {
799 			while (next.endsWith("/")) {
800 				next = next.substring(0, next.length() - 1);
801 			}
802 			treatBaseUrlsAsLocal.add(next);
803 		}
804 		myTreatBaseUrlsAsLocal = treatBaseUrlsAsLocal;
805 	}
806 
807 	/**
808 	 * This setting may be used to advise the server that any references found in
809 	 * resources that have any of the base URLs given here will be treated as logical
810 	 * references instead of being treated as real references.
811 	 * <p>
812 	 * A logical reference is a reference which is treated as an identifier, and
813 	 * does not neccesarily resolve. See <a href="http://hl7.org/fhir/references.html">references</a> for
814 	 * a description of logical references. For example, the valueset
815 	 * <a href="http://hl7.org/fhir/valueset-quantity-comparator.html">valueset-quantity-comparator</a> is a logical
816 	 * reference.
817 	 * </p>
818 	 * <p>
819 	 * Values for this field may take either of the following forms:
820 	 * </p>
821 	 * <ul>
822 	 * <li><code>http://example.com/some-url</code> <b>(will be matched exactly)</b></li>
823 	 * <li><code>http://example.com/some-base*</code> <b>(will match anything beginning with the part before the *)</b></li>
824 	 * </ul>
825 	 *
826 	 * @see #DEFAULT_LOGICAL_BASE_URLS Default values for this property
827 	 */
828 	public Set<String> getTreatReferencesAsLogical() {
829 		return myTreatReferencesAsLogical;
830 	}
831 
832 	/**
833 	 * This setting may be used to advise the server that any references found in
834 	 * resources that have any of the base URLs given here will be treated as logical
835 	 * references instead of being treated as real references.
836 	 * <p>
837 	 * A logical reference is a reference which is treated as an identifier, and
838 	 * does not neccesarily resolve. See <a href="http://hl7.org/fhir/references.html">references</a> for
839 	 * a description of logical references. For example, the valueset
840 	 * <a href="http://hl7.org/fhir/valueset-quantity-comparator.html">valueset-quantity-comparator</a> is a logical
841 	 * reference.
842 	 * </p>
843 	 * <p>
844 	 * Values for this field may take either of the following forms:
845 	 * </p>
846 	 * <ul>
847 	 * <li><code>http://example.com/some-url</code> <b>(will be matched exactly)</b></li>
848 	 * <li><code>http://example.com/some-base*</code> <b>(will match anything beginning with the part before the *)</b></li>
849 	 * </ul>
850 	 *
851 	 * @see #DEFAULT_LOGICAL_BASE_URLS Default values for this property
852 	 */
853 	public DaoConfig setTreatReferencesAsLogical(Set<String> theTreatReferencesAsLogical) {
854 		myTreatReferencesAsLogical = theTreatReferencesAsLogical;
855 		return this;
856 	}
857 
858 	/**
859 	 * If enabled, the server will support the use of :contains searches,
860 	 * which are helpful but can have adverse effects on performance.
861 	 * <p>
862 	 * Default is <code>false</code> (Note that prior to HAPI FHIR
863 	 * 3.5.0 the default was <code>true</code>)
864 	 * </p>
865 	 * <p>
866 	 * Note: If you change this value after data already has
867 	 * already been stored in the database, you must for a reindexing
868 	 * of all data in the database or resources may not be
869 	 * searchable.
870 	 * </p>
871 	 */
872 	public boolean isAllowContainsSearches() {
873 		return myAllowContainsSearches;
874 	}
875 
876 	/**
877 	 * If enabled, the server will support the use of :contains searches,
878 	 * which are helpful but can have adverse effects on performance.
879 	 * <p>
880 	 * Default is <code>false</code> (Note that prior to HAPI FHIR
881 	 * 3.5.0 the default was <code>true</code>)
882 	 * </p>
883 	 * <p>
884 	 * Note: If you change this value after data already has
885 	 * already been stored in the database, you must for a reindexing
886 	 * of all data in the database or resources may not be
887 	 * searchable.
888 	 * </p>
889 	 */
890 	public void setAllowContainsSearches(boolean theAllowContainsSearches) {
891 		this.myAllowContainsSearches = theAllowContainsSearches;
892 	}
893 
894 	/**
895 	 * If set to <code>true</code> (default is <code>false</code>) the server will allow
896 	 * resources to have references to external servers. For example if this server is
897 	 * running at <code>http://example.com/fhir</code> and this setting is set to
898 	 * <code>true</code> the server will allow a Patient resource to be saved with a
899 	 * Patient.organization value of <code>http://foo.com/Organization/1</code>.
900 	 * <p>
901 	 * Under the default behaviour if this value has not been changed, the above
902 	 * resource would be rejected by the server because it requires all references
903 	 * to be resolvable on the local server.
904 	 * </p>
905 	 * <p>
906 	 * Note that external references will be indexed by the server and may be searched
907 	 * (e.g. <code>Patient:organization</code>), but
908 	 * chained searches (e.g. <code>Patient:organization.name</code>) will not work across
909 	 * these references.
910 	 * </p>
911 	 * <p>
912 	 * It is recommended to also set {@link #setTreatBaseUrlsAsLocal(Set)} if this value
913 	 * is set to <code>true</code>
914 	 * </p>
915 	 *
916 	 * @see #setTreatBaseUrlsAsLocal(Set)
917 	 * @see #setAllowExternalReferences(boolean)
918 	 */
919 	public boolean isAllowExternalReferences() {
920 		return myAllowExternalReferences;
921 	}
922 
923 	/**
924 	 * If set to <code>true</code> (default is <code>false</code>) the server will allow
925 	 * resources to have references to external servers. For example if this server is
926 	 * running at <code>http://example.com/fhir</code> and this setting is set to
927 	 * <code>true</code> the server will allow a Patient resource to be saved with a
928 	 * Patient.organization value of <code>http://foo.com/Organization/1</code>.
929 	 * <p>
930 	 * Under the default behaviour if this value has not been changed, the above
931 	 * resource would be rejected by the server because it requires all references
932 	 * to be resolvable on the local server.
933 	 * </p>
934 	 * <p>
935 	 * Note that external references will be indexed by the server and may be searched
936 	 * (e.g. <code>Patient:organization</code>), but
937 	 * chained searches (e.g. <code>Patient:organization.name</code>) will not work across
938 	 * these references.
939 	 * </p>
940 	 * <p>
941 	 * It is recommended to also set {@link #setTreatBaseUrlsAsLocal(Set)} if this value
942 	 * is set to <code>true</code>
943 	 * </p>
944 	 *
945 	 * @see #setTreatBaseUrlsAsLocal(Set)
946 	 * @see #setAllowExternalReferences(boolean)
947 	 */
948 	public void setAllowExternalReferences(boolean theAllowExternalReferences) {
949 		myAllowExternalReferences = theAllowExternalReferences;
950 	}
951 
952 	/**
953 	 * @see #setAllowInlineMatchUrlReferences(boolean)
954 	 */
955 	public boolean isAllowInlineMatchUrlReferences() {
956 		return myAllowInlineMatchUrlReferences;
957 	}
958 
959 	/**
960 	 * Should references containing match URLs be resolved and replaced in create and update operations. For
961 	 * example, if this property is set to true and a resource is created containing a reference
962 	 * to "Patient?identifier=12345", this is reference match URL will be resolved and replaced according
963 	 * to the usual match URL rules.
964 	 * <p>
965 	 * Default is {@literal true} beginning in HAPI FHIR 2.4, since this
966 	 * feature is now specified in the FHIR specification. (Previously it
967 	 * was an experimental/rpposed feature)
968 	 * </p>
969 	 *
970 	 * @since 1.5
971 	 */
972 	public void setAllowInlineMatchUrlReferences(boolean theAllowInlineMatchUrlReferences) {
973 		myAllowInlineMatchUrlReferences = theAllowInlineMatchUrlReferences;
974 	}
975 
976 	public boolean isAllowMultipleDelete() {
977 		return myAllowMultipleDelete;
978 	}
979 
980 	public void setAllowMultipleDelete(boolean theAllowMultipleDelete) {
981 		myAllowMultipleDelete = theAllowMultipleDelete;
982 	}
983 
984 	/**
985 	 * When creating or updating a resource: If this property is set to <code>true</code>
986 	 * (default is <code>false</code>), if the resource has a reference to another resource
987 	 * on the local server but that reference does not exist, a placeholder resource will be
988 	 * created.
989 	 * <p>
990 	 * In other words, if an observation with subject <code>Patient/FOO</code> is created, but
991 	 * there is no resource called <code>Patient/FOO</code> on the server, this property causes
992 	 * an empty patient with ID "FOO" to be created in order to prevent this operation
993 	 * from failing.
994 	 * </p>
995 	 * <p>
996 	 * This property can be useful in cases where replication between two servers is wanted.
997 	 * Note however that references containing purely numeric IDs will not be auto-created
998 	 * as they are never allowed to be client supplied in HAPI FHIR JPA.
999 	 * </p>
1000 	 */
1001 	public boolean isAutoCreatePlaceholderReferenceTargets() {
1002 		return myAutoCreatePlaceholderReferenceTargets;
1003 	}
1004 
1005 	/**
1006 	 * When creating or updating a resource: If this property is set to <code>true</code>
1007 	 * (default is <code>false</code>), if the resource has a reference to another resource
1008 	 * on the local server but that reference does not exist, a placeholder resource will be
1009 	 * created.
1010 	 * <p>
1011 	 * In other words, if an observation with subject <code>Patient/FOO</code> is created, but
1012 	 * there is no resource called <code>Patient/FOO</code> on the server, this property causes
1013 	 * an empty patient with ID "FOO" to be created in order to prevent this operation
1014 	 * from failing.
1015 	 * </p>
1016 	 * <p>
1017 	 * This property can be useful in cases where replication between two servers is wanted.
1018 	 * Note however that references containing purely numeric IDs will not be auto-created
1019 	 * as they are never allowed to be client supplied in HAPI FHIR JPA.
1020 	 * </p>
1021 	 */
1022 	public void setAutoCreatePlaceholderReferenceTargets(boolean theAutoCreatePlaceholderReferenceTargets) {
1023 		myAutoCreatePlaceholderReferenceTargets = theAutoCreatePlaceholderReferenceTargets;
1024 	}
1025 
1026 	/**
1027 	 * If set to {@code true} the default search params (i.e. the search parameters that are
1028 	 * defined by the FHIR specification itself) may be overridden by uploading search
1029 	 * parameters to the server with the same code as the built-in search parameter.
1030 	 * <p>
1031 	 * This can be useful if you want to be able to disable or alter
1032 	 * the behaviour of the default search parameters.
1033 	 * </p>
1034 	 * <p>
1035 	 * The default value for this setting is {@code false}
1036 	 * </p>
1037 	 */
1038 	public boolean isDefaultSearchParamsCanBeOverridden() {
1039 		return myDefaultSearchParamsCanBeOverridden;
1040 	}
1041 
1042 	/**
1043 	 * If set to {@code true} the default search params (i.e. the search parameters that are
1044 	 * defined by the FHIR specification itself) may be overridden by uploading search
1045 	 * parameters to the server with the same code as the built-in search parameter.
1046 	 * <p>
1047 	 * This can be useful if you want to be able to disable or alter
1048 	 * the behaviour of the default search parameters.
1049 	 * </p>
1050 	 * <p>
1051 	 * The default value for this setting is {@code false}
1052 	 * </p>
1053 	 */
1054 	public void setDefaultSearchParamsCanBeOverridden(boolean theDefaultSearchParamsCanBeOverridden) {
1055 		myDefaultSearchParamsCanBeOverridden = theDefaultSearchParamsCanBeOverridden;
1056 	}
1057 
1058 	/**
1059 	 * If set to <code>false</code> (default is <code>true</code>) resources will be permitted to be
1060 	 * deleted even if other resources currently contain references to them.
1061 	 * <p>
1062 	 * This property can cause confusing results for clients of the server since searches, includes,
1063 	 * and other FHIR features may not behave as expected when referential integrity is not
1064 	 * preserved. Use this feature with caution.
1065 	 * </p>
1066 	 */
1067 	public boolean isEnforceReferentialIntegrityOnDelete() {
1068 		return myEnforceReferentialIntegrityOnDelete;
1069 	}
1070 
1071 	/**
1072 	 * If set to <code>false</code> (default is <code>true</code>) resources will be permitted to be
1073 	 * deleted even if other resources currently contain references to them.
1074 	 * <p>
1075 	 * This property can cause confusing results for clients of the server since searches, includes,
1076 	 * and other FHIR features may not behave as expected when referential integrity is not
1077 	 * preserved. Use this feature with caution.
1078 	 * </p>
1079 	 */
1080 	public void setEnforceReferentialIntegrityOnDelete(boolean theEnforceReferentialIntegrityOnDelete) {
1081 		myEnforceReferentialIntegrityOnDelete = theEnforceReferentialIntegrityOnDelete;
1082 	}
1083 
1084 	/**
1085 	 * If set to <code>false</code> (default is <code>true</code>) resources will be permitted to be
1086 	 * created or updated even if they contain references to local resources that do not exist.
1087 	 * <p>
1088 	 * For example, if a patient contains a reference to managing organization <code>Organization/FOO</code>
1089 	 * but FOO is not a valid ID for an organization on the server, the operation will be blocked unless
1090 	 * this propery has been set to <code>false</code>
1091 	 * </p>
1092 	 * <p>
1093 	 * This property can cause confusing results for clients of the server since searches, includes,
1094 	 * and other FHIR features may not behave as expected when referential integrity is not
1095 	 * preserved. Use this feature with caution.
1096 	 * </p>
1097 	 */
1098 	public boolean isEnforceReferentialIntegrityOnWrite() {
1099 		return myEnforceReferentialIntegrityOnWrite;
1100 	}
1101 
1102 	/**
1103 	 * If set to <code>false</code> (default is <code>true</code>) resources will be permitted to be
1104 	 * created or updated even if they contain references to local resources that do not exist.
1105 	 * <p>
1106 	 * For example, if a patient contains a reference to managing organization <code>Organization/FOO</code>
1107 	 * but FOO is not a valid ID for an organization on the server, the operation will be blocked unless
1108 	 * this propery has been set to <code>false</code>
1109 	 * </p>
1110 	 * <p>
1111 	 * This property can cause confusing results for clients of the server since searches, includes,
1112 	 * and other FHIR features may not behave as expected when referential integrity is not
1113 	 * preserved. Use this feature with caution.
1114 	 * </p>
1115 	 */
1116 	public void setEnforceReferentialIntegrityOnWrite(boolean theEnforceReferentialIntegrityOnWrite) {
1117 		myEnforceReferentialIntegrityOnWrite = theEnforceReferentialIntegrityOnWrite;
1118 	}
1119 
1120 	/**
1121 	 * If this is set to <code>false</code> (default is <code>true</code>) the stale search deletion
1122 	 * task will be disabled (meaning that search results will be retained in the database indefinitely). USE WITH CAUTION.
1123 	 * <p>
1124 	 * This feature is useful if you want to define your own process for deleting these (e.g. because
1125 	 * you are running in a cluster)
1126 	 * </p>
1127 	 */
1128 	public boolean isExpireSearchResults() {
1129 		return myDeleteStaleSearches;
1130 	}
1131 
1132 	/**
1133 	 * If this is set to <code>false</code> (default is <code>true</code>) the stale search deletion
1134 	 * task will be disabled (meaning that search results will be retained in the database indefinitely). USE WITH CAUTION.
1135 	 * <p>
1136 	 * This feature is useful if you want to define your own process for deleting these (e.g. because
1137 	 * you are running in a cluster)
1138 	 * </p>
1139 	 */
1140 	public void setExpireSearchResults(boolean theDeleteStaleSearches) {
1141 		myDeleteStaleSearches = theDeleteStaleSearches;
1142 	}
1143 
1144 	/**
1145 	 * If set to <code>true</code> (default is <code>false</code>), the $expunge operation
1146 	 * will be enabled on this server. This operation is potentially dangerous since it allows
1147 	 * a client to physically delete data in a way that can not be recovered (without resorting
1148 	 * to backups).
1149 	 * <p>
1150 	 * It is recommended to not enable this setting without appropriate security
1151 	 * in place on your server to prevent non-administrators from using this
1152 	 * operation.
1153 	 * </p>
1154 	 */
1155 	public boolean isExpungeEnabled() {
1156 		return myExpungeEnabled;
1157 	}
1158 
1159 	/**
1160 	 * If set to <code>true</code> (default is <code>false</code>), the $expunge operation
1161 	 * will be enabled on this server. This operation is potentially dangerous since it allows
1162 	 * a client to physically delete data in a way that can not be recovered (without resorting
1163 	 * to backups).
1164 	 * <p>
1165 	 * It is recommended to not enable this setting without appropriate security
1166 	 * in place on your server to prevent non-administrators from using this
1167 	 * operation.
1168 	 * </p>
1169 	 */
1170 	public void setExpungeEnabled(boolean theExpungeEnabled) {
1171 		myExpungeEnabled = theExpungeEnabled;
1172 	}
1173 
1174 	/**
1175 	 * Should contained IDs be indexed the same way that non-contained IDs are (default is
1176 	 * <code>true</code>)
1177 	 */
1178 	public boolean isIndexContainedResources() {
1179 		return myIndexContainedResources;
1180 	}
1181 
1182 	/**
1183 	 * Should contained IDs be indexed the same way that non-contained IDs are (default is
1184 	 * <code>true</code>)
1185 	 */
1186 	public void setIndexContainedResources(boolean theIndexContainedResources) {
1187 		myIndexContainedResources = theIndexContainedResources;
1188 	}
1189 
1190 	/**
1191 	 * Should resources be marked as needing reindexing when a
1192 	 * SearchParameter resource is added or changed. This should generally
1193 	 * be true (which is the default)
1194 	 */
1195 	public boolean isMarkResourcesForReindexingUponSearchParameterChange() {
1196 		return myMarkResourcesForReindexingUponSearchParameterChange;
1197 	}
1198 
1199 	/**
1200 	 * Should resources be marked as needing reindexing when a
1201 	 * SearchParameter resource is added or changed. This should generally
1202 	 * be true (which is the default)
1203 	 */
1204 	public void setMarkResourcesForReindexingUponSearchParameterChange(boolean theMarkResourcesForReindexingUponSearchParameterChange) {
1205 		myMarkResourcesForReindexingUponSearchParameterChange = theMarkResourcesForReindexingUponSearchParameterChange;
1206 	}
1207 
1208 	public boolean isSchedulingDisabled() {
1209 		return mySchedulingDisabled;
1210 	}
1211 
1212 	public void setSchedulingDisabled(boolean theSchedulingDisabled) {
1213 		mySchedulingDisabled = theSchedulingDisabled;
1214 	}
1215 
1216 	/**
1217 	 * If set to {@literal true} (default is true), if a client performs an update which does not actually
1218 	 * result in any chance to a given resource (e.g. an update where the resource body matches the
1219 	 * existing resource body in the database) the operation will succeed but a new version (and corresponding history
1220 	 * entry) will not actually be created. The existing resource version will be returned to the client.
1221 	 * <p>
1222 	 * If set to {@literal false}, all updates will result in the creation of a new version
1223 	 * </p>
1224 	 */
1225 	public boolean isSuppressUpdatesWithNoChange() {
1226 		return mySuppressUpdatesWithNoChange;
1227 	}
1228 
1229 	/**
1230 	 * If set to {@literal true} (default is true), if a client performs an update which does not actually
1231 	 * result in any chance to a given resource (e.g. an update where the resource body matches the
1232 	 * existing resource body in the database) the operation will succeed but a new version (and corresponding history
1233 	 * entry) will not actually be created. The existing resource version will be returned to the client.
1234 	 * <p>
1235 	 * If set to {@literal false}, all updates will result in the creation of a new version
1236 	 * </p>
1237 	 */
1238 	public void setSuppressUpdatesWithNoChange(boolean theSuppressUpdatesWithNoChange) {
1239 		mySuppressUpdatesWithNoChange = theSuppressUpdatesWithNoChange;
1240 
1241 	}
1242 
1243 	/**
1244 	 * When using {@link #setUniqueIndexesEnabled(boolean) unique indexes}, if this
1245 	 * setting is set to <code>true</code> (default is <code>true</code>) the system
1246 	 * will test for the existence of a particular unique index value prior to saving
1247 	 * a new one.
1248 	 * <p>
1249 	 * This causes friendlier error messages to be generated, but adds an
1250 	 * extra round-trip to the database for eavh save so it can cause
1251 	 * a small performance hit.
1252 	 * </p>
1253 	 */
1254 	public boolean isUniqueIndexesCheckedBeforeSave() {
1255 		return myUniqueIndexesCheckedBeforeSave;
1256 	}
1257 
1258 	/**
1259 	 * When using {@link #setUniqueIndexesEnabled(boolean) unique indexes}, if this
1260 	 * setting is set to <code>true</code> (default is <code>true</code>) the system
1261 	 * will test for the existence of a particular unique index value prior to saving
1262 	 * a new one.
1263 	 * <p>
1264 	 * This causes friendlier error messages to be generated, but adds an
1265 	 * extra round-trip to the database for each save so it can cause
1266 	 * a small performance hit.
1267 	 * </p>
1268 	 */
1269 	public void setUniqueIndexesCheckedBeforeSave(boolean theUniqueIndexesCheckedBeforeSave) {
1270 		myUniqueIndexesCheckedBeforeSave = theUniqueIndexesCheckedBeforeSave;
1271 	}
1272 
1273 	/**
1274 	 * If set to <code>true</code> (default is <code>true</code>), indexes will be
1275 	 * created for search parameters marked as {@link JpaConstants#EXT_SP_UNIQUE}.
1276 	 * This is a HAPI FHIR specific extension which can be used to specify that no more than one
1277 	 * resource can exist which matches a given criteria, using a database constraint to
1278 	 * enforce this.
1279 	 */
1280 	public boolean isUniqueIndexesEnabled() {
1281 		return myUniqueIndexesEnabled;
1282 	}
1283 
1284 	/**
1285 	 * If set to <code>true</code> (default is <code>true</code>), indexes will be
1286 	 * created for search parameters marked as {@link JpaConstants#EXT_SP_UNIQUE}.
1287 	 * This is a HAPI FHIR specific extension which can be used to specify that no more than one
1288 	 * resource can exist which matches a given criteria, using a database constraint to
1289 	 * enforce this.
1290 	 */
1291 	public void setUniqueIndexesEnabled(boolean theUniqueIndexesEnabled) {
1292 		myUniqueIndexesEnabled = theUniqueIndexesEnabled;
1293 	}
1294 
1295 	/**
1296 	 * If <code>true</code> (default is <code>true</code>), before allowing a
1297 	 * SearchParameter resource to be stored (create, update, etc.) the
1298 	 * expression will be performed against an empty resource to ensure that
1299 	 * the FHIRPath executor is able to process it.
1300 	 * <p>
1301 	 * This should proabably always be set to true, but is configurable
1302 	 * in order to support some unit tests.
1303 	 * </p>
1304 	 */
1305 	public boolean isValidateSearchParameterExpressionsOnSave() {
1306 		return myValidateSearchParameterExpressionsOnSave;
1307 	}
1308 
1309 	/**
1310 	 * If <code>true</code> (default is <code>true</code>), before allowing a
1311 	 * SearchParameter resource to be stored (create, update, etc.) the
1312 	 * expression will be performed against an empty resource to ensure that
1313 	 * the FHIRPath executor is able to process it.
1314 	 * <p>
1315 	 * This should proabably always be set to true, but is configurable
1316 	 * in order to support some unit tests.
1317 	 * </p>
1318 	 */
1319 	public void setValidateSearchParameterExpressionsOnSave(boolean theValidateSearchParameterExpressionsOnSave) {
1320 		myValidateSearchParameterExpressionsOnSave = theValidateSearchParameterExpressionsOnSave;
1321 	}
1322 
1323 	/**
1324 	 * Do not call this method, it exists only for legacy reasons. It
1325 	 * will be removed in a future version. Configure the page size on your
1326 	 * paging provider instead.
1327 	 *
1328 	 * @deprecated This method does not do anything. Configure the page size on your
1329 	 * paging provider instead. Deprecated in HAPI FHIR 2.3 (Jan 2017)
1330 	 */
1331 	@Deprecated
1332 	public void setHardSearchLimit(int theHardSearchLimit) {
1333 		// this method does nothing
1334 	}
1335 
1336 	/**
1337 	 * This is the maximum number of resources that will be added to a single page of returned resources. Because of
1338 	 * includes with wildcards and other possibilities it is possible for a client to make requests that include very
1339 	 * large amounts of data, so this hard limit can be imposed to prevent runaway requests.
1340 	 *
1341 	 * @deprecated Deprecated in HAPI FHIR 3.2.0 as this method doesn't actually do anything
1342 	 */
1343 	@Deprecated
1344 	public void setIncludeLimit(@SuppressWarnings("unused") int theIncludeLimit) {
1345 		// nothing
1346 	}
1347 
1348 	/**
1349 	 * @deprecated As of HAPI FHIR 3.0.0, subscriptions no longer use polling for
1350 	 * detecting changes, so this setting has no effect
1351 	 */
1352 	@Deprecated
1353 	public void setSubscriptionEnabled(boolean theSubscriptionEnabled) {
1354 		// nothing
1355 	}
1356 
1357 	/**
1358 	 * @deprecated As of HAPI FHIR 3.0.0, subscriptions no longer use polling for
1359 	 * detecting changes, so this setting has no effect
1360 	 */
1361 	@Deprecated
1362 	public void setSubscriptionPollDelay(long theSubscriptionPollDelay) {
1363 		// ignore
1364 	}
1365 
1366 	/**
1367 	 * @deprecated As of HAPI FHIR 3.0.0, subscriptions no longer use polling for
1368 	 * detecting changes, so this setting has no effect
1369 	 */
1370 	@Deprecated
1371 	public void setSubscriptionPurgeInactiveAfterMillis(Long theMillis) {
1372 		// ignore
1373 	}
1374 
1375 	public void setSubscriptionPurgeInactiveAfterSeconds(int theSeconds) {
1376 		setSubscriptionPurgeInactiveAfterMillis(theSeconds * DateUtils.MILLIS_PER_SECOND);
1377 	}
1378 
1379 	/**
1380 	 * This setting sets the number of search results to prefetch. For example, if this list
1381 	 * is set to [100, 1000, -1] then the server will initially load 100 results and not
1382 	 * attempt to load more. If the user requests subsequent page(s) of results and goes
1383 	 * past 100 results, the system will load the next 900 (up to the following threshold of 1000).
1384 	 * The system will progressively work through these thresholds.
1385 	 *
1386 	 * <p>
1387 	 * A threshold of -1 means to load all results. Note that if the final threshold is a
1388 	 * number other than <code>-1</code>, the system will never prefetch more than the
1389 	 * given number.
1390 	 * </p>
1391 	 */
1392 	public List<Integer> getSearchPreFetchThresholds() {
1393 		return mySearchPreFetchThresholds;
1394 	}
1395 
1396 	/**
1397 	 * This setting sets the number of search results to prefetch. For example, if this list
1398 	 * is set to [100, 1000, -1] then the server will initially load 100 results and not
1399 	 * attempt to load more. If the user requests subsequent page(s) of results and goes
1400 	 * past 100 results, the system will load the next 900 (up to the following threshold of 1000).
1401 	 * The system will progressively work through these thresholds.
1402 	 *
1403 	 * <p>
1404 	 * A threshold of -1 means to load all results. Note that if the final threshold is a
1405 	 * number other than <code>-1</code>, the system will never prefetch more than the
1406 	 * given number.
1407 	 * </p>
1408 	 */
1409 	public void setSearchPreFetchThresholds(List<Integer> thePreFetchThresholds) {
1410 		Validate.isTrue(thePreFetchThresholds.size() > 0, "thePreFetchThresholds must not be empty");
1411 		int last = 0;
1412 		for (Integer nextInteger : thePreFetchThresholds) {
1413 			int nextInt = nextInteger.intValue();
1414 			Validate.isTrue(nextInt > 0 || nextInt == -1, nextInt + " is not a valid prefetch threshold");
1415 			Validate.isTrue(nextInt != last, "Prefetch thresholds must be sequential");
1416 			Validate.isTrue(nextInt > last || nextInt == -1, "Prefetch thresholds must be sequential");
1417 			Validate.isTrue(last != -1, "Prefetch thresholds must be sequential");
1418 			last = nextInt;
1419 		}
1420 		mySearchPreFetchThresholds = thePreFetchThresholds;
1421 	}
1422 
1423 	/**
1424 	 * If set to <code>true</code> (default is false) the server will not use
1425 	 * hash based searches. These searches were introduced in HAPI FHIR 3.5.0
1426 	 * and are the new default way of searching. However they require a very
1427 	 * large data migration if an existing system has a large amount of data
1428 	 * so this setting can be used to use the old search mechanism while data
1429 	 * is migrated.
1430 	 *
1431 	 * @since 3.6.0
1432 	 */
1433 	public boolean getDisableHashBasedSearches() {
1434 		return myDisableHashBasedSearches;
1435 	}
1436 
1437 	/**
1438 	 * If set to <code>true</code> (default is false) the server will not use
1439 	 * hash based searches. These searches were introduced in HAPI FHIR 3.5.0
1440 	 * and are the new default way of searching. However they require a very
1441 	 * large data migration if an existing system has a large amount of data
1442 	 * so this setting can be used to use the old search mechanism while data
1443 	 * is migrated.
1444 	 *
1445 	 * @since 3.6.0
1446 	 */
1447 	public void setDisableHashBasedSearches(boolean theDisableHashBasedSearches) {
1448 		myDisableHashBasedSearches = theDisableHashBasedSearches;
1449 	}
1450 
1451 	public enum IndexEnabledEnum {
1452 		ENABLED,
1453 		DISABLED
1454 	}
1455 
1456 	public enum IdStrategyEnum {
1457 		/**
1458 		 * This strategy is the default strategy, and it simply uses a sequential
1459 		 * numeric ID for each newly created resource.
1460 		 */
1461 		SEQUENTIAL_NUMERIC,
1462 		/**
1463 		 * Each resource will receive a randomly generated UUID
1464 		 */
1465 		UUID
1466 	}
1467 
1468 	public enum ClientIdStrategyEnum {
1469 		/**
1470 		 * Clients are not allowed to supply IDs for resources that do not
1471 		 * already exist
1472 		 */
1473 		NOT_ALLOWED,
1474 
1475 		/**
1476 		 * Clients may supply IDs but these IDs are not permitted to be purely
1477 		 * numeric. In other words, values such as "A", "A1" and "000A" would be considered
1478 		 * valid but "123" would not.
1479 		 * <p><b>This is the default setting.</b></p>
1480 		 */
1481 		ALPHANUMERIC,
1482 
1483 		/**
1484 		 * Clients may supply any ID including purely numeric IDs. Note that this setting should
1485 		 * only be set on an empty database, or on a database that has always had this setting
1486 		 * set as it causes a "forced ID" to be used for all resources.
1487 		 * <p>
1488 		 * Note that if you use this setting, it is highly recommended that you also
1489 		 * set the {@link #setResourceServerIdStrategy(IdStrategyEnum) ResourceServerIdStrategy}
1490 		 * to {@link IdStrategyEnum#UUID} in order to avoid any potential for conflicts. Otherwise
1491 		 * a database sequence will be used to generate IDs and these IDs can conflict with
1492 		 * client-assigned numeric IDs.
1493 		 * </P>
1494 		 */
1495 		ANY
1496 	}
1497 
1498 	private static void validateTreatBaseUrlsAsLocal(String theUrl) {
1499 		Validate.notBlank(theUrl, "Base URL must not be null or empty");
1500 
1501 		int starIdx = theUrl.indexOf('*');
1502 		if (starIdx != -1) {
1503 			if (starIdx != theUrl.length() - 1) {
1504 				throw new IllegalArgumentException("Base URL wildcard character (*) can only appear at the end of the string: " + theUrl);
1505 			}
1506 		}
1507 
1508 	}
1509 
1510 }