4 Replies Latest reply on Apr 10, 2009 7:43 PM by Volker Börchers

    Hibernate Error when persist the outer ProcessInstance.

    Ramon Wang Newbie

      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.
          Volker Börchers Newbie

          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.
            Ramon Wang Newbie

             

            "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.
              Ramon Wang Newbie

              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.
                Volker Börchers Newbie

                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