Ticket #332: EventContext.cfc

File EventContext.cfc, 35.8 kB (added by cfgrok, 17 years ago)
Line 
1<cfcomponent output="false" extends="ModelGlue.Core.Event" hint="I represent an event request and its context.  I am what you see as arguments.event.">
2
3<cffunction name="init" access="public" returnType="any" output="false" hint="I build a new EventContext.">
4        <cfargument name="eventHandlers" default="#structNew()#" hint="Available event handlers." />
5        <cfargument name="messageListeners" default="#structNew()#" hint="Message subscribers." />
6        <cfargument name="requestPhases" hint="Request phases." />
7        <cfargument name="modelglue" required="false" hint="The framework itself." />
8        <cfargument name="statePersister" required="false" default="#createObject("component", "ModelGlue.gesture.eventrequest.statepersistence.SessionBasedStatePersister")#" hint="StatePersister to use during stateful redirects." />
9        <cfargument name="viewRenderer" required="false" default="#createObject("component", "ModelGlue.gesture.view.ViewRenderer")#" hint="ViewRenderer to use to render included views to HTML." />
10        <cfargument name="beanPopulator" required="false" default="#createObject("component", "ModelGlue.gesture.externaladapters.beanpopulation.BeanUtilsPopulator").init()#" hint="Populator used by makeEventBean()." />
11        <cfargument name="logWriter" required="false" default="#createObject("component", "ModelGlue.gesture.eventrequest.log.LogWriter").init()#" hint="LogWriter used by trace()." />
12        <cfargument name="values" required="false" default="#arrayNew(1)#" hint="A single structure or array of structures to merge into this collection." />
13        <cfargument name="helpers" required="false" hint="Helpers available as part of the event context." default="#structNew()#" />
14       
15        <cfset variables._state = createObject("component", "ModelGlue.gesture.collections.MapCollection").init(values) />
16        <cfset variables._viewCollection = createObject("component", "ModelGlue.gesture.collections.ViewCollection").init() />
17        <cfset variables._readyForExecution = false />
18        <cfset variables._initialEvent = "" />
19        <cfset variables._currentEventHandler = "" />
20        <cfset variables._currentMessage = "" />
21        <cfset this.log = arrayNew(1) />
22        <cfset this.created = getTickCount() />
23        <cfset variables._helpers = arguments.helpers />
24        <cfset variables._logWriter = arguments.logWriter />
25       
26        <cfif structKeyExists(arguments, "modelglue")>
27                <!--- External maps of listeners and handlers --->
28                <cfset variables._listeners = arguments.modelglue.messageListeners />
29                <cfset variables._eventHandlers = arguments.modelglue.eventHandlers />
30       
31                <!--- Default to MG's list of phases if none are passed. --->
32                <cfif not structKeyExists(arguments, "requestPhases")>
33                        <cfset variables._requestPhases = arguments.modelglue.phases />
34                <cfelse>
35                        <cfset variables._requestPhases = arguments.requestPhases />
36                </cfif>
37                       
38                <cfset variables._modelGlue = arguments.modelglue />
39        <cfelse>
40                <!--- External maps of listeners and handlers --->
41                <cfset variables._listeners = arguments.messageListeners />
42                <cfset variables._eventHandlers = arguments.eventHandlers />
43       
44                <!--- External list of event phases --->
45                <cfif not structKeyExists(arguments, "requestPhases")>
46                        <cfset variables._requestPhases = arrayNew(1) />
47                <cfelse>
48                        <cfset variables._requestPhases = arguments.requestPhases />
49                </cfif>
50        </cfif>
51       
52        <!--- Event Handler and View queues are implemented as linked lists --->
53        <cfset variables._nextEventHandler = "" />
54        <cfset variables._lastEventHandler = "" />
55        <cfset variables._nextView = "" />
56        <cfset variables._lastView = "" />
57       
58        <cfset setStatePersister(arguments.statePersister) />
59        <cfset setViewRenderer(arguments.viewRenderer) />
60        <cfset setBeanPopulator(arguments.beanPopulator) />
61
62        <cfset resetResults() />
63
64        <cfset trace("Creation", "Event Context Created") />
65         
66        <cfreturn this />
67</cffunction>
68
69<cffunction name="setListenerMap" output="false" hint="I set the map of message listeners to be used for message broadcasting.">
70        <cfargument name="listenerMap" type="struct" hint="The listener map." />
71        <cfset variables._listeners = arguments.listenerMap /> 
72</cffunction>
73
74<cffunction name="setEventHandlerMap" output="false" hint="I set the map of event handlers registered with Model-Glue.">
75        <cfargument name="eventHandlerMap" type="struct" hint="The event handlers map." />
76        <cfset variables._eventHandlers = arguments.eventHandlerMap /> 
77</cffunction>
78
79<cffunction name="setViewRenderer" output="false" hint="I set the instance of the view renderer to use when a request is made to render a view.">
80        <cfargument name="viewRenderer" hint="The view renderer to use." />
81        <cfset variables._viewRenderer = arguments.viewRenderer />     
82</cffunction>
83
84<cffunction name="setRequestPhases" output="false" hint="I set the instance of the view renderer to use when a request is made to render a view.">
85        <cfargument name="requestPhases" hint="The view renderer to use." />
86        <cfset variables._requestPhases = arguments.requestPhases />   
87</cffunction>
88
89<cffunction name="setStatePersister" output="false" hint="I set the mechanism by which this event context should persist and recall its state across requests.">
90        <cfargument name="statePersister" />
91       
92        <cfset variables._statePersister = arguments.statePersister />
93</cffunction>
94
95<cffunction name="setBeanPopulator" output="false" hint="I set Populator used by makeEventBean.">
96        <cfargument name="beanPopulator" />
97       
98        <cfset variables._beanPopulator = arguments.beanPopulator />
99</cffunction>
100
101<cffunction name="getModelGlue" output="false" hint="Gets the instance of ModelGlue associated with this context.">
102        <cfreturn variables._modelGlue />
103</cffunction>
104                                               
105<!--- EVENT HANDLER QUEUE MANAGEMENT --->
106<cffunction name="addEventHandler" output="false" hint="Queues an event handler to be executed as part of this request.">
107        <cfargument name="eventHandler" hint="An EventHandler instance to queue.  Duck-typed for speed." />
108       
109        <cfset var link = structNew() />
110
111        <cfset link.eventHandler = arguments.eventHandler />
112        <cfset link.next = "" />
113
114        <cfset trace("Event Queue", "Queueing event handler: #arguments.eventHandler.name#") />
115       
116        <cfif variables._readyForExecution and not isObject(variables._initialEvent)>
117                <cfset variables._initialEvent = arguments.eventHandler />
118        </cfif>
119
120        <cfif isSimpleValue(variables._nextEventHandler)>
121                <cfset variables._nextEventHandler = link />
122                <cfset variables._lastEventHandler = link />
123        <cfelse>
124                <cfset variables._lastEventHandler.next = link />
125                <cfset variables._lastEventHandler = link />
126        </cfif>
127</cffunction>
128
129<cffunction name="getNextEventHandler" access="public" output="false" hint="Returns the next event handler in the queue.">
130        <cfset var eh = variables._nextEventHandler.eventHandler />
131        <cfset variables._nextEventHandler = variables._nextEventHandler.next />
132       
133        <cfreturn eh />
134</cffunction>
135
136<cffunction name="hasNextEventHandler" output="false" hint="Returns if there's another event handler in the queue.">
137        <cfreturn not isSimpleValue(variables._nextEventHandler) />
138</cffunction>
139
140<cffunction name="prepareForInvocation" access="public" output="false" hint="Invoked when all ""under the hood"" events (onRequestStart, etc.) are complete.">
141        <cfset variables._readyForExecution = true />
142</cffunction>
143
144<!--- REQUEST EXECUTION --->
145<cffunction name="execute" output="false" hint="Executes the event request.  Duck typed for speed:  returns the request itself.">
146        <cfset var i = "" />
147        <cfset var exceptionEventHandler = "" />
148       
149        <!--- Try to execute the event phases or nonphased request --->
150        <cftry>
151                <cfif isArray(variables._requestPhases) and arrayLen(variables._requestPhases)>
152                        <cfloop from="1" to="#arrayLen(variables._requestPhases)#" index="i">
153                                <cfset this.trace(variables._requestPhases[i].name, "Beginning request phase.") />
154                               
155                                <cfset variables._requestPhases[i].execute(this) />
156                               
157                                <cfset this.trace(variables._requestPhases[i].name, "Request phase complete.") />
158                        </cfloop>
159                <cfelse>
160                        <cfset executeEventQueue() />
161                </cfif>
162                <cfcatch>
163                        <!--- Bus the exception --->
164                        <cfset setValue("exception", cfcatch) />
165                       
166                        <!--- Trace the exception.  Maybe people will like this ;) --->
167                        <cfset trace("Exception", cfcatch) />
168                       
169                        <cfif structKeyExists(variables, "_modelGlue")>
170                                <!--- If we're not running the exception handler, queue the exception handler. --->
171                                <cfset exceptionEventHandler = variables._modelGlue.getConfigSetting("defaultExceptionHandler") />
172                       
173                                <cfif isObject(getCurrentEventHandler()) and getCurrentEventHandler().name neq exceptionEventHandler and variables._modelGlue.hasEventHandler(exceptionEventHandler)>
174                                        <cfset addEventHandler(variables._modelGlue.getEventHandler(exceptionEventHandler)) />
175                                        <cfset executeEventQueue() />
176                                <cfelse>
177                                        <cfrethrow />
178                                </cfif>
179                        <cfelse>
180                                <cfrethrow />
181                        </cfif>
182                </cfcatch>
183        </cftry>
184       
185        <cfreturn this />
186</cffunction>
187
188<cffunction name="executeEventQueue" access="public" output="false" hint="Executes all event handlers currently in the event queue and renders queued views.">
189        <cfargument name="signalCompletion" />
190       
191        <cfset var initialEh = variables._initialEvent />
192        <cfset var eh = 0 />
193        <cfset var cacheKey = 0 />
194        <cfset var cacheReq = "" />
195        <cfset var i = 0 />
196        <cfset var requestFormat = getValue(variables._modelGlue.getConfigSetting("requestFormatValue")) />
197        <cfset var view = "" />
198       
199        <cfif not isStruct(variables._nextEventHandler)>
200                <!--- Nothing to do! --->
201                <cfreturn />
202        </cfif>
203
204        <cfif isObject(variables._initialEvent) and initialEh.cache>
205                <cfset cacheKey = initialEh.cacheKey />
206                <cfloop list="#initialEh.cacheKeyValues#" index="i">
207                        <cfset cacheKey = "#requestFormat#." & cacheKey & ".#getValue(i)#" />
208                </cfloop>
209               
210                <cfset cacheReq = variables._modelglue.cacheAdapter.get(cacheKey) />
211
212                <cfif cacheReq.success>
213                        <cfset this.trace("Event Handler Cache", "Cached initial event handler used.", "Key: #cacheKey#") />
214                        <cfset this.addView(cacheReq.content.key, cacheReq.content.output) />
215               
216                        <!--- Reset the queue --->
217                        <cfset variables._nextEventHandler = "" />
218                        <cfreturn />
219                </cfif>
220        </cfif>
221         
222        <!--- Run event handlers (broadcast/listener/result addition) --->
223        <cfloop condition="not isSimpleValue(variables._nextEventHandler)">
224                <cfset eh = getNextEventHandler() />
225                <cfset executeEventHandler(eh) />
226        </cfloop>
227
228        <!--- If we need to signal completion, do so. --->
229        <cfif structKeyExists(arguments, "signalCompletion")
230                                and structKeyExists(variables._eventHandlers, "modelGlue.onQueueComplete")             
231        >
232                <cfset executeEventHandler(variables._eventHandlers["modelglue.onQueueComplete"]) />
233        </cfif>
234       
235        <!--- Render all views queued - moved inline after tooling heavy load situations.
236        <cfif not isSimpleValue(variables._nextView)>
237                <cfset renderViewQueue() />
238        </cfif>
239         --->
240
241        <cfloop condition="not isSimpleValue(variables._nextView)">
242                <cfset view = getNextView() />
243
244                <cfset this.trace("Views", "Rendering view ""#view.name#"" (#view.template#)", "<include name=""#view.name#"" template=""#view.template#"" />") />
245
246                <cfset renderView(view) />
247        </cfloop>
248
249        <cfif isObject(initialEh) and initialEh.cache>
250                <cfset cacheReq = structNew() />
251                <cfset cacheReq.key = variables._viewCollection.getFinalViewKey() />
252                <cfset cacheReq.output = variables._viewCollection.getFinalView() />
253               
254                <cfif initialEh.cacheTimeout>
255                        <cfset variables._modelglue.cacheAdapter.put(cacheKey, cacheReq, initialEh.cacheTimeout) />
256                <cfelse>
257                        <cfset variables._modelglue.cacheAdapter.put(cacheKey, cacheReq) />
258                </cfif>
259
260                <cfset this.trace("Event Handler Cache", "Caching initial event handler", "Key: #cacheKey#") />
261        </cfif>
262</cffunction>
263
264<cffunction name="executeEventHandler" output="false" hint="Executes an event handler:  invokes listener functions, handles results, and queues views for rendering">
265        <cfargument name="eventHandler" hint="The event handler to execute.  Duck-typed for speed." />
266       
267        <cfset var message = "" />
268        <cfset var results = "" />
269        <cfset var result = "" />
270       
271        <cfset var i = "" />
272        <cfset var j = "" />
273        <cfset var requestFormat = getValue("requestFormat", "") />
274        <cfset var cacheKey = "" />
275               
276        <cfset variables._currentEventHandler = arguments.eventHandler />
277       
278        <cfset this.trace("Event Handler", "Execute ""#arguments.eventHandler.name#""", "<event-handler name=""#arguments.eventHAndler.name#"">") />
279       
280        <!---
281                Invoke "" message broadcasts.  Code repeated for format, if necessary, to
282                avoid string parsing - this is a per-request invocation!
283        --->
284        <cfloop from="1" to="#arrayLen(arguments.eventHandler.messages.cfNullKeyWorkaround)#" index="i">
285                <cfset message = arguments.eventHandler.messages.cfNullKeyWorkaround[i] />
286               
287                <cfset variables._currentMessage = message />
288
289                <cfset this.trace("Message Broadcast", "Broadcasting ""#message.name#""", "<message name=""#message.name#"">") />
290
291                <cfif structKeyExists(variables._listeners, message.name)>
292                        <cfloop from="1" to="#arrayLen(variables._listeners[message.name])#" index="j">
293                                <cfset this.trace("Message Listener", "Invoking #variables._listeners[message.name][j].listenerFunction# in #getMetadata(variables._listeners[message.name][j].target).name#", "<message-listener message=""#message.name#"" function=""#variables._listeners[message.name][j].listenerFunction#"" />") />
294                                <!---
295                                <cfset variables._listeners[message.name][j].invokeListener(this) />
296                                --->
297                                <cfinvoke component="#variables._listeners[message.name][j].target#" method="#variables._listeners[message.name][j].listenerFunction#">
298                                        <cfinvokeargument name="event" value="#this#" />
299                                </cfinvoke>
300                        </cfloop>
301                </cfif>
302        </cfloop>
303        <cfif len(requestFormat) and structKeyExists(arguments.eventHandler.messages, requestFormat)>
304                <cfloop from="1" to="#arrayLen(arguments.eventHandler.messages[requestFormat])#" index="i">
305                        <cfset message = arguments.eventHandler.messages[requestFormat][i] />
306                       
307                        <cfset variables._currentMessage = message />
308       
309                        <cfset this.trace("Message Broadcast", "Broadcasting ""#message.name#""", "<message name=""#message.name#"">") />
310       
311                        <cfif structKeyExists(variables._listeners, message.name)>
312                                <cfloop from="1" to="#arrayLen(variables._listeners[message.name])#" index="j">
313                                        <cfset this.trace("Message Listener", "Invoking #variables._listeners[message.name][j].listenerFunction# in #getMetadata(variables._listeners[message.name][j].target).name#", "<message-listener message=""#message.name#"" function=""#variables._listeners[message.name][j].listenerFunction#"" />") />
314                                        <cfset variables._listeners[message.name][j].invokeListener(this) />
315                                </cfloop>
316                        </cfif>
317                </cfloop>
318        </cfif>
319               
320        <!--- Get, queue, and reset results. --->
321        <cfset results = getResults() />
322       
323        <!--- Queue explicit results: repetitive on purpose. --->
324        <cfloop from="1" to="#arrayLen(results)#" index="i">
325                <cfif len(results[i]) and arguments.eventHandler.hasResult(results[i]) and isArray(arguments.eventHandler.results.cfNullKeyWorkaround[results[i]])>
326                        <cfloop from="1" to="#arrayLen(arguments.eventHandler.results.cfNullKeyWorkaround[results[i]])#" index="j">
327                                <cfset result = arguments.eventHandler.results.cfNullKeyWorkaround[results[i]][j] />
328                               
329                                <cfif result.redirect>
330                                        <cfset this.trace("Result", "Explicit result ""#result.name#"" added, redirecting to event event ""#result.event#""", "<result name=""#result.name#"" do=""#result.event#"" redirect=""#true#"" />") />
331                                        <cfset forward(eventName:result.event, preserveState:result.preserveState, addToken:false, append:result.append, anchor:result.anchor) />
332                                <cfelse>
333                                        <cfset this.trace("Result", "Explicit result ""#result.name#"" added, queueing event event ""#result.event#""", "<result name=""#result.name#"" do=""#result.event#"" />") />
334                                        <cfset addEventHandler(variables._eventHandlers[arguments.eventHandler.results.cfNullKeyWorkaround[results[i]][j].event]) />
335                                </cfif>
336                        </cfloop>
337                </cfif>
338        </cfloop>
339        <cfif len(requestFormat)>
340               
341                <cfloop from="1" to="#arrayLen(results)#" index="i">
342                        <cfif len(results[i]) and arguments.eventHandler.hasResult(results[i], requestFormat) and isArray(arguments.eventHandler.results[requestFormat][results[i]])>
343                                <cfloop from="1" to="#arrayLen(arguments.eventHandler.results[requestFormat][results[i]])#" index="j">
344                                        <cfset result = arguments.eventHandler.results[requestFormat][results[i]][j] />
345                                       
346                                        <cfif result.redirect>
347                                                <cfset this.trace("Result", "Explicit result ""#result.name#"" added, redirecting to event event ""#result.event#""", "<result name=""#result.name#"" do=""#result.event#"" redirect=""#true#"" />") />
348                                                <cfset forward(eventName:result.event, preserveState:result.preserveState, addToken:false, append:result.append, anchor:result.anchor) />
349                                        <cfelse>
350                                                <cfset this.trace("Result", "Explicit result ""#result.name#"" added, queing event ""#result.event#""", "<result name=""#result.name#"" do=""#result.event#"" />") />
351                                                <cfset addEventHandler(variables._eventHandlers[arguments.eventHandler.results[requestFormat][results[i]][j].event]) />
352                                        </cfif>
353                                </cfloop>
354                        </cfif>
355                </cfloop>
356        </cfif>
357       
358        <!--- Queue implicit results --->
359        <cfif structKeyExists(arguments.eventHandler.results.cfNullKeyWorkaround, "cfNullKeyWorkaround") and isArray(arguments.eventHandler.results.cfNullKeyWorkaround.cfNullKeyWorkaround)>
360                <cfset results = arguments.eventHandler.results.cfNullKeyWorkaround.cfNullKeyWorkaround />
361               
362                <cfloop from="1" to="#arrayLen(results)#" index="i">
363                                <cfset result = results[i] />
364
365                                <cfif result.redirect>
366                                        <cfset this.trace("Result", "Implicit result redirecting to event ""#result.event#""", "<result do=""#result.event#"" redirect=""true"" />") />
367                                        <cfset forward(eventName:result.event, preserveState:result.preserveState, addToken:false, append:result.append, anchor:result.anchor) />
368                                <cfelse>
369                                        <cfset this.trace("Result", "Implicit result queing event ""#result.event#""", "<result do=""#result.event#"" />") />
370                                        <cfset addEventHandler(variables._eventHandlers[results[i].event]) />
371                                </cfif>
372                </cfloop>
373        </cfif>
374        <cfif len(requestFormat) and structKeyExists(arguments.eventHandler.results, requestFormat)>
375                <cfif structKeyExists(arguments.eventHandler.results[requestFormat], "cfNullKeyWorkaround")
376                                        and isArray(arguments.eventHandler.results[requestFormat].cfNullKeyWorkaround)>
377                        <cfset results = arguments.eventHandler.results[requestFormat].cfNullKeyWorkaround />
378                       
379                        <cfloop from="1" to="#arrayLen(results)#" index="i">
380                                        <cfset result = results[i] />
381       
382                                        <cfif result.redirect>
383                                                <cfset this.trace("Result", "Implicit result redirecting to event ""#result.event#""", "<result do=""#result.event#"" redirect=""true"" />") />
384                                                <cfset forward(eventName:result.event, preserveState:result.preserveState, addToken:false, append:result.append, anchor:result.anchor) />
385                                        <cfelse>
386                                                <cfset this.trace("Result", "Implicit result queing event ""#result.event#""", "<result do=""#result.event#"" />") />
387                                                <cfset addEventHandler(variables._eventHandlers[results[i].event]) />
388                                        </cfif>
389                        </cfloop>
390                </cfif>
391        </cfif>
392               
393        <!--- Reset results --->
394        <cfset resetResults() />
395       
396        <!--- Queue views.  Repetitive on purpose - speed over elegance here. --->
397        <cfloop from="1" to="#arrayLen(arguments.eventHandler.views.cfNullKeyWorkaround)#" index="i">
398                <cfset queueView(arguments.eventHandler.views.cfNullKeyWorkaround[i]) />
399        </cfloop>
400        <cfif len(requestFormat) and structKeyExists(arguments.eventHandler.views, requestFormat)>
401                <cfloop from="1" to="#arrayLen(arguments.eventHandler.views[requestFormat])#" index="i">
402                        <cfset queueView(arguments.eventHandler.views[requestFormat][i]) />
403                </cfloop>
404        </cfif>
405</cffunction>
406
407<!--- EVENT KNOWLEDGE --->
408<cffunction name="getCurrentEventHandler" access="public" hint="Returns the current event handler.  Modifying the instance returned alters the behavior of the event handler for all users of the application!">
409        <cfreturn variables._currentEventHandler />
410</cffunction>
411
412<cffunction name="getCurrentEventHandlerName" access="public" hint="Returns the name of the currently executing event handler.">
413        <cfreturn getCurrentEventHandler().name />
414</cffunction>
415
416<cffunction name="getInitialEventHandler" access="public" output="false" hint="Returns the initial event in this request.  Modifying the instance returned alters the behavior of the event handler for all users of the application!">
417        <cfreturn variables._initialEvent />
418</cffunction>
419
420<cffunction name="getInitialEventHandlerName" access="public" hint="Returns the name of the user-requested event handler.">
421        <cfreturn getInitialEventHandler().name />
422</cffunction>
423
424<cffunction name="getEventHandlerName" access="public" hint="Returns the name of the user-requested event handler.">
425        <cfreturn getInitialEventHandler().name />
426</cffunction>
427
428<cffunction name="getMessage" access="public" hint="Returns the name of the currently broadcast message.">
429        <cfreturn variables._currentMessage />
430</cffunction>
431
432<cffunction name="getArgument" access="public" hint="Gets a value of an argument from the currently broadcast message.">
433        <cfargument name="name" type="string" required="true" />
434        <cfargument name="default" type="string" required="false" />
435       
436        <cfif structKeyExists(arguments, "default")>
437                <cfreturn variables._currentMessage.arguments.getValue(arguments.name, arguments.default) />
438        <cfelse>
439                <cfreturn variables._currentMessage.arguments.getValue(arguments.name) />
440        </cfif>
441</cffunction>
442                       
443<cffunction name="getAllArguments" access="public" returntype="struct" output="false" hint="I return the message's arguments (by value)">
444  <cfreturn variables._currentMessage.arguments.getAll() />
445</cffunction>
446
447<cffunction name="argumentExists" access="public" hint="Does an argument of the given name exist in the currently broadcast message?">
448        <cfargument name="argumentName" type="string" />
449       
450        <cfreturn variables._currentMessage.arguments.exists(arguments.argumentName) />
451</cffunction>
452
453<!--- RESULT MANAGEMENT --->
454<cffunction name="resetResults" access="public" hint="Resets results to an empty array.">
455        <cfset variables._results = arrayNew(1) />
456</cffunction>
457
458<cffunction name="getResults" access="public" hint="Gets the result names added by a listener function.">
459        <cfreturn variables._results />
460</cffunction>
461
462<cffunction name="addResult" access="public" hint="Adds a result, by name, to the result queue.">
463        <cfargument name="resultName" type="string" hint="The name of the result (e.g., ""formInvalid"" or the like) to add." />
464       
465        <cfset var results = getResults() />
466        <cfset var format = "" />
467        <cfset var i = "" />
468        <cfset var eh = getCurrentEventHandler() />
469        <cfset var result = "" />
470       
471       
472        <cfset trace("Message Listener", "A named result ""#arguments.resultName#"" has been added.") />
473       
474        <cfloop collection="#eh.results#" item="format">
475                <cfif structKeyExists(eh.results[format], arguments.resultName)>
476                        <cfloop from="1" to="#arrayLen(eh.results[format][arguments.resultName])#" index="i">
477                                <cfset result = eh.results[format][arguments.resultName][i] />
478                               
479                                <cfif result.redirect>
480                                        <cfset this.trace("Result", "Explicit result redirecting to event ""#result.event#""", "<result do=""#result.event#"" redirect=""true"" />") />
481                                        <cfset forward(eventName:result.event, preserveState:result.preserveState, addToken:false, append:result.append, anchor:result.anchor) />
482                                </cfif>
483                        </cfloop>
484                </cfif>
485        </cfloop>
486       
487        <cfset arrayAppend(variables._results, arguments.resultName) />
488</cffunction>
489
490<!--- LOCATION MANAGEMENT --->
491<cffunction name="formatUrlParameter" output="false" hint="Formats a key/value pair for the URL.">
492        <cfargument name="key" />
493        <cfargument name="value" />
494
495        <cfset var urlManager = variables._modelglue.getInternalBean("modelglue.urlManager") />
496
497        <cfreturn urlManager.formatUrlParameter(argumentCollection=arguments) />
498</cffunction>
499
500<cffunction name="linkTo" access="public" hint="Creates URLs using the configured URL manager." output="false">
501        <cfargument name="eventName" type="string" hint="Name of the event to forward to." />
502        <cfargument name="append" default="" hint="The list of values to append." />
503        <cfargument name="anchor" default="" hint="The anchor literal for the resultant URL." />
504
505        <cfset var urlManager = variables._modelglue.getInternalBean("modelglue.urlManager") />
506
507        <cfreturn urlManager.linkTo(arguments.eventName, arguments.append, arguments.anchor, this) />
508</cffunction>
509
510<cffunction name="forwardToUrl" access="public" hint="Forwards to a given URL, optionally storing state across the redirect.">
511        <cfargument name="url" type="string" hint="The URL to redirect to using <cflocation />">
512        <cfargument name="preserveState" type="boolean" required="false" default="false" hint="Preserve state across the redirect?" />
513        <cfargument name="addToken" type="boolean" default="false" hint="Should session tokens be added to the url?">
514       
515        <cfif arguments.preserveState>
516                <cfset saveState() />
517        </cfif>
518       
519        <cflocation url="#arguments.url#" addToken="#arguments.addToken#" />
520</cffunction>
521
522<cffunction name="forward" access="public" hint="Forwards the request to a given event name, optionally storing state across the redirect.">
523        <cfargument name="eventName" type="string" hint="Name of the event to forward to." />
524        <cfargument name="append" default="" hint="The list of values to append." />
525        <cfargument name="preserveState" type="boolean" required="false" default="false" hint="Preserve state across the redirect?" />
526        <cfargument name="anchor" default="" hint="The anchor literal for the resultant URL." />
527        <cfargument name="addToken" type="boolean" default="false" hint="Should session tokens be added to the url?">
528
529        <!--- Was:
530        <cfargument name="eventName" type="string" hint="Name of the event to forward to." />
531        <cfargument name="preserveState" type="boolean" required="false" default="false" hint="Preserve state across the redirect?" />
532        <cfargument name="addToken" type="boolean" default="false" hint="Should session tokens be added to the url?">
533        <cfargument name="append" default="" hint="The list of values to append." />
534        <cfargument name="anchor" default="" hint="The anchor literal for the resultant URL." />
535        --->
536               
537        <cfset var urlManager = variables._modelglue.getInternalBean("modelglue.urlManager") />
538       
539        <cfset var targeturl  = urlManager.linkTo(arguments.eventName, arguments.append, arguments.anchor, this) />
540       
541        <cfset forwardToUrl(targeturl, arguments.preserveState, arguments.addToken) />
542</cffunction>
543
544<!--- STATE (DATA BUS) MANAGEMENT --->
545<cffunction name="getAllValues" access="public" returnType="struct" output="false" hint="DEPRECATED:  Use getAll().  Still supported for reverse compatibility.  I return the entire view's current state.">
546  <cfreturn getAll() />
547</cffunction>
548
549<cffunction name="getAll" access="public" returnType="struct" output="false" hint="I get all values by reference.">
550  <cfreturn variables._state.getAll() />
551</cffunction>
552
553<cffunction name="setValue" access="public" returnType="void" output="false" hint="I set a value in the collection.">
554        <cfargument name="name" type="string" required="true" hint="I am the name of the value.">
555        <cfargument name="value" type="any" required="true" hint="I am the value.">
556
557        <cfreturn variables._state.setValue(argumentCollection=arguments) />
558</cffunction>
559
560<cffunction name="getValue" access="public" returnType="any" output="false" hint="I get a value from the collection.">
561  <cfargument name="name" hint="I am the name of the value.">
562  <cfargument name="default" required="false" type="any" hint="I am a default value to set and return if the value does not exist." />
563
564        <cfreturn variables._state.getValue(argumentCollection=arguments) />
565</cffunction>
566
567<cffunction name="removeValue" access="public" returnType="void" output="false" hint="I remove a value from the collection.">
568  <cfargument name="name" type="string" required="true" hint="I am the name of the value.">
569       
570        <cfreturn variables._state.removeValue(argumentCollection=arguments) />
571</cffunction>
572
573<cffunction name="valueExists" access="public" returnType="boolean" output="false" hint="DEPRECATED:  Use exists().  Still supported for reverse compatibility.  I state if a value exists.">
574  <cfargument name="name" type="string" required="true" hint="I am the name of the value.">
575
576        <cfreturn exists(argumentCollection=arguments) />
577</cffunction>
578
579<cffunction name="exists" access="public" returnType="boolean" output="false" hint="I state if a value exists.">
580  <cfargument name="name" type="string" required="true" hint="I am the name of the value.">
581
582        <cfreturn variables._state.exists(argumentCollection=arguments) />
583</cffunction>
584
585<cffunction name="merge" access="public" returnType="void" output="false" hint="I merge an entire struct into the collection.">
586  <cfargument name="struct" type="struct" required="true" hint="I am the struct to merge." />
587
588        <cfreturn variables._state.merge(argumentCollection=arguments) />
589</cffunction>
590
591<cffunction name="saveState" access="public" returntype="void" output="false" hint="I save all state to session">
592        <cfset variables._statePersister.save(this) />
593</cffunction>
594
595<cffunction name="loadState" access="public" returntype="void" output="false" hint="I load state from session.">
596        <cftry>
597                <cfset variables._statePersister.load(this) />
598                <cfcatch></cfcatch>
599        </cftry>
600</cffunction>
601
602
603<cffunction name="copyToScope" output="false" access="public" returntype="void" hint="I copy values from the event into the desired scope">
604        <cfargument name="scope" type="struct" required="true"/>
605        <cfargument name="ListOfEventKeys" type="string" default="true"/>
606        <cfargument name="ArrayOfDefaults" type="array" default="#arrayNew(1)#"/>
607        <cfset var EventKeyArray =  listToArray( arguments.ListOfEventKeys ) />
608        <cfset var thisEventKeyArray = "" />
609        <cfset var ScopeContext = "" />
610        <cfset var i = "" />
611        <cfset var j = "" />
612        <cfloop from="1" to="#arrayLen( EventKeyArray )#" index="i">
613                <cfset thisEventKeyArray = listToArray( EventKeyArray[ i ], ".") />
614                <!--- make sure the scope context is set so we can dot-walk up the variable --->
615                <cfset ScopeContext = arguments.Scope />
616               
617                <cfloop from="1" to="#arrayLen( thisEventKeyArray)#" index="j">
618                        <cfif structKeyExists( ScopeContext, thisEventKeyArray[j]) IS false OR isStruct( ScopeContext[ thisEventKeyArray[j] ]  ) IS false >
619                                <!--- so we don't have something we can attach keys to, lets make something--->
620                                <cfset ScopeContext[ thisEventKeyArray[j] ] = structNew() />
621                        </cfif>
622                        <cfif j IS arrayLen( thisEventKeyArray ) AND i LTE arrayLen( arguments.ArrayOfDefaults )>
623                                <!--- if we are done dot-walking, and have a default, lets use it. We should be done in the inner loop after this---->
624                                <cfset ScopeContext[ thisEventKeyArray[j] ] = arguments.ArrayOfDefaults[i] />
625                        <cfelseif j IS arrayLen( thisEventKeyArray )>
626                                <!--- ok, done dot-walking, grab something from the event. We should be done in the inner loop after this--->
627                                <cfset ScopeContext[ thisEventKeyArray[j] ] = variables._state.getValue( EventKeyArray[i] ) />
628                        <cfelse>
629                                <!--- walk down the dot path another level and go around the merry go round again --->
630                                <cfset ScopeContext = ScopeContext[ thisEventKeyArray[j] ] />
631                        </cfif>
632                </cfloop>       
633        </cfloop>
634</cffunction>
635
636<!--- VIEW MANAGEMENT --->
637<cffunction name="getViewCollection" access="public" output="false" hint="I return the view collection for the event request.">
638        <cfreturn variables._viewCollection />
639</cffunction>
640
641<cffunction name="addView" access="public" returnType="void" output="false" hint="I add a rendered view to the view collection.">
642  <cfargument name="key" type="string" required="true" hint="I am the name of the view to add.">
643  <cfargument name="content" type="string" required="true" hint="I am the HTML of the view.">
644  <cfargument name="append" type="boolean" required="false" default="false" hint="Should the HTML be appended on to an existing view of the same name?">
645       
646        <cfset variables._viewCollection.addRenderedView(argumentCollection=arguments) />
647</cffunction>
648
649<cffunction name="getView" access="public" output="false" hint="I get a rendered view by name.">
650  <cfargument name="name" required="true" hint="I am the name of the view to get.">
651       
652        <cfreturn variables._viewCollection.getView(argumentCollection=arguments) />
653</cffunction>
654
655<cffunction name="renderView" access="public" output="false" hint="I render a view into the view collection.">
656  <cfargument name="view" type="any" hint="I am the view to render.">
657
658        <cfset var content = variables._viewRenderer.renderView(this, arguments.view, variables._helpers) />
659       
660        <cfset addView(arguments.view.name, content, arguments.view.append) />
661</cffunction>
662
663<cffunction name="queueView" access="private" returnType="void" output="false" hint="I add a view to the queue of views to render.">
664  <cfargument name="view" type="any" hint="I am the view to queue.">
665
666        <cfset var link = structNew() />
667
668        <cfset link.view = arguments.view />
669        <cfset link.next = "" />
670
671        <cfset trace("View Queue", "View queued: #view.template#") />
672       
673        <cfif not isStruct(variables._nextView)>
674                <cfset variables._nextView = link />
675                <cfset variables._lastView = link />
676        <cfelse>
677                <cfset variables._lastView.next = link />
678                <cfset variables._lastView = link />
679        </cfif>
680       
681</cffunction>
682
683<cffunction name="getNextView" access="private" output="false" hint="Returns the next view in the queue.">
684        <cfset var view = variables._nextView.view />
685        <cfset variables._nextView = variables._nextView.next />
686
687        <cfreturn view />
688</cffunction>
689
690<cffunction name="renderViewQueue" access="private" returnType="void" output="false" hint="I render all views currently in the queue.">
691        <cfset var view = "" />
692
693        <cfloop condition="isStruct(variables._nextView)">
694                <cfset view = getNextView() />
695
696                <cfset this.trace("Views", "Rendering view ""#view.name#"" (#view.template#)", "<include name=""#view.name#"" template=""#view.template#"" />") />
697
698                <cfset renderView(view) />
699        </cfloop>
700</cffunction>
701
702<cffunction name="getLastRendereredView" access="public" returntype="string" output="false" hint="Gets the last renderered view content.">
703        <cfreturn variables._viewCollection.getFinalView() />
704</cffunction>
705
706<!--- TRACE LOG --->
707<cffunction name="getTrace" access="public" returntype="array" output="false" hint="Gets the trace log for the event context.">
708        <cfreturn this.log />
709</cffunction>
710
711<cffunction name="getCreated" access="public" returntype="numeric" output="false" hint="Gets the tick count for when this event context was initialized.">
712        <cfreturn this.created />
713</cffunction>
714
715<cffunction name="trace" access="public" returnType="Void" output="false" hint="I add a message to the trace log.">
716  <cfargument name="type" type="string" />
717  <cfargument name="message" type="any" />
718  <cfargument name="tag" type="string" default="" />
719  <cfargument name="traceType" type="string" default="OK" />
720
721        <cfset arguments.time = getTickCount() />
722       
723        <cfif not isSimpleValue(arguments.message)>
724                <cfsavecontent variable="arguments.message"><cfdump var="#arguments.message#" /></cfsavecontent>
725        </cfif>
726       
727        <cfset variables._logWriter.write(this, arguments) />
728</cffunction>
729
730
731<!--- BEAN POPULATION --->
732<cffunction name="makeEventBean" access="public" returnType="any" output="false" hint="Populates a CFC instance's properties with like-named event values (or the list of values passed in the VALUES argument).">
733        <cfargument name="target" type="any" hint="An instance of a CFC or the name of a CFC to instantiate and populate." />
734        <cfargument name="fields" type="string" default="" hint="(Optional) List of properties to populate." />
735       
736        <cfset var source = "" />
737        <cfset var i = "" />
738       
739        <cfreturn variables._beanPopulator.populate(arguments.target, variables._state, fields) />
740</cffunction>
741
742</cfcomponent>