Railo 3.0.015 with Transfer (AOP advice and stack overflow)

4 views
Skip to first unread message

whostheJBoss

unread,
Jun 23, 2009, 7:29:56 AM6/23/09
to transfer-dev
Hey guys,

I've been following the discussion about using Transfer on Railo while
trying to resolve a few issues, but I can't quite figure them out out.
I was hoping someone else had maybe run into this problem and had some
clarification as to what might be going on here. I am very close to
having everything working except for just these few issues. Hopefully
my explanation isn't too dense. The first problem is pretty
straightforward, the second is a little more complex. I've given a
short version of the problems at the end of the post to clarify.

Here is a brief explanation of my problem. I am running Railo 3.0.015:


Issue # 1.)

When I use: <order property="sortOrder" order="asc"/> (sortOrder is
the name of a numeric column in my database) I receive the following
error:

Application Execution Exception
Error Type: database : 0
Error Messages: Column 'sortOrder' in order clause is ambiguous

I have tried manually filling in the sortOrder column with ascending
values to test, I have tried using all zero values, but nothing seems
to work. In my application sometimes this column will have a value
higher than 0, sometimes it will not. This works fine on CF8, but
fails on Railo. As of now I have to remove the order property
completely from my transfer definition file for Transfer not to give
me this error when trying to use the object. On CF8 it will simply
output them in default order, if the column is filled in it will order
them by the column value, if not it ignores it.

--------------------------------------
--------------------------------------

Issue # 2.) I have a function (a ColdBox handler action) that creates
some objects in a composition and saves them to the database. If I
visit this create page in CF8 the database entries and corresponding
objects are all created properly. I can refresh this page multiple
times in a row and new objects/records are created every time. I can
then view all of the objects / records in an output page I have
created. So, CF8 works fine everytime with no changes to my existing
code.

When using Railo, if I visit my create page BEFORE visiting any other
page (such as my output page) that calls objects of the type I want to
create, I get this error:

Application Execution Exception
Error Type: expression : 0
Error Messages: component [catalog.components.decorators.catalogs] has
no function with name [ACTIONBEFORECREATETRANSFEREVENT]
existing functions are
[getuser2ID,setuser1ID,getcatPrefsMemento,actionAfterUpdateTransferEvent,getOriginalTransferObject,validate,sortcatPrefs,gethash,getMemento,setstatus,actionAfterDeleteTransferEvent,setIsDirty,emptycatPrefs,getuser1ID,equalsTransfer,findcatPrefs,getaccess,getIsLoaded,loadcatPrefs,getedithash,clone,setcatalogID,setaccess,getcatPrefs,setMemento,getcatalogID,setPropertyMemento,setIsClone,removecatPrefs,init,getIsPersisted,copyValuesTo,setcatPrefsMemento,sameTransfer,setlabel,addcatPrefs,getTransferObject,getLoadedObject,containscatPrefs,getIsProxy,setIsPersisted,actionAfterDiscardTransferEvent,clearcatPrefs,getcatPrefsArray,getPropertyMemento,sethash,getClassName,validateCacheState,gettype,settype,actionAfterCreateTransferEvent,getlabel,setedithash,getIsDirty,getIsClone,getcatPrefsIterator,setuser2ID,getcatPrefsisLoaded,getstatus]


After receiving this error, additional attempts to visit the create
page result in the following error:

Application Execution Exception
Error Type: java.lang.stackoverflowerror : 0
Error Messages: java.lang.StackOverflowError
Tag Context:
ID: ??
LINE: 80
Template: C:\railo\railo-3.1.0.015-railo-express-with-jre-windows
\webroot\transfer\com\sql\transaction\Transaction.cfc
ID: ??
LINE: 8
Template: C:\railo\railo-3.1.0.015-railo-express-with-jre-windows
\webroot\catalog\config\definitions
\catalog.handlers.lm.createSv.aop.transfer
ID: ??
LINE: 210
Template: C:\railo\railo-3.1.0.015-railo-express-with-jre-windows
\webroot\transfer\com\sql\transaction\Transaction.cfc
ID: ??
LINE: 81
Template: C:\railo\railo-3.1.0.015-railo-express-with-jre-windows
\webroot\transfer\com\sql\transaction\Transaction.cfc
ID: ??
LINE: 8
Template: C:\railo\railo-3.1.0.015-railo-express-with-jre-windows
\webroot\catalog\config\definitions
\catalog.handlers.lm.createSv.aop.transfer
ID: ??
LINE: 210
Template: C:\railo\railo-3.1.0.015-railo-express-with-jre-windows
\webroot\transfer\com\sql\transaction\Transaction.cfc

********
It goes on like this for quite a while, alternating between these
methods. I see maybe a hundred of these. I'm guessing there is some
kind of loop happening. Here is the stack trace:
********

ava.lang.StackOverflowError
at railo.commons.lang.CharBuffer$Entity.(CharBuffer.java:216):216
at railo.commons.lang.CharBuffer$Entity.(CharBuffer.java:216):216
at railo.commons.lang.CharBuffer.(CharBuffer.java:18):18
at railo.runtime.writer.BodyContentImpl.(BodyContentImpl.java:19):19
at railo.commons.io.BodyContentStack.push(BodyContentStack.java:60):
60
at railo.runtime.PageContextImpl.pushBody(PageContextImpl.java:1547):
1547
at railo.runtime.type.UDFImpl._call(UDFImpl.java:278):278
at railo.runtime.type.UDFImpl.call(UDFImpl.java:260):260
at railo.runtime.util.VariableUtilImpl.callFunctionWithoutNamedValues
(VariableUtilImpl.java:622):622
at railo.runtime.PageContextImpl.getFunction(PageContextImpl.java:
1252):1252
at transfer.com.sql.transaction.transaction_cfc$cf.udfCall1(C:\railo
\railo-3.1.0.015-railo-express-with-jre-windows\webroot\transfer\com
\sql\transaction\Transaction.cfc:80):80
at transfer.com.sql.transaction.transaction_cfc$cf.udfCall(C:\railo
\railo-3.1.0.015-railo-express-with-jre-windows\webroot\transfer\com
\sql\transaction\Transaction.cfc):-1




Now, if I visit a page that does a list or get on the type of object I
was trying to create FIRST and THEN visit the create page it will work
and create the objects and database entrys. However, attempting to
call the create page again results in the same stack overflow error as
above.

So, I can call the create page once, but after that I get a stack
overflow error. If I try to call the create page without having called
another page that uses those same type of objects I'm trying to
create, it fails with the error about
"ACTIONBEFORECREATETRANSFEREVENT".

If I add the following method to a decorator for every object that I
try to use in the compositions, then I can call the create page
without having to visit a page that gets or lists the object of that
type first:

<cffunction name="actionBeforeCreateTransferEvent" access="public"
returntype="void" output="false" hint="I set the created date before I
am persisted for the first time.">
<cfargument name="event" hint="The event object"
type="transfer.com.events.TransferEvent" required="Yes">
</cffunction>

Once I add this function, I can call the create page right off the bat
and it works, but the subsequent calls still give me the stack
overflow. So, adding "actionBeforeCreateTransferEvent" removes the
error about that, but still leaves the stack overflow error. Why am I
having to add this method???


Also, I am advising the handler action with AOP for transactions. If I
disable the AOP advice for the handler action (without using
"actionBeforeCreateTransferEvent" in my decorator), then I receive the
following error, just as above:

Application Execution Exception
Error Type: expression : 0
Error Messages: component [catalog.components.decorators.catalogs] has
no function with name [ACTIONBEFORECREATETRANSFEREVENT]
existing functions are

So, I have to have AOP turned on to even be able to call the create
page if I haven't added the "actionBeforeCreateTransferEvent" method
to the decorator. Even then, if I have added the method, it just works
the once and then starts giving me stack overflow errors.


I am not sure what to do about these issues. It's working here and
there. Transfer can delete, view and manage objects. It can handle
compositions, but it fails when I try to create more than once (with
AOP transaction advice enabled) or if I create without having called a
page that views those types of objects without having a
"actionBeforeCreateTransferEvent" method on my decorators. It only
does this on compositions, regular objects can be created without an
issue.




So, a quick recap in easier terms:

Issue #1: <collection type="array"><order property="sortOrder"
order="asc"/></collection> throws an error about an ambiguous clause.

----------------------

