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.model.api;
021
022import ca.uhn.fhir.parser.DataFormatException;
023import org.apache.commons.lang3.StringUtils;
024import org.apache.commons.lang3.builder.EqualsBuilder;
025import org.apache.commons.lang3.builder.HashCodeBuilder;
026
027import java.io.Externalizable;
028import java.io.IOException;
029import java.io.ObjectInput;
030import java.io.ObjectOutput;
031
032public abstract class BasePrimitive<T> extends BaseIdentifiableElement
033                implements IPrimitiveDatatype<T>, Externalizable {
034
035        private T myCoercedValue;
036        private String myStringValue;
037
038        /**
039         * Subclasses must override to convert a "coerced" value into an encoded one.
040         *
041         * @param theValue
042         *           Will not be null
043         * @return May return null if the value does not correspond to anything
044         */
045        protected abstract String encode(T theValue);
046
047        @Override
048        public boolean equals(Object theObj) {
049                if (theObj == null) {
050                        return false;
051                }
052                if (!(theObj.getClass() == getClass())) {
053                        return false;
054                }
055
056                BasePrimitive<?> o = (BasePrimitive<?>) theObj;
057
058                EqualsBuilder b = new EqualsBuilder();
059                b.append(getValue(), o.getValue());
060                return b.isEquals();
061        }
062
063        @Override
064        public T getValue() {
065                return myCoercedValue;
066        }
067
068        @Override
069        public String getValueAsString() throws DataFormatException {
070                return myStringValue;
071        }
072
073        @Override
074        public int hashCode() {
075                return new HashCodeBuilder().append(getValue()).toHashCode();
076        }
077
078        @Override
079        public boolean isEmpty() {
080                return super.isBaseEmpty() && getValue() == null;
081        }
082
083        /**
084         * Subclasses must override to convert an encoded representation of this datatype into a "coerced" one
085         *
086         * @param theValue
087         *           Will not be null
088         * @return May return null if the value does not correspond to anything
089         */
090        protected abstract T parse(String theValue);
091
092        @Override
093        public void readExternal(ObjectInput theIn) throws IOException, ClassNotFoundException {
094                String object = (String) theIn.readObject();
095                setValueAsString(object);
096        }
097
098        @Override
099        public BasePrimitive<T> setValue(T theValue) throws DataFormatException {
100                myCoercedValue = theValue;
101                updateStringValue();
102                return this;
103        }
104
105        @Override
106        public void setValueAsString(String theValue) throws DataFormatException {
107                if (theValue == null) {
108                        myCoercedValue = null;
109                } else {
110                        // NB this might be null
111                        myCoercedValue = parse(theValue);
112                }
113                myStringValue = theValue;
114        }
115
116        @Override
117        public String toString() {
118                return getClass().getSimpleName() + "[" + getValueAsString() + "]";
119        }
120
121        protected void updateStringValue() {
122                if (myCoercedValue == null) {
123                        myStringValue = null;
124                } else {
125                        // NB this might be null
126                        myStringValue = encode(myCoercedValue);
127                }
128        }
129
130        @Override
131        public void writeExternal(ObjectOutput theOut) throws IOException {
132                theOut.writeObject(getValueAsString());
133        }
134
135        @Override
136        public boolean hasValue() {
137                return !StringUtils.isBlank(getValueAsString());
138        }
139}