org.jbpm.persistence.processinstance.ProcessInstanceInfo Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2017 Red Hat, Inc. and/or its affiliates.
*
* 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.
*/
package org.jbpm.persistence.processinstance;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Index;
import javax.persistence.JoinColumn;
import javax.persistence.Lob;
import javax.persistence.SequenceGenerator;
import javax.persistence.Transient;
import javax.persistence.Version;
import org.drools.core.common.InternalKnowledgeRuntime;
import org.drools.core.impl.InternalKnowledgeBase;
import org.drools.core.impl.StatefulKnowledgeSessionImpl;
import org.drools.core.marshalling.impl.MarshallerReaderContext;
import org.drools.core.marshalling.impl.MarshallerWriteContext;
import org.drools.serialization.protobuf.PersisterHelper;
import org.drools.serialization.protobuf.ProtobufMarshaller;
import org.drools.serialization.protobuf.ProtobufMarshallerReaderContext;
import org.drools.serialization.protobuf.ProtobufProcessMarshallerWriteContext;
import org.jbpm.marshalling.impl.JBPMMessages;
import org.jbpm.marshalling.impl.ProcessInstanceMarshaller;
import org.jbpm.marshalling.impl.ProcessMarshallerRegistry;
import org.jbpm.marshalling.impl.ProtobufRuleFlowProcessInstanceMarshaller;
import org.jbpm.persistence.api.PersistentProcessInstance;
import org.jbpm.process.instance.impl.ProcessInstanceImpl;
import org.jbpm.workflow.instance.impl.WorkflowProcessInstanceImpl;
import org.kie.api.runtime.Environment;
import org.kie.api.runtime.process.ProcessInstance;
@Entity
@SequenceGenerator(name="processInstanceInfoIdSeq", sequenceName="PROCESS_INSTANCE_INFO_ID_SEQ")
public class ProcessInstanceInfo implements PersistentProcessInstance {
@Id
@GeneratedValue(strategy = GenerationType.AUTO, generator="processInstanceInfoIdSeq")
@Column(name = "InstanceId")
private Long processInstanceId;
@Version
@Column(name = "OPTLOCK")
private int version;
private String processId;
private Date startDate;
private Date lastReadDate;
private Date lastModificationDate;
private int state;
@Lob
@Column(length=2147483647)
byte[] processInstanceByteArray;
@ElementCollection
@CollectionTable(name="EventTypes", joinColumns=@JoinColumn(name="InstanceId"),
indexes = {@Index(name = "IDX_EventTypes_Id", columnList="InstanceId"),
@Index(name = "IDX_EventTypes_element", columnList="element")})
@Column(name="element")
private Set eventTypes = new HashSet();
@Transient
ProcessInstance processInstance;
@Transient
Environment env;
protected ProcessInstanceInfo() {
}
public ProcessInstanceInfo(ProcessInstance processInstance) {
this.processInstance = processInstance;
this.processId = processInstance.getProcessId();
startDate = new Date();
}
public ProcessInstanceInfo(ProcessInstance processInstance,
Environment env) {
this(processInstance);
this.env = env;
}
/**
* Added in order to satisfy Hibernate AND the JBPMorm.xml:
* - Hibernate needs getter/setters for a the field that's mapped.
*
- (field access is inefficient/dangerous, and not necessary)
* - The JBPMorm.xml queries reference .processInstanceId as well.
*
* If we mapped the field using 'name="id"', the queries would thus fail.
*
* So instead of that, we just add the getters and use 'name="processInstanceId"'.
* @return The processInstanceId field value.
*/
public Long getProcessInstanceId() {
return processInstanceId;
}
public void setProcessInstanceId(Long processInstanceId) {
this.processInstanceId = processInstanceId;
}
public Long getId() {
return processInstanceId;
}
public void setId(Long processInstanceId) {
this.processInstanceId = processInstanceId;
}
public String getProcessId() {
return processId;
}
public Date getStartDate() {
return startDate;
}
public Date getLastModificationDate() {
return lastModificationDate;
}
public Date getLastReadDate() {
return lastReadDate;
}
public void updateLastReadDate() {
Date updateTo = new Date();
if (lastReadDate == null || lastReadDate.compareTo(updateTo) < 0) {
lastReadDate = updateTo;
} else {
lastReadDate = new Date(lastReadDate.getTime() + 1);
}
}
public int getState() {
return state;
}
public ProcessInstance getProcessInstance(InternalKnowledgeRuntime kruntime,
Environment env) {
return getProcessInstance(kruntime, env, false);
}
public ProcessInstance getProcessInstance(InternalKnowledgeRuntime kruntime,
Environment env,
boolean readOnly) {
this.env = env;
if ( processInstance == null ) {
try {
ByteArrayInputStream bais = new ByteArrayInputStream( processInstanceByteArray );
ProtobufMarshallerReaderContext context = new ProtobufMarshallerReaderContext( bais,
(InternalKnowledgeBase) kruntime.getKieBase(),
null,
null,
ProtobufMarshaller.TIMER_READERS,
this.env
);
ProcessInstanceMarshaller marshaller = getMarshallerFromContext( context );
context.setWorkingMemory( ((StatefulKnowledgeSessionImpl) kruntime).getInternalWorkingMemory() );
processInstance = marshaller.readProcessInstance(context);
((WorkflowProcessInstanceImpl) processInstance).setPersisted(false);
if (readOnly) {
((WorkflowProcessInstanceImpl) processInstance).disconnect();
}
context.close();
} catch ( IOException e ) {
throw new IllegalArgumentException( "IOException while loading process instance: " + e.getMessage(), e);
}
}
((WorkflowProcessInstanceImpl) processInstance).internalSetStartDate(this.startDate);
return processInstance;
}
private ProcessInstanceMarshaller getMarshallerFromContext(MarshallerReaderContext context) throws IOException {
String processInstanceType = context.readUTF();
return ProcessMarshallerRegistry.INSTANCE.getMarshaller( processInstanceType );
}
private void saveProcessInstanceType(MarshallerWriteContext context,
ProcessInstance processInstance,
String processInstanceType) throws IOException {
// saves the processInstance type first
context.writeUTF( processInstanceType );
}
public void transform() {
// if (processInstance == null) {
// return;
// }
ByteArrayOutputStream baos = new ByteArrayOutputStream();
boolean variablesChanged = false;
try {
ProtobufProcessMarshallerWriteContext context = new ProtobufProcessMarshallerWriteContext( baos,
null,
null,
null,
null,
this.env );
context.setProcessInstanceId(processInstance.getId());
context.setState(processInstance.getState() == ProcessInstance.STATE_ACTIVE ?
ProtobufProcessMarshallerWriteContext.STATE_ACTIVE :
ProtobufProcessMarshallerWriteContext.STATE_COMPLETED);
String processType = ((ProcessInstanceImpl) processInstance).getProcess().getType();
saveProcessInstanceType( context,
processInstance,
processType );
ProcessInstanceMarshaller marshaller = ProcessMarshallerRegistry.INSTANCE.getMarshaller( processType );
Object result = marshaller.writeProcessInstance( context,
processInstance);
if( marshaller instanceof ProtobufRuleFlowProcessInstanceMarshaller && result != null ) {
JBPMMessages.ProcessInstance _instance = (JBPMMessages.ProcessInstance)result;
PersisterHelper.writeToStreamWithHeader( context,
_instance );
}
context.close();
} catch ( IOException e ) {
throw new IllegalArgumentException( "IOException while storing process instance "
+ processInstance.getId() + ": " + e.getMessage(), e );
}
byte[] newByteArray = baos.toByteArray();
if ( variablesChanged || !Arrays.equals( newByteArray,
processInstanceByteArray ) ) {
this.state = processInstance.getState();
this.lastModificationDate = new Date();
this.processInstanceByteArray = newByteArray;
this.eventTypes.clear();
for ( String type : processInstance.getEventTypes() ) {
eventTypes.add( type );
}
}
if (!processInstance.getProcessId().equals(this.processId)) {
this.processId = processInstance.getProcessId();
}
((WorkflowProcessInstanceImpl) processInstance).setPersisted(true);
}
@Override
public boolean equals(Object obj) {
if ( obj == null ) {
return false;
}
if ( getClass() != obj.getClass() ) {
return false;
}
final ProcessInstanceInfo other = (ProcessInstanceInfo) obj;
if ( this.processInstanceId != other.processInstanceId && (this.processInstanceId == null || !this.processInstanceId.equals( other.processInstanceId )) ) {
return false;
}
if ( this.version != other.version ) {
return false;
}
if ( (this.processId == null) ? (other.processId != null) : !this.processId.equals( other.processId ) ) {
return false;
}
if ( this.startDate != other.startDate && (this.startDate == null || !this.startDate.equals( other.startDate )) ) {
return false;
}
if ( this.lastReadDate != other.lastReadDate && (this.lastReadDate == null || !this.lastReadDate.equals( other.lastReadDate )) ) {
return false;
}
if ( this.lastModificationDate != other.lastModificationDate && (this.lastModificationDate == null || !this.lastModificationDate.equals( other.lastModificationDate )) ) {
return false;
}
if ( this.state != other.state ) {
return false;
}
if ( !Arrays.equals( this.processInstanceByteArray,
other.processInstanceByteArray ) ) {
return false;
}
if ( this.eventTypes != other.eventTypes && (this.eventTypes == null || !this.eventTypes.equals( other.eventTypes )) ) {
return false;
}
if ( this.processInstance != other.processInstance && (this.processInstance == null || !this.processInstance.equals( other.processInstance )) ) {
return false;
}
if ( this.env != other.env && (this.env == null || !this.env.equals( other.env )) ) {
return false;
}
return true;
}
@Override
public int hashCode() {
int hash = 7;
hash = 61 * hash + (this.processInstanceId != null ? this.processInstanceId.hashCode() : 0);
hash = 61 * hash + this.version;
hash = 61 * hash + (this.processId != null ? this.processId.hashCode() : 0);
hash = 61 * hash + (this.startDate != null ? this.startDate.hashCode() : 0);
hash = 61 * hash + (this.lastReadDate != null ? this.lastReadDate.hashCode() : 0);
hash = 61 * hash + (this.lastModificationDate != null ? this.lastModificationDate.hashCode() : 0);
hash = 61 * hash + this.state;
hash = 61 * hash + Arrays.hashCode( this.processInstanceByteArray );
hash = 61 * hash + (this.eventTypes != null ? this.eventTypes.hashCode() : 0);
hash = 61 * hash + (this.processInstance != null ? this.processInstance.hashCode() : 0);
hash = 61 * hash + (this.env != null ? this.env.hashCode() : 0);
return hash;
}
public int getVersion() {
return version;
}
public Set getEventTypes() {
return eventTypes;
}
public byte [] getProcessInstanceByteArray() {
return processInstanceByteArray;
}
public void clearProcessInstance(){
processInstance = null;
}
public Environment getEnv() {
return env;
}
public void setEnv(Environment env) {
this.env = env;
}
}