/*
* Licensed under the Apache License, Version 2.0 (the "License");
*
* You may not use this file except in compliance with the License.
*
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Contributions from 2013-2017 where performed either by US government
* employees, or under US Veterans Health Administration contracts.
*
* US Veterans Health Administration contributions by government employees
* are work of the U.S. Government and are not subject to copyright
* protection in the United States. Portions contributed by government
* employees are USGovWork (17USC ยง105). Not subject to copyright.
*
* Contribution by contractors to the US Veterans Health Administration
* during this period are contractually contributed under the
* Apache License, Version 2.0.
*
* See: https://www.usa.gov/government-works
*
* Contributions prior to 2013:
*
* Copyright (C) International Health Terminology Standards Development Organisation.
* Licensed under the Apache License, Version 2.0.
*
*/
package sh.isaac.provider.workflow.model.contents;
//~--- JDK imports ------------------------------------------------------------
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Comparator;
import java.util.UUID;
//~--- non-JDK imports --------------------------------------------------------
import sh.isaac.api.externalizable.ByteArrayDataBuffer;
import sh.isaac.provider.workflow.BPMNInfo;
//~--- classes ----------------------------------------------------------------
/**
* A single advancement (history) of a given workflow process. A new entry is
* added for every workflow action a user takes.
*
* {@link AbstractStorableWorkflowContents}
*
* @author <a href="mailto:jefron@westcoastinformatics.com">Jesse Efron</a>
*/
public class ProcessHistory
extends AbstractStorableWorkflowContents {
/** The workflow process key for which the Process History is relevant. */
private UUID processId;
/** The user who advanced the process. */
private UUID userId;
/** The time the workflow was advanced. */
private long timeAdvanced;
/** The workflow process state before an action was taken. */
private String initialState;
/** The workflow action taken by the user. */
private String action;
/** The workflow process state that exists after the action was taken. */
private String outcomeState;
/** The comment added by the user when performing the workflow action. */
private String comment;
/** The sequence in the process which the history represents. */
private int historySequence;
/** Process uuid most significant bits. */
private long processIdMsb;
/** Process uuid least significant bits. */
private long processIdLsb;
/** User uuid most significant bits. */
private long userIdMsb;
/** User uuid least significant bits. */
private long userIdLsb;
//~--- constructors --------------------------------------------------------
/**
* Constructor for a new process history based on serialized content.
*
* @param data
* The data to deserialize into its components
*/
public ProcessHistory(byte[] data) {
readData(new ByteArrayDataBuffer(data));
}
/**
* Constructor for a new process history based on specified entry fields.
*
* @param processId the process id
* @param userId the user id
* @param timeAdvanced the time advanced
* @param initialState the initial state
* @param action the action
* @param outcomeState the outcome state
* @param comment the comment
* @param historySequence the history sequence
*/
public ProcessHistory(UUID processId,
UUID userId,
long timeAdvanced,
String initialState,
String action,
String outcomeState,
String comment,
int historySequence) {
this.processId = processId;
this.userId = userId;
this.timeAdvanced = timeAdvanced;
this.initialState = initialState;
this.action = action;
this.outcomeState = outcomeState;
this.comment = comment;
this.historySequence = historySequence;
this.processIdMsb = processId.getMostSignificantBits();
this.processIdLsb = processId.getLeastSignificantBits();
this.userIdMsb = userId.getMostSignificantBits();
this.userIdLsb = userId.getLeastSignificantBits();
}
//~--- methods -------------------------------------------------------------
/**
* Equals.
*
* @param obj the obj
* @return true, if successful
*/
@Override
public boolean equals(Object obj) {
final ProcessHistory other = (ProcessHistory) obj;
return this.processId.equals(other.processId) &&
this.userId.equals(other.userId) &&
(this.timeAdvanced == other.timeAdvanced) &&
this.initialState.equals(other.initialState) &&
this.action.equals(other.action) &&
this.outcomeState.equals(other.outcomeState) &&
this.comment.equals(other.comment) &&
(this.historySequence == other.historySequence);
}
/**
* Hash code.
*
* @return the int
*/
@Override
public int hashCode() {
return this.processId.hashCode() + this.userId.hashCode() + new Long(this.timeAdvanced).hashCode() +
this.initialState.hashCode() + this.action.hashCode() + this.outcomeState.hashCode() +
this.comment.hashCode() + this.historySequence;
}
/**
* To string.
*
* @return the string
*/
@Override
public String toString() {
final LocalDateTime date = LocalDateTime.from(Instant.ofEpochMilli(this.timeAdvanced)
.atZone(ZoneId.systemDefault()));
final String timeAdvancedString = BPMNInfo.workflowDateFormatter.format(date);
return "\n\t\tId: " + this.id + "\n\t\tProcess Id: " + this.processId + "\n\t\tWorkflowUser Id: " + this.userId +
"\n\t\tTime Advanced as Long: " + this.timeAdvanced + "\n\t\tTime Advanced: " + timeAdvancedString +
"\n\t\tInitial State: " + this.initialState + "\n\t\tAction: " + this.action + "\n\t\tOutcome State: " +
this.outcomeState + "\n\t\tComment: " + this.comment + "\n\t\tHistory Sequence: " + this.historySequence;
}
/**
* Put additional workflow fields.
*
* @param out the out
*/
@Override
protected void putAdditionalWorkflowFields(ByteArrayDataBuffer out) {
out.putLong(this.processIdMsb);
out.putLong(this.processIdLsb);
out.putLong(this.userIdMsb);
out.putLong(this.userIdLsb);
out.putLong(this.timeAdvanced);
out.putByteArrayField(this.initialState.getBytes());
out.putByteArrayField(this.action.getBytes());
out.putByteArrayField(this.outcomeState.getBytes());
out.putByteArrayField(this.comment.getBytes());
out.putInt(this.historySequence);
}
//~--- get methods ---------------------------------------------------------
/**
* Gets the action performed upon the workflow process.
*
* @return the action taken
*/
public String getAction() {
return this.action;
}
/**
* Gets the additional workflow fields.
*
* @param in the in
* @return the additional workflow fields
*/
@Override
protected void getAdditionalWorkflowFields(ByteArrayDataBuffer in) {
this.processIdMsb = in.getLong();
this.processIdLsb = in.getLong();
this.userIdMsb = in.getLong();
this.userIdLsb = in.getLong();
this.timeAdvanced = in.getLong();
this.initialState = new String(in.getByteArrayField());
this.action = new String(in.getByteArrayField());
this.outcomeState = new String(in.getByteArrayField());
this.comment = new String(in.getByteArrayField());
this.historySequence = in.getInt();
this.processId = new UUID(this.processIdMsb, this.processIdLsb);
this.userId = new UUID(this.userIdMsb, this.userIdLsb);
}
/**
* Gets the comment provided by the user when advancing the process.
*
* @return the comment
*/
public String getComment() {
return this.comment;
}
/**
* Gets the sequence within the process which the history represents.
*
* @return the history sequence
*/
public int getHistorySequence() {
return this.historySequence;
}
//~--- set methods ---------------------------------------------------------
/**
* Sets the sequence within the process which the history represents.
*
* @param seq the new sequence in the process which the history represents
* @return the history sequence
*/
public void setHistorySequence(int seq) {
this.historySequence = seq;
}
//~--- get methods ---------------------------------------------------------
/**
* Gets the state of the process prior to it being advanced.
*
* @return the initial state of the process
*/
public String getInitialState() {
return this.initialState;
}
/**
* Gets the state of the process following it being advanced.
*
* @return the outcome state
*/
public String getOutcomeState() {
return this.outcomeState;
}
/**
* Gets the key of the process entry.
*
* @return process key
*/
public UUID getProcessId() {
return this.processId;
}
/**
* Gets the time which the workflow process was advanced.
*
* @return the time the process was advanced
*/
public long getTimeAdvanced() {
return this.timeAdvanced;
}
/**
* Gets the user's id that advanced the workflow process.
*
* @return the user nid
*/
public UUID getUserId() {
return this.userId;
}
//~--- inner classes -------------------------------------------------------
/**
* A custom comparator to assist in ordering process history information.
* Based on advancement time.
*
*/
public static class ProcessHistoryComparator
implements Comparator<ProcessHistory> {
/**
* Instantiates a new process history comparator.
*/
public ProcessHistoryComparator() {}
//~--- methods ----------------------------------------------------------
/**
* Compare.
*
* @param o1 the o 1
* @param o2 the o 2
* @return the int
*/
@Override
public int compare(ProcessHistory o1, ProcessHistory o2) {
if (o1.getProcessId()
.equals(o2.getProcessId())) {
final long seq1 = o1.getHistorySequence();
final long seq2 = o2.getHistorySequence();
if (seq1 > seq2) {
return 1;
} else if (seq1 < seq2) {
return -1;
}
}
return 0;
}
}
}