001package ca.uhn.fhir.model.api;
002
003/*
004 * #%L
005 * HAPI FHIR - Core Library
006 * %%
007 * Copyright (C) 2014 - 2021 Smile CDR, Inc.
008 * %%
009 * Licensed under the Apache License, Version 2.0 (the "License");
010 * you may not use this file except in compliance with the License.
011 * You may obtain a copy of the License at
012 *
013 *      http://www.apache.org/licenses/LICENSE-2.0
014 *
015 * Unless required by applicable law or agreed to in writing, software
016 * distributed under the License is distributed on an "AS IS" BASIS,
017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018 * See the License for the specific language governing permissions and
019 * limitations under the License.
020 * #L%
021 */
022
023import java.io.Externalizable;
024import java.io.IOException;
025import java.io.ObjectInput;
026import java.io.ObjectOutput;
027
028import org.apache.commons.lang3.StringUtils;
029import org.apache.commons.lang3.builder.EqualsBuilder;
030import org.apache.commons.lang3.builder.HashCodeBuilder;
031
032import ca.uhn.fhir.parser.DataFormatException;
033
034public abstract class BasePrimitive<T> extends BaseIdentifiableElement implements IPrimitiveDatatype<T>, Externalizable {
035
036        private T myCoercedValue;
037        private String myStringValue;
038
039        /**
040         * Subclasses must override to convert a "coerced" value into an encoded one.
041         * 
042         * @param theValue
043         *           Will not be null
044         * @return May return null if the value does not correspond to anything
045         */
046        protected abstract String encode(T theValue);
047
048        @Override
049        public boolean equals(Object theObj) {
050                if (theObj == null) {
051                        return false;
052                }
053                if (!(theObj.getClass() == getClass())) {
054                        return false;
055                }
056
057                BasePrimitive<?> o = (BasePrimitive<?>) theObj;
058
059                EqualsBuilder b = new EqualsBuilder();
060                b.append(getValue(), o.getValue());
061                return b.isEquals();
062        }
063
064        @Override
065        public T getValue() {
066                return myCoercedValue;
067        }
068
069        @Override
070        public String getValueAsString() throws DataFormatException {
071                return myStringValue;
072        }
073
074        @Override
075        public int hashCode() {
076                return new HashCodeBuilder().append(getValue()).toHashCode();
077        }
078
079        @Override
080        public boolean isEmpty() {
081                return super.isBaseEmpty() && getValue() == null;
082        }
083
084        /**
085         * Subclasses must override to convert an encoded representation of this datatype into a "coerced" one
086         * 
087         * @param theValue
088         *           Will not be null
089         * @return May return null if the value does not correspond to anything
090         */
091        protected abstract T parse(String theValue);
092
093        @Override
094        public void readExternal(ObjectInput theIn) throws IOException, ClassNotFoundException {
095                String object = (String) theIn.readObject();
096                setValueAsString(object);
097        }
098
099        @Override
100        public BasePrimitive<T> setValue(T theValue) throws DataFormatException {
101                myCoercedValue = theValue;
102                updateStringValue();
103                return this;
104        }
105
106        @Override
107        public void setValueAsString(String theValue) throws DataFormatException {
108                if (theValue == null) {
109                        myCoercedValue = null;
110                } else {
111                        // NB this might be null
112                        myCoercedValue = parse(theValue);
113                }
114                myStringValue = theValue;
115        }
116
117        @Override
118        public String toString() {
119                return getClass().getSimpleName() + "[" + getValueAsString() + "]";
120        }
121
122        protected void updateStringValue() {
123                if (myCoercedValue == null) {
124                        myStringValue = null;
125                } else {
126                        // NB this might be null
127                        myStringValue = encode(myCoercedValue);
128                }
129        }
130
131        @Override
132        public void writeExternal(ObjectOutput theOut) throws IOException {
133                theOut.writeObject(getValueAsString());
134        }
135
136        @Override
137        public boolean hasValue() {
138                return !StringUtils.isBlank(getValueAsString());
139        }
140
141}