Skip to content

Commit

Permalink
More session/transaction management work
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelborn committed Nov 2, 2024
1 parent ad4b502 commit 635b2ea
Show file tree
Hide file tree
Showing 9 changed files with 50 additions and 24 deletions.
3 changes: 3 additions & 0 deletions src/main/java/ortus/boxlang/modules/orm/ORMApp.java
Original file line number Diff line number Diff line change
Expand Up @@ -249,9 +249,12 @@ public Session getSession( IBoxContext context, DataSource datasource ) {
IBoxContext jdbcContext = ( IBoxContext ) context.getParentOfType( IJDBCCapableContext.class );
Key sessionKey = Key.of( "orm_session_" + datasource.getUniqueName().getName() );

logger.debug( "Getting session from context attachments with key: {}", sessionKey.getName() );
if ( jdbcContext.hasAttachment( sessionKey ) ) {
logger.debug( "key exists; returning session" );
return jdbcContext.getAttachment( sessionKey );
}
logger.debug( "key DOES NOT exist; opening NEW session" );

SessionFactory sessionFactory = getSessionFactoryOrThrow( datasource );
jdbcContext.putAttachment( sessionKey, sessionFactory.openSession() );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,12 @@ public EntityLoadByPK() {
* @param arguments Argument scope for the BIF.
*/
public Object _invoke( IBoxContext context, ArgumentsScope arguments ) {
Session session = this.ormService.getORMApp( context ).getSession( context );
Session session = this.ormService.getORMApp( context ).getSession( context );

// @TODO: Move this to a more sensible location.
if ( session.getTransaction() == null ) {
session.beginTransaction();
}
// if ( session.getTransaction() == null ) {
// session.beginTransaction();
// }

String entityName = arguments.getAsString( ORMKeys.entity );
Object keyValue = arguments.get( Key.id );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import ortus.boxlang.modules.orm.ORMService;
import ortus.boxlang.modules.orm.config.ORMConfig;
import ortus.boxlang.modules.orm.config.ORMKeys;
import ortus.boxlang.runtime.BoxRuntime;
import ortus.boxlang.runtime.context.RequestBoxContext;
import ortus.boxlang.runtime.events.BaseInterceptor;
import ortus.boxlang.runtime.events.InterceptionPoint;
Expand Down Expand Up @@ -39,6 +40,11 @@ public void configure( IStruct properties ) {
*/
@InterceptionPoint
public void afterApplicationListenerLoad( IStruct args ) {
BoxRuntime instance = BoxRuntime.getInstance();
if ( !instance.hasGlobalService( ORMKeys.ORMService ) ) {
logger.info( "Adding ORMService to global services" );
instance.putGlobalService( ORMKeys.ORMService, ORMService.getInstance() );
}
logger.info(
"afterApplicationListenerLoad fired; checking for ORM configuration in the application context config" );

Expand All @@ -58,7 +64,8 @@ public void afterApplicationListenerLoad( IStruct args ) {
ORMConfig config = getORMConfig( context );
if ( config != null ) {
logger.info( "ORMEnabled is true and ORM settings are specified - Firing ORM application startup." );
ORMService.getInstance().startupApp( context, config );
( ( ORMService ) instance.getGlobalService( ORMKeys.ORMService ) )
.startupApp( context, config );
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public void configure( IStruct properties ) {

@InterceptionPoint
public void onRequestStart( IStruct args ) {
logger.debug( "Starting ORM session" );
logger.debug( "onRequestStart - Starting ORM session" );
RequestBoxContext context = args.getAs( RequestBoxContext.class, Key.context );

TransactionManager ORMTransactionManager = new TransactionManager( context, config );
Expand Down Expand Up @@ -74,9 +74,9 @@ public void onRequestEnd( IStruct args ) {

// @TODO: if ormConfig.flushAtRequestEnd and ormConfig.autoManageSession, flush the current session.
// @TODO: end ORM session
logger.debug( "Ending ORM session" );
logger.debug( "onRequestEnd - closing ORM sessions" );
if ( config.flushAtRequestEnd ) {
logger.debug( "Flushing all ORM sessions for this request" );
logger.debug( "'flushAtRequestEnd' is enabled; Flushing all ORM sessions for this request" );
// @TODO: Consider moving this into the ORMApp itself.
ormApp.getDatasources().forEach( datasource -> {
ormApp.getSession( context, datasource ).flush();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import ortus.boxlang.modules.orm.ORMService;
import ortus.boxlang.modules.orm.config.ORMConfig;
import ortus.boxlang.modules.orm.config.ORMKeys;
import ortus.boxlang.runtime.BoxRuntime;
import ortus.boxlang.runtime.context.RequestBoxContext;
import ortus.boxlang.runtime.events.BaseInterceptor;
import ortus.boxlang.runtime.events.InterceptionPoint;
Expand Down Expand Up @@ -49,9 +48,7 @@ public TransactionManager( RequestBoxContext context, ORMConfig config ) {
this.context = context;
this.config = config;
this.ormApp = ORMService.getInstance().getORMApp( context );
// @TODO: I am quite certain this is the WRONG interceptor pool to be using.
// This needs to be fixed in BoxLang Core, refactoring `ortus.boxlang.runtime.jdbc.Transaction` to use the application-level interceptor pool.
this.interceptorPool = BoxRuntime.getInstance().getInterceptorService();
this.interceptorPool = context.getApplicationListener().getInterceptorPool();
}

/**
Expand Down Expand Up @@ -85,19 +82,19 @@ public void configure( IStruct properties ) {

@InterceptionPoint
public void onTransactionBegin( IStruct args ) {
logger.debug( "Starting ORM transaction" );
// @TODO: Wait... don't we have a Session per configured datasource?
// This is going to need to be refactored to handle multiple datasources.
Session ormSession = ormApp.getSession( context );
ormSession.beginTransaction();
ormApp.getDatasources().forEach( ( datasource ) -> {
Session ormSession = ormApp.getSession( context, datasource );
logger.debug( "Starting ORM transaction on session {}", ormSession );
ormSession.beginTransaction();
} );
}

@InterceptionPoint
public void onTransactionEnd( IStruct args ) {
logger.debug( "Ending ORM transaction" );
// @TODO: Wait... don't we have a Session per configured datasource?
// This is going to need to be refactored to handle multiple datasources.
Session ormSession = ormApp.getSession( context );
ormSession.getTransaction().commit();
ormApp.getDatasources().forEach( ( datasource ) -> {
Session ormSession = ormApp.getSession( context, datasource );
logger.debug( "Ending ORM transaction on session {}", ormSession );
ormSession.getTransaction().commit();
} );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
@Disabled( "connection management issues when run in a full suite. Passes when run solo." )
public class EntitySaveTest extends BaseORMTest {

@Disabled( "Not working until we have a better transaction management strategy." )
@DisplayName( "It can save new entities to the database" )
@Test
public void testEntitySave() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
@Disabled( "Breaks the test suite." )
public class ORMFlushTest extends BaseORMTest {

@Disabled( "Not working until we have a better transaction management strategy." )
@DisplayName( "It can flush the session" )
@Test
public void testORMFlush() {
Expand Down
8 changes: 6 additions & 2 deletions src/test/java/tools/BaseORMTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import ortus.boxlang.modules.orm.ORMService;
import ortus.boxlang.modules.orm.SessionFactoryBuilder;
import ortus.boxlang.modules.orm.config.ORMConfig;
import ortus.boxlang.modules.orm.config.ORMKeys;
import ortus.boxlang.runtime.BoxRuntime;
import ortus.boxlang.runtime.context.ApplicationBoxContext;
import ortus.boxlang.runtime.context.IBoxContext;
Expand Down Expand Up @@ -56,8 +57,11 @@ public class BaseORMTest {

@BeforeAll
public static void setUp() {
instance = BoxRuntime.getInstance( true );
ormService = ORMService.getInstance();
instance = BoxRuntime.getInstance( true );
ormService = ORMService.getInstance();
if ( !instance.hasGlobalService( ORMKeys.ORMService ) ) {
instance.putGlobalService( ORMKeys.ORMService, ormService );
}
startupContext = new ScriptingRequestBoxContext( instance.getRuntimeContext() );
datasource = JDBCTestUtils.constructTestDataSource( "TestDB" );

Expand Down
13 changes: 13 additions & 0 deletions src/test/resources/app/models/AlternateDS.cfc
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
component entityName="MappingFromAnotherMother" datasource="dsn2" persistent="true" {

property
name="id"
type="string"
fieldtype="id"
ormtype="string"
generator="assigned";

property
name="name"
type="string";
}

0 comments on commit 635b2ea

Please sign in to comment.