001/*
002 * #%L
003 * HAPI FHIR - Core Library
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.model.api;
021
022import ca.uhn.fhir.i18n.Msg;
023import ca.uhn.fhir.model.api.annotation.Child;
024import ca.uhn.fhir.model.api.annotation.DatatypeDef;
025import ca.uhn.fhir.model.primitive.StringDt;
026import jakarta.annotation.Nullable;
027import org.apache.commons.lang3.Validate;
028import org.apache.commons.lang3.builder.ToStringBuilder;
029import org.apache.commons.lang3.builder.ToStringStyle;
030import org.hl7.fhir.instance.model.api.IBaseDatatype;
031import org.hl7.fhir.instance.model.api.IBaseExtension;
032
033import java.util.ArrayList;
034import java.util.List;
035
036@DatatypeDef(name = "Extension")
037public class ExtensionDt extends BaseIdentifiableElement
038                implements ICompositeDatatype, IBaseExtension<ExtensionDt, IDatatype> {
039
040        private static final long serialVersionUID = 6399491332783085935L;
041
042        private boolean myModifier;
043
044        @Child(name = "url", type = StringDt.class, order = 0, min = 1, max = 1)
045        private StringDt myUrl;
046
047        @Child(name = "value", type = IDatatype.class, order = 1, min = 0, max = 1)
048        private IBaseDatatype myValue;
049
050        public ExtensionDt() {}
051
052        public ExtensionDt(boolean theIsModifier) {
053                myModifier = theIsModifier;
054        }
055
056        public ExtensionDt(boolean theIsModifier, String theUrl) {
057                Validate.notEmpty(theUrl, "URL must be populated");
058
059                myModifier = theIsModifier;
060                myUrl = new StringDt(theUrl);
061        }
062
063        public ExtensionDt(boolean theIsModifier, String theUrl, IBaseDatatype theValue) {
064                Validate.notEmpty(theUrl, "URL must be populated");
065                Validate.notNull(theValue, "Value must not be null");
066
067                myModifier = theIsModifier;
068                myUrl = new StringDt(theUrl);
069                myValue = theValue;
070        }
071
072        /**
073         * Returns the URL for this extension.
074         * <p>
075         * Note that before HAPI 0.9 this method returned a {@link StringDt} but as of
076         * HAPI 0.9 this method returns a plain string. This was changed because it does not make sense to use a StringDt here
077         * since the URL itself can not contain extensions and it was therefore misleading.
078         * </p>
079         */
080        @Override
081        public String getUrl() {
082                return myUrl != null ? myUrl.getValue() : null;
083        }
084
085        /**
086         * Returns the internal string containing the URL for this extension (may return null)
087         */
088        @Nullable
089        public StringDt getUrlElement() {
090                return myUrl;
091        }
092
093        /**
094         * Retained for backward compatibility
095         *
096         * @see ExtensionDt#getUrl()
097         */
098        public String getUrlAsString() {
099                return getUrl();
100        }
101
102        /**
103         * Returns the value of this extension, if one exists.
104         * <p>
105         * Note that if this extension contains extensions (instead of a datatype) then <b>this method will return null</b>. In that case, you must use {@link #getUndeclaredExtensions()} and
106         * {@link #getUndeclaredModifierExtensions()} to retrieve the child extensions.
107         * </p>
108         */
109        @Override
110        public IBaseDatatype getValue() {
111                return myValue;
112        }
113
114        /**
115         * Returns the value of this extension, casted to a primitive datatype. This is a convenience method which should only be called if you are sure that the value for this particular extension will
116         * be a primitive.
117         * <p>
118         * Note that if this extension contains extensions (instead of a datatype) then <b>this method will return null</b>. In that case, you must use {@link #getUndeclaredExtensions()} and
119         * {@link #getUndeclaredModifierExtensions()} to retrieve the child extensions.
120         * </p>
121         *
122         * @throws ClassCastException
123         *             If the value of this extension is not a primitive datatype
124         */
125        public IPrimitiveDatatype<?> getValueAsPrimitive() {
126                if (!(getValue() instanceof IPrimitiveDatatype)) {
127                        throw new ClassCastException(
128                                        Msg.code(1887) + "Extension with URL[" + myUrl + "] can not be cast to primitive type, type is: "
129                                                        + getClass().getCanonicalName());
130                }
131                return (IPrimitiveDatatype<?>) getValue();
132        }
133
134        @Override
135        public boolean isEmpty() {
136                return super.isBaseEmpty() && (myValue == null || myValue.isEmpty());
137        }
138
139        public boolean isModifier() {
140                return myModifier;
141        }
142
143        public void setModifier(boolean theModifier) {
144                myModifier = theModifier;
145        }
146
147        @Override
148        public ExtensionDt setUrl(String theUrl) {
149                myUrl = theUrl != null ? new StringDt(theUrl) : myUrl;
150                return this;
151        }
152
153        public ExtensionDt setUrl(StringDt theUrl) {
154                myUrl = theUrl;
155                return this;
156        }
157
158        @Override
159        public ExtensionDt setValue(IBaseDatatype theValue) {
160                myValue = theValue;
161                return this;
162        }
163
164        @Override
165        @Deprecated // override deprecated method
166        public <T extends IElement> List<T> getAllPopulatedChildElementsOfType(Class<T> theType) {
167                return new ArrayList<T>();
168        }
169
170        @Override
171        public List<ExtensionDt> getExtension() {
172                return getAllUndeclaredExtensions();
173        }
174
175        @Override
176        public String toString() {
177                ToStringBuilder retVal = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
178                retVal.append("url", getUrl());
179                retVal.append("value", getValue());
180                return retVal.build();
181        }
182}