Issue #2: I can call my handler that creates objects and database
entries based on a composition when AOP transaction advice is NOT
being used and I have added the "actionBeforeCreateTransferEvent" to
the decorator for each object involved in the create sequence. This
causes no errors, but I am forced to add this decorator method and am
not able to use transaction advice. None of this is required in CF8,
it all works. I need transaction advice, so this is a major issue.

If I have AOP transaction advice enabled, then I can call the create
page once successfully, but subsequent attempts fail with the stack
overflow error.

If I do not include the "actionBeforeCreateTransferEvent" on all
objects involved in the creation, then trying to call the handler
action that creates my objects and database entries will fail with the
error above about "has no function with name
[ACTIONBEFORECREATETRANSFEREVENT]" unless I have visited a page that
lists or gets the types of objects I am trying to create before
calling the create page.

Either way, once I have successfully called the create handler action,
if I have AOP transaction advice enabled I will always receive the
stack overflow error on subsequent calls. If I disable the transaction
advice AND have added the "actionBeforeCreateTransferEvent" method to
my decorators then I can call the create as many times as I want.

I have added passby="value" to all of my arguments of type array and I
have added lazy="true" to all of my relationships, but neither do
anything to resolve my stack overflow error.

Any help with this would be greatly appreciated! This is a MAJOR
hurdle for me.

THANKS!!!!

Mark Mandel

unread,
Jun 23, 2009, 8:38:05 AM6/23/09
to transf...@googlegroups.com
Just because I'm going to bed soon....

but from my understanding, Transfer barely works, except on Railo 3.1+... no?

Mark
--
E: mark....@gmail.com
T: http://www.twitter.com/neurotic
W: www.compoundtheory.com

whostheJBoss

unread,
Jun 23, 2009, 8:51:56 AM6/23/09
to transfer-dev
I'm using 3.1.015 and it still barely works. I'm very close though,
almost all of my application is working save for these two issues:

1.) ordering of array collection, as mentioned above (I can workaround
this with a manual sort)

2.) stack overflow when using AOP (looks like loop between the methods
below)

I can live with adding the decorator method to overcome the
[ACTIONBEFORECREATETRANSFEREVENT] error, that's not too painful and it
doesn't break on CF8. The overflow issue is something I can't get
around.

Here is what seems to be causing the issue, I get about a hundred of
these (same lines, 210, 8, 81 of the same files):

ID: ??
LINE: 210
Template: C:\railo\railo-3.1.0.015-railo-express-with-jre-
windows
\webroot\transfer\com\sql\transaction\Transaction.cfc
ID: ??
LINE: 81
Template: C:\railo\railo-3.1.0.015-railo-express-with-jre-
windows
\webroot\transfer\com\sql\transaction\Transaction.cfc
ID: ??
LINE: 8
Template: C:\railo\railo-3.1.0.015-railo-express-with-jre-
windows
\webroot\catalog\config\definitions
\catalog.handlers.lm.createSv.aop.transfer

I haven't tried any TQL, so we'll see how that goes, but this overflow
thing is killing me :(

On Jun 23, 5:38 am, Mark Mandel <mark.man...@gmail.com> wrote:
> Just because I'm going to bed soon....
>
> but from my understanding, Transfer barely works, except on Railo 3.1+...
> no?
>
> Mark
>
> ...
>
> read more »

whostheJBoss

unread,
Jun 23, 2009, 8:52:50 AM6/23/09
to transfer-dev
I had originally meant 3.1.015, not 3.0, sorry! This is on 3.1.015
> ...
>
> read more »

whostheJBoss

unread,
Jun 23, 2009, 10:09:01 AM6/23/09
to transfer-dev
Quick update:

<cfscript>
transaction = getPlugin("ioc").getBean("TransferTransaction");
</cfscript>

<cfset transaction.execute(this, "doCreateSv", arguments)>

Using your non-preferred solution I am able to get Transfer fully
working on Railo.

I would MUCH rather use AOP transaction advice (as this requires me to
re-factor and double my handlers up), but it gives me that stack
overflow issue.

I think there must be some issue in the AOP transaction advisor.
> ...
>
> read more »

whostheJBoss

unread,
Jun 23, 2009, 11:12:58 AM6/23/09
to transfer-dev
Ok, so this is absolutely something in the AOP advisor / transaction
manager.

I stripped my handler down to nothing, not using any Transfer calls at
all. I simply have Transfer loaded into the instance scope. Besides
that, my handler just sets a variable called temp to "hello world" and
outputs that on a page.

I apply AOP to the simple hello world method and it runs once fine...
the next request gives me stack overflow. If I remove the AOP advice
it works perfectly every time.

So, something in the AOP / transaction manager is looping back upon
itself or something. I thought this might have been an array by
reference vs. array by value issue, but I have added a passby="value"
attribute to all of my arguments and still get the same issue.

So, any ideas? :)
> ...
>
> read more »

