001/*-
002 * #%L
003 * HAPI FHIR JPA Server
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.jpa.entity;
021
022import ca.uhn.fhir.batch2.model.WorkChunk;
023import ca.uhn.fhir.batch2.model.WorkChunkStatusEnum;
024import jakarta.persistence.Basic;
025import jakarta.persistence.Column;
026import jakarta.persistence.Entity;
027import jakarta.persistence.EnumType;
028import jakarta.persistence.Enumerated;
029import jakarta.persistence.FetchType;
030import jakarta.persistence.ForeignKey;
031import jakarta.persistence.Id;
032import jakarta.persistence.Index;
033import jakarta.persistence.JoinColumn;
034import jakarta.persistence.Lob;
035import jakarta.persistence.ManyToOne;
036import jakarta.persistence.Table;
037import jakarta.persistence.Temporal;
038import jakarta.persistence.TemporalType;
039import jakarta.persistence.Version;
040import org.apache.commons.lang3.builder.ToStringBuilder;
041import org.apache.commons.lang3.builder.ToStringStyle;
042import org.hibernate.Length;
043
044import java.io.Serializable;
045import java.util.Date;
046
047import static ca.uhn.fhir.batch2.model.JobDefinition.ID_MAX_LENGTH;
048import static ca.uhn.fhir.jpa.entity.Batch2JobInstanceEntity.STATUS_MAX_LENGTH;
049import static org.apache.commons.lang3.StringUtils.left;
050
051@Entity
052@Table(
053                name = "BT2_WORK_CHUNK",
054                indexes = {
055                        @Index(name = "IDX_BT2WC_II_SEQ", columnList = "INSTANCE_ID,SEQ"),
056                        @Index(name = "IDX_BT2WC_II_SI_S_SEQ_ID", columnList = "INSTANCE_ID,TGT_STEP_ID,STAT,SEQ,ID")
057                })
058public class Batch2WorkChunkEntity implements Serializable {
059
060        public static final int ERROR_MSG_MAX_LENGTH = 500;
061        public static final int WARNING_MSG_MAX_LENGTH = 4000;
062        private static final long serialVersionUID = -6202771941965780558L;
063
064        @Id
065        @Column(name = "ID", length = ID_MAX_LENGTH)
066        private String myId;
067
068        @Column(name = "SEQ", nullable = false)
069        private int mySequence;
070
071        @Column(name = "CREATE_TIME", nullable = false)
072        @Temporal(TemporalType.TIMESTAMP)
073        private Date myCreateTime;
074
075        @Column(name = "START_TIME", nullable = true)
076        @Temporal(TemporalType.TIMESTAMP)
077        private Date myStartTime;
078
079        @Column(name = "END_TIME", nullable = true)
080        @Temporal(TemporalType.TIMESTAMP)
081        private Date myEndTime;
082
083        @Version
084        @Column(name = "UPDATE_TIME", nullable = true)
085        @Temporal(TemporalType.TIMESTAMP)
086        private Date myUpdateTime;
087
088        @Column(name = "RECORDS_PROCESSED", nullable = true)
089        private Integer myRecordsProcessed;
090
091        @Column(name = "DEFINITION_ID", length = ID_MAX_LENGTH, nullable = false)
092        private String myJobDefinitionId;
093
094        @Column(name = "DEFINITION_VER", length = ID_MAX_LENGTH, nullable = false)
095        private int myJobDefinitionVersion;
096
097        @Column(name = "TGT_STEP_ID", length = ID_MAX_LENGTH, nullable = false)
098        private String myTargetStepId;
099
100        @Lob // TODO: VC column added in 7.2.0 - Remove non-VC column later
101        @Basic(fetch = FetchType.LAZY)
102        @Column(name = "CHUNK_DATA", nullable = true, length = Integer.MAX_VALUE - 1)
103        private String mySerializedData;
104
105        @Column(name = "CHUNK_DATA_VC", nullable = true, length = Length.LONG32)
106        private String mySerializedDataVc;
107
108        @Column(name = "STAT", length = STATUS_MAX_LENGTH, nullable = false)
109        @Enumerated(EnumType.STRING)
110        private WorkChunkStatusEnum myStatus;
111
112        @ManyToOne(fetch = FetchType.LAZY)
113        @JoinColumn(
114                        name = "INSTANCE_ID",
115                        insertable = false,
116                        updatable = false,
117                        foreignKey = @ForeignKey(name = "FK_BT2WC_INSTANCE"))
118        private Batch2JobInstanceEntity myInstance;
119
120        @Column(name = "INSTANCE_ID", length = ID_MAX_LENGTH, nullable = false)
121        private String myInstanceId;
122
123        @Column(name = "ERROR_MSG", length = ERROR_MSG_MAX_LENGTH, nullable = true)
124        private String myErrorMessage;
125
126        @Column(name = "ERROR_COUNT", nullable = false)
127        private int myErrorCount;
128
129        @Column(name = "WARNING_MSG", length = WARNING_MSG_MAX_LENGTH, nullable = true)
130        private String myWarningMessage;
131
132        /**
133         * The next time the work chunk can attempt to rerun its work step.
134         */
135        @Column(name = "NEXT_POLL_TIME", nullable = true)
136        @Temporal(TemporalType.TIMESTAMP)
137        private Date myNextPollTime;
138
139        /**
140         * The number of times the work chunk has had its state set back to POLL_WAITING.
141         * <p>
142         * TODO: Note that this column was added in 7.2.0, so it is nullable in order to
143         * account for existing rows that were added before the column was added. In
144         * the future we should make this non-null.
145         */
146        @Column(name = "POLL_ATTEMPTS", nullable = true)
147        private Integer myPollAttempts;
148
149        /**
150         * Default constructor for Hibernate.
151         */
152        public Batch2WorkChunkEntity() {
153                myPollAttempts = 0;
154        }
155
156        /**
157         * Projection constructor for no-data path.
158         */
159        public Batch2WorkChunkEntity(
160                        String theId,
161                        int theSequence,
162                        String theJobDefinitionId,
163                        int theJobDefinitionVersion,
164                        String theInstanceId,
165                        String theTargetStepId,
166                        WorkChunkStatusEnum theStatus,
167                        Date theCreateTime,
168                        Date theStartTime,
169                        Date theUpdateTime,
170                        Date theEndTime,
171                        String theErrorMessage,
172                        int theErrorCount,
173                        Integer theRecordsProcessed,
174                        String theWarningMessage,
175                        Date theNextPollTime,
176                        Integer thePollAttempts) {
177                myId = theId;
178                mySequence = theSequence;
179                myJobDefinitionId = theJobDefinitionId;
180                myJobDefinitionVersion = theJobDefinitionVersion;
181                myInstanceId = theInstanceId;
182                myTargetStepId = theTargetStepId;
183                myStatus = theStatus;
184                myCreateTime = theCreateTime;
185                myStartTime = theStartTime;
186                myUpdateTime = theUpdateTime;
187                myEndTime = theEndTime;
188                myErrorMessage = theErrorMessage;
189                myErrorCount = theErrorCount;
190                myRecordsProcessed = theRecordsProcessed;
191                myWarningMessage = theWarningMessage;
192                myNextPollTime = theNextPollTime;
193                myPollAttempts = thePollAttempts != null ? thePollAttempts : 0;
194        }
195
196        public static Batch2WorkChunkEntity fromWorkChunk(WorkChunk theWorkChunk) {
197                Batch2WorkChunkEntity entity = new Batch2WorkChunkEntity(
198                                theWorkChunk.getId(),
199                                theWorkChunk.getSequence(),
200                                theWorkChunk.getJobDefinitionId(),
201                                theWorkChunk.getJobDefinitionVersion(),
202                                theWorkChunk.getInstanceId(),
203                                theWorkChunk.getTargetStepId(),
204                                theWorkChunk.getStatus(),
205                                theWorkChunk.getCreateTime(),
206                                theWorkChunk.getStartTime(),
207                                theWorkChunk.getUpdateTime(),
208                                theWorkChunk.getEndTime(),
209                                theWorkChunk.getErrorMessage(),
210                                theWorkChunk.getErrorCount(),
211                                theWorkChunk.getRecordsProcessed(),
212                                theWorkChunk.getWarningMessage(),
213                                theWorkChunk.getNextPollTime(),
214                                theWorkChunk.getPollAttempts());
215                entity.setSerializedData(theWorkChunk.getData());
216
217                return entity;
218        }
219
220        public int getErrorCount() {
221                return myErrorCount;
222        }
223
224        public void setErrorCount(int theErrorCount) {
225                myErrorCount = theErrorCount;
226        }
227
228        public String getErrorMessage() {
229                return myErrorMessage;
230        }
231
232        public void setErrorMessage(String theErrorMessage) {
233                myErrorMessage = left(theErrorMessage, ERROR_MSG_MAX_LENGTH);
234        }
235
236        public String getWarningMessage() {
237                return myWarningMessage;
238        }
239
240        public void setWarningMessage(String theWarningMessage) {
241                myWarningMessage = theWarningMessage;
242        }
243
244        public int getSequence() {
245                return mySequence;
246        }
247
248        public void setSequence(int theSequence) {
249                mySequence = theSequence;
250        }
251
252        public Date getCreateTime() {
253                return myCreateTime;
254        }
255
256        public void setCreateTime(Date theCreateTime) {
257                myCreateTime = theCreateTime;
258        }
259
260        public Date getStartTime() {
261                return myStartTime;
262        }
263
264        public void setStartTime(Date theStartTime) {
265                myStartTime = theStartTime;
266        }
267
268        public Date getEndTime() {
269                return myEndTime;
270        }
271
272        public void setEndTime(Date theEndTime) {
273                myEndTime = theEndTime;
274        }
275
276        public Date getUpdateTime() {
277                return myUpdateTime;
278        }
279
280        public Integer getRecordsProcessed() {
281                return myRecordsProcessed;
282        }
283
284        public void setRecordsProcessed(Integer theRecordsProcessed) {
285                myRecordsProcessed = theRecordsProcessed;
286        }
287
288        public Batch2JobInstanceEntity getInstance() {
289                return myInstance;
290        }
291
292        public void setInstance(Batch2JobInstanceEntity theInstance) {
293                myInstance = theInstance;
294        }
295
296        public String getJobDefinitionId() {
297                return myJobDefinitionId;
298        }
299
300        public void setJobDefinitionId(String theJobDefinitionId) {
301                myJobDefinitionId = theJobDefinitionId;
302        }
303
304        public int getJobDefinitionVersion() {
305                return myJobDefinitionVersion;
306        }
307
308        public void setJobDefinitionVersion(int theJobDefinitionVersion) {
309                myJobDefinitionVersion = theJobDefinitionVersion;
310        }
311
312        public String getTargetStepId() {
313                return myTargetStepId;
314        }
315
316        public void setTargetStepId(String theTargetStepId) {
317                myTargetStepId = theTargetStepId;
318        }
319
320        public String getSerializedData() {
321                return mySerializedDataVc != null ? mySerializedDataVc : mySerializedData;
322        }
323
324        public void setSerializedData(String theSerializedData) {
325                mySerializedData = null;
326                mySerializedDataVc = theSerializedData;
327        }
328
329        public WorkChunkStatusEnum getStatus() {
330                return myStatus;
331        }
332
333        public void setStatus(WorkChunkStatusEnum theStatus) {
334                myStatus = theStatus;
335        }
336
337        public String getId() {
338                return myId;
339        }
340
341        public void setId(String theId) {
342                myId = theId;
343        }
344
345        public String getInstanceId() {
346                return myInstanceId;
347        }
348
349        public void setInstanceId(String theInstanceId) {
350                myInstanceId = theInstanceId;
351        }
352
353        public Date getNextPollTime() {
354                return myNextPollTime;
355        }
356
357        public void setNextPollTime(Date theNextPollTime) {
358                myNextPollTime = theNextPollTime;
359        }
360
361        public Integer getPollAttempts() {
362                if (myPollAttempts == null) {
363                        return 0;
364                }
365                return myPollAttempts;
366        }
367
368        public void setPollAttempts(int thePollAttempts) {
369                myPollAttempts = thePollAttempts;
370        }
371
372        @Override
373        public String toString() {
374                return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
375                                .append("id", myId)
376                                .append("instanceId", myInstanceId)
377                                .append("sequence", mySequence)
378                                .append("errorCount", myErrorCount)
379                                .append("jobDefinitionId", myJobDefinitionId)
380                                .append("jobDefinitionVersion", myJobDefinitionVersion)
381                                .append("createTime", myCreateTime)
382                                .append("startTime", myStartTime)
383                                .append("endTime", myEndTime)
384                                .append("updateTime", myUpdateTime)
385                                .append("recordsProcessed", myRecordsProcessed)
386                                .append("targetStepId", myTargetStepId)
387                                .append("serializedData", getSerializedData())
388                                .append("status", myStatus)
389                                .append("errorMessage", myErrorMessage)
390                                .append("warningMessage", myWarningMessage)
391                                .append("nextPollTime", myNextPollTime)
392                                .append("pollAttempts", myPollAttempts)
393                                .toString();
394        }
395}