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}