I thought I'd share what I've done to accomplish what I needed. I have
solved the problem a couple of different ways.
1.) Interceptor for Transfer transactions
Since Transfer's AOP was giving me nightmares, I wrote a quick
interceptor with this method:
<cffunction name="adviseAction" access="public">
<cfargument name="Event" required="true"
type="coldbox.system.beans.requestContext" hint="The event object.">
<cfargument name="interceptData" required="true" type="struct" hint="A
structure containing intercepted information. NONE BY DEFAULT HERE">
<cfscript>
transaction = getPlugin("ioc").getBean("TransferTransaction");
</cfscript>
<cfset transaction.execute(interceptData.component,
interceptData.action, arguments)>
<!--- continue interceptin chain --->
<cfreturn false>
</cffunction>
Then in my preHandler() function for the handler who's actions I want
to be able to advise I added this switch:
switch(Event.getCurrentAction())
{
case "adviseTransaction":
{
data = structnew();
data.action = Event.getValue("originalAction");
data.component = this;
announceInterception('adviseAction', data)
break;
}
}
I then added a route for my handler:
<cfset addCourse(pattern="user/:originalAction",
handler="user",
action="adviseTransaction")>
Finally, for the user.adviseTransaction action that the course matches
to I created an empty method that doesn't do anything but is there to
allow the preHandler to run (which executes the original action on the
handler inside of a transaction):
<cffunction name="adviseTransaction" access="public"
returntype="void" output="false">
<cfargument name="Event" type="coldbox.system.beans.requestContext">
<cfset var rc = event.getCollection()>
</cffunction>
So basically what happens here is this:
When the user.create event is called it is routed to
user.adviseTransaction with a variable available called
"originalAction" which contains the real action that we want to
execute inside of a transaction. In this case, "create".
When user.adviseTransaction runs, the preHandler first matches to the
case and announces an interception to the adviseAction() method of the
interceptor, passing in a structure containing the original action as
data.action and the user handler reference as data.component
The interceptor then retrieves the transaction manager for Transfer
and executes the original method ("create") by using the
interceptData.action variable to identify the action and the
data.component varible to reference the handler. The views, etc are
set inside of the create method since it has access to the Event, the
adviseTransaction method on the handler doesn't need to do anything.
This executes the create method on the user component inside of a
transaction without having to user runEvent(). The Event argument to
the interceptor's adviseAction() method is passed through to
user.create during the execute call.
This effectively wraps an entire handler method inside of a
transaction, so that in case you want to call multiple service layers
and have all of them wrapped under one transaction, you are free to do
so by wrapping the entire handler action.
One thing to remember is that when I have a route such as:
<cfset addCourse(pattern="user/:originalAction",
handler="user",
action="adviseTransaction",
packageResolverExempt="false")>
This sends user.[anything] to user.adviseTransaction, obviously I
don't want this. My user.viewUser has no need to be inside of a
transaction.
So I can do this:
<cfset addCourse(pattern="user/create",
handler="user",
action="adviseTransaction",
packageResolverExempt="false",
matchVariables="originalAction=create")>
This will send only the user/create event to the adviseTransaction()
method.
On alternative way of doing all of this is to avoid the interceptor
entirely and put the method inside of the user handler, like so:
<cffunction name="adviseAction" access="public" returntype="void"
output="false">
<cfargument name="Event" type="coldbox.system.beans.requestContext">
<cfset var rc = event.getCollection()>
<cfscript>
transaction =
getPlugin("ioc").getBean("TransferTransaction");
</cfscript>
<cfset transaction.execute(this, rc.originalAction, arguments)>
</cffunction>
And then tell the route to do:
<cfset addCourse(pattern="user/create",
handler="user",
action="adviseAction",
packageResolverExempt="false",
matchVariables="originalAction=create")>
With this configuration, you don't need anything in the preHandler()
method or have an interceptor. The route will pass user/create to
user.adviseAction, which in turn executes the originalAction from the
request collection on "this" (the current handler) inside of a
transaction.
I prefer the handler because it is more flexible, but either way, it
works :)
I can use AOP for singletons, such as service calls and I can wrap my
entire handler action in a transaction using this method.
This has eliminated my stack overflow issues.
On Jun 28, 11:53 pm, Mark Mandel <[email protected]> wrote:
> It * sounds * like Transfer is being loaded on every request... I would put
> some <cflog> statements in TransferFactory's init() function, and see if
> that is the case.
>
> Mark
>
> On Mon, Jun 29, 2009 at 4:35 PM, whostheJBoss
> <[email protected]>wrote:
>
>
>
>
>
> > Ok, a few things. I will explain my configuration first.
>
> > I have my Transfer wired up in ColdBox via the Transfer Loader
> > interceptor:
>
> > <!-- Transfer Loader -->
> > <Interceptor class="coldbox.system.extras.transfer.TransferLoader">
> > <Property name="ConfigPath">/${AppMapping}/config/transfer.xml.cfm</
> > Property>
> > <Property name="definitionPath">/${AppMapping}/config/definitions</
> > Property>
> > <Property name="datasourceAlias">MyDataSource</Property>
> > </Interceptor>
>
> > This loads Transfer, TransferTransaction and TransferFactory into the
> > ColdBox OCM at application startup.
>
> > My ColdSpring configuration is set to retrieve Transfer and its
> > associated beans from the OCM:
>
> > <!-- Define Transfer to be used as a bean -->
> > <bean id="Transfer" factory-bean="ColdboxOCM" factory-method="get">
> > <constructor-arg name="objectKey"><value>Transfer</value></
> > constructor-arg>
> > </bean>
> > <bean id="TransferTransaction" factory-bean="ColdboxOCM" factory-
> > method="get">
> > <constructor-arg name="objectKey"><value>TransferTransaction</
> > value></constructor-arg>
> > </bean>
> > <bean id="TransferFactory" factory-bean="ColdboxOCM" factory-
> > method="get">
> > <constructor-arg name="objectKey"><value>TransferFactory</value></
> > constructor-arg>
> > </bean>
>
> > I have IoC caching off and handler caching disable in my ColdBox
> > configuration.
>
> > When I load up my app for the first time and then visit the view page,
> > it takes a few seconds (generating objects, etc) and then loads. After
> > that, any subsequent visits load nearly instantly, so the objects must
> > already be ready.
>
> > For my transfer.xml.cfm I have:
>
> > <objectCache>
> > <defaultcache>
> > <scope type="instance" />
> > </defaultcache>
> > </objectCache>
>
> > That is the only reference to caching. Since transfer is loaded into
> > the OCM by the Transfer Loader interceptor, that is the instance where
> > the objects should be cached, right?
>
> > So...
>
> > 1.) I check the ColdBox cache for hits and I see that the IoC gets
> > hits when I refresh my view page but the ColdBox OCM cache for
> > Transfer stays at 2. Every time I refresh the view page, the IoC in
> > the ColdBox cache goes up. So, I was wondering how this works. If
> > Transfer is loaded into the ColdBox cache as Transfer, it shows 2 hits
> > and never changes, but everytime I call instance.Transfer.get() from
> > one of my handlers (instance.Transfer is injected from ColdSpring
> > which is wired to the OCM) the IoC hits go up but the Transfer hits
> > stay at 2. So, do I have a copy of Transfer in the IoC or what? Is the
> > one being injected by ColdSpring the one from the cache but the hits
> > are just being recorded in the IoC hit counter?
>
> > 2.) I set a variable rc.cache = getPlugin("ioc").getBean
> > ("TransferFactory").getTransfer().getCacheMonitor().getCachedClasses
> > ();
>
> > And the result is always an empty array. When I load my pages after
> > the first time they are fast, so they must be cached somewhere.
>
> > Any ideas?
>
> > On Jun 28, 5:56 pm, Mark Mandel <[email protected]> wrote:
> > > Oh yeah.. what's your cache config?
>
> > > Mark
>
> > > On Mon, Jun 29, 2009 at 10:49 AM, whostheJBoss
> > > <[email protected]>wrote:
>
> > > > I reload the app on the first request to make sure it's fresh, but no
> > > > reinits after that.
>
> > > > I have a page that does a view of all of my user objects and a page
> > > > that creates them.
>
> > > > The first time I hit the view page it takes a second or two, so I know
> > > > it's loading things up. Any hit after that loads almost instantly, so
> > > > the objects must already be ready.
>
> > > > I'm on Railo 3.1.0.017 on CentOS 5.3
>
> > > > I know there are some Railo issues, but I've managed to fix most of my
> > > > issues I believe.
>
> > > > On Jun 28, 5:36 pm, Mark Mandel <[email protected]> wrote:
> > > > > Should there be anything in there?
>
> > > > > Are you reloading your CB app on every request?
>
> > > > > What platform are you on?
>
> > > > > Mark
>
> > > > > On Mon, Jun 29, 2009 at 10:33 AM, whostheJBoss
> > > > > <[email protected]>wrote:
>
> > > > > > I'm having an issue with the cache and I can't seem to figure out
> > what
> > > > > > the problem is.
>
> > > > > > I'm using ColdBox / ColdSpring/ Transfer and loading Transfer as a
> > > > > > ColdSpring Bean into the instance scope of one of my handlers from
> > the
> > > > > > ColdBox cache.
>
> > > > > > So:
>
> > > > > > <!-- Define Transfer to be used as a bean -->
> > > > > > <bean id="Transfer" factory-bean="ColdboxOCM" factory-method="get">
> > > > > > <constructor-arg name="objectKey"><value>Transfer</value></
> > > > > > constructor-arg>
> > > > > > </bean>
>
> > > > > > I then call instance.Transfer.get() or save(), etc inside of the
> > > > > > handler and it works fine. It loads a little slowly the first time
> > > > > > while creating the object, but subsequent requests load fast, so
> > I'm
> > > > > > assuming they are cached.
>
> > > > > > However, if I do this:
>
> > > > > > rc.cacheTest =
> > instance.Transfer.getCacheMonitor().getCachedClasses();
>
> > > > > > And then dump the rc.cacheTest variable it always shows up as an
> > empty
> > > > > > array.
>
> > > > > > instance.Transfer.getCacheMonitor().getTotalCalculatedSize() always
> > > > > > shows up as 0
>
> > > > > > Why is my Transfer cache not showing anything?
>
> > > > > --
> > > > > E: [email protected]
> > > > > T:http://www.twitter.com/neurotic
> > > > > W:www.compoundtheory.com
>
> > > --
> > > E: [email protected]
> > > T:http://www.twitter.com/neurotic
> > > W:www.compoundtheory.com
>
> --
> E: [email protected]
> T:http://www.twitter.com/neurotic
> W:www.compoundtheory.com
--~--~---------~--~----~------------~-------~--~----~
Before posting questions to the group please read:
http://groups.google.com/group/transfer-dev/web/how-to-ask-support-questions-on-transfer
You received this message because you are subscribed to the Google Groups
"transfer-dev" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/transfer-dev?hl=en
-~----------~----~----~----~------~----~------~--~---