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.batch2.model.JobDefinition; 023import ca.uhn.fhir.batch2.model.StatusEnum; 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.Id; 031import jakarta.persistence.Index; 032import jakarta.persistence.Lob; 033import jakarta.persistence.Table; 034import jakarta.persistence.Temporal; 035import jakarta.persistence.TemporalType; 036import jakarta.persistence.Version; 037import org.apache.commons.lang3.builder.ToStringBuilder; 038import org.apache.commons.lang3.builder.ToStringStyle; 039import org.hibernate.Length; 040import org.hibernate.annotations.JdbcTypeCode; 041import org.hibernate.type.SqlTypes; 042 043import java.io.Serializable; 044import java.util.Date; 045 046import static ca.uhn.fhir.batch2.model.JobDefinition.ID_MAX_LENGTH; 047import static ca.uhn.fhir.jpa.entity.Batch2WorkChunkEntity.ERROR_MSG_MAX_LENGTH; 048import static ca.uhn.fhir.jpa.entity.Batch2WorkChunkEntity.WARNING_MSG_MAX_LENGTH; 049import static org.apache.commons.lang3.StringUtils.left; 050 051@Entity 052@Table( 053 name = "BT2_JOB_INSTANCE", 054 indexes = {@Index(name = "IDX_BT2JI_CT", columnList = "CREATE_TIME")}) 055public class Batch2JobInstanceEntity implements Serializable { 056 057 public static final int STATUS_MAX_LENGTH = 20; 058 public static final int TIME_REMAINING_LENGTH = 100; 059 public static final int PARAMS_JSON_MAX_LENGTH = 2000; 060 private static final long serialVersionUID = 8187134261799095422L; 061 public static final int INITIATING_USER_NAME_MAX_LENGTH = 200; 062 public static final int INITIATING_CLIENT_ID_MAX_LENGTH = 200; 063 064 @Id 065 @Column(name = "ID", length = JobDefinition.ID_MAX_LENGTH, nullable = false) 066 private String myId; 067 068 @Column(name = "CREATE_TIME", nullable = false) 069 @Temporal(TemporalType.TIMESTAMP) 070 private Date myCreateTime; 071 072 @Column(name = "START_TIME", nullable = true) 073 @Temporal(TemporalType.TIMESTAMP) 074 private Date myStartTime; 075 076 @Column(name = "END_TIME", nullable = true) 077 @Temporal(TemporalType.TIMESTAMP) 078 private Date myEndTime; 079 080 @Version 081 @Column(name = "UPDATE_TIME", nullable = true) 082 @Temporal(TemporalType.TIMESTAMP) 083 private Date myUpdateTime; 084 085 @Column(name = "DEFINITION_ID", length = JobDefinition.ID_MAX_LENGTH, nullable = false) 086 private String myDefinitionId; 087 088 @Column(name = "DEFINITION_VER", nullable = false) 089 private int myDefinitionVersion; 090 091 @Column(name = "STAT", length = STATUS_MAX_LENGTH, nullable = false) 092 @Enumerated(EnumType.STRING) 093 @JdbcTypeCode(SqlTypes.VARCHAR) 094 private StatusEnum myStatus; 095 096 @Column(name = "JOB_CANCELLED", nullable = false) 097 private boolean myCancelled; 098 099 @Column(name = "FAST_TRACKING", nullable = true) 100 private Boolean myFastTracking; 101 102 // TODO: VC column added in 7.2.0 - Remove non-VC column later 103 @Column(name = "PARAMS_JSON", length = PARAMS_JSON_MAX_LENGTH, nullable = true) 104 private String myParamsJson; 105 106 @Lob // TODO: VC column added in 7.2.0 - Remove non-VC column later 107 @Column(name = "PARAMS_JSON_LOB", nullable = true) 108 private String myParamsJsonLob; 109 110 @Column(name = "PARAMS_JSON_VC", nullable = true, length = Length.LONG32) 111 private String myParamsJsonVc; 112 113 @Column(name = "CMB_RECS_PROCESSED", nullable = true) 114 private Integer myCombinedRecordsProcessed; 115 116 @Column(name = "CMB_RECS_PER_SEC", nullable = true) 117 private Double myCombinedRecordsProcessedPerSecond; 118 119 @Column(name = "TOT_ELAPSED_MILLIS", nullable = true) 120 private Integer myTotalElapsedMillis; 121 122 @Column(name = "WORK_CHUNKS_PURGED", nullable = false) 123 private boolean myWorkChunksPurged; 124 125 @Column(name = "PROGRESS_PCT", nullable = false) 126 private double myProgress; 127 128 @Column(name = "ERROR_MSG", length = ERROR_MSG_MAX_LENGTH, nullable = true) 129 private String myErrorMessage; 130 131 @Column(name = "ERROR_COUNT", nullable = false) 132 private int myErrorCount; 133 134 @Column(name = "EST_REMAINING", length = TIME_REMAINING_LENGTH, nullable = true) 135 private String myEstimatedTimeRemaining; 136 137 @Column(name = "CUR_GATED_STEP_ID", length = ID_MAX_LENGTH, nullable = true) 138 private String myCurrentGatedStepId; 139 140 @Column(name = "WARNING_MSG", length = WARNING_MSG_MAX_LENGTH, nullable = true) 141 private String myWarningMessages; 142 143 @Column(name = "USER_NAME", length = INITIATING_USER_NAME_MAX_LENGTH, nullable = true) 144 private String myTriggeringUsername; 145 146 @Column(name = "CLIENT_ID", length = INITIATING_CLIENT_ID_MAX_LENGTH, nullable = true) 147 private String myTriggeringClientId; 148 149 /** 150 * Any output from the job can be held in this column 151 * Even serialized json 152 */ 153 @Lob // TODO: VC column added in 7.2.0 - Remove non-VC column later 154 @Basic(fetch = FetchType.LAZY) 155 @Column(name = "REPORT", nullable = true, length = Integer.MAX_VALUE - 1) 156 private String myReport; 157 158 @Column(name = "REPORT_VC", nullable = true, length = Length.LONG32) 159 private String myReportVc; 160 161 public String getCurrentGatedStepId() { 162 return myCurrentGatedStepId; 163 } 164 165 public void setCurrentGatedStepId(String theCurrentGatedStepId) { 166 myCurrentGatedStepId = theCurrentGatedStepId; 167 } 168 169 public boolean isCancelled() { 170 return myCancelled; 171 } 172 173 public void setCancelled(boolean theCancelled) { 174 myCancelled = theCancelled; 175 } 176 177 public int getErrorCount() { 178 return myErrorCount; 179 } 180 181 public void setErrorCount(int theErrorCount) { 182 myErrorCount = theErrorCount; 183 } 184 185 public Integer getTotalElapsedMillis() { 186 return myTotalElapsedMillis; 187 } 188 189 public void setTotalElapsedMillis(Integer theTotalElapsedMillis) { 190 myTotalElapsedMillis = theTotalElapsedMillis; 191 } 192 193 public Integer getCombinedRecordsProcessed() { 194 return myCombinedRecordsProcessed; 195 } 196 197 public void setCombinedRecordsProcessed(Integer theCombinedRecordsProcessed) { 198 myCombinedRecordsProcessed = theCombinedRecordsProcessed; 199 } 200 201 public Double getCombinedRecordsProcessedPerSecond() { 202 return myCombinedRecordsProcessedPerSecond; 203 } 204 205 public void setCombinedRecordsProcessedPerSecond(Double theCombinedRecordsProcessedPerSecond) { 206 myCombinedRecordsProcessedPerSecond = theCombinedRecordsProcessedPerSecond; 207 } 208 209 public Date getCreateTime() { 210 return myCreateTime; 211 } 212 213 public void setCreateTime(Date theCreateTime) { 214 myCreateTime = theCreateTime; 215 } 216 217 public Date getStartTime() { 218 return myStartTime; 219 } 220 221 public void setStartTime(Date theStartTime) { 222 myStartTime = theStartTime; 223 } 224 225 public Date getEndTime() { 226 return myEndTime; 227 } 228 229 public void setEndTime(Date theEndTime) { 230 myEndTime = theEndTime; 231 } 232 233 public void setUpdateTime(Date theTime) { 234 myUpdateTime = theTime; 235 } 236 237 public Date getUpdateTime() { 238 return myUpdateTime; 239 } 240 241 public String getId() { 242 return myId; 243 } 244 245 public void setId(String theId) { 246 myId = theId; 247 } 248 249 public String getDefinitionId() { 250 return myDefinitionId; 251 } 252 253 public void setDefinitionId(String theDefinitionId) { 254 myDefinitionId = theDefinitionId; 255 } 256 257 public int getDefinitionVersion() { 258 return myDefinitionVersion; 259 } 260 261 public void setDefinitionVersion(int theDefinitionVersion) { 262 myDefinitionVersion = theDefinitionVersion; 263 } 264 265 public StatusEnum getStatus() { 266 return myStatus; 267 } 268 269 public void setStatus(StatusEnum theStatus) { 270 myStatus = theStatus; 271 } 272 273 public String getParams() { 274 if (myParamsJsonVc != null) { 275 return myParamsJsonVc; 276 } 277 if (myParamsJsonLob != null) { 278 return myParamsJsonLob; 279 } 280 return myParamsJson; 281 } 282 283 public void setParams(String theParams) { 284 myParamsJsonVc = theParams; 285 myParamsJsonLob = null; 286 myParamsJson = null; 287 } 288 289 public boolean getWorkChunksPurged() { 290 return myWorkChunksPurged; 291 } 292 293 public void setWorkChunksPurged(boolean theWorkChunksPurged) { 294 myWorkChunksPurged = theWorkChunksPurged; 295 } 296 297 public double getProgress() { 298 return myProgress; 299 } 300 301 public void setProgress(double theProgress) { 302 myProgress = theProgress; 303 } 304 305 public String getErrorMessage() { 306 return myErrorMessage; 307 } 308 309 public void setErrorMessage(String theErrorMessage) { 310 myErrorMessage = left(theErrorMessage, ERROR_MSG_MAX_LENGTH); 311 } 312 313 public String getEstimatedTimeRemaining() { 314 return myEstimatedTimeRemaining; 315 } 316 317 public void setEstimatedTimeRemaining(String theEstimatedTimeRemaining) { 318 myEstimatedTimeRemaining = left(theEstimatedTimeRemaining, TIME_REMAINING_LENGTH); 319 } 320 321 public String getReport() { 322 return myReportVc != null ? myReportVc : myReport; 323 } 324 325 public void setReport(String theReport) { 326 myReportVc = theReport; 327 myReport = null; 328 } 329 330 public String getWarningMessages() { 331 return myWarningMessages; 332 } 333 334 public void setWarningMessages(String theWarningMessages) { 335 myWarningMessages = theWarningMessages; 336 } 337 338 public String getTriggeringUsername() { 339 return myTriggeringUsername; 340 } 341 342 public Batch2JobInstanceEntity setTriggeringUsername(String theTriggeringUsername) { 343 myTriggeringUsername = theTriggeringUsername; 344 return this; 345 } 346 347 public String getTriggeringClientId() { 348 return myTriggeringClientId; 349 } 350 351 public Batch2JobInstanceEntity setTriggeringClientId(String theTriggeringClientId) { 352 myTriggeringClientId = theTriggeringClientId; 353 return this; 354 } 355 356 @Override 357 public String toString() { 358 return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) 359 .append("id", myId) 360 .append("definitionId", myDefinitionId) 361 .append("definitionVersion", myDefinitionVersion) 362 .append("errorCount", myErrorCount) 363 .append("createTime", myCreateTime) 364 .append("startTime", myStartTime) 365 .append("endTime", myEndTime) 366 .append("updateTime", myUpdateTime) 367 .append("status", myStatus) 368 .append("cancelled", myCancelled) 369 .append("combinedRecordsProcessed", myCombinedRecordsProcessed) 370 .append("combinedRecordsProcessedPerSecond", myCombinedRecordsProcessedPerSecond) 371 .append("totalElapsedMillis", myTotalElapsedMillis) 372 .append("workChunksPurged", myWorkChunksPurged) 373 .append("progress", myProgress) 374 .append("errorMessage", myErrorMessage) 375 .append("estimatedTimeRemaining", myEstimatedTimeRemaining) 376 .append("report", getReport()) 377 .append("warningMessages", myWarningMessages) 378 .append("initiatingUsername", myTriggeringUsername) 379 .append("initiatingclientId", myTriggeringClientId) 380 .toString(); 381 } 382 383 /** 384 * @return true if every step of the job has produced exactly 1 chunk. 385 */ 386 public boolean isFastTracking() { 387 if (myFastTracking == null) { 388 myFastTracking = false; 389 } 390 return myFastTracking; 391 } 392 393 public void setFastTracking(boolean theFastTracking) { 394 myFastTracking = theFastTracking; 395 } 396}