/* * JBoss, Home of Professional Open Source * Copyright 2005, JBoss Inc., and individual contributors as indicated * by the @authors tag. See the copyright.txt in the distribution for a * full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jbpm.pvm.internal.hibernate; import java.io.Serializable; import java.util.Collection; import java.util.List; import org.hibernate.LockMode; import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.metadata.ClassMetadata; import org.jbpm.api.Execution; import org.jbpm.api.JbpmException; import org.jbpm.api.ProcessDefinition; import org.jbpm.api.history.HistoryComment; import org.jbpm.api.history.HistoryProcessInstance; import org.jbpm.api.task.Task; import org.jbpm.internal.log.Log; import org.jbpm.pvm.internal.client.ClientExecution; import org.jbpm.pvm.internal.client.ClientProcessDefinition; import org.jbpm.pvm.internal.env.EnvironmentImpl; import org.jbpm.pvm.internal.history.model.HistoryCommentImpl; import org.jbpm.pvm.internal.history.model.HistoryProcessInstanceImpl; import org.jbpm.pvm.internal.id.DbidGenerator; import org.jbpm.pvm.internal.job.JobImpl; import org.jbpm.pvm.internal.model.ExecutionImpl; import org.jbpm.pvm.internal.query.DeploymentQueryImpl; import org.jbpm.pvm.internal.query.HistoryActivityInstanceQueryImpl; import org.jbpm.pvm.internal.query.HistoryDetailQueryImpl; import org.jbpm.pvm.internal.query.HistoryProcessInstanceQueryImpl; import org.jbpm.pvm.internal.query.JobQueryImpl; import org.jbpm.pvm.internal.query.ProcessInstanceQueryImpl; import org.jbpm.pvm.internal.query.TaskQueryImpl; import org.jbpm.pvm.internal.session.DbSession; import org.jbpm.pvm.internal.task.TaskImpl; import org.jbpm.pvm.internal.util.Clock; /** * @author Tom Baeyens */ public class DbSessionImpl implements DbSession { private static Log log = Log.getLog(DbSessionImpl.class.getName()); protected Session session; public void close() { session.close(); } public T get(Class entityClass, Object primaryKey) { return entityClass.cast(session.get(entityClass, (Serializable) primaryKey)); } public void flush() { session.flush(); } public void forceVersionUpdate(Object entity) { session.lock(entity, LockMode.FORCE); } public void lockPessimistically(Object entity) { session.lock(entity, LockMode.UPGRADE); } public void save(Object entity) { session.save(entity); } public void update(Object entity) { session.update(entity); } public void merge(Object entity) { session.merge(entity); } public void delete(Object entity) { session.delete(entity); } public Session getSession() { return session; } public void setSession(Session session) { this.session = session; } public List findProcessDefinitionKeys() { return session.getNamedQuery("findProcessDefinitionKeys").list(); } public ClientProcessDefinition findLatestProcessDefinitionByKey(String processDefinitionKey) { Query query = session.getNamedQuery("findProcessDefinitionsByKey"); query.setString("key", processDefinitionKey); query.setMaxResults(1); ClientProcessDefinition processDefinition = (ClientProcessDefinition) query.uniqueResult(); return processDefinition; } public List findProcessDefinitionsByKey(String processDefinitionKey) { Query query = session.getNamedQuery("findProcessDefinitionsByKey"); query.setString("key", processDefinitionKey); return query.list(); } public ClientProcessDefinition findProcessDefinitionById(String processDefinitionId) { Query query = session.getNamedQuery("findProcessDefinitionById"); query.setString("id", processDefinitionId); query.setMaxResults(1); ClientProcessDefinition processDefinition = (ClientProcessDefinition) query.uniqueResult(); return processDefinition; } public void deleteProcessDefinition(String processDefinitionId, boolean deleteProcessInstances, boolean deleteHistory) { List processInstanceIds = findProcessInstanceIds(processDefinitionId); if ( deleteHistory // and if hibernate knows about the history class && (isHistoryEnabled()) ) { List historyProcessInstances = createHistoryProcessInstanceQuery() .processDefinitionId(processDefinitionId) .list(); for (HistoryProcessInstance historyProcessInstance : historyProcessInstances) { session.delete(historyProcessInstance); } } if (deleteProcessInstances) { for (String processInstanceId : processInstanceIds) { deleteProcessInstance(processInstanceId, deleteHistory); } } else { if (processInstanceIds.size()>0) { throw new JbpmException("still "+processInstanceIds.size()+" process instances for process definition "+processDefinitionId); } } ProcessDefinition processDefinition = findProcessDefinitionById(processDefinitionId); session.delete(processDefinition); } public void deleteProcessDefinitionHistory(String processDefinitionId) { List historyProcessInstances = session.createQuery( "select hpi " + "from "+HistoryProcessInstanceImpl.class.getName()+" hpi "+ "where hpi.processDefinitionId = :processDefinitionId " ) .setString("processDefinitionId", processDefinitionId) .list(); for (HistoryProcessInstanceImpl hpi: historyProcessInstances) { session.delete(hpi); } } public boolean isHistoryEnabled() { ClassMetadata historyHibernateMetadata = session.getSessionFactory().getClassMetadata(HistoryProcessInstanceImpl.class); return historyHibernateMetadata!=null; } // process execution queries //////////////////////////////////////////////// public ClientExecution findExecutionById(String executionId) { // query definition can be found at the bottom of resource jbpm.pvm.execution.hbm.xml Query query = session.getNamedQuery("findExecutionById"); query.setString("id", executionId); query.setMaxResults(1); return (ClientExecution) query.uniqueResult(); } public ClientExecution findProcessInstanceById(String processInstanceId) { // query definition can be found at the bottom of resource jbpm.pvm.execution.hbm.xml Query query = session.getNamedQuery("findProcessInstanceById"); query.setString("processInstanceId", processInstanceId); query.setMaxResults(1); return (ClientExecution) query.uniqueResult(); } public ClientExecution findProcessInstanceByIdIgnoreSuspended(String processInstanceId) { // query definition can be found at the bottom of resource jbpm.pvm.execution.hbm.xml Query query = session.getNamedQuery("findProcessInstanceByIdIgnoreSuspended"); query.setString("processInstanceId", processInstanceId); query.setMaxResults(1); return (ClientExecution) query.uniqueResult(); } public List findProcessInstanceIds(String processDefinitionId) { // query definition can be found at the bottom of resource jbpm.pvm.job.hbm.xml Query query = session.createQuery( "select processInstance.id " + "from org.jbpm.pvm.internal.model.ExecutionImpl as processInstance " + "where processInstance.processDefinitionId = :processDefinitionId " + " and processInstance.parent is null" ); query.setString("processDefinitionId", processDefinitionId); return query.list(); } public void deleteProcessInstance(String processInstanceId) { deleteProcessInstance(processInstanceId, true); } public void deleteProcessInstance(String processInstanceId, boolean deleteHistory) { if (processInstanceId==null) { throw new JbpmException("processInstanceId is null"); } // if history should be deleted if ( deleteHistory && (isHistoryEnabled()) ) { // try to get the history HistoryProcessInstanceImpl historyProcessInstance = findHistoryProcessInstanceById(processInstanceId); // if there is a history process instance in the db if (historyProcessInstance!=null) { if (log.isDebugEnabled()) { log.debug("deleting history process instance "+processInstanceId); } session.delete(historyProcessInstance); } } ExecutionImpl processInstance = (ExecutionImpl) findProcessInstanceByIdIgnoreSuspended(processInstanceId); if (processInstance!=null) { deleteSubProcesses(processInstance, deleteHistory); // delete remaining tasks for this process instance List tasks = findTasks(processInstanceId); for (TaskImpl task: tasks) { session.delete(task); } // delete remaining jobs for this process instance JobImpl currentJob = EnvironmentImpl.getFromCurrent(JobImpl.class, false); List jobs = findJobs(processInstanceId); for (JobImpl job: jobs) { if (job!=currentJob){ session.delete(job); } } if (log.isDebugEnabled()) { log.debug("deleting process instance "+processInstanceId); } session.delete(processInstance); } } private void deleteSubProcesses(ExecutionImpl execution, boolean deleteHistory) { ExecutionImpl subProcessInstance = execution.getSubProcessInstance(); if (subProcessInstance!=null) { subProcessInstance.setSuperProcessExecution(null); execution.setSubProcessInstance(null); deleteProcessInstance(subProcessInstance.getId(), deleteHistory); } Collection childExecutions = execution.getExecutions(); if (childExecutions!=null) { for (ExecutionImpl childExecution: childExecutions) { deleteSubProcesses(childExecution, deleteHistory); } } } public HistoryProcessInstanceImpl findHistoryProcessInstanceById(String processInstanceId) { return (HistoryProcessInstanceImpl) session .createQuery( "select hpi " + "from "+HistoryProcessInstance.class.getName()+" as hpi " + "where hpi.processInstanceId = '"+processInstanceId+"'" ).uniqueResult(); } List findTasks(String processInstanceId) { Query query = session.createQuery( "select task " + "from "+TaskImpl.class.getName()+" as task " + "where task.processInstance.id = :processInstanceId" ); query.setString("processInstanceId", processInstanceId); return query.list(); } List findJobs(String processInstanceId) { Query query = session.createQuery( "select job " + "from "+JobImpl.class.getName()+" as job " + "where job.processInstance.id = :processInstanceId" ); query.setString("processInstanceId", processInstanceId); return query.list(); } public void cascadeExecutionSuspend(ExecutionImpl execution) { // cascade suspend to jobs Query query = session.createQuery( "select job " + "from "+JobImpl.class.getName()+" as job " + "where job.execution = :execution " + " and job.state != '"+JobImpl.STATE_SUSPENDED+"' " ); query.setEntity("execution", execution); List jobs = query.list(); for (JobImpl job: jobs) { job.suspend(); } // cascade suspend to tasks query = session.createQuery( "select task " + "from "+TaskImpl.class.getName()+" as task " + "where task.execution = :execution " + " and task.state != '"+Task.STATE_SUSPENDED+"' " ); query.setEntity("execution", execution); List tasks = query.list(); for (TaskImpl task: tasks) { task.suspend(); } } public void cascadeExecutionResume(ExecutionImpl execution) { // cascade suspend to jobs Query query = session.createQuery( "select job " + "from "+JobImpl.class.getName()+" as job " + "where job.execution = :execution " + " and job.state = '"+Task.STATE_SUSPENDED+"' " ); query.setEntity("execution", execution); List jobs = query.list(); for (JobImpl job: jobs) { job.resume(); } // cascade suspend to tasks query = session.createQuery( "select task " + "from "+TaskImpl.class.getName()+" as task " + "where task.execution = :execution " + " and task.state = '"+Task.STATE_SUSPENDED+"' " ); query.setEntity("execution", execution); List tasks = query.list(); for (TaskImpl task: tasks) { task.resume(); } } public TaskImpl createTask() { TaskImpl task = newTask(); task.setCreateTime(Clock.getCurrentTime()); return task; } protected TaskImpl newTask() { TaskImpl task = new TaskImpl(); long dbid = EnvironmentImpl.getFromCurrent(DbidGenerator.class).getNextId(); task.setDbid(dbid); task.setNew(true); return task; } public TaskImpl findTaskByDbid(long taskDbid) { return (TaskImpl) session.get(TaskImpl.class, taskDbid); } public TaskImpl findTaskByExecution(Execution execution) { Query query = session.createQuery( "select task " + "from "+TaskImpl.class.getName()+" as task " + "where task.execution = :execution" ); query.setEntity("execution", execution); return (TaskImpl) query.uniqueResult(); } public JobImpl findFirstAcquirableJob() { Query query = session.getNamedQuery("findFirstAcquirableJob"); query.setTimestamp("now", Clock.getCurrentTime()); query.setMaxResults(1); return (JobImpl) query.uniqueResult(); } public List> findExclusiveJobs(Execution processInstance) { Query query = session.getNamedQuery("findExclusiveJobs"); query.setTimestamp("now", Clock.getCurrentTime()); query.setEntity("processInstance", processInstance); return query.list(); } public JobImpl findFirstDueJob() { Query query = session.getNamedQuery("findFirstDueJob"); query.setMaxResults(1); return (JobImpl) query.uniqueResult(); } public ProcessInstanceQueryImpl createProcessInstanceQuery() { return new ProcessInstanceQueryImpl(); } public TaskQueryImpl createTaskQuery() { return new TaskQueryImpl(); } public HistoryProcessInstanceQueryImpl createHistoryProcessInstanceQuery() { return new HistoryProcessInstanceQueryImpl(); } public HistoryActivityInstanceQueryImpl createHistoryActivityInstanceQuery() { return new HistoryActivityInstanceQueryImpl(); } public HistoryDetailQueryImpl createHistoryDetailQuery() { return new HistoryDetailQueryImpl(); } public JobQueryImpl createJobQuery() { return new JobQueryImpl(); } public DeploymentQueryImpl createDeploymentQuery() { return new DeploymentQueryImpl(); } public List findCommentsByTaskId(String taskId) { Long taskDbid = null; try { taskDbid = Long.parseLong(taskId); } catch (Exception e) { throw new JbpmException("invalid taskId: "+taskId); } return session.createQuery( "select hc " + "from "+HistoryCommentImpl.class.getName()+" as hc " + "where hc.historyTask.dbid = :taskDbid " + "order by hc.historyTaskIndex asc " ).setLong("taskDbid", taskDbid) .list(); } }