rhinds
rhinds

Reputation: 10043

Coldfusion Proxy confusion

I am using a proxy/delegate pattern in a coldfusion component, and am getting unexpected results (from my point of view). Below is my proxy component - its pretty straight forward, I just init the CFC with the actual component I want to delegate to, and then map the named functions from that CFC through to a proxy function (the below is simplified for this example)

I have created a proxy component as follows:

component output="false"{

    /** Constructor for proxy - requires an instance of myFusebox **/
    public MyFuseboxProxy function init( Required any myFb ){
        variables.myFusebox = arguments.myFb;
        return this;
    }

    this.do = variables.proxy;
    this.getApplication = variables.proxy;
    this.getApplicationData = variables.proxy;

    private any function proxy(){    
        var local.functionName = getFunctionCalledName();
        var local.function = variables.myFusebox[local.functionName];
        var local.returnVal = local.function( argumentCollection=arguments );

        return local.returnVal;
    }
}

From my application I call the following code:

    variables.myFusebox = new ab.MyFuseboxProxy( variables.myFusebox );
    variables.myFusebox.getApplicationData().startTime = now();

Now, in the above scenario, I would expect my proxy component to map the getApplicationData() function straight through to the original myFusebox component (via my proxy() function).

That function in the underlying component is as follows:

<cffunction name="getApplicationData" returntype="struct" access="public" output="false"
            hint="I am a convenience method to return a reference to the application data cache.">
    <cfreturn getApplication().getApplicationData() />
</cffunction>

That proxy all works fine, however, once I am in the above function in the original myFusebox I get the following error:

Message: Variable GETAPPLICATION is undefined.
StackTrace: coldfusion.runtime.UndefinedVariableException: Variable GETAPPLICATION is undefined.

And if I dump "this" inside that function, it actually dumps my proxy object.

Can anyone explain this or what I have done wrong? I was expecting that once the function call was inside the underlying object, it would just use its own context from there (my proxy just being a pass through really to the delegate)

Upvotes: 1

Views: 280

Answers (1)

Adam Cameron
Adam Cameron

Reputation: 29870

I think this is the key point:

I was expecting that once the function call was inside the underlying object

You've got this:

private any function proxy(){    
    var local.functionName = getFunctionCalledName();
    var local.function = variables.myFusebox[local.functionName];
    var local.returnVal = local.function( argumentCollection=arguments );

    return local.returnVal;
}

When you do this bit:

var local.function = variables.myFusebox[local.functionName];

you are effectively pulling the function referenced by local.functionName out of variables.myFusebox, and putting it into the current function, within the context of your MyFuseboxProxy instance.

So when you do this:

var local.returnVal = local.function( argumentCollection=arguments );

You are not running variables.myFusebox[local.functionName]() (so in the context of variables.myFusebox), but you are running local.function() (so in the context of your proxy object).

I don't have the patience to try to follow your logic here, but I am still surprised you get that error. I would have expected this to happen:

  1. local.function (a reference to getApplicationData from variables.myFusebox) runs getApplication().
  2. getApplication() in the context of the MyFuseboxProxy instance should be a reference to variables.proxy().
  3. variables.proxy() resolves the proxied function as getApplication(), and pulls that out of variables.myFusebox, and runs it in the context of your MyFuseboxProxy instance.
  4. You do not include the code of the getApplication() function from variables.myFusebox, so I dunno what would happen next, but this is not what you want to be happening.

Anyway, the crux is - I think - that instead of running the functions inside variables.myFusebox, you're running them in your MyFuseboxProxy instance instead. If you want to do this sort of proxying (and ignoring for a moment you have invoke() specifically for doing this), you need to still call the function in its original context, not reference it in some new context.

I guess you're doing all this horsing around because ColdFusion doesn't like this syntax:

someObject[someMethodName]()

It baulks at the []() notation. However the solution is not this:

someOutOfContextReference = someObject[someMethodName] result = someOutOfContextReference()

It's this:

someObject.someInContextReference = someObject[someMethodName] result = someObject.someInContextReference()

See the subtle difference?

ColdFusion functions are not intrinsically closures, which is what you'd need them to be to work the way you want.

Upvotes: 1

Related Questions