001package org.hl7.fhir.dstu3.model;
002
003import java.io.Externalizable;
004import java.io.IOException;
005import java.io.ObjectInput;
006import java.io.ObjectOutput;
007
008import org.apache.commons.lang3.StringUtils;
009import org.apache.commons.lang3.builder.EqualsBuilder;
010import org.apache.commons.lang3.builder.HashCodeBuilder;
011import org.hl7.fhir.instance.model.api.IBaseHasExtensions;
012import org.hl7.fhir.instance.model.api.IPrimitiveType;
013
014import ca.uhn.fhir.model.api.IElement;
015
016public abstract class PrimitiveType<T> extends Type implements IPrimitiveType<T>, IBaseHasExtensions, IElement, Externalizable {
017
018        private static final long serialVersionUID = 3L;
019
020        private T myCoercedValue;
021        private String myStringValue;
022
023        public String asStringValue() {
024                return myStringValue;
025        }
026
027        public abstract Type copy();
028
029        /**
030         * Subclasses must override to convert a "coerced" value into an encoded one.
031         * 
032         * @param theValue
033         *            Will not be null
034         * @return May return null if the value does not correspond to anything
035         */
036        protected abstract String encode(T theValue);
037
038        @Override
039        public boolean equalsDeep(Base obj) {
040                if (!super.equalsDeep(obj))
041                        return false;
042                if (obj == null) {
043                        return false;
044                }
045                if (!(obj.getClass() == getClass())) {
046                        return false;
047                }
048
049                PrimitiveType<?> o = (PrimitiveType<?>) obj;
050
051                EqualsBuilder b = new EqualsBuilder();
052                b.append(getValue(), o.getValue());
053                return b.isEquals();
054        }
055
056        @Override
057        public boolean equalsShallow(Base obj) {
058                if (obj == null) {
059                        return false;
060                }
061                if (!(obj.getClass() == getClass())) {
062                        return false;
063                }
064
065                PrimitiveType<?> o = (PrimitiveType<?>) obj;
066
067                EqualsBuilder b = new EqualsBuilder();
068                b.append(getValue(), o.getValue());
069                return b.isEquals();
070        }
071
072        public void fromStringValue(String theValue) {
073                myStringValue = theValue;
074                if (theValue == null) {
075                        myCoercedValue = null;
076                } else {
077                        // NB this might be null
078                        myCoercedValue = parse(theValue);
079                }
080        }
081
082        public T getValue() {
083                return myCoercedValue;
084        }
085
086        public String getValueAsString() {
087                return asStringValue();
088        }
089
090        @Override
091        public int hashCode() {
092                return new HashCodeBuilder().append(getValue()).toHashCode();
093        }
094
095        public boolean hasValue() {
096          return !StringUtils.isBlank(getValueAsString());
097        }
098        
099        @Override
100        public boolean isEmpty() {
101                return super.isEmpty() && StringUtils.isBlank(getValueAsString());
102        }
103
104        public boolean isPrimitive() {
105                return true;
106        }
107
108        /**
109         * Subclasses must override to convert an encoded representation of this datatype into a "coerced" one
110         * 
111         * @param theValue
112         *            Will not be null
113         * @return May return null if the value does not correspond to anything
114         */
115        protected abstract T parse(String theValue);
116
117        public String primitiveValue() {
118                return asStringValue();
119        }
120
121        @Override
122        public void readExternal(ObjectInput theIn) throws IOException, ClassNotFoundException {
123                String object = (String) theIn.readObject();
124                setValueAsString(object);
125        }
126
127        public PrimitiveType<T> setValue(T theValue) {
128                myCoercedValue = theValue;
129                updateStringValue();
130                return this;
131        }
132
133        public void setValueAsString(String theValue) {
134                fromStringValue(theValue);
135        }
136
137        @Override
138        public String toString() {
139                return getClass().getSimpleName() + "[" + asStringValue() + "]";
140        }
141
142        protected Type typedCopy() {
143                return copy();
144        }
145
146        protected void updateStringValue() {
147                if (myCoercedValue == null) {
148                        myStringValue = null;
149                } else {
150                        // NB this might be null
151                        myStringValue = encode(myCoercedValue);
152                }
153        }
154
155        @Override
156        public void writeExternal(ObjectOutput theOut) throws IOException {
157                theOut.writeObject(getValueAsString());
158        }
159
160}