Autowiring the Request Decorator

I am implementing a request decorator to modify the default behavior
of the buildLink method. I would like to reference parts of my model
in the decorator. Alas, it appears the request decorator cannot be
autowired since it is created in the requestService line 192 and
nothing special is done to it save the init call.

My first attempted at hacking around to see what I could find,
involved changing my RequestContextDecorator setting in
coldbox.xml.cfm to "model:requestDecorator" and then modifying the
requestService to check for that and call up the beanFactory plugins'
getModel method to retreive it. That backfired, since the beanFactory
wants to call the init method, but it isn't passing in the required
content and controller arguments. I had some other ideas there, but I
temporarily abondoned them to try something new.

Next I played around with placing this in my request decorators init:
controller.getPlugin("beanFactory").autowire(target=this)

I hoped it would convince the beanFactory to inject any dependancies
the decorator needed. Instead, it managed to create an infinite loop
of doom that resulted in a 500 null coming from JRUN with an
intersting stack trace...

What DOES work is the following code in my decorator's init:
<cfset variables.myService = controller.getPlugin
("beanFactory").getModel("myService")>

At any rate, as interesting as an exercise this has been, I figured I
should be fair, and ask the list what the appropriate way (if any) was
to reference my model from my request decorator. I know autowiring
isn't the only way, but it seemed the easiest.

Thanks.

~Brad

I can’t think of a use case where I would be in favor of having the request context (decorator) interact with the model, but apparently you have one. In that light, I would say that what you’ve ultimately found to “work” would be the best way of doing it.

Mind me asking why you want your model to be exposed to the event object? I really think that’s a bad idea and will lead to trouble down the road, but I’m quite curious to know if there’s some use case that I simply cannot envision. :slight_smile:

LOL. It's quite possibly a bad idea-- I was attempting to share
code. :slight_smile:

Basically, we have a setting in our app which is a list of all the
events which need to be SSL.

<Setting name="sslEventList" value="ehCheckout.*,ehAuthentication.*" /

These rules may be more complex in the future and might be pulled from
somewhere other than a CB setting. Therefore I created a simple
SSLService with a method called "isSSLRequired". You pass a handler/
event in, and it returns a boolean telling you whether or not that
event needs to be secure. This allows me to turn on or off SSL for my
entire site or for an entire set of events etc in one easy place
instead of hundreds of places all over the app.

We want to make sure that all of those events are handled over SSL.
That means we need to use this logic in two places.

The first of which is when we build links using the event.buildLink()
method.
I want build link to be smart enough to automatically give me a HTTP
or HTTPS link based on the event I am asking it to build. I had two
options there. The first was to call the service each and every time I
used the buildLink function to calculate whether or not that event
required SSL and pass it into the ssl attribute. That would require
me to inject the service into just about every component in my model
and continually pass it on to the view where all links are being
built. A much simpler method to me was to use a request decorator and
modify the decorator's buildLink to consult the SSLService before
passing the results on to the base buildLink function.

The second main place we wanted to use this was in our SSL interceptor
which checks to ensure that the CURRENT EVENT being accessed is using
the correct protocol. That way, if someone attempts to access our
checkout by manually typing in the URL and leaving off the HTTPS, we
will automatically redirect them to the SSL version of their event. I
also want the SSL interceptor to use the SAME SSLService to determine
if the event in question needs to be secure since I want to keep all
of that logic wrapped up nicely in one place.

So, that is basically why I want to inject a service (which is part of
my model and also expects to have things auto-wired into it) into my
request decorator (as well as my SSL interceptor).

If you have any suggestions as to a better way to wrap up the "who
should be SSL" logic in one place and use it in both the buildLink
functionality AND SSL interceptor WITHOUT having to place or inject
that logic into every view in my entire application I am certainly all
ears!

Thanks.

~Brad

Brad,

since version 2.6.1 the decorator receives also the main coldbox controller. So within your decorator you have access to everything if you so want to.

getController().getPlugin(“beanFactory”).getModel()

Thanks Luis. That was my final solution. I just wanted to make sure
there wasn't an easier way since I REALLY dig the cfproperty
autowiring everywhere else.

On another note, that endless loop of doom I mentioned in the original
post appears to also happen when I attempt to get the Logger plugin

<cfset variables.logger = controller.getPlugin("logger")>

It results in this error:

java.lang.StackOverflowError at
coldfusion.runtime.NeoBodyContent.enablecfoutputonly
(NeoBodyContent.java:138) at
coldfusion.runtime.NeoBodyContent.enablecfoutputonly
(NeoBodyContent.java:138) at
coldfusion.runtime.NeoBodyContent.enablecfoutputonly
(NeoBodyContent.java:138) at
coldfusion.runtime.NeoBodyContent.enablecfoutputonly
(NeoBodyContent.java:138) at
coldfusion.runtime.NeoBodyContent.enablecfoutputonly
(NeoBodyContent.java:138) at
coldfusion.runtime.NeoBodyContent.enablecfoutputonly
(NeoBodyContent.java:138) at
coldfusion.runtime.NeoBodyContent.enablecfoutputonly
(NeoBodyContent.java:138) at
coldfusion.runtime.NeoBodyContent.enablecfoutputonly
(NeoBodyContent.java:138) at
coldfusion.runtime.NeoBodyContent.enablecfoutputonly
(NeoBodyContent.java:138) at
coldfusion.runtime.NeoBodyContent.enablecfoutputonly
(NeoBodyContent.java:138) at
coldfusion.runtime.NeoBodyContent.enablecfoutputonly
(NeoBodyContent.java:138) at
coldfusion.runtime.NeoBodyContent.enablecfoutputonly
(NeoBodyContent.java:138) at
coldfusion.runtime.NeoBodyContent.enablecfoutputonly
(NeoBodyContent.java:138) at
coldfusion.runtime.NeoBodyContent.enablecfoutputonly
(NeoBodyContent.java:138) at
coldfusion.runtime.NeoBodyContent.enablecfoutputonly
(NeoBodyContent.java:138) at
coldfusion.runtime.NeoBodyContent.enablecfoutputonly
(NeoBodyContent.java:138) at

... this continues for quite a while.

coldfusion.runtime.EventHandlerException
An exception occurred when invoking a event handler method from
Application.cfc. The method name is: onRequestStart.

Any suggestions on that. ?

Thanks.

~Brad

NeoBodyContent had me snagged for a while… I despised that error… until I figured out that when ever I try to get at a plugin from CB in my Request Decorator’s configure() method is when I see that Neo crap.

What I think is going on, and I hope someone corrects me if I’m wrong, is that configure() runs before the decorator has access to the plugin’s, but once the decorator is created, is has access to everything you need, just from outside of the configure(). I can use getController().getSetting() within the configure() method though.

What I have done, and its been working for me… is set up functions in the RequestDecorator which provides access to what i need… and I can use it anywhere I have an event, obviously there are a few caveats and things you probably shouldn’t be exposing here, so that’s up to you figure out… but based on your example… you could call event.getLogger(), and in my case, event.getDrunk(), ect. ect. ect. an example of this in my decorator is how I get at a custom factory my apps use to do voodoo majik…

<cfif getController().settingExists(“Google.PropertyID”,false)>
<cfset rc.GooglePropertyID = getController().getSetting(“Google.PropertyID”,false)/>

// setup vars loadMajikSettings(); trimCollection();

Hope this helps any.

It was a lot of code there, so I didn't quite dig through. Have you
considered, though, using either an interceptor geared toward what
you're planning here? You can use the afterAspectsLoad interception
point to ensure everything is ready to use, like models and plugins.
You also have onRequestStart() in your 'main' handler. It's not
likely the best place, but it is certainly a place. Both of those
styles work for any request handler call.

If you only need whatever you have below for a specific handler, you
can always use the preHandler() method within the handler. It runs
before any event does, but should definitely have all the aspects
loaded by then.

- WB

Also -- you're trimCollection() function looks like it should be
involved in some kind of UDF lib, probably not how you're trying to
place it now.

- WB

@Captain, As all of the code i posted above is something I’m currently working on, it was ment only as some examples of the kind of things I’m doing within my RCD… and may not actually be representing exactly how I do it. Since my RCD gets used by any number of my different CB applications, which gets used in the many different handlers, I felt a concrete preHandler() approach is not really the right place for some of these things I need to do on a global level… Although I do implement a preHandler as required to massage what i get with my RCD…

I also have my concrete handlers extending a majik.voodoo.Handler which extends coldbox.system.handler. In the voodoo.Handler, I have a preHandler() which deals with generic stuff and some other things I need it to do to mesh up with the RCD. I have considered switching over to interceptors where applicable for some of this as you have mentioned. Sadly I am not proficient enough in AOP nor do I feel comfortable enough to be changing things that are currently working for me as I need them to work today, although I do relize there may be a better solution… I’m not there yet.

Also, the trimCollection() was shown above as a private RCD method as an example only… sorry for posting all this crap, I had thought it might be relivent to the converstation… or at least, It is for me, and doing so helped me see my own code a little better… so thanks for the feedback.

@All, After re-reading the Request Context Decorator Guide once more just to be safe… I couldn’t find any ‘do this, don’t do that’ guidance there…
Does anyone have a blog link or other advice about what NOT to be doing in a RCD? Did I miss something on the docs?
That page ends with …“The possibilities are endless with this feature.”
From what I’ve seen with my RDC and handler approach, that statement is true, but now I’m nervous that I may do something that becomes a problem later on…

As Matt has mentioned above - he doesn’t see a use case for us exposing our model here… So I just for clarification, I want to understand if its ok to grab my factory that does work with my models, call udfs that play with settings and vars, but that I should NOT be dealing with actual User/Form/Post/Comment objects here… Would this be the correct understanding of what you ment by not exposing the model here?

thanks!
-ad

As with anything, use your code smells to determine if what you are doing will be a headache or not. The decorator was done with the purpose of having creativity in extending the request context to applciation specifc purposes. Everybody has different goals and purposes in mind, so there is no one size fits all kinda thing.

As for best practices, well, it is like building anything in an object oriented manner. Think of how you are coupling the decorator to external forces? Does it encapsulate the behavior that I want? Is it sustainable? Will it kaboom if I extend it even more?

Luis