whostheJBoss

unread,
Jun 23, 2009, 2:34:28 PM6/23/09
to transfer-dev
Here is a quick fix for Transfer on Railo to prevent the stack
overflow error:

In the AOPAdvisor.cfc add the following item to the
__findPointCutsmethod:

var adviseCount = 0;

And modify the ArrayAppend to have the following conditional
statement:

if (isDefined(request.adviseLimit) and adviseCount lt
request.adviseLimit) {
ArrayAppend(pointCuts, item);
adviseCount++;
} else {
ArrayAppend(pointCuts, item);
}

So that it looks like:

<cffunction name="__findPointCuts" hint="builds an array of method
point cuts from a string regex" access="public" returntype="array"
output="false">
<cfargument name="pointcut" hint="a regex for functions to advise"
type="string" required="Yes">
<cfscript>
var pointCuts = ArrayNew(1);
var keys = StructKeyArray(variables);
var key = 0;
var len = ArrayLen(keys);
var counter = 1;
var item = 0;
var adviseCount = 0;

for(; counter lte len; counter = counter + 1)
{
key = keys[counter];
item = variables[key];

if(isCustomFunction(item) AND reFindNoCase(arguments.pointCut,
key))
{

if (isDefined(request.adviseLimit) and adviseCount lt
request.adviseLimit) {
ArrayAppend(pointCuts, item);
adviseCount++;
} else {
ArrayAppend(pointCuts, item);
}

}
}

return pointCuts;
</cfscript>

</cffunction>


In Transaction.cfc add:

<cfargument name="adviseLimit" type="numeric" required="no"
default="0">

<cfif arguments.adviseLimit gt 0>
<cfset request.adviseLimit = arguments.adviseLimit>
</cfif>

So that it looks like:

<cffunction name="advise" hint="wrap transaction advise around a given
method, or regex pattern of methods" access="public" returntype="void"
output="false">
<cfargument name="component" hint="the component to apply the advice
to" type="any" required="Yes">
<cfargument name="pointcut" hint="either a function, or a regex for
functions to advise" type="any" required="Yes">
<cfargument name="debug" hint="when true, cftrace's the method names
that gets adviced" type="boolean" required="No" default="false">
<cfargument name="adviseLimit" type="numeric" required="no"
default="0">

<cfif arguments.adviseLimit gt 0>
<cfset request.adviseLimit = arguments.adviseLimit>
</cfif>

<cfscript>
getAOPManager().advise(arguments.component, arguments.pointcut,
getTransactionAdviceBuilder(), arguments.debug);
</cfscript>
</cffunction>


You can now pass an additional parameter adviseLimit with the value of
1 when calling the AOP advisor:

adviseArgs = structNew();
adviseArgs.component = this;
adviseArgs.pointcut = 'yourmethod';
adviseArgs.adviseLimit = 1;
getPlugin("ioc").getBean("transferTransaction").advise
(argumentCollection=adviseArgs);

This will tell AOP advisor to stop looping through itself after 1
loop. If you do not provide the adviseLimit argument, an infinite loop
happens in Railo. The argument is not needed in CF8, so if you don't
pass it in then it is not set or used.

I haven't tested this extensively, I'm hoping Mark will take a look at
this, but I think we might be pretty close here... :)

As of right now... I'm using Transfer with AOP transactions inside of
Railo with no errors.

I'm hoping I didn't do all of this for nothing and I wasn't missing
some simple concept or had a bad configuration, but I tried passby,
lazy and everything else under the sun but kept getting stack overflow
errors with AOP advice. This fixes that issue.
> ...
>
> read more »
Reply all
Reply to author
Forward
0 new messages