001package ca.uhn.fhir.jpa.entity;
002
003/*
004 * #%L
005 * HAPI FHIR JPA Server
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 ca.uhn.fhir.util.ValidateUtil;
024import org.apache.commons.lang3.Validate;
025import org.apache.commons.lang3.builder.EqualsBuilder;
026import org.apache.commons.lang3.builder.HashCodeBuilder;
027import org.apache.commons.lang3.builder.ToStringBuilder;
028import org.apache.commons.lang3.builder.ToStringStyle;
029import org.hibernate.validator.constraints.NotBlank;
030
031import javax.annotation.Nonnull;
032import javax.persistence.Column;
033import javax.persistence.Entity;
034import javax.persistence.FetchType;
035import javax.persistence.ForeignKey;
036import javax.persistence.GeneratedValue;
037import javax.persistence.GenerationType;
038import javax.persistence.Id;
039import javax.persistence.JoinColumn;
040import javax.persistence.Lob;
041import javax.persistence.ManyToOne;
042import javax.persistence.SequenceGenerator;
043import javax.persistence.Table;
044import java.io.Serializable;
045import java.nio.charset.StandardCharsets;
046
047import static org.apache.commons.lang3.StringUtils.left;
048import static org.apache.commons.lang3.StringUtils.length;
049
050@Entity
051@Table(name = "TRM_CONCEPT_PROPERTY", uniqueConstraints = {
052})
053public class TermConceptProperty implements Serializable {
054        public static final int MAX_PROPTYPE_ENUM_LENGTH = 6;
055        private static final long serialVersionUID = 1L;
056        private static final int MAX_LENGTH = 500;
057        @ManyToOne(fetch = FetchType.LAZY)
058        @JoinColumn(name = "CONCEPT_PID", referencedColumnName = "PID", foreignKey = @ForeignKey(name = "FK_CONCEPTPROP_CONCEPT"))
059        private TermConcept myConcept;
060        /**
061         * TODO: Make this non-null
062         *
063         * @since 3.5.0
064         */
065        @ManyToOne(fetch = FetchType.LAZY)
066        @JoinColumn(name = "CS_VER_PID", nullable = true, referencedColumnName = "PID", foreignKey = @ForeignKey(name = "FK_CONCEPTPROP_CSV"))
067        private TermCodeSystemVersion myCodeSystemVersion;
068        @Id()
069        @SequenceGenerator(name = "SEQ_CONCEPT_PROP_PID", sequenceName = "SEQ_CONCEPT_PROP_PID")
070        @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_CONCEPT_PROP_PID")
071        @Column(name = "PID")
072        private Long myId;
073        @Column(name = "PROP_KEY", nullable = false, length = MAX_LENGTH)
074        @NotBlank
075        private String myKey;
076        @Column(name = "PROP_VAL", nullable = true, length = MAX_LENGTH)
077        private String myValue;
078        @Column(name = "PROP_VAL_LOB")
079        @Lob()
080        private byte[] myValueLob;
081        @Column(name = "PROP_TYPE", nullable = false, length = MAX_PROPTYPE_ENUM_LENGTH)
082        private TermConceptPropertyTypeEnum myType;
083        /**
084         * Relevant only for properties of type {@link TermConceptPropertyTypeEnum#CODING}
085         */
086        @Column(name = "PROP_CODESYSTEM", length = MAX_LENGTH, nullable = true)
087        private String myCodeSystem;
088        /**
089         * Relevant only for properties of type {@link TermConceptPropertyTypeEnum#CODING}
090         */
091        @Column(name = "PROP_DISPLAY", length = MAX_LENGTH, nullable = true)
092        private String myDisplay;
093
094        /**
095         * Constructor
096         */
097        public TermConceptProperty() {
098                super();
099        }
100
101        /**
102         * Relevant only for properties of type {@link TermConceptPropertyTypeEnum#CODING}
103         */
104        public String getCodeSystem() {
105                return myCodeSystem;
106        }
107
108        /**
109         * Relevant only for properties of type {@link TermConceptPropertyTypeEnum#CODING}
110         */
111        public TermConceptProperty setCodeSystem(String theCodeSystem) {
112                ValidateUtil.isNotTooLongOrThrowIllegalArgument(theCodeSystem, MAX_LENGTH,
113                        "Property code system exceeds maximum length (" + MAX_LENGTH + "): " + length(theCodeSystem));
114                myCodeSystem = theCodeSystem;
115                return this;
116        }
117
118        /**
119         * Relevant only for properties of type {@link TermConceptPropertyTypeEnum#CODING}
120         */
121        public String getDisplay() {
122                return myDisplay;
123        }
124
125        /**
126         * Relevant only for properties of type {@link TermConceptPropertyTypeEnum#CODING}
127         */
128        public TermConceptProperty setDisplay(String theDisplay) {
129                myDisplay = left(theDisplay, MAX_LENGTH);
130                return this;
131        }
132
133        public String getKey() {
134                return myKey;
135        }
136
137        public TermConceptProperty setKey(@Nonnull String theKey) {
138                ValidateUtil.isNotBlankOrThrowIllegalArgument(theKey, "theKey must not be null or empty");
139                ValidateUtil.isNotTooLongOrThrowIllegalArgument(theKey, MAX_LENGTH,
140                        "Code exceeds maximum length (" + MAX_LENGTH + "): " + length(theKey));
141                myKey = theKey;
142                return this;
143        }
144
145        public TermConceptPropertyTypeEnum getType() {
146                return myType;
147        }
148
149        public TermConceptProperty setType(@Nonnull TermConceptPropertyTypeEnum theType) {
150                Validate.notNull(theType);
151                myType = theType;
152                return this;
153        }
154
155        /**
156         * This will contain the value for a {@link TermConceptPropertyTypeEnum#STRING string}
157         * property, and the code for a {@link TermConceptPropertyTypeEnum#CODING coding} property.
158         */
159        public String getValue() {
160                if (hasValueLob()) {
161                        return getValueLobAsString();
162                }
163                return myValue;
164        }
165
166        /**
167         * This will contain the value for a {@link TermConceptPropertyTypeEnum#STRING string}
168         * property, and the code for a {@link TermConceptPropertyTypeEnum#CODING coding} property.
169         */
170        public TermConceptProperty setValue(String theValue) {
171                if (theValue.length() > MAX_LENGTH) {
172                        setValueLob(theValue);
173                } else {
174                        myValueLob = null;
175                }
176                myValue = left(theValue, MAX_LENGTH);
177                return this;
178        }
179
180        public boolean hasValueLob() {
181                if (myValueLob != null && myValueLob.length > 0) {
182                        return true;
183                }
184                return false;
185        }
186
187        public byte[] getValueLob() {
188                return myValueLob;
189        }
190
191        public TermConceptProperty setValueLob(byte[] theValueLob) {
192                myValueLob = theValueLob;
193                return this;
194        }
195
196        public TermConceptProperty setValueLob(String theValueLob) {
197                myValueLob = theValueLob.getBytes(StandardCharsets.UTF_8);
198                return this;
199        }
200
201        public String getValueLobAsString() {
202                return new String(myValueLob, StandardCharsets.UTF_8);
203        }
204
205        public TermConceptProperty setCodeSystemVersion(TermCodeSystemVersion theCodeSystemVersion) {
206                myCodeSystemVersion = theCodeSystemVersion;
207                return this;
208        }
209
210        public TermConceptProperty setConcept(TermConcept theConcept) {
211                myConcept = theConcept;
212                return this;
213        }
214
215        @Override
216        public String toString() {
217                return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
218                        .append("key", myKey)
219                        .append("value", getValue())
220                        .toString();
221        }
222
223        @Override
224        public boolean equals(Object theO) {
225                if (this == theO) {
226                        return true;
227                }
228
229                if (theO == null || getClass() != theO.getClass()) {
230                        return false;
231                }
232
233                TermConceptProperty that = (TermConceptProperty) theO;
234
235                return new EqualsBuilder()
236                        .append(myKey, that.myKey)
237                        .append(myValue, that.myValue)
238                        .append(myType, that.myType)
239                        .append(myCodeSystem, that.myCodeSystem)
240                        .append(myDisplay, that.myDisplay)
241                        .isEquals();
242        }
243
244        @Override
245        public int hashCode() {
246                return new HashCodeBuilder(17, 37)
247                        .append(myKey)
248                        .append(myValue)
249                        .append(myType)
250                        .append(myCodeSystem)
251                        .append(myDisplay)
252                        .toHashCode();
253        }
254
255        public Long getPid() {
256                return myId;
257        }
258}