org.jbpm.services.task.persistence.JPATaskPersistenceContext Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jbpm-human-task-jpa Show documentation
Show all versions of jbpm-human-task-jpa Show documentation
jBPM JPA Human Task Persistence
/*
* Copyright 2017 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jbpm.services.task.persistence;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import javax.persistence.EntityExistsException;
import javax.persistence.EntityManager;
import javax.persistence.FlushModeType;
import javax.persistence.Id;
import javax.persistence.LockModeType;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import org.drools.core.util.StringUtils;
import org.jbpm.persistence.api.integration.EventManagerProvider;
import org.jbpm.persistence.api.integration.model.TaskInstanceView;
import org.jbpm.query.jpa.data.QueryWhere;
import org.jbpm.services.task.impl.model.AttachmentImpl;
import org.jbpm.services.task.impl.model.CommentImpl;
import org.jbpm.services.task.impl.model.ContentImpl;
import org.jbpm.services.task.impl.model.ContentImpl_;
import org.jbpm.services.task.impl.model.DeadlineImpl;
import org.jbpm.services.task.impl.model.EmailImpl;
import org.jbpm.services.task.impl.model.GroupImpl;
import org.jbpm.services.task.impl.model.OrganizationalEntityImpl;
import org.jbpm.services.task.impl.model.TaskDataImpl_;
import org.jbpm.services.task.impl.model.TaskImpl;
import org.jbpm.services.task.impl.model.TaskImpl_;
import org.jbpm.services.task.impl.model.UserImpl;
import org.kie.api.task.UserGroupCallback;
import org.kie.api.task.model.Attachment;
import org.kie.api.task.model.Comment;
import org.kie.api.task.model.Content;
import org.kie.api.task.model.Email;
import org.kie.api.task.model.Group;
import org.kie.api.task.model.OrganizationalEntity;
import org.kie.api.task.model.Task;
import org.kie.api.task.model.TaskSummary;
import org.kie.api.task.model.User;
import org.kie.internal.task.api.TaskPersistenceContext;
import org.kie.internal.task.api.model.ContentData;
import org.kie.internal.task.api.model.Deadline;
import org.kie.internal.task.api.model.FaultData;
import org.kie.internal.task.api.model.InternalTaskData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.jbpm.services.task.persistence.TaskQueryManager.adaptQueryString;
import static org.kie.internal.query.QueryParameterIdentifiers.FILTER;
import static org.kie.internal.query.QueryParameterIdentifiers.FIRST_RESULT;
import static org.kie.internal.query.QueryParameterIdentifiers.FLUSH_MODE;
import static org.kie.internal.query.QueryParameterIdentifiers.MAX_RESULTS;
import static org.kie.internal.query.QueryParameterIdentifiers.ORDER_BY;
import static org.kie.internal.query.QueryParameterIdentifiers.ORDER_TYPE;
public class JPATaskPersistenceContext implements TaskPersistenceContext {
// logger set to public for test reasons, see the org.jbpm.services.task.TaskQueryBuilderLocalTest
public final static Logger logger = LoggerFactory.getLogger(JPATaskPersistenceContext.class);
private static TaskQueryManager querymanager = TaskQueryManager.get();
protected EntityManager em;
protected final boolean isJTA;
protected final boolean pessimisticLocking;
protected LockModeType lockMode;
public JPATaskPersistenceContext(EntityManager em) {
this(em, true, false, null);
}
public JPATaskPersistenceContext(EntityManager em, boolean isJTA) {
this(em, isJTA, false, null);
}
public JPATaskPersistenceContext(EntityManager em, boolean isJTA, boolean locking, String lockingMode) {
this.em = em;
this.isJTA = isJTA;
this.pessimisticLocking = locking;
this.lockMode = LockModeType.valueOf(lockingMode == null ? LockModeType.PESSIMISTIC_FORCE_INCREMENT.name() : lockingMode);
logger.debug("TaskPersistenceManager configured with em {}, isJTA {}, pessimistic locking {}", em, isJTA, locking);
}
// Package level getters ------------------------------------------------------------------------------------------------------
EntityManager getEntityManager() {
return this.em;
}
// Interface methods ----------------------------------------------------------------------------------------------------------
@Override
public Task findTask(Long taskId) {
check();
Task task = null;
if( this.pessimisticLocking ) {
return this.em.find( TaskImpl.class, taskId, lockMode );
}
task = this.em.find( TaskImpl.class, taskId );
return task;
}
@Override
public Task persistTask(Task task) {
check();
this.em.persist( task );
if( this.pessimisticLocking ) {
this.em.flush();
return this.em.find(TaskImpl.class, task.getId(), lockMode );
}
EventManagerProvider.getInstance().get().create(new TaskInstanceView(task));
return task;
}
@Override
public Task updateTask(Task task) {
check();
Task updated = this.em.merge(task);
EventManagerProvider.getInstance().get().update(new TaskInstanceView(task));
return updated;
}
@Override
public Task removeTask(Task task) {
check();
em.remove( task );
EventManagerProvider.getInstance().get().delete(new TaskInstanceView(task));
return task;
}
@Override
public Group findGroup(String groupId) {
check();
if( this.pessimisticLocking ) {
return this.em.find( GroupImpl.class, groupId, LockModeType.PESSIMISTIC_WRITE );
}
return this.em.find( GroupImpl.class, groupId );
}
@Override
public Group persistGroup(Group group) {
check();
try {
this.em.persist( group );
if( this.pessimisticLocking ) {
this.em.flush();
return this.em.find(GroupImpl.class, group.getId(), LockModeType.PESSIMISTIC_WRITE );
}
} catch (EntityExistsException e) {
throw new RuntimeException("Group already exists with " + group
+ " id, please check that there is no group and user with same id");
}
return group;
}
@Override
public Group updateGroup(Group group) {
check();
return this.em.merge(group);
}
@Override
public Group removeGroup(Group group) {
check();
em.remove( group );
return group;
}
@Override
public User findUser(String userId) {
check();
if( this.pessimisticLocking ) {
return this.em.find( UserImpl.class, userId, LockModeType.PESSIMISTIC_WRITE );
}
return this.em.find( UserImpl.class, userId );
}
@Override
public User persistUser(User user) {
check();
try {
this.em.persist( user );
if( this.pessimisticLocking ) {
this.em.flush();
return this.em.find(UserImpl.class, user.getId(), LockModeType.PESSIMISTIC_WRITE );
}
} catch (EntityExistsException e) {
throw new RuntimeException("User already exists with " + user
+ " id, please check that there is no group and user with same id");
}
return user;
}
@Override
public User updateUser(User user) {
check();
return this.em.merge(user);
}
@Override
public User removeUser(User user) {
check();
em.remove(user);
return user;
}
@Override
public Email findEmail(String emailId) {
check();
if (this.pessimisticLocking) {
return this.em.find(EmailImpl.class, emailId, LockModeType.PESSIMISTIC_WRITE);
}
return this.em.find(EmailImpl.class, emailId);
}
@Override
public Email persistEmail(Email email) {
check();
try {
this.em.persist(email);
if (this.pessimisticLocking) {
this.em.flush();
return this.em.find(EmailImpl.class, email.getId(), LockModeType.PESSIMISTIC_WRITE);
}
} catch (EntityExistsException e) {
throw new RuntimeException("Email already exists with " + email + " id, please check that there is no email with same id");
}
return email;
}
@Override
public Email updateEmail(Email email) {
check();
return this.em.merge(email);
}
@Override
public Email removeEmail(Email email) {
check();
em.remove(email);
return email;
}
@Override
public OrganizationalEntity findOrgEntity(String orgEntityId) {
check();
if( this.pessimisticLocking ) {
return this.em.find( OrganizationalEntityImpl.class, orgEntityId, LockModeType.PESSIMISTIC_WRITE );
}
return this.em.find( OrganizationalEntityImpl.class, orgEntityId );
}
@Override
public OrganizationalEntity persistOrgEntity(OrganizationalEntity orgEntity) {
check();
if (!StringUtils.isEmpty(orgEntity.getId())) {
try {
this.em.persist( orgEntity );
if( this.pessimisticLocking ) {
this.em.flush();
return this.em.find(OrganizationalEntityImpl.class, orgEntity.getId(), LockModeType.PESSIMISTIC_WRITE );
}
} catch (EntityExistsException e) {
throw new RuntimeException("Organizational entity already exists with " + orgEntity
+ " id, please check that there is no group and user with same id");
}
}
return orgEntity;
}
@Override
public OrganizationalEntity updateOrgEntity(OrganizationalEntity orgEntity) {
check();
return this.em.merge(orgEntity);
}
@Override
public OrganizationalEntity removeOrgEntity(OrganizationalEntity orgEntity) {
check();
em.remove( orgEntity );
return orgEntity;
}
@Override
public Content findContent(Long contentId) {
check();
if( this.pessimisticLocking ) {
return this.em.find( ContentImpl.class, contentId, LockModeType.PESSIMISTIC_WRITE );
}
return this.em.find( ContentImpl.class, contentId );
}
@Override
public Content persistContent(Content content) {
check();
this.em.persist( content );
if( this.pessimisticLocking ) {
this.em.flush();
return this.em.find(ContentImpl.class, content.getId(), LockModeType.PESSIMISTIC_WRITE );
}
return content;
}
@Override
public Content updateContent(Content content) {
check();
return this.em.merge(content);
}
@Override
public Content removeContent(Content content) {
check();
em.remove( content );
return content;
}
@Override
public Task setDocumentToTask(Content content, ContentData contentData, Task task) {
Long id = 0L;
if (content != null) {
id = content.getId();
}
((InternalTaskData) task.getTaskData()).setDocument(id, contentData);
return task;
}
@Override
public Task setFaultToTask(Content content, FaultData faultData, Task task) {
Long id = 0L;
if (content != null) {
id = content.getId();
}
((InternalTaskData) task.getTaskData()).setFault(id, faultData);
return task;
}
@Override
public Task setOutputToTask(Content content, ContentData contentData,
Task task) {
Long id = 0L;
if (content != null) {
id = content.getId();
}
((InternalTaskData) task.getTaskData()).setOutput(id, contentData);
return task;
}
@Override
public Attachment findAttachment(Long attachmentId) {
check();
if( this.pessimisticLocking ) {
return this.em.find( AttachmentImpl.class, attachmentId, LockModeType.PESSIMISTIC_WRITE );
}
return this.em.find( AttachmentImpl.class, attachmentId );
}
@Override
public Attachment persistAttachment(Attachment attachment) {
check();
this.em.persist( attachment );
if( this.pessimisticLocking ) {
this.em.flush();
return this.em.find(AttachmentImpl.class, attachment.getId(), LockModeType.PESSIMISTIC_WRITE );
}
return attachment;
}
@Override
public Attachment updateAttachment(Attachment attachment) {
check();
return this.em.merge(attachment);
}
@Override
public Attachment removeAttachment(Attachment attachment) {
check();
em.remove( attachment );
return attachment;
}
@Override
public Attachment removeAttachmentFromTask(Task task, long attachmentId) {
Attachment removed = ((InternalTaskData) task.getTaskData()).removeAttachment(attachmentId);
EventManagerProvider.getInstance().get().update(new TaskInstanceView(task));
return removed;
}
@Override
public Attachment addAttachmentToTask(Attachment attachment, Task task) {
((InternalTaskData) task.getTaskData()).addAttachment(attachment);
EventManagerProvider.getInstance().get().update(new TaskInstanceView(task));
return attachment;
}
@Override
public Comment findComment(Long commentId) {
check();
if( this.pessimisticLocking ) {
return this.em.find( CommentImpl.class, commentId, LockModeType.PESSIMISTIC_WRITE );
}
return this.em.find( CommentImpl.class, commentId );
}
@Override
public Comment persistComment(Comment comment) {
check();
this.em.persist( comment );
if( this.pessimisticLocking ) {
this.em.flush();
return this.em.find(CommentImpl.class, comment.getId(), LockModeType.PESSIMISTIC_WRITE );
}
return comment;
}
@Override
public Comment updateComment(Comment comment) {
check();
return this.em.merge(comment);
}
@Override
public Comment removeComment(Comment comment) {
check();
em.remove( comment );
return comment;
}
@Override
public Comment removeCommentFromTask(Comment comment, Task task) {
((InternalTaskData) task.getTaskData()).removeComment(comment.getId());
EventManagerProvider.getInstance().get().update(new TaskInstanceView(task));
return comment;
}
@Override
public Comment addCommentToTask(Comment comment, Task task) {
((InternalTaskData) task.getTaskData()).addComment(comment);
EventManagerProvider.getInstance().get().update(new TaskInstanceView(task));
return comment;
}
@Override
public Deadline findDeadline(Long deadlineId) {
check();
if( this.pessimisticLocking ) {
return this.em.find( DeadlineImpl.class, deadlineId, LockModeType.PESSIMISTIC_WRITE );
}
return this.em.find( DeadlineImpl.class, deadlineId );
}
@Override
public Deadline persistDeadline(Deadline deadline) {
check();
this.em.persist( deadline );
if( this.pessimisticLocking ) {
this.em.flush();
return this.em.find(DeadlineImpl.class, deadline.getId(), LockModeType.PESSIMISTIC_WRITE );
}
return deadline;
}
@Override
public Deadline updateDeadline(Deadline deadline) {
check();
return this.em.merge(deadline);
}
@Override
public Deadline removeDeadline(Deadline deadline) {
check();
em.remove( deadline );
return deadline;
}
@Override
public T queryWithParametersInTransaction(String queryName,
Map params, Class clazz) {
check();
Query query = getQueryByName(queryName, params);
return queryStringWithParameters(params, false, LockModeType.NONE, clazz, query);
}
@Override
public T queryWithParametersInTransaction(String queryName, boolean singleResult,
Map params, Class clazz) {
check();
Query query = getQueryByName(queryName, params);
return queryStringWithParameters(params, singleResult, LockModeType.NONE, clazz, query);
}
@Override
public T queryAndLockWithParametersInTransaction(String queryName,
Map params, boolean singleResult, Class clazz) {
check();
Query query = getQueryByName(queryName, params);
return queryStringWithParameters(params, singleResult, LockModeType.NONE, clazz, query);
}
@Override
public T queryInTransaction(String queryName, Class clazz) {
check();
Query query = this.em.createNamedQuery(queryName);
return (T) query.getResultList();
}
@Override
public T queryStringInTransaction(String queryString, Class clazz) {
check();
Query query = this.em.createQuery(queryString);
return (T) query.getResultList();
}
@Override
public T queryStringWithParametersInTransaction(String queryString,
Map params, Class clazz) {
check();
String newQueryString = adaptQueryString(new StringBuilder(queryString), params);
if( newQueryString != null ) {
queryString = newQueryString;
}
// logging
logger.debug("QUERY:\n {}", queryString);
if( logger.isDebugEnabled() ) {
StringBuilder paramsStr = new StringBuilder("PARAMS:");
Map orderedParams = new TreeMap(params);
for( Entry entry : orderedParams.entrySet() ) {
paramsStr.append("\n " + entry.getKey() + " : '" + entry.getValue() + "'");
}
logger.debug(paramsStr.toString());
}
Query query = this.em.createQuery(queryString);
return queryStringWithParameters(params, false, LockModeType.NONE, clazz, query);
}
@Override
public T queryStringWithParametersInTransaction(String queryString, boolean singleResult,
Map params, Class clazz) {
check();
Query query = this.em.createQuery(queryString);
return queryStringWithParameters(params, singleResult, LockModeType.NONE, clazz, query);
}
@Override
public T queryAndLockStringWithParametersInTransaction(
String queryName, Map params, boolean singleResult,
Class clazz) {
check();
Query query = getQueryByName(queryName, params);
return queryStringWithParameters(params, singleResult, LockModeType.PESSIMISTIC_WRITE, clazz, query);
}
@Override
public int executeUpdateString(String updateString) {
check();
Query query = this.em.createQuery(updateString);
return query.executeUpdate();
}
@Override
public int executeUpdate(String queryName, Map params) {
check();
Query query = this.em.createNamedQuery(queryName);
if (params != null) {
for (Map.Entry paramEntry : params.entrySet()) {
query.setParameter(paramEntry.getKey(), paramEntry.getValue());
}
}
return query.executeUpdate();
}
@Override
public HashMap addParametersToMap(Object... parameterValues) {
HashMap parameters = new HashMap();
if( parameterValues.length % 2 != 0 ) {
throw new RuntimeException("Expected an even number of parameters, not " + parameterValues.length);
}
for( int i = 0; i < parameterValues.length; ++i ) {
String parameterName = null;
if( parameterValues[i] instanceof String ) {
parameterName = (String) parameterValues[i];
} else {
throw new RuntimeException("Expected a String as the parameter name, not a " + parameterValues[i].getClass().getSimpleName());
}
++i;
parameters.put(parameterName, parameterValues[i]);
}
return parameters;
}
@SuppressWarnings("unchecked")
@Override
public T persist(T object) {
check();
this.em.persist( object );
if( this.pessimisticLocking ) {
this.em.flush();
Object primaryKey = getFieldValueWithAnnotation(object, Id.class);
return (T) this.em.find( object.getClass(), primaryKey, LockModeType.PESSIMISTIC_WRITE );
}
return object;
}
@Override
public T find(Class entityClass, Object primaryKey) {
check();
if( this.pessimisticLocking ) {
return this.em.find( entityClass, primaryKey, LockModeType.PESSIMISTIC_WRITE );
}
return this.em.find( entityClass, primaryKey );
}
@Override
public T remove(T entity) {
check();
em.remove( entity );
return entity;
}
@Override
public T merge(T entity) {
check();
return this.em.merge(entity);
}
private T queryStringWithParameters(Map params, boolean singleResult, LockModeType lockMode,
Class clazz, Query query) {
if (lockMode != null) {
query.setLockMode(lockMode);
}
if (params != null && !params.isEmpty()) {
for (Entry paramEntry : params.entrySet()) {
String name = paramEntry.getKey();
if (FIRST_RESULT.equals(name)) {
query.setFirstResult((Integer) paramEntry.getValue());
continue;
} else if (MAX_RESULTS.equals(name)) {
if (((Integer) paramEntry.getValue()) > 0) {
query.setMaxResults((Integer) paramEntry.getValue());
}
continue;
} else if (FLUSH_MODE.equals(name)) {
query.setFlushMode(FlushModeType.valueOf((String) paramEntry.getValue()));
continue;
}
// skip control parameters
else if ( ORDER_TYPE.equals(name)
|| ORDER_BY.equals(name)
|| FILTER.equals(name)) {
continue;
}
query.setParameter(name, params.get(name));
}
}
if (singleResult) {
List results = query.getResultList();
return (T) ((results.isEmpty() )? null : results.get(0));
}
return (T) query.getResultList();
}
@Override
public boolean isOpen() {
if (this.em == null) {
return false;
}
return this.em.isOpen();
}
@Override
public void joinTransaction() {
if (this.em == null) {
return;
}
if (this.isJTA) {
this.em.joinTransaction();
}
}
@Override
public void close() {
check();
this.em.close();
}
protected void check() {
if (em == null || !em.isOpen()) {
throw new IllegalStateException("Entity manager is null or is closed, exiting...");
}
}
protected Query getQueryByName(String queryName, Map params) {
String queryStr = querymanager.getQuery(queryName, params);
Query query = null;
if (queryStr != null) {
query = this.em.createQuery(queryStr);
} else {
query = this.em.createNamedQuery(queryName);
}
return query;
}
private Object getFieldValueWithAnnotation(Object object, Class extends Annotation> annotation) {
try {
Field[] fields = object.getClass().getDeclaredFields();
for (Field f : fields) {
if (f.isAnnotationPresent(annotation)) {
f.setAccessible(true);
return f.get(object);
}
}
} catch (Exception e) {
logger.error("Unable to find primary key of class {} sure to {}", object.getClass(), e.getMessage());
}
return null;
}
@Override
public Long findTaskIdByContentId( Long contentId ) {
check();
CriteriaBuilder builder = this.em.getCriteriaBuilder();
CriteriaQuery query = builder.createQuery(Long.class);
Root taskRoot = query.from(TaskImpl.class);
Root contentRoot = query.from(ContentImpl.class);
query.select(taskRoot.get(TaskImpl_.id));
Predicate taskContentJoinPred = builder.equal(
contentRoot.get(ContentImpl_.id),
taskRoot.get(TaskImpl_.taskData).get(TaskDataImpl_.outputContentId));
Predicate contentIdPred = builder.equal(
contentRoot.get(ContentImpl_.id),
contentId);
query.where(builder.and(taskContentJoinPred, contentIdPred));
Query choppedLiver = em.createQuery(query);
return (Long) choppedLiver.getSingleResult();
}
private TaskSummaryQueryCriteriaUtil queryUtil = new TaskSummaryQueryCriteriaUtil(this);
@Override
public List doTaskSummaryCriteriaQuery(String userId, UserGroupCallback userGroupCallback, Object queryWhere) {
check();
List result = queryUtil.doCriteriaQuery(userId, userGroupCallback, (QueryWhere) queryWhere);
return result;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy