001/*
002 * #%L
003 * HAPI FHIR - Core Library
004 * %%
005 * Copyright (C) 2014 - 2024 Smile CDR, Inc.
006 * %%
007 * Licensed under the Apache License, Version 2.0 (the "License");
008 * you may not use this file except in compliance with the License.
009 * You may obtain a copy of the License at
010 *
011 *      http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 * #L%
019 */
020package ca.uhn.fhir.context;
021
022import ca.uhn.fhir.parser.IParser;
023import ca.uhn.fhir.util.CollectionUtil;
024import jakarta.annotation.Nonnull;
025import jakarta.annotation.Nullable;
026
027import java.util.Collection;
028import java.util.Collections;
029import java.util.HashSet;
030import java.util.List;
031import java.util.Set;
032
033/**
034 * This object supplies default configuration to all {@link IParser parser} instances
035 * created by a given {@link FhirContext}. It is accessed using {@link FhirContext#getParserOptions()}
036 * and {@link FhirContext#setParserOptions(ParserOptions)}.
037 * <p>
038 * It is fine to share a ParserOptions instances across multiple context instances.
039 * </p>
040 */
041public class ParserOptions {
042
043        private boolean myStripVersionsFromReferences = true;
044        private Set<String> myDontStripVersionsFromReferencesAtPaths = Collections.emptySet();
045        private boolean myOverrideResourceIdWithBundleEntryFullUrl = true;
046        private boolean myAutoContainReferenceTargetsWithNoId = true;
047        private Set<String> myEncodeElementsForSummaryMode = null;
048        private Set<String> myDontEncodeElementsForSummaryMode = null;
049
050        /**
051         * If set to {@literal true} (which is the default), contained resources may be specified by
052         * populating the target (contained) resource directly in {@link org.hl7.fhir.instance.model.api.IBaseReference#setReference(String)}
053         * and the parser will automatically locate it and insert it into <code>Resource.contained</code> when
054         * serializing. This is convenient, but also imposes a performance cost when serializing large numbers
055         * of resources, so this can be disabled if it is not needed.
056         * <p>
057         * If disabled, only resources that are directly placed in <code>Resource.contained</code> will be
058         * serialized.
059         * </p>
060         *
061         * @since 5.7.0
062         */
063        public boolean isAutoContainReferenceTargetsWithNoId() {
064                return myAutoContainReferenceTargetsWithNoId;
065        }
066
067        /**
068         * If set to {@literal true} (which is the default), contained resources may be specified by
069         * populating the target (contained) resource directly in {@link org.hl7.fhir.instance.model.api.IBaseReference#setReference(String)}
070         * and the parser will automatically locate it and insert it into <code>Resource.contained</code> when
071         * serializing. This is convenient, but also imposes a performance cost when serializing large numbers
072         * of resources, so this can be disabled if it is not needed.
073         * <p>
074         * If disabled, only resources that are directly placed in <code>Resource.contained</code> will be
075         * serialized.
076         * </p>
077         *
078         * @since 5.7.0
079         */
080        public void setAutoContainReferenceTargetsWithNoId(boolean theAllowAutoContainedReferences) {
081                myAutoContainReferenceTargetsWithNoId = theAllowAutoContainedReferences;
082        }
083
084        /**
085         * If set to <code>true<code> (which is the default), resource references containing a version
086         * will have the version removed when the resource is encoded. This is generally good behaviour because
087         * in most situations, references from one resource to another should be to the resource by ID, not
088         * by ID and version. In some cases though, it may be desirable to preserve the version in resource
089         * links. In that case, this value should be set to <code>false</code>.
090         *
091         * @return Returns the parser instance's configuration setting for stripping versions from resource references when
092         * encoding. Default is <code>true</code>.
093         */
094        public boolean isStripVersionsFromReferences() {
095                return myStripVersionsFromReferences;
096        }
097
098        /**
099         * If set to <code>true<code> (which is the default), resource references containing a version
100         * will have the version removed when the resource is encoded. This is generally good behaviour because
101         * in most situations, references from one resource to another should be to the resource by ID, not
102         * by ID and version. In some cases though, it may be desirable to preserve the version in resource
103         * links. In that case, this value should be set to <code>false</code>.
104         * <p>
105         * This method provides the ability to globally disable reference encoding. If finer-grained
106         * control is needed, use {@link #setDontStripVersionsFromReferencesAtPaths(String...)}
107         * </p>
108         *
109         * @param theStripVersionsFromReferences Set this to <code>false<code> to prevent the parser from removing
110         *                                       resource versions from references.
111         * @return Returns a reference to <code>this</code> parser so that method calls can be chained together
112         * @see #setDontStripVersionsFromReferencesAtPaths(String...)
113         */
114        public ParserOptions setStripVersionsFromReferences(boolean theStripVersionsFromReferences) {
115                myStripVersionsFromReferences = theStripVersionsFromReferences;
116                return this;
117        }
118
119        /**
120         * Returns the value supplied to {@link IParser#setDontStripVersionsFromReferencesAtPaths(String...)}
121         *
122         * @see #setDontStripVersionsFromReferencesAtPaths(String...)
123         * @see #setStripVersionsFromReferences(boolean)
124         */
125        public Set<String> getDontStripVersionsFromReferencesAtPaths() {
126                return myDontStripVersionsFromReferencesAtPaths;
127        }
128
129        /**
130         * If supplied value(s), any resource references at the specified paths will have their
131         * resource versions encoded instead of being automatically stripped during the encoding
132         * process. This setting has no effect on the parsing process.
133         * <p>
134         * This method provides a finer-grained level of control than {@link #setStripVersionsFromReferences(boolean)}
135         * and any paths specified by this method will be encoded even if {@link #setStripVersionsFromReferences(boolean)}
136         * has been set to <code>true</code> (which is the default)
137         * </p>
138         *
139         * @param thePaths A collection of paths for which the resource versions will not be removed automatically
140         *                 when serializing, e.g. "Patient.managingOrganization" or "AuditEvent.object.reference". Note that
141         *                 only resource name and field names with dots separating is allowed here (no repetition
142         *                 indicators, FluentPath expressions, etc.)
143         * @return Returns a reference to <code>this</code> parser so that method calls can be chained together
144         * @see #setStripVersionsFromReferences(boolean)
145         */
146        public ParserOptions setDontStripVersionsFromReferencesAtPaths(String... thePaths) {
147                if (thePaths == null) {
148                        setDontStripVersionsFromReferencesAtPaths((List<String>) null);
149                } else {
150                        setDontStripVersionsFromReferencesAtPaths(CollectionUtil.newSet(thePaths));
151                }
152                return this;
153        }
154
155        /**
156         * If supplied value(s), any resource references at the specified paths will have their
157         * resource versions encoded instead of being automatically stripped during the encoding
158         * process. This setting has no effect on the parsing process.
159         * <p>
160         * This method provides a finer-grained level of control than {@link #setStripVersionsFromReferences(boolean)}
161         * and any paths specified by this method will be encoded even if {@link #setStripVersionsFromReferences(boolean)}
162         * has been set to <code>true</code> (which is the default)
163         * </p>
164         *
165         * @param thePaths A collection of paths for which the resource versions will not be removed automatically
166         *                 when serializing, e.g. "Patient.managingOrganization" or "AuditEvent.object.reference". Note that
167         *                 only resource name and field names with dots separating is allowed here (no repetition
168         *                 indicators, FluentPath expressions, etc.)
169         * @return Returns a reference to <code>this</code> parser so that method calls can be chained together
170         * @see #setStripVersionsFromReferences(boolean)
171         */
172        @SuppressWarnings("unchecked")
173        public ParserOptions setDontStripVersionsFromReferencesAtPaths(Collection<String> thePaths) {
174                if (thePaths == null) {
175                        myDontStripVersionsFromReferencesAtPaths = Collections.emptySet();
176                } else if (thePaths instanceof HashSet) {
177                        myDontStripVersionsFromReferencesAtPaths = (Set<String>) ((HashSet<String>) thePaths).clone();
178                } else {
179                        myDontStripVersionsFromReferencesAtPaths = new HashSet<>(thePaths);
180                }
181                return this;
182        }
183
184        /**
185         * If set to <code>true</code> (which is the default), the Bundle.entry.fullUrl will override the Bundle.entry.resource's
186         * resource id if the fullUrl is defined. This behavior happens when parsing the source data into a Bundle object. Set this
187         * to <code>false</code> if this is not the desired behavior (e.g. the client code wishes to perform additional
188         * validation checks between the fullUrl and the resource id).
189         *
190         * @return Returns the parser instance's configuration setting for overriding resource ids with Bundle.entry.fullUrl when
191         * parsing the source data into a Bundle object. Default is <code>true</code>.
192         */
193        public boolean isOverrideResourceIdWithBundleEntryFullUrl() {
194                return myOverrideResourceIdWithBundleEntryFullUrl;
195        }
196
197        /**
198         * If set to <code>true</code> (which is the default), the Bundle.entry.fullUrl will override the Bundle.entry.resource's
199         * resource id if the fullUrl is defined. This behavior happens when parsing the source data into a Bundle object. Set this
200         * to <code>false</code> if this is not the desired behavior (e.g. the client code wishes to perform additional
201         * validation checks between the fullUrl and the resource id).
202         *
203         * @param theOverrideResourceIdWithBundleEntryFullUrl Set this to <code>false</code> to prevent the parser from overriding resource ids with the
204         *                                                    Bundle.entry.fullUrl
205         * @return Returns a reference to <code>this</code> parser so that method calls can be chained together
206         */
207        public ParserOptions setOverrideResourceIdWithBundleEntryFullUrl(
208                        boolean theOverrideResourceIdWithBundleEntryFullUrl) {
209                myOverrideResourceIdWithBundleEntryFullUrl = theOverrideResourceIdWithBundleEntryFullUrl;
210                return this;
211        }
212
213        /**
214         * This option specifies one or more elements that should be included when the parser is encoding
215         * a resource in {@link IParser#setSummaryMode(boolean) summary mode}, even if the element is not
216         * a part of the base FHIR specification's list of summary elements. Examples of valid values
217         * include:
218         * <ul>
219         * <li><b>Patient.maritalStatus</b> - Encode the entire maritalStatus CodeableConcept, even though Patient.maritalStatus is not a summary element</li>
220         * <li><b>Patient.maritalStatus.text</b> - Encode only the text component of the patient's maritalStatus</li>
221         * <li><b>*.text</b> - Encode the text element on any resource (only the very first position may contain a
222         * wildcard)</li>
223         * </ul>
224         *
225         * @see IParser#setSummaryMode(boolean)
226         * @see IParser#setEncodeElements(Set) Can be used to specify these values for an individual parser instance.
227         * @since 7.4.0
228         */
229        @SuppressWarnings({"UnusedReturnValue"})
230        @Nonnull
231        public ParserOptions setEncodeElementsForSummaryMode(@Nonnull String... theEncodeElements) {
232                return setEncodeElementsForSummaryMode(CollectionUtil.newSet(theEncodeElements));
233        }
234
235        /**
236         * This option specifies one or more elements that should be included when the parser is encoding
237         * a resource in {@link IParser#setSummaryMode(boolean) summary mode}, even if the element is not
238         * a part of the base FHIR specification's list of summary elements. Examples of valid values
239         * include:
240         * <ul>
241         * <li><b>Patient.maritalStatus</b> - Encode the entire maritalStatus CodeableConcept, even though Patient.maritalStatus is not a summary element</li>
242         * <li><b>Patient.maritalStatus.text</b> - Encode only the text component of the patient's maritalStatus</li>
243         * <li><b>*.text</b> - Encode the text element on any resource (only the very first position may contain a
244         * wildcard)</li>
245         * </ul>
246         *
247         * @see IParser#setSummaryMode(boolean)
248         * @see IParser#setEncodeElements(Set) Can be used to specify these values for an individual parser instance.
249         * @since 7.4.0
250         */
251        @Nonnull
252        public ParserOptions setEncodeElementsForSummaryMode(@Nullable Collection<String> theEncodeElements) {
253                Set<String> encodeElements = null;
254                if (theEncodeElements != null && !theEncodeElements.isEmpty()) {
255                        encodeElements = new HashSet<>(theEncodeElements);
256                }
257                myEncodeElementsForSummaryMode = encodeElements;
258                return this;
259        }
260
261        /**
262         * @return Returns the values provided to {@link #setEncodeElementsForSummaryMode(Collection)}
263         * or <code>null</code>
264         *
265         * @since 7.4.0
266         */
267        @Nullable
268        public Set<String> getEncodeElementsForSummaryMode() {
269                return myEncodeElementsForSummaryMode;
270        }
271
272        /**
273         * This option specifies one or more elements that should be excluded when the parser is encoding
274         * a resource in {@link IParser#setSummaryMode(boolean) summary mode}, even if the element is
275         * a part of the base FHIR specification's list of summary elements. Examples of valid values
276         * include:
277         * <ul>
278         * <li><b>Patient.name</b> - Do not include the patient's name</li>
279         * <li><b>Patient.name.family</b> - Do not include the patient's family name</li>
280         * <li><b>*.name</b> - Do not include the name element on any resource type</li>
281         * </ul>
282         *
283         * @see IParser#setSummaryMode(boolean)
284         * @see IParser#setDontEncodeElements(Collection) Can be used to specify these values for an individual parser instance.
285         * @since 7.4.0
286         */
287        @SuppressWarnings({"UnusedReturnValue"})
288        @Nonnull
289        public ParserOptions setDontEncodeElementsForSummaryMode(@Nonnull String... theEncodeElements) {
290                return setDontEncodeElementsForSummaryMode(CollectionUtil.newSet(theEncodeElements));
291        }
292
293        /**
294         * This option specifies one or more elements that should be excluded when the parser is encoding
295         * a resource in {@link IParser#setSummaryMode(boolean) summary mode}, even if the element is
296         * a part of the base FHIR specification's list of summary elements. Examples of valid values
297         * include:
298         * <ul>
299         * <li><b>Patient.name</b> - Do not include the patient's name</li>
300         * <li><b>Patient.name.family</b> - Do not include the patient's family name</li>
301         * <li><b>*.name</b> - Do not include the name element on any resource type</li>
302         * </ul>
303         *
304         * @see IParser#setSummaryMode(boolean)
305         * @see IParser#setDontEncodeElements(Collection) Can be used to specify these values for an individual parser instance.
306         * @since 7.4.0
307         */
308        @Nonnull
309        public ParserOptions setDontEncodeElementsForSummaryMode(@Nullable Collection<String> theDontEncodeElements) {
310                Set<String> dontEncodeElements = null;
311                if (theDontEncodeElements != null && !theDontEncodeElements.isEmpty()) {
312                        dontEncodeElements = new HashSet<>(theDontEncodeElements);
313                }
314                myDontEncodeElementsForSummaryMode = dontEncodeElements;
315                return this;
316        }
317
318        /**
319         * @return Returns the values provided to {@link #setDontEncodeElementsForSummaryMode(Collection)}
320         * or <code>null</code>
321         * @since 7.4.0
322         */
323        @Nullable
324        public Set<String> getDontEncodeElementsForSummaryMode() {
325                return myDontEncodeElementsForSummaryMode;
326        }
327}