4 Replies Latest reply on Apr 10, 2009 7:43 PM by boercher

    Hibernate Error when persist the outer ProcessInstance.

      Hi guys

      I'm using JBPM 3.3.0.GA, I have a use case that want to create a new ProcessInstance (name as A) inside an actionHandler of an outer one, the code in the action handler would like this:

      @Override
       public void execute(ExecutionContext executionContext) throws Exception {
       // get operation context from workflow
       OperationContext context = (OperationContext) executionContext
       .getContextInstance().getTransientVariable(
       Operation.OPERATION_CONTEXT);
       // create discovery operation
       WorkflowOperation discoveryOperation = new WorkflowOperation(context);
       // create discovery related workflow
       ProcessDefinition processDefinition = ProcessDefinition.parseXmlString(definition);
       ProcessInstance processInstance =
       new ProcessInstance(processDefinition);
       discoveryOperation.setProcessInstance(processInstance);
      
       new JBossCacheServiceFactory().getCacheService(
       CacheRegionConstants.TASK).put(context.getOperationId(),
       discoveryOperation);
       if (logger.isDebugEnabled()) {
       logger.debug("Discovery Operation with Workflow created successfully.");
       }
       }
      


      For this inner processInstance I didn't do anything like call the save method to make it persisted, and this is also what i expected, because i want to put it in the cache, and the following code show how i created the outer processInstance:

      public static final void createProcess(OperationContext context) {
       JbpmContext jbpmContext = JbpmConfingurationFactory.jbpmConfiguration
       .createJbpmContext();
       try {
       ProcessDefinition retrievedPd = jbpmContext.getGraphSession()
       .findLatestProcessDefinition(context.getWorkflowName());
       if (retrievedPd == null) {
       logger.error("Can not find Process Definition with name: " + context.getWorkflowName());
       throw new DMException("Can not find Process Definition with name: " + context.getWorkflowName());
       }
       ProcessInstance processInstance = new ProcessInstance(retrievedPd);
       processInstance.setKey(context.getTaskId());
       processInstance.getContextInstance().setTransientVariable(Operation.OPERATION_CONTEXT, context);
       // ready to signal work flow
       processInstance.signal();
       jbpmContext.save(processInstance);
       if (logger.isDebugEnabled()) {
       logger.debug("---------------- create processinstance -----------------");
       logger.debug("---------------- complete [" + context.getTaskId() + "] -----------------");
       }
       } finally {
       jbpmContext.close();
       }
       }
      


      You see i call the save method and try to make the outer processInstance persisted, so I expect the outer processInstance should be persisted successfully but the inner one shouldn't, because i explicitily call the save method for the outer one not for the inner one, this make sense to me and i think it's a correct logic, but when i close the jbpmContext, i got the following error:
      10:36:36,392 ERROR [DbPersistenceService] hibernate commit failed
      org.hibernate.TransientObjectException: object references an unsaved transient instance - save the t
      ransient instance before flushing: org.jbpm.graph.def.Node
       at org.hibernate.engine.ForeignKeys.getEntityIdentifierIfNotUnsaved(ForeignKeys.java:219)
       at org.hibernate.type.EntityType.getIdentifier(EntityType.java:397)
       at org.hibernate.type.ManyToOneType.isDirty(ManyToOneType.java:242)
       at org.hibernate.type.TypeFactory.findDirty(TypeFactory.java:597)
       at org.hibernate.persister.entity.AbstractEntityPersister.findDirty(AbstractEntityPersister.
      java:3128)
       at org.hibernate.event.def.DefaultFlushEntityEventListener.dirtyCheck(DefaultFlushEntityEven
      tListener.java:479)
       at org.hibernate.event.def.DefaultFlushEntityEventListener.isUpdateNecessary(DefaultFlushEnt
      ityEventListener.java:204)
       at org.hibernate.event.def.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityE
      ventListener.java:127)
       at org.hibernate.event.def.AbstractFlushingEventListener.flushEntities(AbstractFlushingEvent
      Listener.java:196)
       at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(Abstrac
      tFlushingEventListener.java:76)
       at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:
      26)
       at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
       at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
       at org.hibernate.transaction.JTATransaction.commit(JTATransaction.java:135)
       at org.jbpm.persistence.db.DbPersistenceService.commit(DbPersistenceService.java:262)
       at org.jbpm.persistence.db.DbPersistenceService.close(DbPersistenceService.java:218)
       at org.jbpm.svc.Services.close(Services.java:236)
       at org.jbpm.JbpmContext.close(JbpmContext.java:136)
      
      


      So, please tell me, did i miss something? Thank you very very much.

      P.S. I post a similar topic yesterday, but it's not as clear as this one, so i post this new one.

        • 1. Re: Hibernate Error when persist the outer ProcessInstance.

          Obviously creation of ProcessInstances involves the database. I've looked up the ProcessInstance constructor:

          public ProcessInstance(ProcessDefinition processDefinition, Map<String, Object> variables, String key)
           {
           [...]
           // if this process instance is created in the context of a persistent operation
           Services.assignId(this);
           [...]
           }
          

          You are surely operating in the context of a persistent operation so this call to this static method of Services (I guess these are the services from the jbpm.cfg.xml) will do some Hibernate stuff.

          Since jBPM heavily relies on a database for everything (transaction safety, logging, ...) I would guess that it will be hard to work around that by other means than by crude hacks.

          Volker

          • 2. Re: Hibernate Error when persist the outer ProcessInstance.

             

            "boercher" wrote:
            Obviously creation of ProcessInstances involves the database. I've looked up the ProcessInstance constructor:

            public ProcessInstance(ProcessDefinition processDefinition, Map<String, Object> variables, String key)
             {
             [...]
             // if this process instance is created in the context of a persistent operation
             Services.assignId(this);
             [...]
             }
            

            You are surely operating in the context of a persistent operation so this call to this static method of Services (I guess these are the services from the jbpm.cfg.xml) will do some Hibernate stuff.

            Since jBPM heavily relies on a database for everything (transaction safety, logging, ...) I would guess that it will be hard to work around that by other means than by crude hacks.

            Volker


            Yes, Volker, you are right. What I have to do is to extend from the ProcessInstance to create a new type of ProcessInstance -- NonPersistProcessInstance. Code would like:
            public NonPersistProcessInstance(ProcessDefinition processDefinition,
             Map variables, String key) {
            
             if (processDefinition == null)
             throw new JbpmException(
             "can't create a process instance when processDefinition is null");
            
             // initialize the members
             this.processDefinition = processDefinition;
             this.rootToken = new Token(this);
             this.start = Clock.getCurrentTime();
             this.key = key;
            
             // if this process instance is created in the context of a persistent
             // operation
             // DO NOT PERSIST
             //Services.assignId(this);
            
             // create the optional definitions
             Map definitions = processDefinition.getDefinitions();
             // if the state-definition has optional definitions
             if (definitions != null) {
             instances = new HashMap();
             // loop over each optional definition
             Iterator iter = definitions.values().iterator();
             while (iter.hasNext()) {
             ModuleDefinition definition = (ModuleDefinition) iter.next();
             // and create the corresponding optional instance
             ModuleInstance instance = definition.createInstance();
             if (instance != null) {
             addInstance(instance);
             }
             }
             }
            
             // add the creation log
             rootToken.addLog(new ProcessInstanceCreateLog());
            
             // set the variables
             ContextInstance contextInstance = getContextInstance();
             if ((contextInstance != null) && (variables != null)) {
             contextInstance.addVariables(variables);
             }
            
             Node initialNode = rootToken.getNode();
             // fire the process start event
             if (initialNode != null) {
             ExecutionContext executionContext = new ExecutionContext(rootToken);
             processDefinition.fireEvent(Event.EVENTTYPE_PROCESS_START,
             executionContext);
            
             // execute the start node
             initialNode.execute(executionContext);
             }
            
             }
            


            I commented the "assignId" method call in the constructor, this seems to be rude, but I don't know if there is any better idea...

            Thank you Volker.

            • 3. Re: Hibernate Error when persist the outer ProcessInstance.

              So is there any jBPM guy can answer my question? Is this the rude way is the only way for this question? thanks.

              • 4. Re: Hibernate Error when persist the outer ProcessInstance.

                It seems that jBPM 4 will support transient process executions. See "Execution Modes" in these slides: http://processdevelopments.blogspot.com/2009/03/jbpm-slides-of-bejug-event-yesterday.html

                Volker