Package org.drools.persistence.processinstance

Source Code of org.drools.persistence.processinstance.ProcessInstanceInfo

package org.drools.persistence.processinstance;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.Lob;
import javax.persistence.MapKey;
import javax.persistence.OneToMany;
import javax.persistence.PreUpdate;
import javax.persistence.Transient;
import javax.persistence.Version;

import org.drools.WorkingMemory;
import org.drools.common.InternalRuleBase;
import org.drools.common.InternalWorkingMemory;
import org.drools.marshalling.impl.MarshallerReaderContext;
import org.drools.marshalling.impl.MarshallerWriteContext;
import org.drools.marshalling.impl.ProcessInstanceMarshaller;
import org.drools.marshalling.impl.ProcessMarshallerRegistry;
import org.drools.persistence.processinstance.variabletypes.VariableInstanceInfo;
import org.drools.process.core.context.variable.VariableScope;
import org.drools.process.instance.ContextInstance;
import org.drools.process.instance.ContextInstanceContainer;
import org.drools.process.instance.ContextableInstance;
import org.drools.process.instance.context.variable.VariableScopeInstance;
import org.drools.process.instance.impl.ProcessInstanceImpl;
import org.drools.runtime.Environment;
import org.drools.runtime.process.NodeInstance;
import org.drools.runtime.process.NodeInstanceContainer;
import org.drools.runtime.process.ProcessInstance;
import org.drools.runtime.process.WorkflowProcessInstance;
import org.drools.workflow.instance.impl.WorkflowProcessInstanceImpl;
import org.hibernate.annotations.CollectionOfElements;

@Entity
public class ProcessInstanceInfo {

    private static final String               VARIABLE_SEPARATOR = ":";

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @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;
    // TODO How do I mark a process instance info as dirty when the process
    // instance has changed (so that byte array is regenerated and saved) ?
    private @Lob
    byte[]                                    processInstanceByteArray;
   
//  @OneToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
//  @JoinColumn(name = "processInstanceId")
//  private Set<EventType>                    eventTypes         = new HashSet<EventType>();   
    private @CollectionOfElements

    @JoinTable(name = "EventTypes", joinColumns = @JoinColumn(name = "InstanceId"))
    Set<String>                               eventTypes         = new HashSet<String>();
    private @Transient
    ProcessInstance                           processInstance;
    private @Transient
    Environment                               env;
    @OneToMany(cascade = CascadeType.ALL)
    @JoinColumn(name = "processInstanceId")
    @MapKey(name = "name")
    private Map<String, VariableInstanceInfo> variables          = new HashMap<String, VariableInstanceInfo>();
    private boolean                           externalVariables  = false;

    protected ProcessInstanceInfo() {
    }

    public ProcessInstanceInfo(ProcessInstance processInstance) {
        this.processInstance = processInstance;
        this.processId = processInstance.getProcessId();
        startDate = new Date();
    }

    public ProcessInstanceInfo(ProcessInstance processInstance,
                               Environment env) {
        this.processInstance = processInstance;
        this.processId = processInstance.getProcessId();
        startDate = new Date();
        this.env = env;
    }

    public long getId() {
        return processInstanceId;
    }

    public String getProcessId() {
        return processId;
    }

    public Date getStartDate() {
        return startDate;
    }

    public Date getLastModificationDate() {
        return lastModificationDate;
    }

    public Date getLastReadDate() {
        return lastReadDate;
    }

    public void updateLastReadDate() {
        lastReadDate = new Date();
    }

    public int getState() {
        return state;
    }

    public ProcessInstance getProcessInstance(WorkingMemory workingMemory,
                                              Environment env) {
        this.env = env;
        if ( processInstance == null ) {
            try {
                ByteArrayInputStream bais = new ByteArrayInputStream( processInstanceByteArray );
                MarshallerReaderContext context = new MarshallerReaderContext( bais,
                                                                               (InternalRuleBase) workingMemory.getRuleBase(),
                                                                               null,
                                                                               null );
                context.wm = (InternalWorkingMemory) workingMemory;
                ProcessInstanceMarshaller marshaller = getMarshallerFromContext( context );
                processInstance = marshaller.readProcessInstance( context,
                                                                  !externalVariables );
                if ( externalVariables ) {
                    restoreVariables();
                }
                context.close();
            } catch ( IOException e ) {
                e.printStackTrace();
                throw new IllegalArgumentException( "IOException while loading process instance: " + e.getMessage(),
                                                    e );
            }
        }
        return processInstance;
    }

