From d9cd9b1046351f80b7ed9bbd4dfbca6b048158e5 Mon Sep 17 00:00:00 2001 From: Maciej Swiderski Date: Wed, 11 Dec 2013 12:08:37 +0100 Subject: [PATCH] unification of persistence and transaction handling for jbpm and human task --- .../DroolsSpringTransactionManager.java | 9 ++ .../HumanTaskSpringTransactionManager.java | 9 ++ kie-aries-blueprint/pom.xml | 10 ++ .../api/command/RemoteRuntimeEngine.java | 4 +- .../command/RemoteTaskCommandExecutor.java | 10 +- kie-remote/kie-services-remote/pom.xml | 1 - .../remote/cdi/TransactionalExecutor.java | 83 ------------ .../remote/jms/RequestMessageBean.java | 11 +- .../services/remote/rest/ResourceBase.java | 23 ++-- .../remote/rest/RestProcessRequestBean.java | 13 +- .../util/ExecuteAndSerializeCommand.java | 35 +++++ kie-spring/pom.xml | 6 + .../AbstractKieSpringJpaManager.java | 125 ++++++++++++++++++ .../HumanTaskSpringTransactionManager.java | 10 ++ .../persistence/KieSpringJpaManager.java | 91 ++----------- .../persistence/KieSpringTaskJpaManager.java | 67 ++++++++++ .../KieSpringTransactionManager.java | 24 ++++ 17 files changed, 341 insertions(+), 190 deletions(-) delete mode 100644 kie-remote/kie-services-remote/src/main/java/org/kie/services/remote/cdi/TransactionalExecutor.java create mode 100644 kie-remote/kie-services-remote/src/main/java/org/kie/services/remote/util/ExecuteAndSerializeCommand.java create mode 100644 kie-spring/src/main/java/org/kie/spring/persistence/AbstractKieSpringJpaManager.java create mode 100644 kie-spring/src/main/java/org/kie/spring/persistence/KieSpringTaskJpaManager.java diff --git a/drools-spring-legacy5/src/main/java/org/drools/container/spring/beans/persistence/DroolsSpringTransactionManager.java b/drools-spring-legacy5/src/main/java/org/drools/container/spring/beans/persistence/DroolsSpringTransactionManager.java index 995dbfcd5e..7e1cdeda1e 100644 --- a/drools-spring-legacy5/src/main/java/org/drools/container/spring/beans/persistence/DroolsSpringTransactionManager.java +++ b/drools-spring-legacy5/src/main/java/org/drools/container/spring/beans/persistence/DroolsSpringTransactionManager.java @@ -138,4 +138,13 @@ public int getStatus() { public void registerTransactionSynchronization(TransactionSynchronization ts) { TransactionSynchronizationManager.registerSynchronization( new SpringTransactionSynchronizationAdapter( ts ) ); } + + @Override + public void putResource(Object key, Object resource) { + } + + @Override + public Object getResource(Object key) { + return null; + } } diff --git a/drools-spring-legacy5/src/main/java/org/drools/container/spring/beans/persistence/HumanTaskSpringTransactionManager.java b/drools-spring-legacy5/src/main/java/org/drools/container/spring/beans/persistence/HumanTaskSpringTransactionManager.java index de066b9206..cc9192a11e 100644 --- a/drools-spring-legacy5/src/main/java/org/drools/container/spring/beans/persistence/HumanTaskSpringTransactionManager.java +++ b/drools-spring-legacy5/src/main/java/org/drools/container/spring/beans/persistence/HumanTaskSpringTransactionManager.java @@ -130,4 +130,13 @@ public int getStatus() { public void registerTransactionSynchronization(TransactionSynchronization ts) { TransactionSynchronizationManager.registerSynchronization( new SpringTransactionSynchronizationAdapter( ts ) ); } + + @Override + public void putResource(Object key, Object resource) { + } + + @Override + public Object getResource(Object key) { + return null; + } } diff --git a/kie-aries-blueprint/pom.xml b/kie-aries-blueprint/pom.xml index e37bbfb98d..4b0ef3afdd 100644 --- a/kie-aries-blueprint/pom.xml +++ b/kie-aries-blueprint/pom.xml @@ -75,6 +75,16 @@ jbpm-persistence-jpa true + + org.jbpm + jbpm-runtime-manager + true + + + javax.enterprise + cdi-api + true + org.hibernate.javax.persistence diff --git a/kie-remote/kie-services-client/src/main/java/org/kie/services/client/api/command/RemoteRuntimeEngine.java b/kie-remote/kie-services-client/src/main/java/org/kie/services/client/api/command/RemoteRuntimeEngine.java index d498214e37..297aeab4aa 100644 --- a/kie-remote/kie-services-client/src/main/java/org/kie/services/client/api/command/RemoteRuntimeEngine.java +++ b/kie-remote/kie-services-client/src/main/java/org/kie/services/client/api/command/RemoteRuntimeEngine.java @@ -2,8 +2,10 @@ import org.drools.core.command.CommandService; import org.drools.core.command.impl.CommandBasedStatefulKnowledgeSession; +import org.drools.core.impl.EnvironmentFactory; import org.jbpm.process.audit.AuditLogService; import org.jbpm.process.audit.CommandBasedAuditLogService; +import org.jbpm.services.task.events.TaskEventSupport; import org.jbpm.services.task.impl.command.CommandBasedTaskService; import org.kie.api.runtime.CommandExecutor; import org.kie.api.runtime.KieSession; @@ -28,7 +30,7 @@ public KieSession getKieSession() { public TaskService getTaskService() { CommandExecutor executor = new RemoteTaskCommandExecutor(config); - return new CommandBasedTaskService(executor); + return new CommandBasedTaskService((CommandService)executor, new TaskEventSupport()); } public AuditLogService getAuditLogService() { diff --git a/kie-remote/kie-services-client/src/main/java/org/kie/services/client/api/command/RemoteTaskCommandExecutor.java b/kie-remote/kie-services-client/src/main/java/org/kie/services/client/api/command/RemoteTaskCommandExecutor.java index 60aefb37f7..c6a940f5d8 100644 --- a/kie-remote/kie-services-client/src/main/java/org/kie/services/client/api/command/RemoteTaskCommandExecutor.java +++ b/kie-remote/kie-services-client/src/main/java/org/kie/services/client/api/command/RemoteTaskCommandExecutor.java @@ -1,12 +1,18 @@ package org.kie.services.client.api.command; +import org.drools.core.command.CommandService; import org.kie.api.runtime.CommandExecutor; +import org.kie.internal.command.Context; -class RemoteTaskCommandExecutor extends AbstractRemoteCommandObject implements CommandExecutor { +class RemoteTaskCommandExecutor extends AbstractRemoteCommandObject implements CommandService { RemoteTaskCommandExecutor(RemoteConfiguration configuration) { super(configuration); isTaskService = true; } - + + @Override + public Context getContext() { + return null; + } } diff --git a/kie-remote/kie-services-remote/pom.xml b/kie-remote/kie-services-remote/pom.xml index 568ea4d95c..e407f6099e 100644 --- a/kie-remote/kie-services-remote/pom.xml +++ b/kie-remote/kie-services-remote/pom.xml @@ -102,7 +102,6 @@ org.slf4j slf4j-api - junit diff --git a/kie-remote/kie-services-remote/src/main/java/org/kie/services/remote/cdi/TransactionalExecutor.java b/kie-remote/kie-services-remote/src/main/java/org/kie/services/remote/cdi/TransactionalExecutor.java deleted file mode 100644 index 00e0ba714c..0000000000 --- a/kie-remote/kie-services-remote/src/main/java/org/kie/services/remote/cdi/TransactionalExecutor.java +++ /dev/null @@ -1,83 +0,0 @@ -package org.kie.services.remote.cdi; - -import javax.inject.Inject; -import javax.interceptor.Interceptors; - -import org.jboss.seam.transaction.TransactionInterceptor; -import org.jboss.seam.transaction.Transactional; -import org.jbpm.services.task.commands.TaskCommand; -import org.jbpm.services.task.impl.model.ContentImpl; -import org.jbpm.services.task.impl.model.TaskImpl; -import org.jbpm.services.task.impl.model.xml.JaxbContent; -import org.jbpm.services.task.impl.model.xml.JaxbTask; -import org.kie.api.command.Command; -import org.kie.api.runtime.KieSession; -import org.kie.api.task.TaskService; -import org.kie.api.task.model.Content; -import org.kie.api.task.model.Task; -import org.kie.internal.task.api.InternalTaskService; - -@Transactional -@Interceptors({TransactionInterceptor.class}) -public class TransactionalExecutor { - - @Inject - private javax.persistence.EntityManager em; - - /** - * Executes a {@link KieSession} operation within a transaction. - * - * @param kieSession The {@link KieSession} that the operation is being executed on. - * @param cmd The {@link Command} to be executed. - * @return The result of the {@link Command}, possibly null. - */ - public Object execute(KieSession kieSession, Command cmd) { - return kieSession.execute(cmd); - } - - /** - * Executes a {@link TaskService} operation within a transaction. - *

- * This method should only be used for {@link TaskCommand} classes that return objects that are not - * (persistence) entity instances. If the {@link TaskCommand} returns a persistence entity, such as the {@link TaskImpl} - * or {@link ContentImpl}, then use the {@link TransactionalExecutor#executeAndSerialize(InternalTaskService, TaskCommand)} - * method. - * - * @param taskService The {@link TaskService} to execute the operation on. - * @param cmd The {@link TaskCommand} to be executed. - * @return The result of the {@link TaskCommand}, possibly null. - */ - public Object execute(InternalTaskService taskService, TaskCommand cmd) { - em.joinTransaction(); - return ((InternalTaskService) taskService).execute(cmd); - } - - /** - * Executes a {@link TaskService} operation within a transaction. This method also tries to make sure the object returned - * by the {@link TaskCommand} executed is also serialized within the transaction. - *

- * This is done in order to avoid problems with proxy collection objects inserted into the entity instances (such as - * {@link TaskImpl}): if these collection objects are accessed outside of a transaction, errors will occur. - *

- * In essence, we're tightly coupling to the {@link TaskService} here, because of problems with the {@link TaskService}. - * If those problems are ever fixed, this method should no longer be necessary. - * - * @param taskService The {@link TaskService} on which the operation is being executed. - * @param cmd The {@link TaskCommand} to be executed. - * @return The serialized result of the {@link TaskCommand} - */ - public Object executeAndSerialize(InternalTaskService taskService, TaskCommand cmd) { - em.joinTransaction(); - Object cmdResult = ((InternalTaskService) taskService).execute(cmd); - if( cmdResult == null ) { - return null; - } - if( cmdResult instanceof Task ) { - cmdResult = new JaxbTask((Task) cmdResult); - } else if( cmdResult instanceof Content ) { - cmdResult = new JaxbContent((Content) cmdResult); - } - return cmdResult; - } - -} diff --git a/kie-remote/kie-services-remote/src/main/java/org/kie/services/remote/jms/RequestMessageBean.java b/kie-remote/kie-services-remote/src/main/java/org/kie/services/remote/jms/RequestMessageBean.java index ea837b4065..e99a75a6aa 100644 --- a/kie-remote/kie-services-remote/src/main/java/org/kie/services/remote/jms/RequestMessageBean.java +++ b/kie-remote/kie-services-remote/src/main/java/org/kie/services/remote/jms/RequestMessageBean.java @@ -41,10 +41,10 @@ import org.kie.services.client.serialization.jaxb.impl.JaxbCommandsRequest; import org.kie.services.client.serialization.jaxb.impl.JaxbCommandsResponse; import org.kie.services.remote.cdi.DeploymentInfoBean; -import org.kie.services.remote.cdi.TransactionalExecutor; import org.kie.services.remote.exception.DomainNotFoundBadRequestException; import org.kie.services.remote.exception.KieRemoteServicesInternalError; import org.kie.services.remote.exception.KieRemoteServicesRuntimeException; +import org.kie.services.remote.util.ExecuteAndSerializeCommand; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -86,9 +86,6 @@ public class RequestMessageBean implements MessageListener { @Inject private TaskService taskService; - - @Inject - private TransactionalExecutor executor; // Constants / properties @@ -360,7 +357,7 @@ private JaxbCommandsResponse processJaxbCommandsRequest(JaxbCommandsRequest requ // that will cause message reception to be *NOT* acknowledged! if( cmd instanceof TaskCommand && ! AcceptedCommands.TASK_COMMANDS_THAT_INFLUENCE_KIESESSION.contains(cmd.getClass()) ) { - cmdResult = executor.executeAndSerialize((InternalTaskService) taskService, (TaskCommand) cmd); + cmdResult = ((InternalTaskService) taskService).execute(new ExecuteAndSerializeCommand((TaskCommand < ? >) cmd)); } else { String deploymentId = request.getDeploymentId(); if( deploymentId == null ) { @@ -379,9 +376,9 @@ private JaxbCommandsResponse processJaxbCommandsRequest(JaxbCommandsRequest requ // Synchronize around SSCS to avoid race-conditions with kie session cache clearing in afterCompletion synchronized(sscs) { if( cmd instanceof TaskCommand ) { - cmdResult = executor.execute((InternalTaskService) taskService, (TaskCommand) cmd); + cmdResult = ((InternalTaskService) taskService).execute((TaskCommand) cmd); } else { - cmdResult = executor.execute(kieSession, cmd); + cmdResult = kieSession.execute(cmd); } } } diff --git a/kie-remote/kie-services-remote/src/main/java/org/kie/services/remote/rest/ResourceBase.java b/kie-remote/kie-services-remote/src/main/java/org/kie/services/remote/rest/ResourceBase.java index f8057376b4..c5aff2cd91 100644 --- a/kie-remote/kie-services-remote/src/main/java/org/kie/services/remote/rest/ResourceBase.java +++ b/kie-remote/kie-services-remote/src/main/java/org/kie/services/remote/rest/ResourceBase.java @@ -22,13 +22,16 @@ import org.jboss.resteasy.spi.NotAcceptableException; import org.jboss.resteasy.util.HttpHeaderNames; import org.jbpm.services.task.commands.TaskCommand; -import org.jbpm.services.task.impl.model.GroupImpl; -import org.jbpm.services.task.impl.model.TaskImpl; -import org.jbpm.services.task.impl.model.UserImpl; import org.jbpm.services.task.query.TaskSummaryImpl; import org.kie.api.command.Command; +import org.kie.api.task.model.Group; import org.kie.api.task.model.OrganizationalEntity; import org.kie.api.task.model.Status; +import org.kie.api.task.model.Task; +import org.kie.api.task.model.User; +import org.kie.internal.task.api.TaskModelProvider; +import org.kie.internal.task.api.model.InternalOrganizationalEntity; +import org.kie.internal.task.api.model.InternalTask; import org.kie.services.client.api.command.AcceptedCommands; import org.kie.services.client.serialization.jaxb.impl.JaxbCommandsRequest; import org.kie.services.client.serialization.jaxb.impl.JaxbCommandsResponse; @@ -299,17 +302,21 @@ protected static List getOrganizationalEntityListFromParam throw new BadRequestException("At least 1 query parameter (either 'user' or 'group') is required for the '" + operation + "' operation."); } - for( String user : users ) { - orgEntList.add(new UserImpl(user)); + for( String user : users ) { + User newuser = TaskModelProvider.getFactory().newUser(); + ((InternalOrganizationalEntity) newuser).setId(user); + orgEntList.add(newuser); } - for( String group : groups ) { - orgEntList.add(new GroupImpl(group)); + for( String group : groups ) { + Group newuser = TaskModelProvider.getFactory().newGroup(); + ((InternalOrganizationalEntity) newuser).setId(group); + orgEntList.add(newuser); } return orgEntList; } - protected static TaskSummaryImpl convertTaskToTaskSummary(TaskImpl task) { + protected static TaskSummaryImpl convertTaskToTaskSummary(InternalTask task) { TaskSummaryImpl taskSummary = new TaskSummaryImpl( task.getId().longValue(), task.getTaskData().getProcessInstanceId(), diff --git a/kie-remote/kie-services-remote/src/main/java/org/kie/services/remote/rest/RestProcessRequestBean.java b/kie-remote/kie-services-remote/src/main/java/org/kie/services/remote/rest/RestProcessRequestBean.java index b02bb18b4c..9fc986eebc 100644 --- a/kie-remote/kie-services-remote/src/main/java/org/kie/services/remote/rest/RestProcessRequestBean.java +++ b/kie-remote/kie-services-remote/src/main/java/org/kie/services/remote/rest/RestProcessRequestBean.java @@ -17,7 +17,7 @@ import org.kie.api.task.TaskService; import org.kie.internal.task.api.InternalTaskService; import org.kie.services.remote.cdi.DeploymentInfoBean; -import org.kie.services.remote.cdi.TransactionalExecutor; +import org.kie.services.remote.util.ExecuteAndSerializeCommand; /** * This class is used by both the {@link RuntimeResource} and {@link TaskResource} to do the core operations on @@ -41,9 +41,6 @@ public class RestProcessRequestBean { @Inject private TaskService taskService; - @Inject - private TransactionalExecutor executor; - /** * Executes a command on the {@link KieSession} from the proper {@link RuntimeManager}. This method * ends up synchronizing around the retrieved {@link KieSession} in order to avoid race-conditions. @@ -61,7 +58,7 @@ public Object doKieSessionOperation(Command cmd, String deploymentId, Long pr SingleSessionCommandService sscs = (SingleSessionCommandService) ((CommandBasedStatefulKnowledgeSession) kieSession).getCommandService(); synchronized (sscs) { - result = executor.execute(kieSession, cmd); + result = kieSession.execute(cmd); } } catch (Exception e) { if( e instanceof RuntimeException ) { @@ -95,10 +92,10 @@ public Object doTaskOperationOnDeployment(TaskCommand cmd, String deploymentI SingleSessionCommandService sscs = (SingleSessionCommandService) ((CommandBasedStatefulKnowledgeSession) kieSession).getCommandService(); synchronized (sscs) { - result = executor.execute((InternalTaskService) taskService, cmd); + result = ((InternalTaskService) taskService).execute(cmd); } } else { - result = executor.execute((InternalTaskService) taskService, cmd); + result = ((InternalTaskService) taskService).execute(cmd); } } catch (PermissionDeniedException pde) { throw new UnauthorizedException(pde.getMessage(), pde); @@ -133,7 +130,7 @@ public Object doTaskOperation(TaskCommand cmd, String errorMsg) { public Object doTaskOperationAndSerializeResult(TaskCommand cmd, String errorMsg) { Object result = null; try { - result = executor.executeAndSerialize((InternalTaskService) taskService, cmd); + result = ((InternalTaskService) taskService).execute(new ExecuteAndSerializeCommand((TaskCommand) cmd)); } catch (PermissionDeniedException pde) { throw new UnauthorizedException(pde.getMessage(), pde); } catch (RuntimeException re) { diff --git a/kie-remote/kie-services-remote/src/main/java/org/kie/services/remote/util/ExecuteAndSerializeCommand.java b/kie-remote/kie-services-remote/src/main/java/org/kie/services/remote/util/ExecuteAndSerializeCommand.java new file mode 100644 index 0000000000..e348fdf756 --- /dev/null +++ b/kie-remote/kie-services-remote/src/main/java/org/kie/services/remote/util/ExecuteAndSerializeCommand.java @@ -0,0 +1,35 @@ +package org.kie.services.remote.util; + +import org.jbpm.services.task.commands.TaskCommand; +import org.jbpm.services.task.impl.model.xml.JaxbContent; +import org.jbpm.services.task.impl.model.xml.JaxbTask; +import org.kie.api.task.model.Content; +import org.kie.api.task.model.Task; +import org.kie.internal.command.Context; + +public class ExecuteAndSerializeCommand extends TaskCommand{ + + private TaskCommand command; + + public ExecuteAndSerializeCommand(){ + + } + + public ExecuteAndSerializeCommand(TaskCommand command) { + this.command = command; + } + + @Override + public Object execute(Context context) { + Object cmdResult = command.execute(context); + if( cmdResult == null ) { + return null; + } + if( cmdResult instanceof Task) { + cmdResult = new JaxbTask((Task) cmdResult); + } else if( cmdResult instanceof Content) { + cmdResult = new JaxbContent((Content) cmdResult); + } + return cmdResult; + } +} diff --git a/kie-spring/pom.xml b/kie-spring/pom.xml index 32cf6eae57..9ab4713b46 100644 --- a/kie-spring/pom.xml +++ b/kie-spring/pom.xml @@ -55,6 +55,12 @@ true + + org.jbpm + jbpm-human-task-jpa + true + + com.sun.xml.bind jaxb-impl diff --git a/kie-spring/src/main/java/org/kie/spring/persistence/AbstractKieSpringJpaManager.java b/kie-spring/src/main/java/org/kie/spring/persistence/AbstractKieSpringJpaManager.java new file mode 100644 index 0000000000..eb1aeaca4c --- /dev/null +++ b/kie-spring/src/main/java/org/kie/spring/persistence/AbstractKieSpringJpaManager.java @@ -0,0 +1,125 @@ +/* + * Copyright 2010 JBoss Inc + * + * 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.kie.spring.persistence; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; + +import org.drools.persistence.PersistenceContext; +import org.drools.persistence.jpa.JpaPersistenceContext; +import org.jbpm.persistence.JpaProcessPersistenceContext; +import org.jbpm.persistence.ProcessPersistenceContext; +import org.jbpm.persistence.ProcessPersistenceContextManager; +import org.kie.api.runtime.Environment; +import org.kie.api.runtime.EnvironmentName; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.orm.jpa.EntityManagerHolder; +import org.springframework.transaction.support.TransactionSynchronizationManager; + +public abstract class AbstractKieSpringJpaManager + { + + Logger logger = LoggerFactory.getLogger(getClass()); + + protected Environment env; + + protected EntityManagerFactory emf; + + protected EntityManager appScopedEntityManager; + + protected boolean internalAppScopedEntityManager; + + protected boolean isJTA; + + public AbstractKieSpringJpaManager(Environment env) { + this.env = env; + this.emf = (EntityManagerFactory) env.get(EnvironmentName.ENTITY_MANAGER_FACTORY); + + isJTA = true; + Boolean bool = (Boolean) env.get("IS_JTA_TRANSACTION"); + if (bool != null) { + isJTA = bool.booleanValue(); + } + } + + public EntityManager getApplicationScopedEntityManager() { + if (this.appScopedEntityManager == null) { + // Use the App scoped EntityManager if the user has provided it, and it is open. + this.appScopedEntityManager = (EntityManager) this.env.get(EnvironmentName.APP_SCOPED_ENTITY_MANAGER); + if (this.appScopedEntityManager != null && !this.appScopedEntityManager.isOpen()) { + throw new RuntimeException("Provided APP_SCOPED_ENTITY_MANAGER is not open"); + } + + if (this.appScopedEntityManager == null) { + EntityManagerHolder emHolder = (EntityManagerHolder) TransactionSynchronizationManager.getResource(this.emf); + if (emHolder == null) { + this.appScopedEntityManager = this.emf.createEntityManager(); + emHolder = new EntityManagerHolder(this.appScopedEntityManager); + TransactionSynchronizationManager.bindResource(this.emf, emHolder); + internalAppScopedEntityManager = true; + } else { + this.appScopedEntityManager = emHolder.getEntityManager(); + } + + this.env.set(EnvironmentName.APP_SCOPED_ENTITY_MANAGER, + emHolder.getEntityManager()); + } + } + if (TransactionSynchronizationManager.isActualTransactionActive() && isJTA) { + this.appScopedEntityManager.joinTransaction(); + } + return this.appScopedEntityManager; + } + + public EntityManager getCommandScopedEntityManager() { + EntityManager cmdScopedEntityManager = (EntityManager) env.get(EnvironmentName.CMD_SCOPED_ENTITY_MANAGER); + if (cmdScopedEntityManager == null || !cmdScopedEntityManager.isOpen()) { + EntityManagerHolder emHolder = (EntityManagerHolder) TransactionSynchronizationManager.getResource("cmdEM"); + EntityManager em = null; + if (emHolder == null) { + em = this.emf.createEntityManager(); + emHolder = new EntityManagerHolder(em); + TransactionSynchronizationManager.bindResource("cmdEM", emHolder); + } else { + em = emHolder.getEntityManager(); + } + this.env.set(EnvironmentName.CMD_SCOPED_ENTITY_MANAGER, em); + } + return cmdScopedEntityManager; + } + + public abstract void endCommandScopedEntityManager(); + + public void dispose() { + logger.trace("Disposing KieSpringJpaManager"); + if (internalAppScopedEntityManager) { + //TransactionSynchronizationManager.unbindResource( "appEM" ); + TransactionSynchronizationManager.unbindResource(this.emf); + if (this.appScopedEntityManager != null && this.appScopedEntityManager.isOpen()) { + this.appScopedEntityManager.close(); + this.internalAppScopedEntityManager = false; + this.env.set(EnvironmentName.APP_SCOPED_ENTITY_MANAGER, + null); + this.appScopedEntityManager = null; + } + this.endCommandScopedEntityManager(); + } + } + + +} diff --git a/kie-spring/src/main/java/org/kie/spring/persistence/HumanTaskSpringTransactionManager.java b/kie-spring/src/main/java/org/kie/spring/persistence/HumanTaskSpringTransactionManager.java index c611c2e4a8..e2959ef25b 100644 --- a/kie-spring/src/main/java/org/kie/spring/persistence/HumanTaskSpringTransactionManager.java +++ b/kie-spring/src/main/java/org/kie/spring/persistence/HumanTaskSpringTransactionManager.java @@ -130,4 +130,14 @@ public int getStatus() { public void registerTransactionSynchronization(TransactionSynchronization ts) { TransactionSynchronizationManager.registerSynchronization(new SpringTransactionSynchronizationAdapter(ts)); } + + @Override + public void putResource(Object key, Object resource) { + throw new UnsupportedOperationException(); + } + + @Override + public Object getResource(Object key) { + throw new UnsupportedOperationException(); + } } diff --git a/kie-spring/src/main/java/org/kie/spring/persistence/KieSpringJpaManager.java b/kie-spring/src/main/java/org/kie/spring/persistence/KieSpringJpaManager.java index deab5d3290..d2f7ba9203 100644 --- a/kie-spring/src/main/java/org/kie/spring/persistence/KieSpringJpaManager.java +++ b/kie-spring/src/main/java/org/kie/spring/persistence/KieSpringJpaManager.java @@ -31,64 +31,21 @@ import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; -public class KieSpringJpaManager +public class KieSpringJpaManager extends AbstractKieSpringJpaManager implements ProcessPersistenceContextManager { - Logger logger = LoggerFactory.getLogger(getClass()); - - Environment env; - - private EntityManagerFactory emf; - - private EntityManager appScopedEntityManager; - - private boolean internalAppScopedEntityManager; - - private boolean isJTA; public KieSpringJpaManager(Environment env) { - this.env = env; - this.emf = (EntityManagerFactory) env.get(EnvironmentName.ENTITY_MANAGER_FACTORY); - - isJTA = true; - Boolean bool = (Boolean) env.get("IS_JTA_TRANSACTION"); - if (bool != null) { - isJTA = bool.booleanValue(); - } + super(env); getApplicationScopedPersistenceContext(); // we create this on initialisation so that we own the EMF reference // otherwise Spring will close it after the transaction finishes } public PersistenceContext getApplicationScopedPersistenceContext() { - if (this.appScopedEntityManager == null) { - // Use the App scoped EntityManager if the user has provided it, and it is open. - this.appScopedEntityManager = (EntityManager) this.env.get(EnvironmentName.APP_SCOPED_ENTITY_MANAGER); - if (this.appScopedEntityManager != null && !this.appScopedEntityManager.isOpen()) { - throw new RuntimeException("Provided APP_SCOPED_ENTITY_MANAGER is not open"); - } - if (this.appScopedEntityManager == null) { - EntityManagerHolder emHolder = (EntityManagerHolder) TransactionSynchronizationManager.getResource(this.emf); - if (emHolder == null) { - this.appScopedEntityManager = this.emf.createEntityManager(); - emHolder = new EntityManagerHolder(this.appScopedEntityManager); - TransactionSynchronizationManager.bindResource(this.emf, - emHolder); - internalAppScopedEntityManager = true; - } else { - this.appScopedEntityManager = emHolder.getEntityManager(); - } - - this.env.set(EnvironmentName.APP_SCOPED_ENTITY_MANAGER, - emHolder.getEntityManager()); - } - } - if (TransactionSynchronizationManager.isActualTransactionActive() && isJTA) { - this.appScopedEntityManager.joinTransaction(); - } - return new JpaPersistenceContext(this.appScopedEntityManager, isJTA); + return new JpaPersistenceContext(getApplicationScopedEntityManager(), isJTA); } public PersistenceContext getCommandScopedPersistenceContext() { @@ -96,21 +53,7 @@ public PersistenceContext getCommandScopedPersistenceContext() { } public void beginCommandScopedEntityManager() { - EntityManager cmdScopedEntityManager = (EntityManager) env.get(EnvironmentName.CMD_SCOPED_ENTITY_MANAGER); - if (cmdScopedEntityManager == null || !cmdScopedEntityManager.isOpen()) { - EntityManagerHolder emHolder = (EntityManagerHolder) TransactionSynchronizationManager.getResource("cmdEM"); - EntityManager em = null; - if (emHolder == null) { - em = this.emf.createEntityManager(); - emHolder = new EntityManagerHolder(em); - TransactionSynchronizationManager.bindResource("cmdEM", - emHolder); - } else { - em = emHolder.getEntityManager(); - } - this.env.set(EnvironmentName.CMD_SCOPED_ENTITY_MANAGER, - em); - } + EntityManager cmdScopedEntityManager = getCommandScopedEntityManager(); if (isJTA) { this.getCommandScopedPersistenceContext().joinTransaction(); @@ -118,6 +61,10 @@ public void beginCommandScopedEntityManager() { } } + public ProcessPersistenceContext getProcessPersistenceContext() { + return new JpaProcessPersistenceContext((EntityManager) this.env.get(EnvironmentName.CMD_SCOPED_ENTITY_MANAGER)); + } + public void endCommandScopedEntityManager() { if (TransactionSynchronizationManager.hasResource("cmdEM")) { // Code formerly in the clearPersistenceContext method. @@ -125,32 +72,16 @@ public void endCommandScopedEntityManager() { if (cmdScopedEntityManager != null) { cmdScopedEntityManager.clear(); } - + TransactionSynchronizationManager.unbindResource("cmdEM"); if (this.env.get(EnvironmentName.CMD_SCOPED_ENTITY_MANAGER) != null) { getCommandScopedPersistenceContext().close(); } } - } - public void dispose() { - logger.trace("Disposing KieSpringJpaManager"); - if (internalAppScopedEntityManager) { - //TransactionSynchronizationManager.unbindResource( "appEM" ); - TransactionSynchronizationManager.unbindResource(this.emf); - if (this.appScopedEntityManager != null && this.appScopedEntityManager.isOpen()) { - this.appScopedEntityManager.close(); - this.internalAppScopedEntityManager = false; - this.env.set(EnvironmentName.APP_SCOPED_ENTITY_MANAGER, - null); - this.appScopedEntityManager = null; - } - this.endCommandScopedEntityManager(); + if (TransactionSynchronizationManager.hasResource(KieSpringTransactionManager.RESOURCE_CONTAINER)) { + TransactionSynchronizationManager.unbindResource(KieSpringTransactionManager.RESOURCE_CONTAINER); } } - public ProcessPersistenceContext getProcessPersistenceContext() { - return new JpaProcessPersistenceContext((EntityManager) this.env.get(EnvironmentName.CMD_SCOPED_ENTITY_MANAGER)); - } - } diff --git a/kie-spring/src/main/java/org/kie/spring/persistence/KieSpringTaskJpaManager.java b/kie-spring/src/main/java/org/kie/spring/persistence/KieSpringTaskJpaManager.java new file mode 100644 index 0000000000..2b3c5bc4fc --- /dev/null +++ b/kie-spring/src/main/java/org/kie/spring/persistence/KieSpringTaskJpaManager.java @@ -0,0 +1,67 @@ +package org.kie.spring.persistence; + +import javax.persistence.EntityManager; + +import org.drools.persistence.PersistenceContext; +import org.drools.persistence.jpa.JpaPersistenceContext; +import org.jbpm.persistence.JpaProcessPersistenceContext; +import org.jbpm.persistence.ProcessPersistenceContext; +import org.jbpm.persistence.ProcessPersistenceContextManager; +import org.jbpm.services.task.persistence.JPATaskPersistenceContext; +import org.kie.api.runtime.Environment; +import org.kie.api.runtime.EnvironmentName; +import org.kie.internal.task.api.TaskPersistenceContext; +import org.kie.internal.task.api.TaskPersistenceContextManager; +import org.springframework.transaction.support.TransactionSynchronizationManager; + +public class KieSpringTaskJpaManager extends AbstractKieSpringJpaManager + implements + TaskPersistenceContextManager { + + + public KieSpringTaskJpaManager(Environment env) { + super(env); + + getApplicationScopedPersistenceContext(); // we create this on initialisation so that we own the EMF reference + // otherwise Spring will close it after the transaction finishes + } + + public PersistenceContext getApplicationScopedPersistenceContext() { + + return new JpaPersistenceContext(getApplicationScopedEntityManager(), isJTA); + } + + @Override + public TaskPersistenceContext getPersistenceContext() { + return new JPATaskPersistenceContext((EntityManager) this.env.get(EnvironmentName.CMD_SCOPED_ENTITY_MANAGER), isJTA); + } + + @Override + public void beginCommandScopedEntityManager() { + EntityManager cmdScopedEntityManager = getCommandScopedEntityManager(); + + if (isJTA) { + this.getPersistenceContext().joinTransaction(); + } + } + + public void endCommandScopedEntityManager() { + if (TransactionSynchronizationManager.hasResource("cmdEM")) { + // Code formerly in the clearPersistenceContext method. + EntityManager cmdScopedEntityManager = (EntityManager) this.env.get(EnvironmentName.CMD_SCOPED_ENTITY_MANAGER); + if (cmdScopedEntityManager != null) { + cmdScopedEntityManager.clear(); + } + + TransactionSynchronizationManager.unbindResource("cmdEM"); + if (this.env.get(EnvironmentName.CMD_SCOPED_ENTITY_MANAGER) != null) { + getPersistenceContext().close(); + } + } + + if (TransactionSynchronizationManager.hasResource(KieSpringTransactionManager.RESOURCE_CONTAINER)) { + TransactionSynchronizationManager.unbindResource(KieSpringTransactionManager.RESOURCE_CONTAINER); + } + } + +} diff --git a/kie-spring/src/main/java/org/kie/spring/persistence/KieSpringTransactionManager.java b/kie-spring/src/main/java/org/kie/spring/persistence/KieSpringTransactionManager.java index 90ccb52a15..2d7495f750 100644 --- a/kie-spring/src/main/java/org/kie/spring/persistence/KieSpringTransactionManager.java +++ b/kie-spring/src/main/java/org/kie/spring/persistence/KieSpringTransactionManager.java @@ -16,6 +16,9 @@ package org.kie.spring.persistence; +import java.util.HashMap; +import java.util.Map; + import org.drools.persistence.TransactionManager; import org.drools.persistence.TransactionSynchronization; import org.slf4j.Logger; @@ -30,6 +33,8 @@ public class KieSpringTransactionManager implements TransactionManager { + public static final String RESOURCE_CONTAINER = "org.kie.resources"; + Logger logger = LoggerFactory.getLogger(getClass()); private AbstractPlatformTransactionManager ptm; @@ -138,4 +143,23 @@ public int getStatus() { public void registerTransactionSynchronization(TransactionSynchronization ts) { TransactionSynchronizationManager.registerSynchronization(new SpringTransactionSynchronizationAdapter(ts)); } + + @Override + public void putResource(Object key, Object resource) { + Map resources = (Map) TransactionSynchronizationManager.getResource(RESOURCE_CONTAINER); + if (resources == null) { + resources = new HashMap(); + TransactionSynchronizationManager.bindResource(RESOURCE_CONTAINER, resources); + } + resources.put(key, resource); + } + + @Override + public Object getResource(Object key) { + Map resources = (Map) TransactionSynchronizationManager.getResource(RESOURCE_CONTAINER); + if (resources == null) { + return null; + } + return resources.get(key); + } }