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