/*
* 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.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.Environment;
import org.jbpm.pvm.internal.history.model.HistoryCommentImpl;
import org.jbpm.pvm.internal.history.model.HistoryProcessInstanceImpl;
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.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> T get(Class<T> 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<String> 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<ClientProcessDefinition> 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<String> processInstanceIds = findProcessInstanceIds(processDefinitionId);
if ( deleteHistory
// and if hibernate knows about the history class
&& (isHistoryEnabled())
) {
List<HistoryProcessInstance> 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<HistoryProcessInstanceImpl> 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<String> 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) {
// delete remaining tasks for this process instance
List<TaskImpl> tasks = findTasks(processInstanceId);
for (TaskImpl task: tasks) {
session.delete(task);
}
// delete remaining jobs for this process instance
JobImpl currentJob = Environment.getFromCurrent(JobImpl.class, false);
List<JobImpl> 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);
}
}
public HistoryProcessInstanceImpl findHistoryProcessInstanceById(String processInstanceId) {
return (HistoryProcessInstanceImpl) session
.createQuery(
"select hpi " +
"from "+HistoryProcessInstance.class.getName()+" as hpi " +
"where hpi.processInstanceId = '"+processInstanceId+"'"
).uniqueResult();
}
List<TaskImpl> 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<JobImpl> 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<JobImpl> 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<TaskImpl> 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<JobImpl> 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<TaskImpl> 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();
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<JobImpl<?>> 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 JobQueryImpl createJobQuery() {
return new JobQueryImpl();
}
public DeploymentQueryImpl createDeploymentQuery() {
return new DeploymentQueryImpl();
}
public List<HistoryComment> 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();
}
}