/******************************************************************************* * Copyright 2017 Graz University of Technology * EAAF-Core Components has been developed in a cooperation between EGIZ, * A-SIT+, A-SIT, and Graz University of Technology. * * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the "Licence"); * You may not use this work except in compliance with the Licence. * You may obtain a copy of the Licence at: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * * Unless required by applicable law or agreed to in writing, software * distributed under the Licence is distributed on an "AS IS" basis, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the Licence for the specific language governing permissions and * limitations under the Licence. * * This product combines work with different licenses. See the "NOTICE" text * file for details on the various modules and licenses. * The "NOTICE" text file is part of the distribution. Any derivative works * that you distribute must include a readable copy of the "NOTICE" text file. *******************************************************************************/ /******************************************************************************* *******************************************************************************/ /******************************************************************************* *******************************************************************************/ package at.gv.egiz.eaaf.core.impl.idp.process; import java.io.Serializable; import java.util.Date; import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.time.DurationFormatUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext; import at.gv.egiz.eaaf.core.impl.idp.process.model.ProcessDefinition; import at.gv.egiz.eaaf.core.impl.idp.process.support.SecureRandomHolder; /** * Represents a process being executed. The process instance provides information about the process and its state. * * @author tknall * */ public class ProcessInstance implements Serializable { private static final long serialVersionUID = 1L; private static final int RND_ID_LENGTH = 22; private ProcessDefinition processDefinition; private String nextId; private Date lru; private ExecutionContext executionContext; private ProcessInstanceState state = ProcessInstanceState.NOT_STARTED; private Logger log = LoggerFactory.getLogger(getClass()); /** * Creates a new process instance, based on a given process definition and a * given execution context. If the given execution context is {@code null} a new execution context will be created.

* The process instance id of the execution context will be newly generated if it is {@code null} in the execution context. * * @param processDefinition * The process definition. * @param executionContext * The execution context (may be {@code null}). If {@code null} a new execution context will be created internally. */ ProcessInstance(ProcessDefinition processDefinition, ExecutionContext executionContext) { this.processDefinition = processDefinition; nextId = processDefinition.getStartEvent().getId(); if (executionContext == null) { executionContext = new ExecutionContextImpl(); } if (executionContext.getProcessInstanceId() == null) { String pdIdLocalPart = RandomStringUtils.random(RND_ID_LENGTH, 0, 0, true, true, null, SecureRandomHolder.getInstance()); executionContext.setProcessInstanceId(this.processDefinition.getId() + "-" + pdIdLocalPart); } else { log.debug("Using process instance id from execution context."); } log.debug("Creating process instance with id '{}'.", executionContext.getProcessInstanceId()); this.executionContext = executionContext; touch(); } /** * Returns the underlying process definition. * * @return The underlying process definition. */ ProcessDefinition getProcessDefinition() { touch(); return processDefinition; } /** * Returns the id of the process node to be executed next. * * @return The process node pointer indicating the process node to be executed next. */ public String getNextId() { touch(); return nextId; } /** * Sets the internal pointer to the process node to be executed next. * * @param nextId * The process node id to be executed next. */ void setNextId(String nextId) { touch(); this.nextId = nextId; } /** * Returns the current state of the process instance. * * @return The current state. */ public ProcessInstanceState getState() { touch(); return state; } /** * Sets the current state of the process instance. * * @param state * The current state. */ void setState(ProcessInstanceState state) { touch(); this.state = state; } public String getId() { touch(); return executionContext.getProcessInstanceId(); } /** * Updates the last recently used date of the process instance. */ private void touch() { lru = new Date(); } /** * Returns the date the process instance has been accessed last. * * @return The last recently used date. */ Date getLru() { return lru; } /** * Returns the associated execution context. * @return The execution context (never {@code null}). */ public ExecutionContext getExecutionContext() { touch(); return executionContext; } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("ProcessInstance ["); builder.append("id=").append(executionContext.getProcessInstanceId()); builder.append(", idle since=").append( DurationFormatUtils.formatDurationWords(new Date().getTime() - this.lru.getTime(), true, true)); if (processDefinition != null) { builder.append(", processDefinition.id="); builder.append(processDefinition.getId()); } if (nextId != null) { builder.append(", nextId="); builder.append(nextId); } builder.append(", executionContext=").append(executionContext); builder.append("]"); return builder.toString(); } }