001/*
002 * #%L
003 * HAPI FHIR JPA Server
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.jpa.entity;
021
022import ca.uhn.fhir.jpa.model.entity.BasePartitionable;
023import ca.uhn.fhir.jpa.model.entity.IdAndPartitionId;
024import ca.uhn.fhir.jpa.model.entity.ResourceTable;
025import ca.uhn.fhir.util.ValidateUtil;
026import jakarta.annotation.Nonnull;
027import jakarta.persistence.Column;
028import jakarta.persistence.Entity;
029import jakarta.persistence.FetchType;
030import jakarta.persistence.ForeignKey;
031import jakarta.persistence.GeneratedValue;
032import jakarta.persistence.GenerationType;
033import jakarta.persistence.Id;
034import jakarta.persistence.IdClass;
035import jakarta.persistence.Index;
036import jakarta.persistence.JoinColumn;
037import jakarta.persistence.JoinColumns;
038import jakarta.persistence.ManyToOne;
039import jakarta.persistence.SequenceGenerator;
040import jakarta.persistence.Table;
041import jakarta.persistence.UniqueConstraint;
042import org.apache.commons.lang3.builder.EqualsBuilder;
043import org.apache.commons.lang3.builder.HashCodeBuilder;
044import org.apache.commons.lang3.builder.ToStringBuilder;
045import org.apache.commons.lang3.builder.ToStringStyle;
046
047import java.io.Serializable;
048
049import static org.apache.commons.lang3.StringUtils.left;
050import static org.apache.commons.lang3.StringUtils.length;
051
052@Table(
053                name = "TRM_CODESYSTEM",
054                uniqueConstraints = {
055                        @UniqueConstraint(
056                                        name = "IDX_CS_CODESYSTEM",
057                                        columnNames = {"PARTITION_ID", "CODE_SYSTEM_URI"})
058                },
059                indexes = {
060                        @Index(name = "FK_TRMCODESYSTEM_RES", columnList = "RES_ID"),
061                        @Index(name = "FK_TRMCODESYSTEM_CURVER", columnList = "CURRENT_VERSION_PID")
062                })
063@Entity()
064@IdClass(IdAndPartitionId.class)
065public class TermCodeSystem extends BasePartitionable implements Serializable {
066        public static final int MAX_URL_LENGTH = 200;
067        private static final long serialVersionUID = 1L;
068        private static final int MAX_NAME_LENGTH = 200;
069        public static final String FK_TRMCODESYSTEM_CURVER = "FK_TRMCODESYSTEM_CURVER";
070
071        @Column(name = "CODE_SYSTEM_URI", nullable = false, length = MAX_URL_LENGTH)
072        private String myCodeSystemUri;
073
074        /**
075         * Note that this uses a separate partition_id column because it needs
076         * to be nullable, unlike the PK one which has to be non-nullable
077         * when we're including partition IDs in PKs.
078         */
079        @ManyToOne(fetch = FetchType.LAZY)
080        @JoinColumns(
081                        value = {
082                                @JoinColumn(
083                                                name = "CURRENT_VERSION_PID",
084                                                referencedColumnName = "PID",
085                                                insertable = false,
086                                                updatable = false,
087                                                nullable = true),
088                                @JoinColumn(
089                                                name = "CURRENT_VERSION_PARTITION_ID",
090                                                referencedColumnName = "PARTITION_ID",
091                                                insertable = false,
092                                                updatable = false,
093                                                nullable = true)
094                        },
095                        foreignKey = @ForeignKey(name = FK_TRMCODESYSTEM_CURVER))
096        private TermCodeSystemVersion myCurrentVersion;
097
098        @Column(name = "CURRENT_VERSION_PID", nullable = true, insertable = true, updatable = true)
099        private Long myCurrentVersionPid;
100
101        @Column(name = "CURRENT_VERSION_PARTITION_ID", nullable = true, insertable = true, updatable = true)
102        private Integer myCurrentVersionPartitionId;
103
104        @Id()
105        @SequenceGenerator(name = "SEQ_CODESYSTEM_PID", sequenceName = "SEQ_CODESYSTEM_PID")
106        @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_CODESYSTEM_PID")
107        @Column(name = "PID")
108        private Long myId;
109
110        @ManyToOne(fetch = FetchType.LAZY)
111        @JoinColumns(
112                        value = {
113                                @JoinColumn(
114                                                name = "RES_ID",
115                                                referencedColumnName = "RES_ID",
116                                                nullable = false,
117                                                updatable = false,
118                                                insertable = false),
119                                @JoinColumn(
120                                                name = "PARTITION_ID",
121                                                referencedColumnName = "PARTITION_ID",
122                                                nullable = false,
123                                                updatable = false,
124                                                insertable = false)
125                        },
126                        foreignKey = @ForeignKey(name = "FK_TRMCODESYSTEM_RES"))
127        private ResourceTable myResource;
128
129        @Column(name = "RES_ID", nullable = false)
130        private Long myResourcePid;
131
132        @Column(name = "CS_NAME", nullable = true, length = MAX_NAME_LENGTH)
133        private String myName;
134
135        /**
136         * Constructor
137         */
138        public TermCodeSystem() {
139                super();
140        }
141
142        @Override
143        public boolean equals(Object theO) {
144                if (this == theO) {
145                        return true;
146                }
147
148                if (theO == null || getClass() != theO.getClass()) {
149                        return false;
150                }
151
152                TermCodeSystem that = (TermCodeSystem) theO;
153
154                EqualsBuilder b = new EqualsBuilder();
155                b.append(myCodeSystemUri, that.myCodeSystemUri);
156                return b.isEquals();
157        }
158
159        @Override
160        public int hashCode() {
161                HashCodeBuilder b = new HashCodeBuilder(17, 37);
162                b.append(myCodeSystemUri);
163                return b.toHashCode();
164        }
165
166        public String getCodeSystemUri() {
167                return myCodeSystemUri;
168        }
169
170        public TermCodeSystem setCodeSystemUri(@Nonnull String theCodeSystemUri) {
171                ValidateUtil.isNotBlankOrThrowIllegalArgument(theCodeSystemUri, "theCodeSystemUri must not be null or empty");
172                ValidateUtil.isNotTooLongOrThrowIllegalArgument(
173                                theCodeSystemUri,
174                                MAX_URL_LENGTH,
175                                "URI exceeds maximum length (" + MAX_URL_LENGTH + "): " + length(theCodeSystemUri));
176                myCodeSystemUri = theCodeSystemUri;
177                return this;
178        }
179
180        public String getName() {
181                return myName;
182        }
183
184        public TermCodeSystem setName(String theName) {
185                myName = left(theName, MAX_NAME_LENGTH);
186                return this;
187        }
188
189        public TermCodeSystemVersion getCurrentVersion() {
190                return myCurrentVersion;
191        }
192
193        public TermCodeSystem setCurrentVersion(TermCodeSystemVersion theCurrentVersion) {
194                if (theCurrentVersion == null) {
195                        myCurrentVersion = null;
196                        myCurrentVersionPid = null;
197                        myCurrentVersionPartitionId = null;
198                } else {
199                        myCurrentVersion = theCurrentVersion;
200                        myCurrentVersionPid = theCurrentVersion.getPid();
201                        assert myCurrentVersionPid != null;
202                        myCurrentVersionPartitionId = theCurrentVersion.getPartitionId().getPartitionId();
203                }
204                return this;
205        }
206
207        public Long getPid() {
208                return myId;
209        }
210
211        public IdAndPartitionId getPartitionedId() {
212                return IdAndPartitionId.forId(myId, this);
213        }
214
215        public ResourceTable getResource() {
216                return myResource;
217        }
218
219        public TermCodeSystem setResource(ResourceTable theResource) {
220                myResource = theResource;
221                myResourcePid = theResource.getId().getId();
222                setPartitionId(theResource.getPartitionId());
223                return this;
224        }
225
226        @Override
227        public String toString() {
228                ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
229                b.append("pid", myId);
230                b.append("codeSystemUri", myCodeSystemUri);
231                b.append("currentVersionPid", myCurrentVersionPid);
232                b.append("resourcePid", myResourcePid);
233                b.append("name", myName);
234                return b.toString();
235        }
236}