001/*- 002 * #%L 003 * HAPI FHIR JPA Server - Batch2 Task Processor 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.batch2.model; 021 022import ca.uhn.fhir.model.api.IModelJson; 023import ca.uhn.fhir.rest.server.util.JsonDateDeserializer; 024import ca.uhn.fhir.rest.server.util.JsonDateSerializer; 025import ca.uhn.fhir.util.JsonUtil; 026import com.fasterxml.jackson.annotation.JsonProperty; 027import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 028import com.fasterxml.jackson.databind.annotation.JsonSerialize; 029import org.apache.commons.lang3.builder.ToStringBuilder; 030 031import java.util.Date; 032 033import static ca.uhn.fhir.batch2.util.Batch2Utils.REDUCTION_STEP_CHUNK_ID_PLACEHOLDER; 034import static org.apache.commons.lang3.StringUtils.isNotBlank; 035 036/** 037 * Payload for step processing. 038 * Implements a state machine on {@link WorkChunkStatusEnum}. 039 * 040 * @see hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_jpa_batch/batch2_states.md 041 */ 042public class WorkChunk extends WorkChunkMetadata { 043 044 @JsonProperty("data") 045 private String myData; 046 047 @JsonProperty("createTime") 048 @JsonSerialize(using = JsonDateSerializer.class) 049 @JsonDeserialize(using = JsonDateDeserializer.class) 050 private Date myCreateTime; 051 052 @JsonProperty("startTime") 053 @JsonSerialize(using = JsonDateSerializer.class) 054 @JsonDeserialize(using = JsonDateDeserializer.class) 055 private Date myStartTime; 056 057 @JsonProperty("endTime") 058 @JsonSerialize(using = JsonDateSerializer.class) 059 @JsonDeserialize(using = JsonDateDeserializer.class) 060 private Date myEndTime; 061 062 @JsonProperty("updateTime") 063 @JsonSerialize(using = JsonDateSerializer.class) 064 @JsonDeserialize(using = JsonDateDeserializer.class) 065 private Date myUpdateTime; 066 067 /** 068 * Timestamp of when next to call the current workchunk poll step. 069 */ 070 @JsonProperty("nextPollTimestamp") 071 @JsonSerialize(using = JsonDateSerializer.class) 072 @JsonDeserialize(using = JsonDateDeserializer.class) 073 private Date myNextPollTime; 074 075 /** 076 * Total polling attempts done thus far. 077 */ 078 @JsonProperty("pollAttempts") 079 private Integer myPollAttempts; 080 081 @JsonProperty(value = "recordsProcessed", access = JsonProperty.Access.READ_ONLY) 082 private Integer myRecordsProcessed; 083 084 @JsonProperty(value = "errorMessage", access = JsonProperty.Access.READ_ONLY) 085 private String myErrorMessage; 086 087 @JsonProperty(value = "errorCount", access = JsonProperty.Access.READ_ONLY) 088 private int myErrorCount; 089 090 @JsonProperty(value = "warningMessage", access = JsonProperty.Access.READ_ONLY) 091 private String myWarningMessage; 092 093 /** 094 * Constructor 095 */ 096 public WorkChunk() { 097 super(); 098 } 099 100 public WorkChunk setId(String theId) { 101 super.setId(theId); 102 return this; 103 } 104 105 public WorkChunk setStatus(WorkChunkStatusEnum theStatus) { 106 super.setStatus(theStatus); 107 return this; 108 } 109 110 public WorkChunk setInstanceId(String theInstanceId) { 111 super.setInstanceId(theInstanceId); 112 return this; 113 } 114 115 public WorkChunk setTargetStepId(String theTargetStepId) { 116 super.setTargetStepId(theTargetStepId); 117 return this; 118 } 119 120 public WorkChunk setJobDefinitionVersion(int theJobDefinitionVersion) { 121 super.setJobDefinitionVersion(theJobDefinitionVersion); 122 return this; 123 } 124 125 public WorkChunk setJobDefinitionId(String theJobDefinitionId) { 126 super.setJobDefinitionId(theJobDefinitionId); 127 return this; 128 } 129 130 public int getErrorCount() { 131 return myErrorCount; 132 } 133 134 public WorkChunk setErrorCount(int theErrorCount) { 135 myErrorCount = theErrorCount; 136 return this; 137 } 138 139 public Date getStartTime() { 140 return myStartTime; 141 } 142 143 public WorkChunk setStartTime(Date theStartTime) { 144 myStartTime = theStartTime; 145 return this; 146 } 147 148 public Date getEndTime() { 149 return myEndTime; 150 } 151 152 public WorkChunk setEndTime(Date theEndTime) { 153 myEndTime = theEndTime; 154 return this; 155 } 156 157 public Integer getRecordsProcessed() { 158 return myRecordsProcessed; 159 } 160 161 public WorkChunk setRecordsProcessed(Integer theRecordsProcessed) { 162 myRecordsProcessed = theRecordsProcessed; 163 return this; 164 } 165 166 public String getData() { 167 return myData; 168 } 169 170 public WorkChunk setData(String theData) { 171 myData = theData; 172 return this; 173 } 174 175 public WorkChunk setData(IModelJson theData) { 176 setData(JsonUtil.serializeOrInvalidRequest(theData)); 177 return this; 178 } 179 180 public <T extends IModelJson> T getData(Class<T> theType) { 181 return JsonUtil.deserialize(getData(), theType); 182 } 183 184 public Date getCreateTime() { 185 return myCreateTime; 186 } 187 188 public void setCreateTime(Date theCreateTime) { 189 myCreateTime = theCreateTime; 190 } 191 192 public String getErrorMessage() { 193 return myErrorMessage; 194 } 195 196 public WorkChunk setErrorMessage(String theErrorMessage) { 197 myErrorMessage = theErrorMessage; 198 return this; 199 } 200 201 public Date getUpdateTime() { 202 return myUpdateTime; 203 } 204 205 public void setUpdateTime(Date theUpdateTime) { 206 myUpdateTime = theUpdateTime; 207 } 208 209 public Date getNextPollTime() { 210 return myNextPollTime; 211 } 212 213 public void setNextPollTime(Date theNextPollTime) { 214 myNextPollTime = theNextPollTime; 215 } 216 217 public Integer getPollAttempts() { 218 return myPollAttempts; 219 } 220 221 public void setPollAttempts(int thePollAttempts) { 222 myPollAttempts = thePollAttempts; 223 } 224 225 public String getWarningMessage() { 226 return myWarningMessage; 227 } 228 229 public WorkChunk setWarningMessage(String theWarningMessage) { 230 myWarningMessage = theWarningMessage; 231 return this; 232 } 233 234 /** 235 * Returns true if the workchunk is a reduction workchunk; false otherwise 236 */ 237 public boolean isReductionWorkChunk() { 238 return getId() != null && getId().equals(REDUCTION_STEP_CHUNK_ID_PLACEHOLDER); 239 } 240 241 @Override 242 public String toString() { 243 ToStringBuilder b = new ToStringBuilder(this); 244 b.append("Id", getId()); 245 b.append("Sequence", getSequence()); 246 b.append("Status", getStatus()); 247 b.append("JobDefinitionId", getJobDefinitionId()); 248 b.append("JobDefinitionVersion", getJobDefinitionVersion()); 249 b.append("TargetStepId", getTargetStepId()); 250 b.append("InstanceId", getInstanceId()); 251 b.append("Data", isNotBlank(myData) ? "(present)" : "(absent)"); 252 b.append("CreateTime", myCreateTime); 253 b.append("StartTime", myStartTime); 254 b.append("EndTime", myEndTime); 255 b.append("UpdateTime", myUpdateTime); 256 b.append("RecordsProcessed", myRecordsProcessed); 257 if (myNextPollTime != null) { 258 b.append("NextPollTime", myNextPollTime); 259 } 260 b.append("PollAttempts", myPollAttempts); 261 if (isNotBlank(myErrorMessage)) { 262 b.append("ErrorMessage", myErrorMessage); 263 } 264 if (myErrorCount > 0) { 265 b.append("ErrorCount", myErrorCount); 266 } 267 if (isNotBlank(myWarningMessage)) { 268 b.append("WarningMessage", myWarningMessage); 269 } 270 return b.toString(); 271 } 272}