    private void restoreVariables() {
        for ( Map.Entry<String, VariableInstanceInfo> entry : variables.entrySet() ) {
            String[] variableHierarchy = entry.getKey().split( VARIABLE_SEPARATOR );
            // last one is variable name
            String variableName = variableHierarchy[variableHierarchy.length - 1];
            // other ones are parent ids
            List<Long> parentIds = new ArrayList<Long>();
            for ( int i = 0; i < variableHierarchy.length - 1; i++ ) {
                parentIds.add( Long.valueOf( variableHierarchy[i] ) );
            }
            restoreVariable( entry.getValue(),
                             parentIds,
                             variableName,
                             (WorkflowProcessInstance) processInstance );
        }
    }

    private void restoreVariable(VariableInstanceInfo variableInfo,
                                 List<Long> parentIds,
                                 String variableName,
                                 NodeInstanceContainer nodeInstanceContainer) throws NumberFormatException {
        if ( parentIds.size() == 0 ) {
            if ( !(nodeInstanceContainer instanceof ContextableInstance) ) {
                throw new IllegalArgumentException( "Parent node instance is not a contextable instance: " + nodeInstanceContainer );
            }
            VariableScopeInstance variableScopeInstance = (VariableScopeInstance) ((ContextableInstance) nodeInstanceContainer).getContextInstance( VariableScope.VARIABLE_SCOPE );
            VariablePersistenceStrategy persistenceStrategy = VariablePersistenceStrategyFactory.getVariablePersistenceStrategy();
            Object value = persistenceStrategy.getVariable( variableInfo,
                                                            this.env );
            System.out.println( ">>>>> Restoring variable " + variableName + " = " + value );
            variableScopeInstance.setVariable( variableName,
                                               value );
        } else {
            Long nodeInstanceId = parentIds.get( 0 );
            // find the node and get the variableScopeInstance and insert the
            // variable..
            Collection<NodeInstance> nodeInstances = nodeInstanceContainer.getNodeInstances();
            for ( NodeInstance nodeInstance : nodeInstances ) {
                if ( nodeInstance.getId() == nodeInstanceId ) {
                    parentIds.remove( 0 );
                    if ( !(nodeInstance instanceof NodeInstanceContainer) ) {
                        throw new IllegalArgumentException( "Restoring variable " + variableName + " but node found is not a node instance container:" + nodeInstance );
                    }
                    restoreVariable( variableInfo,
                                     parentIds,
                                     variableName,
                                     (NodeInstanceContainer) nodeInstance );
                }
                return;
            }
            throw new IllegalArgumentException( "Could not find node instance " + nodeInstanceId + " in " + nodeInstanceContainer );
        }
    }

    private ProcessInstanceMarshaller getMarshallerFromContext(MarshallerReaderContext context) throws IOException {
        ObjectInputStream stream = context.stream;
        String processInstanceType = stream.readUTF();
        return ProcessMarshallerRegistry.INSTANCE.getMarshaller( processInstanceType );
    }

    private void saveProcessInstanceType(MarshallerWriteContext context,
                                         ProcessInstance processInstance,
                                         String processInstanceType) throws IOException {
        ObjectOutputStream stream = context.stream;
        // saves the processInstance type first
        stream.writeUTF( processInstanceType );
    }

