SWF-360 Add flow managed persistence context propagation
This commit is contained in:
@@ -105,15 +105,18 @@ public class HibernateFlowExecutionListener extends FlowExecutionListenerAdapter
|
||||
}
|
||||
|
||||
public void sessionStarting(RequestContext context, FlowSession session, MutableAttributeMap input) {
|
||||
if (!session.isRoot()) {
|
||||
FlowSession parent = session.getParent();
|
||||
if (isPersistenceContext(parent.getDefinition())) {
|
||||
unbind(getHibernateSession(parent));
|
||||
boolean reusePersistenceContext = false;
|
||||
if (isParentPersistenceContext(session)) {
|
||||
if (isPersistenceContext(session.getDefinition())) {
|
||||
setHibernateSession(session, getHibernateSession(session.getParent()));
|
||||
reusePersistenceContext = true;
|
||||
} else {
|
||||
unbind(getHibernateSession(session.getParent()));
|
||||
}
|
||||
}
|
||||
if (isPersistenceContext(session.getDefinition())) {
|
||||
if (isPersistenceContext(session.getDefinition()) && (!reusePersistenceContext)) {
|
||||
Session hibernateSession = createSession(context);
|
||||
session.getScope().put(PERSISTENCE_CONTEXT_ATTRIBUTE, hibernateSession);
|
||||
setHibernateSession(session, hibernateSession);
|
||||
bind(hibernateSession);
|
||||
}
|
||||
}
|
||||
@@ -133,6 +136,9 @@ public class HibernateFlowExecutionListener extends FlowExecutionListenerAdapter
|
||||
}
|
||||
|
||||
public void sessionEnding(RequestContext context, FlowSession session, String outcome, MutableAttributeMap output) {
|
||||
if (isParentPersistenceContext(session)) {
|
||||
return;
|
||||
}
|
||||
if (isPersistenceContext(session.getDefinition())) {
|
||||
final Session hibernateSession = getHibernateSession(session);
|
||||
Boolean commitStatus = session.getState().getAttributes().getBoolean("commit");
|
||||
@@ -151,10 +157,9 @@ public class HibernateFlowExecutionListener extends FlowExecutionListenerAdapter
|
||||
}
|
||||
|
||||
public void sessionEnded(RequestContext context, FlowSession session, String outcome, AttributeMap output) {
|
||||
if (!session.isRoot()) {
|
||||
FlowSession parent = session.getParent();
|
||||
if (isPersistenceContext(parent.getDefinition())) {
|
||||
bind(getHibernateSession(parent));
|
||||
if (isParentPersistenceContext(session)) {
|
||||
if (!isPersistenceContext(session.getDefinition())) {
|
||||
bind(getHibernateSession(session.getParent()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -173,6 +178,10 @@ public class HibernateFlowExecutionListener extends FlowExecutionListenerAdapter
|
||||
return flow.getAttributes().contains(PERSISTENCE_CONTEXT_ATTRIBUTE);
|
||||
}
|
||||
|
||||
private boolean isParentPersistenceContext(FlowSession flowSession) {
|
||||
return ((!flowSession.isRoot()) && isPersistenceContext(flowSession.getParent().getDefinition()));
|
||||
}
|
||||
|
||||
private Session createSession(RequestContext context) {
|
||||
Session session = (entityInterceptor != null ? sessionFactory.openSession(entityInterceptor) : sessionFactory
|
||||
.openSession());
|
||||
@@ -184,6 +193,10 @@ public class HibernateFlowExecutionListener extends FlowExecutionListenerAdapter
|
||||
return (Session) session.getScope().get(PERSISTENCE_CONTEXT_ATTRIBUTE);
|
||||
}
|
||||
|
||||
private void setHibernateSession(FlowSession session, Session hibernateSession) {
|
||||
session.getScope().put(PERSISTENCE_CONTEXT_ATTRIBUTE, hibernateSession);
|
||||
}
|
||||
|
||||
private void bind(Session session) {
|
||||
TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session));
|
||||
}
|
||||
|
||||
@@ -95,13 +95,16 @@ public class JpaFlowExecutionListener extends FlowExecutionListenerAdapter {
|
||||
}
|
||||
|
||||
public void sessionStarting(RequestContext context, FlowSession session, MutableAttributeMap input) {
|
||||
if (!session.isRoot()) {
|
||||
FlowSession parent = session.getParent();
|
||||
if (isPersistenceContext(parent.getDefinition())) {
|
||||
unbind(getEntityManager(parent));
|
||||
boolean reusePersistenceContext = false;
|
||||
if (isParentPersistenceContext(session)) {
|
||||
if (isPersistenceContext(session.getDefinition())) {
|
||||
setEntityManager(session, getEntityManager(session.getParent()));
|
||||
reusePersistenceContext = true;
|
||||
} else {
|
||||
unbind(getEntityManager(session.getParent()));
|
||||
}
|
||||
}
|
||||
if (isPersistenceContext(session.getDefinition())) {
|
||||
if (isPersistenceContext(session.getDefinition()) && (!reusePersistenceContext)) {
|
||||
EntityManager em = entityManagerFactory.createEntityManager();
|
||||
session.getScope().put(PERSISTENCE_CONTEXT_ATTRIBUTE, em);
|
||||
bind(em);
|
||||
@@ -121,6 +124,9 @@ public class JpaFlowExecutionListener extends FlowExecutionListenerAdapter {
|
||||
}
|
||||
|
||||
public void sessionEnding(RequestContext context, FlowSession session, String outcome, MutableAttributeMap output) {
|
||||
if (isParentPersistenceContext(session)) {
|
||||
return;
|
||||
}
|
||||
if (isPersistenceContext(session.getDefinition())) {
|
||||
final EntityManager em = getEntityManager(session);
|
||||
Boolean commitStatus = session.getState().getAttributes().getBoolean("commit");
|
||||
@@ -137,10 +143,9 @@ public class JpaFlowExecutionListener extends FlowExecutionListenerAdapter {
|
||||
}
|
||||
|
||||
public void sessionEnded(RequestContext context, FlowSession session, String outcome, AttributeMap output) {
|
||||
if (!session.isRoot()) {
|
||||
FlowSession parent = session.getParent();
|
||||
if (isPersistenceContext(parent.getDefinition())) {
|
||||
bind(getEntityManager(parent));
|
||||
if (isParentPersistenceContext(session)) {
|
||||
if (!isPersistenceContext(session.getDefinition())) {
|
||||
bind(getEntityManager(session.getParent()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -159,10 +164,18 @@ public class JpaFlowExecutionListener extends FlowExecutionListenerAdapter {
|
||||
return flow.getAttributes().contains(PERSISTENCE_CONTEXT_ATTRIBUTE);
|
||||
}
|
||||
|
||||
private boolean isParentPersistenceContext(FlowSession flowSession) {
|
||||
return ((!flowSession.isRoot()) && isPersistenceContext(flowSession.getParent().getDefinition()));
|
||||
}
|
||||
|
||||
private EntityManager getEntityManager(FlowSession session) {
|
||||
return (EntityManager) session.getScope().get(PERSISTENCE_CONTEXT_ATTRIBUTE);
|
||||
}
|
||||
|
||||
private void setEntityManager(FlowSession session, EntityManager em) {
|
||||
session.getScope().put(PERSISTENCE_CONTEXT_ATTRIBUTE, em);
|
||||
}
|
||||
|
||||
private void bind(EntityManager em) {
|
||||
TransactionSynchronizationManager.bindResource(entityManagerFactory, new EntityManagerHolder(em));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
package org.springframework.webflow.persistence;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.jdbc.datasource.DriverManagerDataSource;
|
||||
import org.springframework.webflow.engine.EndState;
|
||||
import org.springframework.webflow.engine.Flow;
|
||||
import org.springframework.webflow.engine.builder.FlowAssembler;
|
||||
import org.springframework.webflow.engine.builder.model.FlowModelFlowBuilder;
|
||||
import org.springframework.webflow.engine.impl.FlowExecutionImplFactory;
|
||||
import org.springframework.webflow.engine.model.builder.DefaultFlowModelHolder;
|
||||
import org.springframework.webflow.engine.model.builder.xml.XmlFlowModelBuilder;
|
||||
import org.springframework.webflow.execution.Action;
|
||||
import org.springframework.webflow.execution.FlowExecution;
|
||||
import org.springframework.webflow.execution.FlowExecutionListener;
|
||||
import org.springframework.webflow.execution.factory.StaticFlowExecutionListenerLoader;
|
||||
import org.springframework.webflow.test.MockExternalContext;
|
||||
import org.springframework.webflow.test.MockFlowBuilderContext;
|
||||
|
||||
public abstract class AbstractFlowManagedPersistenceIntegrationTests extends TestCase {
|
||||
|
||||
private FlowExecutionListener persistenceListener;
|
||||
|
||||
private FlowExecution flowExecution;
|
||||
|
||||
private DataSource dataSource;
|
||||
|
||||
public DataSource getDataSource() {
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
initDataSource();
|
||||
populateDataBase();
|
||||
persistenceListener = createFlowExecutionListener();
|
||||
|
||||
ClassPathResource resource = new ClassPathResource("managed-root-flow.xml", getClass());
|
||||
DefaultFlowModelHolder holder = new DefaultFlowModelHolder(new XmlFlowModelBuilder(resource));
|
||||
FlowModelFlowBuilder builder = new FlowModelFlowBuilder(holder);
|
||||
MockFlowBuilderContext context = new MockFlowBuilderContext("managed-root-flow");
|
||||
FlowAssembler assembler = new FlowAssembler(builder, context);
|
||||
Flow rootFlow = assembler.assembleFlow();
|
||||
|
||||
ClassPathResource childFlowResource = new ClassPathResource("managed-child-flow.xml", getClass());
|
||||
DefaultFlowModelHolder childFlowHolder = new DefaultFlowModelHolder(new XmlFlowModelBuilder(childFlowResource));
|
||||
FlowModelFlowBuilder childFlowBuilder = new FlowModelFlowBuilder(childFlowHolder);
|
||||
MockFlowBuilderContext childFlowContext = new MockFlowBuilderContext("managed-child-flow");
|
||||
FlowAssembler childFlowAssembler = new FlowAssembler(childFlowBuilder, childFlowContext);
|
||||
Flow childFlow = childFlowAssembler.assembleFlow();
|
||||
|
||||
Flow notManaged = new Flow("notmanaged-child-flow");
|
||||
new EndState(notManaged, "finish");
|
||||
|
||||
context.registerSubflow(childFlow);
|
||||
context.registerSubflow(notManaged);
|
||||
|
||||
Action incrementCountAction = incrementCountAction();
|
||||
context.registerBean("incrementCountAction", incrementCountAction);
|
||||
childFlowContext.registerBean("incrementCountAction", incrementCountAction);
|
||||
|
||||
Object assertCountAction = assertCountAction();
|
||||
context.registerBean("assertCountAction", assertCountAction);
|
||||
childFlowContext.registerBean("assertCountAction", assertCountAction);
|
||||
|
||||
FlowExecutionImplFactory factory = new FlowExecutionImplFactory();
|
||||
factory.setExecutionListenerLoader(new StaticFlowExecutionListenerLoader(persistenceListener));
|
||||
flowExecution = factory.createFlowExecution(rootFlow);
|
||||
}
|
||||
|
||||
public void testFlowWithSubflow() {
|
||||
MockExternalContext context = new MockExternalContext();
|
||||
flowExecution.start(null, context);
|
||||
context.setEventId("managed");
|
||||
flowExecution.resume(context);
|
||||
context.setEventId("finish");
|
||||
flowExecution.resume(context);
|
||||
}
|
||||
|
||||
public void testManagedFlowWithUnmanagedSubflow() {
|
||||
MockExternalContext context = new MockExternalContext();
|
||||
flowExecution.start(null, context);
|
||||
context.setEventId("notmanaged");
|
||||
flowExecution.resume(context);
|
||||
}
|
||||
|
||||
/* Methods for subclasses */
|
||||
|
||||
protected abstract FlowExecutionListener createFlowExecutionListener() throws Exception;
|
||||
|
||||
protected abstract Action incrementCountAction();
|
||||
|
||||
protected abstract Object assertCountAction();
|
||||
|
||||
protected abstract void assertSessionBound();
|
||||
|
||||
/* private helper methods */
|
||||
|
||||
private void initDataSource() {
|
||||
DriverManagerDataSource dmds = new DriverManagerDataSource();
|
||||
dmds.setDriverClassName("org.hsqldb.jdbcDriver");
|
||||
dmds.setUrl("jdbc:hsqldb:mem:jpa");
|
||||
dmds.setUsername("sa");
|
||||
dmds.setPassword("");
|
||||
dataSource = dmds;
|
||||
}
|
||||
|
||||
private void populateDataBase() {
|
||||
Connection connection = null;
|
||||
try {
|
||||
connection = dataSource.getConnection();
|
||||
connection.createStatement().execute("drop table T_ADDRESS if exists;");
|
||||
connection.createStatement().execute("drop table T_BEAN if exists;");
|
||||
connection.createStatement().execute(
|
||||
"create table T_BEAN (ID integer primary key, NAME varchar(50) not null, COUNTER integer);");
|
||||
connection.createStatement().execute(
|
||||
"create table T_ADDRESS (ID integer primary key, BEAN_ID integer, VALUE varchar(50) not null);");
|
||||
connection
|
||||
.createStatement()
|
||||
.execute(
|
||||
"alter table T_ADDRESS add constraint FK_BEAN_ADDRESS foreign key (BEAN_ID) references T_BEAN(ID) on delete cascade");
|
||||
connection.createStatement().execute("insert into T_BEAN (ID, NAME, COUNTER) values (0, 'Ben Hale',0);");
|
||||
connection.createStatement().execute(
|
||||
"insert into T_ADDRESS (ID, BEAN_ID, VALUE) values (0, 0, 'Melbourne')");
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException("SQL exception occurred acquiring connection", e);
|
||||
} finally {
|
||||
if (connection != null) {
|
||||
try {
|
||||
connection.close();
|
||||
} catch (SQLException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* Copyright 2004-2010 the original author or authors.
|
||||
*
|
||||
* 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.springframework.webflow.persistence;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.datasource.DriverManagerDataSource;
|
||||
import org.springframework.webflow.engine.EndState;
|
||||
import org.springframework.webflow.execution.FlowExecutionListener;
|
||||
import org.springframework.webflow.execution.FlowSession;
|
||||
import org.springframework.webflow.test.MockFlowSession;
|
||||
import org.springframework.webflow.test.MockRequestContext;
|
||||
|
||||
public abstract class AbstractPersistenceContextPropagationTests extends TestCase {
|
||||
|
||||
private MockRequestContext requestContext;
|
||||
|
||||
private JdbcTemplate jdbcTemplate;
|
||||
|
||||
public JdbcTemplate getJdbcTemplate() {
|
||||
return jdbcTemplate;
|
||||
}
|
||||
|
||||
protected final void setUp() throws Exception {
|
||||
requestContext = new MockRequestContext();
|
||||
DataSource dataSource = getDataSource();
|
||||
jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
populateDataBase(dataSource);
|
||||
setUpResources(dataSource);
|
||||
}
|
||||
|
||||
public void testSessionStarting_NoPc_ParentPc() {
|
||||
MockFlowSession parentSession = newFlowSession(true, null);
|
||||
MockFlowSession childSession = newFlowSession(false, parentSession);
|
||||
|
||||
getListener().sessionStarting(new MockRequestContext(), parentSession, null);
|
||||
assertSessionBound();
|
||||
assertSessionInScope(parentSession);
|
||||
|
||||
getListener().sessionStarting(new MockRequestContext(), childSession, null);
|
||||
assertSessionNotBound();
|
||||
assertSessionNotInScope(childSession);
|
||||
}
|
||||
|
||||
public void testSessionStarting_Pc_ParentPc() {
|
||||
MockFlowSession parentSession = newFlowSession(true, null);
|
||||
MockFlowSession childSession = newFlowSession(true, parentSession);
|
||||
|
||||
getListener().sessionStarting(new MockRequestContext(), parentSession, null);
|
||||
assertSessionBound();
|
||||
assertSessionInScope(parentSession);
|
||||
|
||||
getListener().sessionStarting(new MockRequestContext(), childSession, null);
|
||||
assertSessionBound();
|
||||
assertSessionInScope(childSession);
|
||||
assertSame("Parent PersistenceContext should be re-used", parentSession.getScope().get("persistenceContext"),
|
||||
childSession.getScope().get("persistenceContext"));
|
||||
}
|
||||
|
||||
public void testSessionEnd_Pc_NoParentPc() {
|
||||
MockFlowSession parentSession = newFlowSession(false, null);
|
||||
MockFlowSession childSession = newFlowSession(true, parentSession);
|
||||
|
||||
getListener().sessionStarting(requestContext, parentSession, null);
|
||||
getListener().sessionStarting(requestContext, childSession, null);
|
||||
|
||||
assertCommitState(true, false);
|
||||
|
||||
requestContext.setActiveSession(childSession);
|
||||
|
||||
// Session ending commits, unbinds/closes PersistenceContext
|
||||
getListener().sessionEnding(requestContext, childSession, "success", null);
|
||||
assertSessionNotBound();
|
||||
|
||||
// sessionEnded has no effect
|
||||
getListener().sessionEnded(requestContext, childSession, "success", null);
|
||||
assertSessionNotBound();
|
||||
assertCommitState(false, true);
|
||||
}
|
||||
|
||||
public void testSessionEnd_Pc_ParentPc() {
|
||||
MockFlowSession parentSession = newFlowSession(true, null);
|
||||
MockFlowSession childSession = newFlowSession(true, parentSession);
|
||||
|
||||
getListener().sessionStarting(requestContext, parentSession, null);
|
||||
getListener().sessionStarting(requestContext, childSession, null);
|
||||
|
||||
assertCommitState(true, false);
|
||||
|
||||
requestContext.setActiveSession(childSession);
|
||||
|
||||
// sessionEnding is a no-op
|
||||
getListener().sessionEnding(requestContext, childSession, "success", null);
|
||||
assertSessionBound();
|
||||
assertCommitState(true, false);
|
||||
|
||||
// sessionEnded binds Parent PersistenceContext
|
||||
getListener().sessionEnded(requestContext, childSession, "success", null);
|
||||
assertSessionBound();
|
||||
}
|
||||
|
||||
private MockFlowSession newFlowSession(boolean persistenceContext, FlowSession parent) {
|
||||
MockFlowSession flowSession = new MockFlowSession();
|
||||
flowSession.setParent(parent);
|
||||
if (persistenceContext) {
|
||||
flowSession.getDefinition().getAttributes().put("persistenceContext", "true");
|
||||
}
|
||||
EndState endState = new EndState(flowSession.getDefinitionInternal(), "success");
|
||||
endState.getAttributes().put("commit", Boolean.TRUE);
|
||||
flowSession.setState(endState);
|
||||
return flowSession;
|
||||
}
|
||||
|
||||
private DataSource getDataSource() {
|
||||
DriverManagerDataSource dataSource = new DriverManagerDataSource();
|
||||
dataSource.setDriverClassName("org.hsqldb.jdbcDriver");
|
||||
dataSource.setUrl("jdbc:hsqldb:mem:hspcl");
|
||||
dataSource.setUsername("sa");
|
||||
dataSource.setPassword("");
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
private void populateDataBase(DataSource dataSource) {
|
||||
Connection connection = null;
|
||||
try {
|
||||
connection = dataSource.getConnection();
|
||||
connection.createStatement().execute("drop table T_ADDRESS if exists;");
|
||||
connection.createStatement().execute("drop table T_BEAN if exists;");
|
||||
connection.createStatement().execute(
|
||||
"create table T_BEAN (ID integer primary key, NAME varchar(50) not null);");
|
||||
connection.createStatement().execute(
|
||||
"create table T_ADDRESS (ID integer primary key, BEAN_ID integer, VALUE varchar(50) not null);");
|
||||
connection
|
||||
.createStatement()
|
||||
.execute(
|
||||
"alter table T_ADDRESS add constraint FK_BEAN_ADDRESS foreign key (BEAN_ID) references T_BEAN(ID) on delete cascade");
|
||||
connection.createStatement().execute("insert into T_BEAN (ID, NAME) values (0, 'Ben Hale');");
|
||||
connection.createStatement().execute(
|
||||
"insert into T_ADDRESS (ID, BEAN_ID, VALUE) values (0, 0, 'Melbourne')");
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException("SQL exception occurred acquiring connection", e);
|
||||
} finally {
|
||||
if (connection != null) {
|
||||
try {
|
||||
connection.close();
|
||||
} catch (SQLException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* methods for subclasses */
|
||||
|
||||
protected abstract void setUpResources(DataSource dataSource) throws Exception;
|
||||
|
||||
protected abstract FlowExecutionListener getListener();
|
||||
|
||||
protected abstract void assertSessionBound();
|
||||
|
||||
protected abstract void assertSessionNotBound();
|
||||
|
||||
protected abstract void assertCommitState(boolean b, boolean c);
|
||||
|
||||
/* private helper methods */
|
||||
|
||||
private void assertSessionInScope(FlowSession session) {
|
||||
assertTrue(session.getScope().contains("persistenceContext"));
|
||||
}
|
||||
|
||||
private void assertSessionNotInScope(FlowSession session) {
|
||||
assertFalse(session.getScope().contains("persistenceContext"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -122,7 +122,6 @@ public class HibernateFlowExecutionListenerTests extends TestCase {
|
||||
hibernateListener.sessionEnded(context, flowSession, "success", null);
|
||||
assertEquals("Table should only have two rows", 2, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
|
||||
assertSessionNotBound();
|
||||
assertFalse(flowSession.getScope().contains("hibernate.session"));
|
||||
}
|
||||
|
||||
public void testFlowCommitsAfterMultipleRequests() {
|
||||
@@ -153,11 +152,8 @@ public class HibernateFlowExecutionListenerTests extends TestCase {
|
||||
hibernateListener.sessionEnding(context, flowSession, "success", null);
|
||||
hibernateListener.sessionEnded(context, flowSession, "success", null);
|
||||
assertEquals("Table should only have three rows", 3, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
|
||||
assertFalse(flowSession.getScope().contains("hibernate.session"));
|
||||
|
||||
assertSessionNotBound();
|
||||
assertFalse(flowSession.getScope().contains("hibernate.session"));
|
||||
|
||||
}
|
||||
|
||||
public void testCancelEndState() {
|
||||
@@ -180,7 +176,6 @@ public class HibernateFlowExecutionListenerTests extends TestCase {
|
||||
hibernateListener.sessionEnded(context, flowSession, "cancel", null);
|
||||
assertEquals("Table should only have two rows", 1, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
|
||||
assertSessionNotBound();
|
||||
assertFalse(flowSession.getScope().contains("hibernate.session"));
|
||||
}
|
||||
|
||||
public void testNoCommitAttributeSetOnEndState() {
|
||||
@@ -198,10 +193,8 @@ public class HibernateFlowExecutionListenerTests extends TestCase {
|
||||
hibernateListener.sessionEnding(context, flowSession, "success", null);
|
||||
hibernateListener.sessionEnded(context, flowSession, "cancel", null);
|
||||
assertEquals("Table should only have three rows", 1, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
|
||||
assertFalse(flowSession.getScope().contains("hibernate.session"));
|
||||
|
||||
assertSessionNotBound();
|
||||
assertFalse(flowSession.getScope().contains("hibernate.session"));
|
||||
}
|
||||
|
||||
public void testExceptionThrown() {
|
||||
|
||||
@@ -1,134 +1,64 @@
|
||||
package org.springframework.webflow.persistence;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.jdbc.datasource.DriverManagerDataSource;
|
||||
import org.springframework.orm.hibernate3.HibernateTemplate;
|
||||
import org.springframework.orm.hibernate3.HibernateTransactionManager;
|
||||
import org.springframework.orm.hibernate3.LocalSessionFactoryBean;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
import org.springframework.webflow.engine.EndState;
|
||||
import org.springframework.webflow.engine.Flow;
|
||||
import org.springframework.webflow.engine.builder.FlowAssembler;
|
||||
import org.springframework.webflow.engine.builder.model.FlowModelFlowBuilder;
|
||||
import org.springframework.webflow.engine.impl.FlowExecutionImplFactory;
|
||||
import org.springframework.webflow.engine.model.builder.DefaultFlowModelHolder;
|
||||
import org.springframework.webflow.engine.model.builder.xml.XmlFlowModelBuilder;
|
||||
import org.springframework.webflow.execution.Action;
|
||||
import org.springframework.webflow.execution.Event;
|
||||
import org.springframework.webflow.execution.FlowExecution;
|
||||
import org.springframework.webflow.execution.FlowExecutionListener;
|
||||
import org.springframework.webflow.execution.RequestContext;
|
||||
import org.springframework.webflow.execution.factory.StaticFlowExecutionListenerLoader;
|
||||
import org.springframework.webflow.test.MockExternalContext;
|
||||
import org.springframework.webflow.test.MockFlowBuilderContext;
|
||||
|
||||
public class HibernateFlowManagedPersistenceIntegrationTests extends TestCase {
|
||||
public class HibernateFlowManagedPersistenceIntegrationTests extends AbstractFlowManagedPersistenceIntegrationTests {
|
||||
|
||||
private SessionFactory sessionFactory;
|
||||
|
||||
private HibernateTemplate hibernateTemplate;
|
||||
|
||||
private HibernateFlowExecutionListener hibernateListener;
|
||||
|
||||
private FlowExecution flowExecution;
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
DataSource dataSource = getDataSource();
|
||||
populateDataBase(dataSource);
|
||||
sessionFactory = getSessionFactory(dataSource);
|
||||
hibernateTemplate = new HibernateTemplate(sessionFactory);
|
||||
hibernateTemplate.setCheckWriteOperations(false);
|
||||
@Override
|
||||
protected FlowExecutionListener createFlowExecutionListener() throws Exception {
|
||||
sessionFactory = getSessionFactory(getDataSource());
|
||||
HibernateTransactionManager tm = new HibernateTransactionManager(sessionFactory);
|
||||
hibernateListener = new HibernateFlowExecutionListener(sessionFactory, tm);
|
||||
return new HibernateFlowExecutionListener(sessionFactory, tm);
|
||||
}
|
||||
|
||||
ClassPathResource res = new ClassPathResource("flow-managed-persistence.xml", getClass());
|
||||
DefaultFlowModelHolder holder = new DefaultFlowModelHolder(new XmlFlowModelBuilder(res));
|
||||
FlowModelFlowBuilder builder = new FlowModelFlowBuilder(holder);
|
||||
MockFlowBuilderContext context = new MockFlowBuilderContext("foo");
|
||||
FlowAssembler assembler = new FlowAssembler(builder, context);
|
||||
Flow flow = assembler.assembleFlow();
|
||||
context.registerSubflow(flow);
|
||||
Flow notManaged = new Flow("notmanaged");
|
||||
new EndState(notManaged, "finish");
|
||||
context.registerSubflow(notManaged);
|
||||
context.registerBean("loadTestBean", new Action() {
|
||||
@Override
|
||||
protected Action incrementCountAction() {
|
||||
return new Action() {
|
||||
public Event execute(RequestContext context) throws Exception {
|
||||
assertSessionBound();
|
||||
Session session = (Session) context.getFlowScope().get("persistenceContext");
|
||||
TestBean bean = (TestBean) session.get(TestBean.class, new Long(0));
|
||||
assertNotNull(bean);
|
||||
context.getFlowScope().put("testBean", bean);
|
||||
bean.incrementCount();
|
||||
return new Event(this, "success");
|
||||
}
|
||||
});
|
||||
FlowExecutionImplFactory factory = new FlowExecutionImplFactory();
|
||||
factory.setExecutionListenerLoader(new StaticFlowExecutionListenerLoader(hibernateListener));
|
||||
flowExecution = factory.createFlowExecution(flow);
|
||||
};
|
||||
}
|
||||
|
||||
public void testFlowWithSubflow() {
|
||||
MockExternalContext context = new MockExternalContext();
|
||||
flowExecution.start(null, context);
|
||||
context.setEventId("subflow");
|
||||
flowExecution.resume(context);
|
||||
context.setEventId("finish");
|
||||
flowExecution.resume(context);
|
||||
}
|
||||
|
||||
public void testManagedFlowWithUnmanagedSubflow() {
|
||||
MockExternalContext context = new MockExternalContext();
|
||||
flowExecution.start(null, context);
|
||||
context.setEventId("notmanaged");
|
||||
flowExecution.resume(context);
|
||||
}
|
||||
|
||||
private DataSource getDataSource() {
|
||||
DriverManagerDataSource dataSource = new DriverManagerDataSource();
|
||||
dataSource.setDriverClassName("org.hsqldb.jdbcDriver");
|
||||
dataSource.setUrl("jdbc:hsqldb:mem:jpa");
|
||||
dataSource.setUsername("sa");
|
||||
dataSource.setPassword("");
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
private void populateDataBase(DataSource dataSource) {
|
||||
Connection connection = null;
|
||||
try {
|
||||
connection = dataSource.getConnection();
|
||||
connection.createStatement().execute("drop table T_ADDRESS if exists;");
|
||||
connection.createStatement().execute("drop table T_BEAN if exists;");
|
||||
connection.createStatement().execute(
|
||||
"create table T_BEAN (ID integer primary key, NAME varchar(50) not null);");
|
||||
connection.createStatement().execute(
|
||||
"create table T_ADDRESS (ID integer primary key, BEAN_ID integer, VALUE varchar(50) not null);");
|
||||
connection
|
||||
.createStatement()
|
||||
.execute(
|
||||
"alter table T_ADDRESS add constraint FK_BEAN_ADDRESS foreign key (BEAN_ID) references T_BEAN(ID) on delete cascade");
|
||||
connection.createStatement().execute("insert into T_BEAN (ID, NAME) values (0, 'Ben Hale');");
|
||||
connection.createStatement().execute(
|
||||
"insert into T_ADDRESS (ID, BEAN_ID, VALUE) values (0, 0, 'Melbourne')");
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException("SQL exception occurred acquiring connection", e);
|
||||
} finally {
|
||||
if (connection != null) {
|
||||
try {
|
||||
connection.close();
|
||||
} catch (SQLException e) {
|
||||
}
|
||||
@Override
|
||||
protected Object assertCountAction() {
|
||||
return new Object() {
|
||||
@SuppressWarnings("unused")
|
||||
public void execute(RequestContext context, int expected) throws Exception {
|
||||
assertSessionBound();
|
||||
Session session = (Session) context.getFlowScope().get("persistenceContext");
|
||||
TestBean bean = (TestBean) session.get(TestBean.class, new Long(0));
|
||||
assertEquals(expected, bean.getCount());
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void assertSessionBound() {
|
||||
assertNotNull(TransactionSynchronizationManager.getResource(sessionFactory));
|
||||
}
|
||||
|
||||
/* private helper methods */
|
||||
|
||||
@SuppressWarnings("cast")
|
||||
private SessionFactory getSessionFactory(DataSource dataSource) throws Exception {
|
||||
LocalSessionFactoryBean factory = new LocalSessionFactoryBean();
|
||||
factory.setDataSource(dataSource);
|
||||
@@ -139,7 +69,4 @@ public class HibernateFlowManagedPersistenceIntegrationTests extends TestCase {
|
||||
return (SessionFactory) factory.getObject();
|
||||
}
|
||||
|
||||
private void assertSessionBound() {
|
||||
assertNotNull(TransactionSynchronizationManager.getResource(sessionFactory));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
package org.springframework.webflow.persistence;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.orm.hibernate3.HibernateTemplate;
|
||||
import org.springframework.orm.hibernate3.HibernateTransactionManager;
|
||||
import org.springframework.orm.hibernate3.LocalSessionFactoryBean;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
import org.springframework.webflow.execution.FlowExecutionListener;
|
||||
|
||||
public class HibernatePersistenceContextPropagationTests extends AbstractPersistenceContextPropagationTests {
|
||||
|
||||
private SessionFactory sessionFactory;
|
||||
|
||||
private HibernateTemplate hibernateTemplate;
|
||||
|
||||
private HibernateFlowExecutionListener executionListener;
|
||||
|
||||
private int rowCount;
|
||||
|
||||
@Override
|
||||
protected void setUpResources(DataSource dataSource) throws Exception {
|
||||
sessionFactory = getSessionFactory(dataSource);
|
||||
hibernateTemplate = new HibernateTemplate(sessionFactory);
|
||||
hibernateTemplate.setCheckWriteOperations(false);
|
||||
HibernateTransactionManager tm = new HibernateTransactionManager(sessionFactory);
|
||||
executionListener = new HibernateFlowExecutionListener(sessionFactory, tm);
|
||||
rowCount = 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FlowExecutionListener getListener() {
|
||||
return executionListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void assertSessionNotBound() {
|
||||
assertNull(TransactionSynchronizationManager.getResource(sessionFactory));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void assertSessionBound() {
|
||||
assertNotNull(TransactionSynchronizationManager.getResource(sessionFactory));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void assertCommitState(boolean insertRow, boolean isCommited) {
|
||||
if (insertRow) {
|
||||
hibernateTemplate.save(new TestBean(rowCount++, "Keith Donald"));
|
||||
}
|
||||
if (!isCommited) {
|
||||
assertEquals("Nothing should be committed yet", 1,
|
||||
getJdbcTemplate().queryForInt("select count(*) from T_BEAN"));
|
||||
} else {
|
||||
assertEquals("All rows should be committed", rowCount,
|
||||
getJdbcTemplate().queryForInt("select count(*) from T_BEAN"));
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("cast")
|
||||
private SessionFactory getSessionFactory(DataSource dataSource) throws Exception {
|
||||
LocalSessionFactoryBean factory = new LocalSessionFactoryBean();
|
||||
factory.setDataSource(dataSource);
|
||||
factory.setMappingLocations(new Resource[] {
|
||||
new ClassPathResource("org/springframework/webflow/persistence/TestBean.hbm.xml"),
|
||||
new ClassPathResource("org/springframework/webflow/persistence/TestAddress.hbm.xml") });
|
||||
factory.afterPropertiesSet();
|
||||
return (SessionFactory) factory.getObject();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -72,7 +72,6 @@ public class JpaFlowExecutionListenerTests extends TestCase {
|
||||
jpaListener.sessionEnded(context, flowSession, "success", null);
|
||||
assertEquals("Table should only have two rows", 2, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
|
||||
assertSessionNotBound();
|
||||
assertFalse(flowSession.getScope().contains("hibernate.session"));
|
||||
}
|
||||
|
||||
public void testFlowCommitsAfterMultipleRequests() {
|
||||
@@ -103,10 +102,8 @@ public class JpaFlowExecutionListenerTests extends TestCase {
|
||||
jpaListener.sessionEnding(context, flowSession, "success", null);
|
||||
jpaListener.sessionEnded(context, flowSession, "success", null);
|
||||
assertEquals("Table should only have three rows", 3, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
|
||||
assertFalse(flowSession.getScope().contains("hibernate.session"));
|
||||
|
||||
assertSessionNotBound();
|
||||
assertFalse(flowSession.getScope().contains("hibernate.session"));
|
||||
}
|
||||
|
||||
public void testCancelEndState() {
|
||||
@@ -129,7 +126,6 @@ public class JpaFlowExecutionListenerTests extends TestCase {
|
||||
jpaListener.sessionEnded(context, flowSession, "success", null);
|
||||
assertEquals("Table should only have two rows", 1, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
|
||||
assertSessionNotBound();
|
||||
assertFalse(flowSession.getScope().contains("hibernate.session"));
|
||||
}
|
||||
|
||||
public void testNoCommitAttributeSetOnEndState() {
|
||||
@@ -147,10 +143,8 @@ public class JpaFlowExecutionListenerTests extends TestCase {
|
||||
jpaListener.sessionEnding(context, flowSession, "cancel", null);
|
||||
jpaListener.sessionEnded(context, flowSession, "success", null);
|
||||
assertEquals("Table should only have three rows", 1, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
|
||||
assertFalse(flowSession.getScope().contains("hibernate.session"));
|
||||
|
||||
assertSessionNotBound();
|
||||
assertFalse(flowSession.getScope().contains("hibernate.session"));
|
||||
}
|
||||
|
||||
public void testExceptionThrown() {
|
||||
|
||||
@@ -1,129 +1,64 @@
|
||||
package org.springframework.webflow.persistence;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.jdbc.datasource.DriverManagerDataSource;
|
||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||
import org.springframework.orm.jpa.vendor.OpenJpaVendorAdapter;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
import org.springframework.webflow.engine.EndState;
|
||||
import org.springframework.webflow.engine.Flow;
|
||||
import org.springframework.webflow.engine.builder.FlowAssembler;
|
||||
import org.springframework.webflow.engine.builder.model.FlowModelFlowBuilder;
|
||||
import org.springframework.webflow.engine.impl.FlowExecutionImplFactory;
|
||||
import org.springframework.webflow.engine.model.builder.DefaultFlowModelHolder;
|
||||
import org.springframework.webflow.engine.model.builder.xml.XmlFlowModelBuilder;
|
||||
import org.springframework.webflow.execution.Action;
|
||||
import org.springframework.webflow.execution.Event;
|
||||
import org.springframework.webflow.execution.FlowExecution;
|
||||
import org.springframework.webflow.execution.FlowExecutionListener;
|
||||
import org.springframework.webflow.execution.RequestContext;
|
||||
import org.springframework.webflow.execution.factory.StaticFlowExecutionListenerLoader;
|
||||
import org.springframework.webflow.test.MockExternalContext;
|
||||
import org.springframework.webflow.test.MockFlowBuilderContext;
|
||||
|
||||
public class JpaFlowManagedPersistenceIntegrationTests extends TestCase {
|
||||
public class JpaFlowManagedPersistenceIntegrationTests extends AbstractFlowManagedPersistenceIntegrationTests {
|
||||
|
||||
private EntityManagerFactory entityManagerFactory;
|
||||
|
||||
private JpaFlowExecutionListener jpaListener;
|
||||
|
||||
private FlowExecution flowExecution;
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
DataSource dataSource = getDataSource();
|
||||
populateDataBase(dataSource);
|
||||
entityManagerFactory = getEntityManagerFactory(dataSource);
|
||||
@Override
|
||||
protected FlowExecutionListener createFlowExecutionListener() throws Exception {
|
||||
entityManagerFactory = getEntityManagerFactory(getDataSource());
|
||||
JpaTransactionManager tm = new JpaTransactionManager(entityManagerFactory);
|
||||
jpaListener = new JpaFlowExecutionListener(entityManagerFactory, tm);
|
||||
return new JpaFlowExecutionListener(entityManagerFactory, tm);
|
||||
}
|
||||
|
||||
ClassPathResource res = new ClassPathResource("flow-managed-persistence.xml", getClass());
|
||||
DefaultFlowModelHolder holder = new DefaultFlowModelHolder(new XmlFlowModelBuilder(res));
|
||||
FlowModelFlowBuilder builder = new FlowModelFlowBuilder(holder);
|
||||
MockFlowBuilderContext context = new MockFlowBuilderContext("foo");
|
||||
FlowAssembler assembler = new FlowAssembler(builder, context);
|
||||
Flow flow = assembler.assembleFlow();
|
||||
context.registerSubflow(flow);
|
||||
Flow notManaged = new Flow("notmanaged");
|
||||
new EndState(notManaged, "finish");
|
||||
context.registerSubflow(notManaged);
|
||||
context.registerBean("loadTestBean", new Action() {
|
||||
@Override
|
||||
protected Action incrementCountAction() {
|
||||
return new Action() {
|
||||
@SuppressWarnings("cast")
|
||||
public Event execute(RequestContext context) throws Exception {
|
||||
assertSessionBound();
|
||||
EntityManager em = (EntityManager) context.getFlowScope().get("persistenceContext");
|
||||
TestBean bean = (TestBean) em.getReference(TestBean.class, new Integer(0));
|
||||
bean.incrementCount();
|
||||
assertNotNull(bean);
|
||||
context.getFlowScope().put("testBean", bean);
|
||||
return new Event(this, "success");
|
||||
}
|
||||
});
|
||||
FlowExecutionImplFactory factory = new FlowExecutionImplFactory();
|
||||
factory.setExecutionListenerLoader(new StaticFlowExecutionListenerLoader(jpaListener));
|
||||
flowExecution = factory.createFlowExecution(flow);
|
||||
};
|
||||
}
|
||||
|
||||
public void testManagedFlowWithManagedSubflow() {
|
||||
MockExternalContext context = new MockExternalContext();
|
||||
flowExecution.start(null, context);
|
||||
context.setEventId("subflow");
|
||||
flowExecution.resume(context);
|
||||
context.setEventId("finish");
|
||||
flowExecution.resume(context);
|
||||
}
|
||||
|
||||
public void testManagedFlowWithUnmanagedSubflow() {
|
||||
MockExternalContext context = new MockExternalContext();
|
||||
flowExecution.start(null, context);
|
||||
context.setEventId("notmanaged");
|
||||
flowExecution.resume(context);
|
||||
}
|
||||
|
||||
private DataSource getDataSource() {
|
||||
DriverManagerDataSource dataSource = new DriverManagerDataSource();
|
||||
dataSource.setDriverClassName("org.hsqldb.jdbcDriver");
|
||||
dataSource.setUrl("jdbc:hsqldb:mem:jpa");
|
||||
dataSource.setUsername("sa");
|
||||
dataSource.setPassword("");
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
private void populateDataBase(DataSource dataSource) {
|
||||
Connection connection = null;
|
||||
try {
|
||||
connection = dataSource.getConnection();
|
||||
connection.createStatement().execute("drop table T_ADDRESS if exists;");
|
||||
connection.createStatement().execute("drop table T_BEAN if exists;");
|
||||
connection.createStatement().execute(
|
||||
"create table T_BEAN (ID integer primary key, NAME varchar(50) not null);");
|
||||
connection.createStatement().execute(
|
||||
"create table T_ADDRESS (ID integer primary key, BEAN_ID integer, VALUE varchar(50) not null);");
|
||||
connection
|
||||
.createStatement()
|
||||
.execute(
|
||||
"alter table T_ADDRESS add constraint FK_BEAN_ADDRESS foreign key (BEAN_ID) references T_BEAN(ID) on delete cascade");
|
||||
connection.createStatement().execute("insert into T_BEAN (ID, NAME) values (0, 'Ben Hale');");
|
||||
connection.createStatement().execute(
|
||||
"insert into T_ADDRESS (ID, BEAN_ID, VALUE) values (0, 0, 'Melbourne')");
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException("SQL exception occurred acquiring connection", e);
|
||||
} finally {
|
||||
if (connection != null) {
|
||||
try {
|
||||
connection.close();
|
||||
} catch (SQLException e) {
|
||||
}
|
||||
@Override
|
||||
protected Object assertCountAction() {
|
||||
return new Object() {
|
||||
@SuppressWarnings({ "unused", "cast" })
|
||||
public void execute(RequestContext context, int expected) throws Exception {
|
||||
assertSessionBound();
|
||||
EntityManager em = (EntityManager) context.getFlowScope().get("persistenceContext");
|
||||
TestBean bean = (TestBean) em.getReference(TestBean.class, new Integer(0));
|
||||
assertEquals(expected, bean.getCount());
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void assertSessionBound() {
|
||||
assertNotNull(TransactionSynchronizationManager.getResource(entityManagerFactory));
|
||||
}
|
||||
|
||||
/* private helper methods */
|
||||
|
||||
private EntityManagerFactory getEntityManagerFactory(DataSource dataSource) throws Exception {
|
||||
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
|
||||
factory.setDataSource(dataSource);
|
||||
@@ -134,7 +69,4 @@ public class JpaFlowManagedPersistenceIntegrationTests extends TestCase {
|
||||
return factory.getObject();
|
||||
}
|
||||
|
||||
private void assertSessionBound() {
|
||||
assertNotNull(TransactionSynchronizationManager.getResource(entityManagerFactory));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
package org.springframework.webflow.persistence;
|
||||
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.orm.jpa.JpaTemplate;
|
||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||
import org.springframework.orm.jpa.vendor.OpenJpaVendorAdapter;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
import org.springframework.webflow.execution.FlowExecutionListener;
|
||||
|
||||
public class JpaPersistenceContextPropagationTests extends AbstractPersistenceContextPropagationTests {
|
||||
|
||||
private EntityManagerFactory entityManagerFactory;
|
||||
|
||||
private JpaFlowExecutionListener executionListener;
|
||||
|
||||
private JpaTemplate jpaTemplate;
|
||||
|
||||
private int rowCount;
|
||||
|
||||
@Override
|
||||
protected void setUpResources(DataSource dataSource) throws Exception {
|
||||
entityManagerFactory = getEntityManagerFactory(dataSource);
|
||||
JpaTransactionManager tm = new JpaTransactionManager(entityManagerFactory);
|
||||
executionListener = new JpaFlowExecutionListener(entityManagerFactory, tm);
|
||||
jpaTemplate = new JpaTemplate(entityManagerFactory);
|
||||
rowCount = 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FlowExecutionListener getListener() {
|
||||
return executionListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void assertSessionNotBound() {
|
||||
assertNull(TransactionSynchronizationManager.getResource(entityManagerFactory));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void assertSessionBound() {
|
||||
assertNotNull(TransactionSynchronizationManager.getResource(entityManagerFactory));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void assertCommitState(boolean insertRow, boolean isCommited) {
|
||||
if (insertRow) {
|
||||
jpaTemplate.persist(new TestBean(rowCount++, "Keith Donald"));
|
||||
}
|
||||
if (!isCommited) {
|
||||
assertEquals("Nothing should be committed yet", 1,
|
||||
getJdbcTemplate().queryForInt("select count(*) from T_BEAN"));
|
||||
} else {
|
||||
assertEquals("All rows should be committed", rowCount,
|
||||
getJdbcTemplate().queryForInt("select count(*) from T_BEAN"));
|
||||
}
|
||||
}
|
||||
|
||||
private EntityManagerFactory getEntityManagerFactory(DataSource dataSource) throws Exception {
|
||||
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
|
||||
factory.setDataSource(dataSource);
|
||||
factory.setPersistenceXmlLocation("classpath:org/springframework/webflow/persistence/persistence.xml");
|
||||
OpenJpaVendorAdapter openJpa = new OpenJpaVendorAdapter();
|
||||
factory.setJpaVendorAdapter(openJpa);
|
||||
factory.afterPropertiesSet();
|
||||
return factory.getObject();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -26,6 +26,8 @@ public class TestBean {
|
||||
|
||||
private Set addresses = new HashSet();
|
||||
|
||||
private int count;
|
||||
|
||||
public TestBean() {
|
||||
|
||||
}
|
||||
@@ -62,4 +64,13 @@ public class TestBean {
|
||||
public void setAddresses(Set addresses) {
|
||||
this.addresses = addresses;
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
public void incrementCount() {
|
||||
this.count++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<flow xmlns="http://www.springframework.org/schema/webflow"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">
|
||||
|
||||
<persistence-context/>
|
||||
|
||||
<on-start>
|
||||
<evaluate expression="incrementCountAction" />
|
||||
</on-start>
|
||||
|
||||
<view-state id="view">
|
||||
<transition on="finish" to="finish"/>
|
||||
</view-state>
|
||||
|
||||
<end-state id="finish" commit="true"/>
|
||||
|
||||
</flow>
|
||||
@@ -6,35 +6,29 @@
|
||||
<persistence-context/>
|
||||
|
||||
<on-start>
|
||||
<evaluate expression="loadTestBean" />
|
||||
<evaluate expression="incrementCountAction" />
|
||||
</on-start>
|
||||
|
||||
<view-state id="view">
|
||||
<transition on="view2" to="view2"/>
|
||||
<transition on="subflow" to="subflow"/>
|
||||
<transition on="managed" to="managed"/>
|
||||
<transition on="notmanaged" to="notmanaged"/>
|
||||
<transition on="cancel" to="cancel"/>
|
||||
<transition on="finish" to="finish"/>
|
||||
</view-state>
|
||||
|
||||
<subflow-state id="subflow" subflow="foo">
|
||||
<subflow-state id="managed" subflow="managed-child-flow">
|
||||
<transition on="finish" to="view2">
|
||||
<evaluate expression="loadTestBean" />
|
||||
<evaluate expression="incrementCountAction" />
|
||||
<evaluate expression="assertCountAction.execute(flowRequestContext,3)" />
|
||||
</transition>
|
||||
</subflow-state>
|
||||
|
||||
<subflow-state id="notmanaged" subflow="notmanaged">
|
||||
<subflow-state id="notmanaged" subflow="notmanaged-child-flow">
|
||||
<transition on="finish" to="view2">
|
||||
<evaluate expression="loadTestBean" />
|
||||
<evaluate expression="incrementCountAction" />
|
||||
<evaluate expression="assertCountAction.execute(flowRequestContext,2)" />
|
||||
</transition>
|
||||
</subflow-state>
|
||||
|
||||
|
||||
<view-state id="view2">
|
||||
<transition on="finish" to="finish"/>
|
||||
</view-state>
|
||||
<view-state id="view2"/>
|
||||
|
||||
<end-state id="finish" commit="true"/>
|
||||
<end-state id="cancel"/>
|
||||
|
||||
</flow>
|
||||
@@ -16,6 +16,9 @@
|
||||
<basic name="name">
|
||||
<column name="NAME" />
|
||||
</basic>
|
||||
<basic name="count">
|
||||
<column name="counter" />
|
||||
</basic>
|
||||
<one-to-many name="addresses" target-entity="TestAddress">
|
||||
<join-column name="BEAN_ID"/>
|
||||
</one-to-many>
|
||||
|
||||
Reference in New Issue
Block a user