    @PreUpdate
    public void update() {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        boolean variablesChanged = false;
        try {
            MarshallerWriteContext context = new MarshallerWriteContext( baos,
                                                                         null,
                                                                         null,
                                                                         null,
                                                                         null );
            String processType = ((ProcessInstanceImpl) processInstance).getProcess().getType();
            saveProcessInstanceType( context,
                                     processInstance,
                                     processType );
            ProcessInstanceMarshaller marshaller = ProcessMarshallerRegistry.INSTANCE.getMarshaller( processType );
            externalVariables = VariablePersistenceStrategyFactory.getVariablePersistenceStrategy().isEnabled();
            marshaller.writeProcessInstance( context,
                                             processInstance,
                                             !externalVariables );
            if ( externalVariables ) {
                variablesChanged = persistVariables();
            }
            context.close();
        } catch ( IOException e ) {
            throw new IllegalArgumentException( "IOException while storing process instance " + processInstance.getId() + ": " + e.getMessage() );
        }
        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 );
            }
        }
    }

    private boolean persistVariables() {
        // Get Process Variables
        VariableScopeInstance variableScopeInstance = (VariableScopeInstance) ((WorkflowProcessInstanceImpl) this.processInstance).getContextInstance( VariableScope.VARIABLE_SCOPE );
        Map<String, Object> processVariables = variableScopeInstance.getVariables();
        Map<String, VariableInstanceInfo> newVariables = new HashMap<String, VariableInstanceInfo>();
        // persist process variables
        persist( processVariables,
                 "",
                 newVariables );
        // persist variables in nested variable scopes
        Collection<NodeInstance> nodeInstances = ((WorkflowProcessInstanceImpl) this.processInstance).getNodeInstances();
        if ( nodeInstances.size() > 0 ) {
            persistNodeVariables( nodeInstances,
                                  "",
                                  newVariables );
        }
        if ( newVariables.size() > 0 || this.variables.size() > 0 ) {
            // clear variables so unnecessary values are removed
            this.variables.clear();
            this.variables.putAll( newVariables );
            // TODO: how can I know that no variables were changed?
            return true;
        } else {
            return false;
        }
    }

    private void persist(Map<String, Object> variables,
                         String prefix,
                         Map<String, VariableInstanceInfo> newVariables) {
        VariablePersistenceStrategy persistenceStrategy = VariablePersistenceStrategyFactory.getVariablePersistenceStrategy();
        for ( Map.Entry<String, Object> entries : variables.entrySet() ) {
            String variableName = prefix + entries.getKey();
            Object value = entries.getValue();
            VariableInstanceInfo oldValue = this.variables.get( variableName );
            VariableInstanceInfo variable = persistenceStrategy.persistVariable( variableName,
                                                                                 value,
                                                                                 oldValue,
                                                                                 this.env );

            if ( variable != null ) {
                System.out.println( "<<<<< Persisting variable " + variableName + " = " + value );
                newVariables.put( variableName,
                                  variable );
            } else {
                System.out.println( "<<<<< Variable " + variableName + " not persisted (value null)" );
            }
        }
    }

    private void persistNodeVariables(Collection<NodeInstance> nodeInstances,
                                      String parentPrefix,
                                      Map<String, VariableInstanceInfo> newVariables) {
        for ( NodeInstance nodeInstance : nodeInstances ) {
            String prefix = parentPrefix + nodeInstance.getId() + VARIABLE_SEPARATOR;
            if ( nodeInstance instanceof ContextInstanceContainer ) {
                List<ContextInstance> variableScopeInstances = ((ContextInstanceContainer) nodeInstance).getContextInstances( VariableScope.VARIABLE_SCOPE );
                if ( variableScopeInstances != null ) {
                    for ( ContextInstance contextInstance : variableScopeInstances ) {
                        VariableScopeInstance variableScopeInstance = (VariableScopeInstance) contextInstance;
                        persist( variableScopeInstance.getVariables(),
                                 prefix,
                                 newVariables );
                    }
                }
            }
            if ( nodeInstance instanceof NodeInstanceContainer ) {
                Collection<NodeInstance> nodeInstancesInsideTheContainer = ((NodeInstanceContainer) nodeInstance).getNodeInstances();
                persistNodeVariables( nodeInstancesInsideTheContainer,
                                      prefix,
                                      newVariables );
            }
        }
    }

    public Map<String, VariableInstanceInfo> getVariables() {
        return variables;
    }

    public void setVariables(Map<String, VariableInstanceInfo> variables) {
        this.variables = variables;
    }

    @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;
        }
        if ( this.variables != other.variables && (this.variables == null || !this.variables.equals( other.variables )) ) {
            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);
        hash = 61 * hash + (this.variables != null ? this.variables.hashCode() : 0);
        return hash;
    }

}
TOP

Related Classes of org.drools.persistence.processinstance.ProcessInstanceInfo

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.