- qpscanner/framework.cfc
- develop
- 74 KB
- 2036
1component {
2/*
3 Copyright (c) 2009-2012, Sean Corfield, Ryan Cogswell
4
5 Licensed under the Apache License, Version 2.0 (the "License");
6 you may not use this file except in compliance with the License.
7 You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16*/
17
18 this.name = hash( getBaseTemplatePath() );
19 if ( len( getContextRoot() ) ) {
20 variables.cgiScriptName = replace( CGI.SCRIPT_NAME, getContextRoot(), '' );
21 variables.cgiPathInfo = replace( CGI.PATH_INFO, getContextRoot(), '' );
22 } else {
23 variables.cgiScriptName = CGI.SCRIPT_NAME;
24 variables.cgiPathInfo = CGI.PATH_INFO;
25 }
26 request._fw1 = {
27 cgiScriptName = CGI.SCRIPT_NAME,
28 cgiRequestMethod = CGI.REQUEST_METHOD,
29 controllers = [ ],
30 requestDefaultsInitialized = false,
31 services = [ ],
32 trace = [ ]
33 };
34 // do not rely on these, they are meant to be true magic...
35 variables.magicApplicationSubsystem = '][';
36 variables.magicApplicationController = '[]';
37 variables.magicApplicationAction = '__';
38 variables.magicBaseURL = '-[]-';
39
40 public void function abortController() {
41 request._fw1.abortController = true;
42 frameworkTrace( 'abortController() called' );
43 throw( type='FW1.AbortControllerException', message='abortController() called' );
44 }
45
46 public boolean function actionSpecifiesSubsystem( string action ) {
47
48 if ( !usingSubsystems() ) {
49 return false;
50 }
51 return listLen( action, variables.framework.subsystemDelimiter ) > 1 ||
52 right( action, 1 ) == variables.framework.subsystemDelimiter;
53 }
54
55 public void function addRoute( any routes, string target, any methods = [ ], string statusCode = '' ) {
56 if ( !isArray( routes ) ) routes = [ routes ];
57 if ( !isArray( methods ) ) methods = [ methods ];
58 param name="variables.framework.routes" default="#[ ]#";
59 if ( len( statusCode ) ) target = statusCode & ':' & target;
60 for ( var route in routes ) {
61 if ( arrayLen( methods ) ) {
62 for ( var method in methods ) {
63 arrayAppend( variables.framework.routes, { '$#method##route#' = target } );
64 }
65 } else {
66 arrayAppend( variables.framework.routes, { '#route#' = target } );
67 }
68 }
69 }
70
71 /*
72 * buildURL() should be used from views to construct urls when using subsystems or
73 * in order to provide a simpler transition to using subsystems in the future
74 */
75 public string function buildURL( string action = '.', string path = variables.magicBaseURL, any queryString = '' ) {
76 if ( action == '.' ) action = getFullyQualifiedAction();
77 if ( path == variables.magicBaseURL ) path = getBaseURL();
78 var omitIndex = false;
79 if ( path == 'useSubsystemConfig' ) {
80 var subsystemConfig = getSubsystemConfig( getSubsystem( action ) );
81 if ( structKeyExists( subsystemConfig, 'baseURL' ) ) {
82 path = subsystemConfig.baseURL;
83 } else {
84 path = getBaseURL();
85 }
86 }
87 if ( path == 'useCgiScriptName' ) {
88 path = request._fw1.cgiScriptName;
89 if ( variables.framework.SESOmitIndex ) {
90 path = getDirectoryFromPath( path );
91 omitIndex = true;
92 }
93 } else if ( path == 'useRequestURI' ) {
94 path = getPageContext().getRequest().getRequestURI();
95 if ( variables.framework.SESOmitIndex ) {
96 path = getDirectoryFromPath( path );
97 omitIndex = true;
98 }
99 }
100 // if queryString is a struct, massage it into a string
101 if ( isStruct( queryString ) && structCount( queryString ) ) {
102 var q = '';
103 for( var key in queryString ) {
104 if( isSimpleValue( queryString[key] ) ){
105 q &= '#urlEncodedFormat( key )#=#urlEncodedFormat( queryString[ key ] )#&';
106 }
107 }
108 queryString = q;
109 }
110 else if ( !isSimpleValue( queryString ) ) {
111 queryString = '';
112 }
113 if ( queryString == '' ) {
114 // extract query string from action section:
115 var q = find( '?', action );
116 var a = find( '##', action );
117 if ( q > 0 ) {
118 if ( q < len( action ) ) {
119 queryString = right( action, len( action ) - q );
120 }
121 if ( q == 1 ) {
122 action = '';
123 } else {
124 action = left( action, q - 1 );
125 }
126 } else if ( a > 0 ) {
127 queryString = right( action, len( action ) - a + 1 );
128 if ( a == 1 ) {
129 action = '';
130 } else {
131 action = left( action, a - 1 );
132 }
133 }
134 }
135 var cosmeticAction = getFullyQualifiedAction( action );
136 var isHomeAction = cosmeticAction == getFullyQualifiedAction( variables.framework.home );
137 var isDefaultItem = getItem( cosmeticAction ) == variables.framework.defaultItem;
138
139 var initialDelim = '?';
140 var varDelim = '&';
141 var equalDelim = '=';
142 var basePath = '';
143 var extraArgs = '';
144 var queryPart = '';
145 var anchor = '';
146 var ses = false;
147 if ( find( '?', path ) > 0 ) {
148 if ( right( path, 1 ) == '?' || right( path, 1 ) == '&' ) {
149 initialDelim = '';
150 } else {
151 initialDelim = '&';
152 }
153 } else if ( structKeyExists( request._fw1, 'generateSES' ) && request._fw1.generateSES ) {
154 if ( omitIndex ) {
155 initialDelim = '';
156 } else {
157 initialDelim = '/';
158 }
159 varDelim = '/';
160 equalDelim = '/';
161 ses = true;
162 }
163 var curDelim = varDelim;
164
165 if ( usingSubsystems() && getSubsystem( cosmeticAction ) == variables.framework.defaultSubsystem ) {
166 cosmeticAction = getSectionAndItem( cosmeticAction );
167 }
168
169 if ( len( queryString ) ) {
170 // extract query part and anchor from query string:
171 q = find( '?', queryString );
172 if ( q > 0 ) {
173 queryPart = right( queryString, len( queryString ) - q );
174 if ( q > 1 ) {
175 extraArgs = left( queryString, q - 1 );
176 }
177 a = find( '##', queryPart );
178 if ( a > 0 ) {
179 anchor = right( queryPart, len( queryPart ) - a );
180 if ( a == 1 ) {
181 queryPart = '';
182 } else {
183 queryPart = left( queryPart, a - 1 );
184 }
185 }
186 } else {
187 extraArgs = queryString;
188 a = find( '##', extraArgs );
189 if ( a > 0 ) {
190 anchor = right( extraArgs, len( extraArgs ) - a );
191 if ( a == 1 ) {
192 extraArgs = '';
193 } else {
194 extraArgs = left( extraArgs, a - 1 );
195 }
196 }
197 }
198 if ( ses ) {
199 extraArgs = listChangeDelims( extraArgs, '/', '&=' );
200 }
201 }
202
203 if ( ses ) {
204 if ( isHomeAction && extraArgs == '' ) {
205 basePath = path;
206 } else if ( isDefaultItem && extraArgs == '' ) {
207 basePath = path & initialDelim & listFirst( cosmeticAction, '.' );
208 } else {
209 basePath = path & initialDelim & replace( cosmeticAction, '.', '/' );
210 }
211 } else {
212 if ( isHomeAction ) {
213 basePath = path;
214 curDelim = '?';
215 } else if ( isDefaultItem ) {
216 basePath = path & initialDelim & variables.framework.action & equalDelim & listFirst( cosmeticAction, '.' );
217 } else {
218 basePath = path & initialDelim & variables.framework.action & equalDelim & cosmeticAction;
219 }
220 }
221
222 if ( extraArgs != '' ) {
223 basePath = basePath & curDelim & extraArgs;
224 curDelim = varDelim;
225 }
226 if ( queryPart != '' ) {
227 if ( ses ) {
228 basePath = basePath & '?' & queryPart;
229 } else {
230 basePath = basePath & curDelim & queryPart;
231 }
232 }
233 if ( anchor != '' ) {
234 basePath = basePath & '##' & anchor;
235 }
236 return basePath;
237 }
238
239 /*
240 * call this from your Application.cfc methods to queue up additional controller
241 * method calls at the start of the request
242 */
243 public void function controller( string action ) {
244 var subsystem = getSubsystem( action );
245 var section = getSection( action );
246 var item = getItem( action );
247 var tuple = { };
248
249 if ( structKeyExists( request._fw1, 'controllerExecutionStarted' ) ) {
250 raiseException( type='FW1.controllerExecutionStarted', message="Controller '#action#' may not be added at this point.",
251 detail='The controller execution phase has already started. Controllers may not be added by other controller methods.' );
252 }
253
254 tuple.controller = getController( section = section, subsystem = subsystem );
255 tuple.key = subsystem & variables.framework.subsystemDelimiter & section;
256 tuple.subsystem = subsystem;
257 tuple.section = section;
258 tuple.item = item;
259
260 if ( structKeyExists( tuple, 'controller' ) && isObject( tuple.controller ) && !isNull(tuple.controller)) {
261 frameworkTrace( 'queuing controller', subsystem, section, item );
262 arrayAppend( request._fw1.controllers, tuple );
263 }
264 }
265
266 /*
267 * can be overridden to customize how views and layouts are found - can be
268 * used to provide skinning / common views / layouts etc
269 */
270 public string function customizeViewOrLayoutPath( struct pathInfo, string type, string fullPath ) {
271 // fullPath is: '#pathInfo.base##type#s/#pathInfo.path#.cfm'
272 return fullPath;
273 }
274
275 /*
276 * return the action URL variable name - allows applications to build URLs
277 */
278 public string function getAction() {
279 return variables.framework.action;
280 }
281
282 /*
283 * returns the base URL for redirects and links etc
284 * can be overridden if you need to modify this per-request
285 */
286 public string function getBaseURL() {
287 return variables.framework.baseURL;
288 }
289
290 /*
291 * returns whatever the framework has been told is a bean factory
292 * this will return a subsystem-specific bean factory if one
293 * exists for the current request's subsystem (or for the specified subsystem
294 * if passed in)
295 */
296 public any function getBeanFactory( string subsystem = '' ) {
297 if ( len( subsystem ) > 0 ) {
298 if ( hasSubsystemBeanFactory( subsystem ) ) {
299 return getSubsystemBeanFactory( subsystem );
300 }
301 return getDefaultBeanFactory();
302 }
303 if ( !usingSubsystems() ) {
304 return getDefaultBeanFactory();
305 }
306 if ( structKeyExists( request, 'subsystem' ) && len( request.subsystem ) > 0 ) {
307 return getBeanFactory( request.subsystem );
308 }
309 if ( len( variables.framework.defaultSubsystem ) > 0 ) {
310 return getBeanFactory( variables.framework.defaultSubsystem );
311 }
312 return getDefaultBeanFactory();
313 }
314
315 /*
316 * return the framework configuration
317 */
318 public struct function getConfig()
319 {
320 // return a copy to make it read only from outside the framework:
321 return structCopy( framework );
322 }
323
324 /*
325 * returns the bean factory set via setBeanFactory
326 */
327 public any function getDefaultBeanFactory() {
328 return application[ variables.framework.applicationKey ].factory;
329 }
330
331 /*
332 * returns the name of the default subsystem
333 */
334 public string function getDefaultSubsystem() {
335
336 if ( !usingSubsystems() ) {
337 return '';
338 }
339
340 if ( structKeyExists( request, 'subsystem' ) ) {
341 return request.subsystem;
342 }
343
344 if ( variables.framework.defaultSubsystem == '' ) {
345 raiseException( type='FW1.subsystemNotSpecified', message='No subsystem specified and no default configured.',
346 detail='When using subsystems, every request should specify a subsystem or variables.framework.defaultSubsystem should be configured.' );
347 }
348
349 return variables.framework.defaultSubsystem;
350
351 }
352
353 /*
354 * override this to provide your environment selector
355 */
356 public string function getEnvironment() {
357 return '';
358 }
359
360 /*
361 * return an action with all applicable parts (subsystem, section, and item) specified
362 * using defaults from the configuration or request where appropriate
363 */
364 public string function getFullyQualifiedAction( string action = request.action ) {
365 if ( usingSubsystems() ) {
366 return getSubsystem( action ) & variables.framework.subsystemDelimiter & getSectionAndItem( action );
367 }
368
369 return getSectionAndItem( action );
370 }
371
372 /*
373 * return the local hostname of the server
374 */
375 public string function getHostname() {
376 return createObject( 'java', 'java.net.InetAddress' ).getLocalHost().getHostName();
377 }
378
379 /*
380 * return the item part of the action
381 */
382 public string function getItem( string action = request.action ) {
383 return listLast( getSectionAndItem( action ), '.' );
384 }
385
386
387 /*
388 * return the current route (if any)
389 */
390 public string function getRoute() {
391 return structKeyExists( request._fw1, 'route' ) ? request._fw1.route : '';
392 }
393
394
395 /*
396 * return the configured routes
397 */
398 public array function getRoutes() {
399 return variables.framework.routes;
400 }
401
402
403 /*
404 * return the section part of the action
405 */
406 public string function getSection( string action = request.action ) {
407 return listFirst( getSectionAndItem( action ), '.' );
408 }
409
410
411 /*
412 * return the action without the subsystem
413 */
414 public string function getSectionAndItem( string action = request.action ) {
415 var sectionAndItem = '';
416
417 if ( usingSubsystems() && actionSpecifiesSubsystem( action ) ) {
418 if ( listLen( action, variables.framework.subsystemDelimiter ) > 1 ) {
419 sectionAndItem = listLast( action, variables.framework.subsystemDelimiter );
420 }
421 } else {
422 sectionAndItem = action;
423 }
424
425 if ( len( sectionAndItem ) == 0 ) {
426 sectionAndItem = variables.framework.defaultSection & '.' & variables.framework.defaultItem;
427 } else if ( listLen( sectionAndItem, '.' ) == 1 ) {
428 if ( left( sectionAndItem, 1 ) == '.' ) {
429 if ( structKeyExists( request, 'section' ) ) {
430 sectionAndItem = request.section & '.' & listLast( sectionAndItem, '.' );
431 } else {
432 sectionAndItem = variables.framework.defaultSection & '.' & listLast( sectionAndItem, '.' );
433 }
434 } else {
435 sectionAndItem = listFirst( sectionAndItem, '.' ) & '.' & variables.framework.defaultItem;
436 }
437 } else {
438 sectionAndItem = listFirst( sectionAndItem, '.' ) & '.' & listLast( sectionAndItem, '.' );
439 }
440
441 return sectionAndItem;
442 }
443
444
445 /*
446 * return the default service result key
447 * override this if you want the default service result to be
448 * stored under a different request context key, based on the
449 * requested action, e.g., return getSection( action );
450 */
451 public string function getServiceKey( action ) {
452 return 'data';
453 }
454
455 /*
456 * return the subsystem part of the action
457 */
458 public string function getSubsystem( string action = request.action ) {
459 if ( actionSpecifiesSubsystem( action ) ) {
460 return listFirst( action, variables.framework.subsystemDelimiter );
461 }
462 return getDefaultSubsystem();
463 }
464
465 /*
466 * return the base directory for the current request's subsystem
467 */
468 public string function getSubsystemBase() {
469 return request.subsystemBase;
470 }
471
472 /*
473 * return the (optional) configuration for a subsystem
474 */
475 public struct function getSubsystemConfig( string subsystem ) {
476 if ( structKeyExists( variables.framework.subsystems, subsystem ) ) {
477 // return a copy to make it read only from outside the framework:
478 return structCopy( variables.framework.subsystems[ subsystem ] );
479 }
480 return { };
481 }
482
483 /*
484 * returns the bean factory set via setSubsystemBeanFactory
485 * same effect as getBeanFactory when not using subsystems
486 */
487 public any function getSubsystemBeanFactory( string subsystem ) {
488
489 setupSubsystemWrapper( subsystem );
490
491 return application[ variables.framework.applicationKey ].subsystemFactories[ subsystem ];
492
493 }
494
495 /*
496 * returns true iff a call to getBeanFactory() will successfully return a bean factory
497 * previously set via setBeanFactory or setSubsystemBeanFactory
498 */
499 public boolean function hasBeanFactory() {
500
501 if ( hasDefaultBeanFactory() ) {
502 return true;
503 }
504
505 if ( !usingSubsystems() ) {
506 return false;
507 }
508
509 if ( structKeyExists( request, 'subsystem' ) ) {
510 return hasSubsystemBeanFactory(request.subsystem);
511 }
512
513 if ( len(variables.framework.defaultSubsystem) > 0 ) {
514 return hasSubsystemBeanFactory(variables.framework.defaultSubsystem);
515 }
516
517 return false;
518
519 }
520
521 /*
522 * returns true iff the framework has been told about a bean factory via setBeanFactory
523 */
524 public boolean function hasDefaultBeanFactory() {
525 return structKeyExists( application[ variables.framework.applicationKey ], 'factory' );
526 }
527
528 /*
529 * returns true if a subsystem specific bean factory has been set
530 */
531 public boolean function hasSubsystemBeanFactory( string subsystem ) {
532
533 ensureNewFrameworkStructsExist();
534
535 return structKeyExists( application[ variables.framework.applicationKey ].subsystemFactories, subsystem );
536
537 }
538
539 /*
540 * layout() may be invoked inside layouts
541 * returns the UI generated by the named layout and body
542 */
543 public string function layout( string path, string body ) {
544 var layoutPath = parseViewOrLayoutPath( path, 'layout' );
545 frameworkTrace( 'layout( #path# ) called - rendering #layoutPath#' );
546 return internalLayout( layoutPath, body );
547 }
548
549 /*
550 * it is better to set up your application configuration in
551 * your setupApplication() method since that is called on a
552 * framework reload
553 * if you do override onApplicationStart(), you must call
554 * super.onApplicationStart() first
555 */
556 public any function onApplicationStart() {
557 setupFrameworkDefaults();
558 setupRequestDefaults();
559 setupApplicationWrapper();
560 }
561
562 /*
563 * can be overridden, calling super.onError(exception,event) is optional
564 * depending on what error handling behavior you want
565 * note: you need to rename / disable onError() on OpenBD since it does
566 * not seem to be passed exception or event correctly when something fails
567 * in the code...
568 */
569 public void function onError( any exception, string event ) {
570 try {
571 if ( !structKeyExists( variables, 'framework' ) ||
572 !structKeyExists( variables.framework, 'version' ) ) {
573 // error occurred before framework was initialized
574 failure( exception, event, false, true );
575 return;
576 }
577
578 // record details of the exception:
579 if ( structKeyExists( request, 'action' ) ) {
580 request.failedAction = request.action;
581 }
582 request.exception = exception;
583 request.event = event;
584 // reset lifecycle flags:
585 structDelete( request._fw1, 'controllerExecutionComplete' );
586 structDelete( request._fw1, 'controllerExecutionStarted' );
587 structDelete( request._fw1, 'serviceExecutionComplete' );
588 structDelete( request._fw1, 'overrideViewAction' );
589 // setup the new controller action, based on the error action:
590 request._fw1.controllers = [ ];
591 // reset services for this new action:
592 request._fw1.services = [ ];
593
594 if ( structKeyExists( variables, 'framework' ) && structKeyExists( variables.framework, 'error' ) ) {
595 request.action = variables.framework.error;
596 } else {
597 // this is an edge case so we don't bother with subsystems etc
598 // (because if part of the framework defaults are not present,
599 // we'd have to do a lot of conditional logic here!)
600 request.action = 'main.error';
601 }
602 // ensure request.context is available
603 if ( !structKeyExists( request, 'context' ) ) {
604 request.context = { };
605 }
606 if ( !structKeyExists( request, 'base' ) ) {
607 if ( structKeyExists( variables, 'framework' ) && structKeyExists( variables.framework, 'base' ) ) {
608 request.base = variables.framework.base;
609 } else {
610 request.base = '';
611 }
612 }
613 if ( !structKeyExists( request, 'cfcbase' ) ) {
614 if ( structKeyExists( variables, 'framework' ) && structKeyExists( variables.framework, 'cfcbase' ) ) {
615 request.cfcbase = variables.framework.cfcbase;
616 } else {
617 request.cfcbase = '';
618 }
619 }
620 frameworkTrace( 'onError( #exception.message#, #event# ) called' );
621 setupRequestWrapper( false );
622 onRequest( '' );
623 frameworkTraceRender();
624 } catch ( any e ) {
625 failure( e, 'onError' );
626 failure( exception, event, true );
627 frameworkTraceRender();
628 }
629
630 }
631
632 /*
633 * this can be overridden if you want to change the behavior when
634 * FW/1 cannot find a matching view
635 */
636 public string function onMissingView( struct rc ) {
637 // unable to find a matching view - fail with a nice exception
638 viewNotFound();
639 // if we got here, we would return the string to be rendered
640 // but viewNotFound() throws an exception...
641 // for example, return view( 'main.missing' );
642 }
643
644 /*
645 * This can be overridden if you want to change the behavior when
646 * FW/1 encounters an error when trying to populate bean properties
647 * using all of the keys in the request context (rather than a
648 * specific list of keys). By default FW/1 silently ignores these errors.
649 * Available in the arguments are the bean cfc and the property that was
650 * being set when the error occurred as well as the request context structure.
651 * You can also reference the cfcatch variable for details about the error.
652 */
653 public void function onPopulateError( any cfc, string property, struct rc ) {
654 }
655
656 /*
657 * not intended to be overridden, automatically deleted for CFC requests
658 */
659 public any function onRequest( string targetPath ) {
660
661 var out = 0;
662 var i = 0;
663 var tuple = 0;
664 var _data_fw1 = 0;
665 var once = { };
666 var n = 0;
667
668 request._fw1.controllerExecutionStarted = true;
669 try {
670 n = arrayLen( request._fw1.controllers );
671 for ( i = 1; i <= n; i = i + 1 ) {
672 tuple = request._fw1.controllers[ i ];
673 // run before once per controller:
674 if ( !structKeyExists( once, tuple.key ) ) {
675 once[ tuple.key ] = i;
676 doController( tuple, 'before', 'before' );
677 if ( structKeyExists( request._fw1, 'abortController' ) ) abortController();
678 }
679 doController( tuple, 'start' & tuple.item, 'start' );
680 if ( structKeyExists( request._fw1, 'abortController' ) ) abortController();
681 doController( tuple, tuple.item, 'item' );
682 if ( structKeyExists( request._fw1, 'abortController' ) ) abortController();
683 }
684 n = arrayLen( request._fw1.services );
685 for ( i = 1; i <= n; i = i + 1 ) {
686 tuple = request._fw1.services[ i ];
687 if ( tuple.key == '' ) {
688 // throw the result away:
689 doService( tuple, tuple.item, tuple.args, tuple.enforceExistence );
690 if ( structKeyExists( request._fw1, 'abortController' ) ) abortController();
691 } else {
692 _data_fw1 = doService( tuple, tuple.item, tuple.args, tuple.enforceExistence );
693 if ( structKeyExists( request._fw1, 'abortController' ) ) abortController();
694 if ( isDefined('_data_fw1') ) {
695 frameworkTrace( 'store service result in rc.#tuple.key#', tuple.subsystem, tuple.section, tuple.item );
696 request.context[ tuple.key ] = _data_fw1;
697 } else {
698 frameworkTrace( 'service returned no result for rc.#tuple.key#', tuple.subsystem, tuple.section, tuple.item );
699 }
700 }
701 }
702 request._fw1.serviceExecutionComplete = true;
703 n = arrayLen( request._fw1.controllers );
704 for ( i = n; i >= 1; i = i - 1 ) {
705 tuple = request._fw1.controllers[ i ];
706 doController( tuple, 'end' & tuple.item, 'end' );
707 if ( structKeyExists( request._fw1, 'abortController' ) ) abortController();
708 if ( once[ tuple.key ] eq i ) {
709 doController( tuple, 'after', 'after' );
710 if ( structKeyExists( request._fw1, 'abortController' ) ) abortController();
711 }
712 }
713 } catch ( FW1.AbortControllerException e ) {
714 request._fw1.serviceExecutionComplete = true;
715 }
716 request._fw1.controllerExecutionComplete = true;
717
718 buildViewQueue();
719 frameworkTrace( 'setupView() called' );
720 setupView();
721 if ( structKeyExists(request._fw1, 'view') ) {
722 frameworkTrace( 'rendering #request._fw1.view#' );
723 out = internalView( request._fw1.view );
724 } else {
725 frameworkTrace( 'onMissingView() called' );
726 out = onMissingView( request.context );
727 }
728
729 buildLayoutQueue();
730 for ( i = 1; i <= arrayLen(request._fw1.layouts); i = i + 1 ) {
731 if ( structKeyExists(request, 'layout') && !request.layout ) {
732 frameworkTrace( 'aborting layout rendering' );
733 break;
734 }
735 frameworkTrace( 'rendering #request._fw1.layouts[i]#' );
736 out = internalLayout( request._fw1.layouts[i], out );
737 }
738 writeOutput( out );
739 setupResponseWrapper();
740 }
741
742 /*
743 * if you override onRequestEnd(), call super.onRequestEnd() if you
744 * want tracing functionality to continue working
745 */
746 public any function onRequestEnd() {
747 frameworkTraceRender();
748 }
749
750 /*
751 * it is better to set up your request configuration in
752 * your setupRequest() method
753 * if you do override onRequestStart(), you must call
754 * super.onRequestStart() first
755 */
756 public any function onRequestStart( string targetPath ) {
757 setupFrameworkDefaults();
758 setupRequestDefaults();
759
760 if ( !isFrameworkInitialized() || isFrameworkReloadRequest() ) {
761 setupApplicationWrapper();
762 }
763
764 restoreFlashContext();
765 // ensure flash context cannot override request action:
766 request.context[variables.framework.action] = request.action;
767
768 // allow configured extensions and paths to pass through to the requested template.
769 // NOTE: for unhandledPaths, we make the list into an escaped regular expression so we match on subdirectories.
770 // Meaning /myexcludepath will match '/myexcludepath' and all subdirectories
771 if ( listFindNoCase( variables.framework.unhandledExtensions, listLast( targetPath, '.' ) ) ||
772 REFindNoCase( '^(' & variables.framework.unhandledPathRegex & ')', targetPath ) ) {
773 structDelete(this, 'onRequest');
774 structDelete(variables, 'onRequest');
775 structDelete(this, 'onRequestEnd');
776 structDelete(variables, 'onRequestEnd');
777 if ( !variables.framework.unhandledErrorCaught ) {
778 structDelete(this, 'onError');
779 structDelete(variables, 'onError');
780 }
781 } else {
782 setupRequestWrapper( true );
783 }
784 }
785
786 /*
787 * it is better to set up your session configuration in
788 * your setupSession() method
789 * if you do override onSessionStart(), you must call
790 * super.onSessionStart() first
791 */
792 public any function onSessionStart() {
793 setupFrameworkDefaults();
794 setupRequestDefaults();
795 setupSessionWrapper();
796 }
797
798 // populate() may be invoked inside controllers
799 public any function populate( any cfc, string keys = '', boolean trustKeys = false, boolean trim = false, deep = false ) {
800 if ( keys == '' ) {
801 if ( trustKeys ) {
802 // assume everything in the request context can be set into the CFC
803 for ( var property in request.context ) {
804 try {
805 var args = { };
806 args[ property ] = request.context[ property ];
807 if ( trim && isSimpleValue( args[ property ] ) ) args[ property ] = trim( args[ property ] );
808 // cfc[ 'set'&property ]( argumentCollection = args ); // ugh! no portable script version of this?!?!
809 setProperty( cfc, property, args );
810 } catch ( any e ) {
811 onPopulateError( cfc, property, request.context );
812 }
813 }
814 } else {
815 var setters = findImplicitAndExplicitSetters( cfc );
816 for ( var property in setters ) {
817 if ( structKeyExists( request.context, property ) ) {
818 var args = { };
819 args[ property ] = request.context[ property ];
820 if ( trim && isSimpleValue( args[ property ] ) ) args[ property ] = trim( args[ property ] );
821 // cfc[ 'set'&property ]( argumentCollection = args ); // ugh! no portable script version of this?!?!
822 setProperty( cfc, property, args );
823 } else if ( deep && structKeyExists( cfc, 'get' & property ) ) {
824 //look for a context property that starts with the property
825 for ( var key in request.context ) {
826 if ( listFindNoCase( key, property, '.') ) {
827 try {
828 setProperty( cfc, key, { '#key#' = request.context[ key ] } );
829 } catch ( any e ) {
830 onPopulateError( cfc, key, request.context);
831 }
832 }
833 }
834 }
835 }
836 }
837 } else {
838 var setters = findImplicitAndExplicitSetters( cfc );
839 var keyArray = listToArray( keys );
840 for ( var property in keyArray ) {
841 var trimProperty = trim( property );
842 if ( structKeyExists( setters, trimProperty ) || trustKeys ) {
843 if ( structKeyExists( request.context, trimProperty ) ) {
844 var args = { };
845 args[ trimProperty ] = request.context[ trimProperty ];
846 if ( trim && isSimpleValue( args[ trimProperty ] ) ) args[ trimProperty ] = trim( args[ trimProperty ] );
847 // cfc[ 'set'&trimproperty ]( argumentCollection = args ); // ugh! no portable script version of this?!?!
848 setProperty( cfc, trimProperty, args );
849 }
850 } else if ( deep ) {
851 if ( listLen( trimProperty, '.' ) > 1 ) {
852 var prop = listFirst( trimProperty, '.' );
853 if ( structKeyExists( cfc, 'get' & prop ) ) {
854 setProperty( cfc, trimProperty, { '#trimProperty#' = request.context[ trimProperty ] } );
855 }
856 }
857 }
858 }
859 }
860 return cfc;
861 }
862
863 private void function setProperty( struct cfc, string property, struct args ) {
864 if ( listLen( property, '.' ) > 1 ) {
865 var firstObjName = listFirst( property, '.' );
866 var newProperty = listRest( property, '.' );
867
868 args[ newProperty ] = args[ property ];
869 structDelete( args, property );
870
871 if ( structKeyExists( cfc , 'get' & firstObjName ) ) {
872 var obj = getProperty( cfc, firstObjName );
873 if ( !isNull( obj ) ) setProperty( obj, newProperty, args );
874 }
875 } else {
876 evaluate( 'cfc.set#property#( argumentCollection = args )' );
877 }
878 }
879
880 private any function getProperty( struct cfc, string property ) {
881 if ( structKeyExists( cfc, 'get#property#' ) ) return evaluate( 'cfc.get#property#()' );
882 }
883
884 // call from your controller to redirect to a clean URL based on an action, pushing data to flash scope if necessary:
885 public void function redirect( string action, string preserve = 'none', string append = 'none', string path = variables.magicBaseURL, string queryString = '', string statusCode = '302' ) {
886 if ( path == variables.magicBaseURL ) path = getBaseURL();
887 var preserveKey = '';
888 if ( preserve != 'none' ) {
889 preserveKey = saveFlashContext( preserve );
890 }
891 var baseQueryString = '';
892 if ( append != 'none' ) {
893 if ( append == 'all' ) {
894 for ( var key in request.context ) {
895 if ( isSimpleValue( request.context[ key ] ) ) {
896 baseQueryString = listAppend( baseQueryString, key & '=' & urlEncodedFormat( request.context[ key ] ), '&' );
897 }
898 }
899 } else {
900 var keys = listToArray( append );
901 for ( var key in keys ) {
902 if ( structKeyExists( request.context, key ) && isSimpleValue( request.context[ key ] ) ) {
903 baseQueryString = listAppend( baseQueryString, key & '=' & urlEncodedFormat( request.context[ key ] ), '&' );
904 }
905 }
906
907 }
908 }
909
910 if ( baseQueryString != '' ) {
911 if ( queryString != '' ) {
912 if ( left( queryString, 1 ) == '?' || left( queryString, 1 ) == '##' ) {
913 baseQueryString = baseQueryString & queryString;
914 } else {
915 baseQueryString = baseQueryString & '&' & queryString;
916 }
917 }
918 } else {
919 baseQueryString = queryString;
920 }
921
922 var targetURL = buildURL( action, path, baseQueryString );
923 if ( preserveKey != '' && variables.framework.maxNumContextsPreserved > 1 ) {
924 if ( find( '?', targetURL ) ) {
925 preserveKey = '&#variables.framework.preserveKeyURLKey#=#preserveKey#';
926 } else {
927 preserveKey = '?#variables.framework.preserveKeyURLKey#=#preserveKey#';
928 }
929 if ( find( '##', targetURL ) ) {
930 targetURL = listFirst( targetURL, '##' ) & preserveKey & '##' & listRest( targetURL, '##' );
931 } else {
932 targetURL = targetURL & preserveKey;
933 }
934 }
935 setupResponseWrapper();
936 if ( variables.framework.trace ) {
937 frameworkTrace( 'redirecting to #targetURL# (#statusCode#)' );
938 session._fw1_trace = request._fw1.trace;
939 }
940 location( targetURL, false, statusCode );
941 }
942
943 // call this from your controller to queue up additional services
944 public void function service( string action, string key, struct args = { }, boolean enforceExistence = true ) {
945 var subsystem = getSubsystem( action );
946 var section = getSection( action );
947 var item = getItem( action );
948 var tuple = { };
949
950 if ( structKeyExists( request._fw1, 'serviceExecutionComplete' ) ) {
951 raiseException( type='FW1.serviceExecutionComplete', message="Service '#action#' may not be added at this point.",
952 detail='The service execution phase is complete. Services may not be added by end*() or after() controller methods.' );
953 }
954
955 tuple.service = getService(section=section, subsystem=subsystem);
956 tuple.subsystem = subsystem;
957 tuple.section = section;
958 tuple.item = item;
959 tuple.key = key;
960 tuple.args = args;
961 tuple.enforceExistence = enforceExistence;
962
963 if ( structKeyExists( tuple, 'service' ) && isObject( tuple.service ) ) {
964 frameworkTrace( 'queuing service', subsystem, section, item );
965 arrayAppend( request._fw1.services, tuple );
966 } else if ( enforceExistence ) {
967 raiseException( type='FW1.serviceCfcNotFound', message="Service '#action#' does not exist.",
968 detail="To have the execution of this service be conditional based upon its existence, pass in a third parameter of 'false'." );
969 }
970 }
971 /*
972 * call this from your setupApplication() method to tell the framework
973 * about your bean factory - only assumption is that it supports:
974 * - containsBean(name) - returns true if factory contains that named bean, else false
975 * - getBean(name) - returns the named bean
976 */
977 public void function setBeanFactory( any beanFactory ) {
978
979 application[ variables.framework.applicationKey ].factory = beanFactory;
980
981 }
982
983 /*
984 * use this to override the default layout
985 */
986 public void function setLayout( string action ) {
987 request._fw1.overrideLayoutAction = validateAction( action );
988 }
989
990 /*
991 * call this from your setupSubsystem() method to tell the framework
992 * about your subsystem-specific bean factory - only assumption is that it supports:
993 * - containsBean(name) - returns true if factory contains that named bean, else false
994 * - getBean(name) - returns the named bean
995 */
996 public void function setSubsystemBeanFactory( string subsystem, any factory ) {
997
998 ensureNewFrameworkStructsExist();
999 application[ variables.framework.applicationKey ].subsystemFactories[ subsystem ] = factory;
1000
1001 }
1002
1003 /*
1004 * override this to provide application-specific initialization
1005 * if you want the framework to use a bean factory and autowire
1006 * controllers and services, call setBeanFactory(factory) in your
1007 * setupApplication() method
1008 * you do not need to call super.setupApplication()
1009 */
1010 public void function setupApplication() { }
1011
1012 /*
1013 * override this to provide environment-specific initialization
1014 * you do not need to call super.setupEnvironment()
1015 */
1016 public void function setupEnvironment( string env ) { }
1017
1018 /*
1019 * override this to provide request-specific initialization
1020 * you do not need to call super.setupRequest()
1021 */
1022 public void function setupRequest() { }
1023
1024 /*
1025 * override this to provide request-specific finalization
1026 * you do not need to call super.setupResponse()
1027 */
1028 public void function setupResponse() { }
1029
1030 /*
1031 * override this to provide session-specific initialization
1032 * you do not need to call super.setupSession()
1033 */
1034 public void function setupSession() { }
1035
1036 /*
1037 * override this to provide subsystem-specific initialization
1038 * if you want the framework to use a bean factory and autowire
1039 * controllers and services, call
1040 * setSubsystemBeanFactory( subsystem, factory )
1041 * in your setupSubsystem() method
1042 * you do not need to call super.setupSubsystem( subsystem )
1043 */
1044 public void function setupSubsystem( string subsystem ) { }
1045
1046 /*
1047 * override this to provide pre-rendering logic, e.g., to
1048 * populate the request context with globally required data
1049 * you do not need to call super.setupView()
1050 */
1051 public void function setupView() { }
1052
1053 /*
1054 * use this to override the default view
1055 */
1056 public void function setView( string action ) {
1057 request._fw1.overrideViewAction = validateAction( action );
1058 }
1059
1060 /*
1061 * returns true if the application is configured to use subsystems
1062 */
1063 public boolean function usingSubsystems() {
1064 return variables.framework.usingSubsystems;
1065 }
1066
1067 /*
1068 * view() may be invoked inside views and layouts
1069 * returns the UI generated by the named view
1070 */
1071 public string function view( string path, struct args = { } ) {
1072 var viewPath = parseViewOrLayoutPath( path, 'view' );
1073 frameworkTrace( 'view( #path# ) called - rendering #viewPath#' );
1074 return internalView( viewPath, args );
1075 }
1076
1077 // THE FOLLOWING METHODS SHOULD ALL BE CONSIDERED PRIVATE / UNCALLABLE
1078
1079 private void function autowire( any cfc, any beanFactory ) {
1080 var setters = findImplicitAndExplicitSetters( cfc );
1081 for ( var property in setters ) {
1082 if ( beanFactory.containsBean( property ) ) {
1083 var args = { };
1084 args[ property ] = beanFactory.getBean( property );
1085 // cfc['set'&property](argumentCollection = args) does not work on ACF9
1086 evaluate( 'cfc.set#property#( argumentCollection = args )' );
1087 }
1088 }
1089 }
1090
1091 private void function buildLayoutQueue() {
1092 var siteWideLayoutBase = request.base & getSubsystemDirPrefix( variables.framework.siteWideLayoutSubsystem );
1093 var testLayout = 0;
1094 // default behavior:
1095 var subsystem = request.subsystem;
1096 var section = request.section;
1097 var item = request.item;
1098 var subsystembase = '';
1099
1100 request._fw1.layouts = [ ];
1101
1102 // has layout been overridden?
1103 if ( structKeyExists( request._fw1, 'overrideLayoutAction' ) ) {
1104 subsystem = getSubsystem( request._fw1.overrideLayoutAction );
1105 section = getSection( request._fw1.overrideLayoutAction );
1106 item = getItem( request._fw1.overrideLayoutAction );
1107 structDelete( request._fw1, 'overrideLayoutAction' );
1108 }
1109 subsystembase = request.base & getSubsystemDirPrefix( subsystem );
1110 frameworkTrace( 'building layout queue', subsystem, section, item );
1111 // look for item-specific layout:
1112 testLayout = parseViewOrLayoutPath( subsystem & variables.framework.subsystemDelimiter &
1113 section & '/' & item, 'layout' );
1114 if ( cachedFileExists( testLayout ) ) {
1115 frameworkTrace( 'found item-specific layout #testLayout#', subsystem, section, item );
1116 arrayAppend( request._fw1.layouts, testLayout );
1117 }
1118 // look for section-specific layout:
1119 testLayout = parseViewOrLayoutPath( subsystem & variables.framework.subsystemDelimiter &
1120 section, 'layout' );
1121 if ( cachedFileExists( testLayout ) ) {
1122 frameworkTrace( 'found section-specific layout #testLayout#', subsystem, section, item );
1123 arrayAppend( request._fw1.layouts, testLayout );
1124 }
1125 // look for subsystem-specific layout (site-wide layout if not using subsystems):
1126 if ( request.section != 'default' ) {
1127 testLayout = parseViewOrLayoutPath( subsystem & variables.framework.subsystemDelimiter &
1128 'default', 'layout' );
1129 if ( cachedFileExists( testLayout ) ) {
1130 frameworkTrace( 'found default layout #testLayout#', subsystem, section, item );
1131 arrayAppend( request._fw1.layouts, testLayout );
1132 }
1133 }
1134 // look for site-wide layout (only applicable if using subsystems)
1135 if ( usingSubsystems() && siteWideLayoutBase != subsystembase ) {
1136 testLayout = parseViewOrLayoutPath( variables.framework.siteWideLayoutSubsystem & variables.framework.subsystemDelimiter &
1137 'default', 'layout' );
1138 if ( cachedFileExists( testLayout ) ) {
1139 frameworkTrace( 'found #variables.framework.siteWideLayoutSubsystem# layout #testLayout#', subsystem, section, item );
1140 arrayAppend( request._fw1.layouts, testLayout );
1141 }
1142 }
1143 }
1144
1145
1146 private void function buildViewQueue() {
1147 // default behavior:
1148 var subsystem = request.subsystem;
1149 var section = request.section;
1150 var item = request.item;
1151 var subsystembase = '';
1152
1153 // has view been overridden?
1154 if ( structKeyExists( request._fw1, 'overrideViewAction' ) ) {
1155 subsystem = getSubsystem( request._fw1.overrideViewAction );
1156 section = getSection( request._fw1.overrideViewAction );
1157 item = getItem( request._fw1.overrideViewAction );
1158 structDelete( request._fw1, 'overrideViewAction' );
1159 }
1160 subsystembase = request.base & getSubsystemDirPrefix( subsystem );
1161 frameworkTrace( 'building view queue', subsystem, section, item );
1162 // view and layout setup - used to be in setupRequestWrapper():
1163 request._fw1.view = parseViewOrLayoutPath( subsystem & variables.framework.subsystemDelimiter &
1164 section & '/' & item, 'view' );
1165 if ( cachedFileExists( request._fw1.view ) ) {
1166 frameworkTrace( 'found view #request._fw1.view#', subsystem, section, item );
1167 } else {
1168 frameworkTrace( 'no such view #request._fw1.view#', subsystem, section, item );
1169 request.missingView = request._fw1.view;
1170 // ensures original view not re-invoked for onError() case:
1171 structDelete( request._fw1, 'view' );
1172 }
1173 }
1174
1175
1176 private boolean function cachedFileExists( string filePath ) {
1177 var cache = application[ variables.framework.applicationKey ].cache;
1178 if ( !variables.framework.cacheFileExists ) {
1179 return fileExists( expandPath( filePath) );
1180 }
1181 param name="cache.fileExists" default="#{ }#";
1182 if ( !structKeyExists( cache.fileExists, filePath ) ) {
1183 cache.fileExists[ filePath ] = fileExists( expandPath( filePath ) );
1184 }
1185 return cache.fileExists[ filePath ];
1186 }
1187
1188
1189 private string function cfcFilePath( string dottedPath ) {
1190 if ( dottedPath == '' ) {
1191 return '/';
1192 } else {
1193 return '/' & replace( dottedPath, '.', '/', 'all' ) & '/';
1194 }
1195 }
1196
1197 private void function doController( struct tuple, string method, string lifecycle ) {
1198 var cfc = tuple.controller;
1199 if ( structKeyExists( cfc, method ) ) {
1200 try {
1201 frameworkTrace( 'calling #lifecycle# controller', tuple.subsystem, tuple.section, method );
1202 evaluate( 'cfc.#method#( rc = request.context )' );
1203 } catch ( any e ) {
1204 setCfcMethodFailureInfo( cfc, method );
1205 rethrow;
1206 }
1207 }
1208 else if ( structKeyExists( cfc, 'onMissingMethod' ) ) {
1209 try {
1210 frameworkTrace( 'calling #lifecycle# controller (via onMissingMethod)', tuple.subsystem, tuple.section, method );
1211 evaluate( 'cfc.#method#( rc = request.context, method = lifecycle )' );
1212 } catch ( any e ) {
1213 setCfcMethodFailureInfo( cfc, method );
1214 rethrow;
1215 }
1216 } else {
1217 frameworkTrace( 'no #lifecycle# controller to call', tuple.subsystem, tuple.section, method );
1218 }
1219 }
1220
1221 private any function doService( struct tuple, string method, struct args, boolean enforceExistence ) {
1222 var cfc = tuple.service;
1223 if ( structKeyExists( cfc, method ) || structKeyExists( cfc, 'onMissingMethod' ) ) {
1224 try {
1225 structAppend( args, request.context, false );
1226 frameworkTrace( 'calling service', tuple.subsystem, tuple.section, method );
1227 var _result_fw1 = evaluate( 'cfc.#method#( argumentCollection = args )' );
1228 if ( !isNull( _result_fw1 ) ) {
1229 return _result_fw1;
1230 }
1231 } catch ( any e ) {
1232 setCfcMethodFailureInfo( cfc, method );
1233 rethrow;
1234 }
1235 } else if ( enforceExistence ) {
1236 raiseException( type='FW1.serviceMethodNotFound', message="Service method '#method#' does not exist in service '#getMetadata( cfc ).fullname#'.",
1237 detail="To have the execution of this service method be conditional based upon its existence, pass in a third parameter of 'false'." );
1238 }
1239 }
1240
1241 private void function dumpException( any exception ) {
1242 writeDump( var = exception, label = 'Exception' );
1243 }
1244
1245 private void function ensureNewFrameworkStructsExist() {
1246
1247 var framework = application[variables.framework.applicationKey];
1248
1249 if ( !structKeyExists(framework, 'subsystemFactories') ) {
1250 framework.subsystemFactories = { };
1251 }
1252
1253 if ( !structKeyExists(framework, 'subsystems') ) {
1254 framework.subsystems = { };
1255 }
1256
1257 }
1258
1259 private void function failure( any exception, string event, boolean indirect = false, boolean early = false ) {
1260 var h = indirect ? 3 : 1;
1261 if ( structKeyExists(exception, 'rootCause') ) {
1262 exception = exception.rootCause;
1263 }
1264 getPageContext().getResponse().setStatus( 500 );
1265 if ( arguments.early ) {
1266 writeOutput( '<h1>Exception occured before FW/1 was initialized</h1>');
1267 } else {
1268 writeOutput( '<h#h#>' & ( indirect ? 'Original exception ' : 'Exception' ) & ' in #event#</h#h#>' );
1269 if ( structKeyExists( request, 'failedAction' ) ) {
1270 writeOutput( '<p>The action #request.failedAction# failed.</p>' );
1271 }
1272 writeOutput( '<h#1+h#>#exception.message#</h#1+h#>' );
1273 }
1274
1275 writeOutput( '<p>#exception.detail# (#exception.type#)</p>' );
1276 dumpException(exception);
1277
1278 }
1279
1280 private struct function findImplicitAndExplicitSetters( any cfc ) {
1281 var baseMetadata = getMetadata( cfc );
1282 var setters = { };
1283 // is it already attached to the CFC metadata?
1284 if ( structKeyExists( baseMetadata, '__fw1_setters' ) ) {
1285 setters = baseMetadata.__fw1_setters;
1286 } else {
1287 var md = { extends = baseMetadata };
1288 do {
1289 md = md.extends;
1290 var implicitSetters = false;
1291 // we have implicit setters if: accessors="true" or persistent="true"
1292 if ( structKeyExists( md, 'persistent' ) && isBoolean( md.persistent ) ) {
1293 implicitSetters = md.persistent;
1294 }
1295 if ( structKeyExists( md, 'accessors' ) && isBoolean( md.accessors ) ) {
1296 implicitSetters = implicitSetters || md.accessors;
1297 }
1298 if ( structKeyExists( md, 'properties' ) ) {
1299 // due to a bug in ACF9.0.1, we cannot use var property in md.properties,
1300 // instead we must use an explicit loop index... ugh!
1301 var n = arrayLen( md.properties );
1302 for ( var i = 1; i <= n; ++i ) {
1303 var property = md.properties[ i ];
1304 if ( implicitSetters ||
1305 structKeyExists( property, 'setter' ) && isBoolean( property.setter ) && property.setter ) {
1306 setters[ property.name ] = 'implicit';
1307 }
1308 }
1309 }
1310 } while ( structKeyExists( md, 'extends' ) );
1311 // cache it in the metadata (note: in Railo 3.2 metadata cannot be modified
1312 // which is why we return the local setters structure - it has to be built
1313 // on every controller call; fixed in Railo 3.3)
1314 baseMetadata.__fw1_setters = setters;
1315 }
1316 // gather up explicit setters as well
1317 for ( var member in cfc ) {
1318 var method = cfc[ member ];
1319 var n = len( member );
1320 if ( isCustomFunction( method ) && left( member, 3 ) == 'set' && n > 3 ) {
1321 var property = right( member, n - 3 );
1322 setters[ property ] = 'explicit';
1323 }
1324 }
1325 return setters;
1326 }
1327
1328 private void function frameworkTrace( string message, string subsystem = '', string section = '', string item = '' ) {
1329 if ( variables.framework.trace ) {
1330 if ( isDefined( 'session._fw1_trace' ) && structKeyExists( session, '_fw1_trace' ) ) {
1331 request._fw1.trace = session._fw1_trace;
1332 structDelete( session, '_fw1_trace' );
1333 }
1334 arrayAppend( request._fw1.trace, { tick = getTickCount(), msg = message, sub = subsystem, s = section, i = item } );
1335 }
1336 }
1337
1338 private void function frameworkTraceRender() {
1339 if ( variables.framework.trace && arrayLen( request._fw1.trace ) ) {
1340 var startTime = request._fw1.trace[1].tick;
1341 var font = 'font-family: verdana, helvetica;';
1342 writeOutput( '<hr /><div style="background: ##ccdddd; color: black; border: 1px solid; border-color: black; padding: 5px; #font#">' );
1343 writeOutput( '<div style="#font# font-weight: bold; font-size: large; float: left;">Framework Lifecycle Trace</div><div style="clear: both;"></div>' );
1344 var table = '<table style="border: 1px solid; border-color: black; color: black; #font#" width="100%">';
1345 writeOutput( table );
1346 var colors = [ '##ccd4dd', '##ccddcc' ];
1347 var row = 0;
1348 var n = arrayLen( request._fw1.trace );
1349 for ( var i = 1; i <= n; ++i ) {
1350 var trace = request._fw1.trace[i];
1351 var action = '';
1352 if ( trace.s == variables.magicApplicationController || trace.sub == variables.magicApplicationSubsystem ) {
1353 action = '<em>Application.cfc</em>';
1354 if ( right( trace.i, len( variables.magicApplicationAction ) ) == variables.magicApplicationAction ) {
1355 continue;
1356 }
1357 } else {
1358 action = trace.sub;
1359 if ( action != '' && trace.s != '' ) {
1360 action &= variables.framework.subsystemDelimiter;
1361 }
1362 action &= trace.s;
1363 if ( trace.s != '' ) {
1364 action &= '.';
1365 }
1366 action &= trace.i;
1367 }
1368 ++row;
1369 writeOutput( '<tr style="border: 0; background: #colors[1 + row mod 2]#;">' );
1370 writeOutput( '<td style="border: 0; color: black; #font# font-size: small;" width="5%">#trace.tick - startTime#ms</td>' );
1371 writeOutput( '<td style="border: 0; color: black; #font# font-size: small;" width="10%">#action#</td>' );
1372 var color =
1373 trace.msg.startsWith( 'no ' ) ? '##cc8888' :
1374 trace.msg.startsWith( 'onError( ' ) ? '##cc0000' : '##0000';
1375 writeOutput( '<td style="border: 0; color: #color#; #font# font-size: small;">#trace.msg#</td>' );
1376 writeOutput( '</tr>' );
1377 if ( trace.msg.startsWith( 'redirecting ' ) ) {
1378 writeOutput( '</table>#table#' );
1379 if ( i < n ) startTime = request._fw1.trace[i+1].tick;
1380 }
1381 }
1382 writeOutput( '<table></div>' );
1383 }
1384 }
1385
1386 private any function getCachedComponent( string type, string subsystem, string section ) {
1387
1388 setupSubsystemWrapper( subsystem );
1389 var cache = application[variables.framework.applicationKey].cache;
1390 var types = type & 's';
1391 var cfc = 0;
1392 var subsystemDir = getSubsystemDirPrefix( subsystem );
1393 var subsystemDot = replace( subsystemDir, '/', '.', 'all' );
1394 var subsystemUnderscore = replace( subsystemDir, '/', '_', 'all' );
1395 var componentKey = subsystemUnderscore & section;
1396 var beanName = section & type;
1397
1398 if ( !structKeyExists( cache[ types ], componentKey ) ) {
1399 lock name="fw1_#application.applicationName#_#variables.framework.applicationKey#_#type#_#componentKey#" type="exclusive" timeout="30" {
1400 if ( !structKeyExists( cache[ types ], componentKey ) ) {
1401 if ( usingSubsystems() && hasSubsystemBeanFactory( subsystem ) && getSubsystemBeanFactory( subsystem ).containsBean( beanName ) ) {
1402 cfc = getSubsystemBeanFactory( subsystem ).getBean( beanName );
1403 if ( type == 'controller' ) injectFramework( cfc );
1404 } else if ( !usingSubsystems() && hasDefaultBeanFactory() && getDefaultBeanFactory().containsBean( beanName ) ) {
1405 cfc = getDefaultBeanFactory().getBean( beanName );
1406 if ( type == 'controller' ) injectFramework( cfc );
1407 } else {
1408 if ( type == 'controller' && section == variables.magicApplicationController ) {
1409 // treat this (Application.cfc) as a controller:
1410 cfc = this;
1411 } else if ( cachedFileExists( cfcFilePath( request.cfcbase ) & subsystemDir & types & '/' & section & '.cfc' ) ) {
1412 // we call createObject() rather than new so we can control initialization:
1413 if ( request.cfcbase == '' ) {
1414 cfc = createObject( 'component', subsystemDot & types & '.' & section );
1415 } else {
1416 cfc = createObject( 'component', request.cfcbase & '.' & subsystemDot & types & '.' & section );
1417 }
1418 if ( structKeyExists( cfc, 'init' ) ) {
1419 if ( type == 'controller' ) {
1420 cfc.init( this );
1421 } else {
1422 cfc.init();
1423 }
1424 }
1425 }
1426 if ( isObject( cfc ) && ( hasDefaultBeanFactory() || hasSubsystemBeanFactory( subsystem ) ) ) {
1427 autowire( cfc, getBeanFactory( subsystem ) );
1428 }
1429 }
1430 if ( isObject( cfc ) ) {
1431 cache[ types ][ componentKey ] = cfc;
1432 }
1433 }
1434 }
1435 }
1436
1437 if ( structKeyExists( cache[ types ], componentKey ) ) {
1438 return cache[ types ][ componentKey ];
1439 }
1440 // else "return null" effectively
1441 }
1442
1443 private any function getController( string section, string subsystem = getDefaultSubsystem() ) {
1444 var _controller_fw1 = getCachedComponent( 'controller', subsystem, section );
1445 if ( isDefined( '_controller_fw1' ) ) {
1446 return _controller_fw1;
1447 }
1448 }
1449
1450 private string function getNextPreserveKeyAndPurgeOld() {
1451 var nextPreserveKey = '';
1452 var oldKeyToPurge = '';
1453 try {
1454 if ( variables.framework.maxNumContextsPreserved > 1 ) {
1455 lock scope="session" type="exclusive" timeout="30" {
1456 param name="session.__fw1NextPreserveKey" default="1";
1457 nextPreserveKey = session.__fw1NextPreserveKey;
1458 session.__fw1NextPreserveKey = session.__fw1NextPreserveKey + 1;
1459 }
1460 oldKeyToPurge = nextPreserveKey - variables.framework.maxNumContextsPreserved;
1461 } else {
1462 lock scope="session" type="exclusive" timeout="30" {
1463 session.__fw1PreserveKey = '';
1464 nextPreserveKey = session.__fw1PreserveKey;
1465 }
1466 oldKeyToPurge = '';
1467 }
1468 } catch ( any e ) {
1469 // ignore - assume session scope is disabled
1470 }
1471 var key = getPreserveKeySessionKey( oldKeyToPurge );
1472 if ( structKeyExists( session, key ) ) {
1473 structDelete( session, key );
1474 }
1475 return nextPreserveKey;
1476 }
1477
1478 private string function getPreserveKeySessionKey( string preserveKey ) {
1479 return '__f1' & preserveKey;
1480 }
1481
1482 private any function getService( string section, string subsystem = getDefaultSubsystem() ) {
1483 var _service_fw1 = getCachedComponent( 'service', subsystem, section );
1484 if ( isDefined( '_service_fw1' ) ) {
1485 return _service_fw1;
1486 }
1487 }
1488
1489 private string function getSubsystemDirPrefix( string subsystem ) {
1490
1491 if ( subsystem eq '' ) {
1492 return '';
1493 }
1494
1495 return subsystem & '/';
1496 }
1497
1498 private void function injectFramework( any cfc ) {
1499 var args = { };
1500 if ( structKeyExists( cfc, 'setFramework' ) || structKeyExists( cfc, 'onMissingMethod' ) ) {
1501 args.framework = this;
1502 // allow alternative spellings
1503 args.fw = this;
1504 args.fw1 = this;
1505 evaluate( 'cfc.setFramework( argumentCollection = args )' );
1506 }
1507 }
1508
1509 private string function internalLayout( string layoutPath, string body ) {
1510 var rc = request.context;
1511 var $ = { };
1512 // integration point with Mura:
1513 if ( structKeyExists( rc, '$' ) ) {
1514 $ = rc.$;
1515 }
1516 if ( !structKeyExists( request._fw1, 'controllerExecutionComplete' ) ) {
1517 raiseException( type='FW1.layoutExecutionFromController', message='Invalid to call the layout method at this point.',
1518 detail='The layout method should not be called prior to the completion of the controller execution phase.' );
1519 }
1520 var response = '';
1521 savecontent variable="response" {
1522 include '#layoutPath#';
1523 }
1524 return response;
1525 }
1526
1527 private string function internalView( string viewPath, struct args = { } ) {
1528 var rc = request.context;
1529 var $ = { };
1530 // integration point with Mura:
1531 if ( structKeyExists( rc, '$' ) ) {
1532 $ = rc.$;
1533 }
1534 structAppend( local, args );
1535 if ( !structKeyExists( request._fw1, 'serviceExecutionComplete') &&
1536 structKeyExists( request._fw1, 'services' ) && arrayLen( request._fw1.services ) != 0 ) {
1537 raiseException( type='FW1.viewExecutionFromController', message='Invalid to call the view method at this point.',
1538 detail='The view method should not be called prior to the completion of the service execution phase.' );
1539 }
1540 var response = '';
1541 savecontent variable="response" {
1542 include '#viewPath#';
1543 }
1544 return response;
1545 }
1546
1547 private boolean function isFrameworkInitialized() {
1548 return structKeyExists( application, variables.framework.applicationKey );
1549 }
1550
1551 private boolean function isFrameworkReloadRequest() {
1552 return ( isDefined( 'URL' ) &&
1553 structKeyExists( URL, variables.framework.reload ) &&
1554 URL[ variables.framework.reload ] == variables.framework.password ) ||
1555 variables.framework.reloadApplicationOnEveryRequest;
1556 }
1557
1558 private boolean function isSubsystemInitialized( string subsystem ) {
1559
1560 ensureNewFrameworkStructsExist();
1561
1562 return structKeyExists( application[ variables.framework.applicationKey ].subsystems, subsystem );
1563
1564 }
1565
1566 private string function parseViewOrLayoutPath( string path, string type ) {
1567
1568 var pathInfo = { };
1569 var subsystem = getSubsystem( path );
1570
1571 // allow for :section/action to simplify logic in setupRequestWrapper():
1572 pathInfo.path = listLast( path, variables.framework.subsystemDelimiter );
1573 pathInfo.base = request.base;
1574 pathInfo.subsystem = subsystem;
1575 if ( usingSubsystems() ) {
1576 pathInfo.base = pathInfo.base & getSubsystemDirPrefix( subsystem );
1577 }
1578
1579 return customizeViewOrLayoutPath( pathInfo, type, '#pathInfo.base##type#s/#pathInfo.path#.cfm' );
1580
1581 }
1582
1583 private struct function processRouteMatch( string route, string target, string path ) {
1584 // TODO: could cache preprocessed versions of route / target / etc
1585 var routeMatch = { matched = false, redirect = false, method = '' };
1586 // if target has numeric prefix, strip it and set redirect:
1587 var prefix = listFirst( target, ':' );
1588 if ( isNumeric( prefix ) ) {
1589 routeMatch.redirect = true;
1590 routeMatch.statusCode = prefix;
1591 target = listRest( target, ':' );
1592 }
1593 // special routes begin with $METHOD, * is also a wildcard
1594 var routeLen = len( route );
1595 if ( routeLen ) {
1596 if ( left( route, 1 ) == '$' ) {
1597 // check HTTP method
1598 routeMatch.method = listFirst( route, '*/' );
1599 var methodLen = len( routeMatch.method );
1600 if ( routeLen == methodLen ) {
1601 route = '*';
1602 } else {
1603 route = right( route, routeLen - methodLen );
1604 }
1605 }
1606 if ( route == '*' ) {
1607 route = '/';
1608 } else if ( right( route, 1 ) != '/' && right( route, 1 ) != '$' ) {
1609 // only add the closing backslash if last position is not already a "/" or a "$" to respect regex end of string
1610 route &= '/';
1611 }
1612 } else {
1613 route = '/';
1614 }
1615 if ( !len( target ) || right( target, 1) != '/' ) target &= '/';
1616 // walk for self defined (regex) and :var - replace :var with ([^/]*) in route and back reference in target:
1617 var n = 1;
1618 var placeholders = rematch( '(:[^/]+)|(\([^\)]+)', route );
1619 for ( var placeholder in placeholders ) {
1620 if ( left( placeholder, 1 ) == ':') {
1621 route = replace( route, placeholder, '([^/]*)' );
1622 target = replace( target, placeholder, chr(92) & n );
1623 }
1624 ++n;
1625 }
1626 // add trailing match/back reference: if last character is not "$" to respect regex end of string
1627 if (right( route, 1 ) != '$')
1628 route &= '(.*)';
1629 target &= chr(92) & n;
1630 // end of preprocessing section
1631 if ( !len( path ) || right( path, 1) != '/' ) path &= '/';
1632 var matched = len( routeMatch.method ) ? ( '$' & request._fw1.cgiRequestMethod == routeMatch.method ) : true;
1633 if ( matched && reFind( route, path ) ) {
1634 routeMatch.matched = true;
1635 routeMatch.pattern = route;
1636 routeMatch.target = target;
1637 routeMatch.path = path;
1638 }
1639 return routeMatch;
1640 }
1641
1642 private string function processRoutes( string path ) {
1643 for ( var routePack in variables.framework.routes ) {
1644 for ( var route in routePack ) {
1645 if ( route != 'hint' ) {
1646 var routeMatch = processRouteMatch( route, routePack[ route ], path );
1647 if ( routeMatch.matched ) {
1648 path = rereplace( routeMatch.path, routeMatch.pattern, routeMatch.target );
1649 if ( routeMatch.redirect ) {
1650 location( path, false, routeMatch.statusCode );
1651 } else {
1652 request._fw1.route = route;
1653 return path;
1654 }
1655 }
1656 }
1657 }
1658 }
1659 return path;
1660 }
1661
1662 private void function raiseException( string type, string message, string detail ) {
1663 throw( type = type, message = message, detail = detail );
1664 }
1665
1666 private void function restoreFlashContext() {
1667 if ( variables.framework.maxNumContextsPreserved > 1 ) {
1668 if ( !structKeyExists( URL, variables.framework.preserveKeyURLKey ) ) {
1669 return;
1670 }
1671 var preserveKey = URL[ variables.framework.preserveKeyURLKey ];
1672 var preserveKeySessionKey = getPreserveKeySessionKey( preserveKey );
1673 } else {
1674 var preserveKeySessionKey = getPreserveKeySessionKey( '' );
1675 }
1676 try {
1677 if ( structKeyExists( session, preserveKeySessionKey ) ) {
1678 structAppend( request.context, session[ preserveKeySessionKey ], false );
1679 if ( variables.framework.maxNumContextsPreserved == 1 ) {
1680 /*
1681 When multiple contexts are preserved, the oldest context is purged
1682 within getNextPreserveKeyAndPurgeOld once the maximum is reached.
1683 This allows for a browser refresh after the redirect to still receive
1684 the same context.
1685 */
1686 structDelete( session, preserveKeySessionKey );
1687 }
1688 }
1689 } catch ( any e ) {
1690 // session scope not enabled, do nothing
1691 }
1692 }
1693
1694 private string function saveFlashContext( string keys ) {
1695 var curPreserveKey = getNextPreserveKeyAndPurgeOld();
1696 var preserveKeySessionKey = getPreserveKeySessionKey( curPreserveKey );
1697 try {
1698 param name="session.#preserveKeySessionKey#" default="#{ }#";
1699 if ( keys == 'all' ) {
1700 structAppend( session[ preserveKeySessionKey ], request.context );
1701 } else {
1702 var key = 0;
1703 var keyNames = listToArray( keys );
1704 for ( key in keyNames ) {
1705 if ( structKeyExists( request.context, key ) ) {
1706 session[ preserveKeySessionKey ][ key ] = request.context[ key ];
1707 }
1708 }
1709 }
1710 } catch ( any ex ) {
1711 // session scope not enabled, do nothing
1712 }
1713 return curPreserveKey;
1714 }
1715
1716 private void function setCfcMethodFailureInfo( any cfc, string method ) {
1717 var meta = getMetadata( cfc );
1718 if ( structKeyExists( meta, 'fullname' ) ) {
1719 request.failedCfcName = meta.fullname;
1720 } else {
1721 request.failedCfcName = meta.name;
1722 }
1723 request.failedMethod = method;
1724 }
1725
1726 private void function setupApplicationWrapper() {
1727 /*
1728 since this can be called on a reload, we need to lock it to prevent other threads
1729 trying to reload the app at the same time since we're messing with the main application
1730 data struct... if the application is already running, we don't blow away the factories
1731 because we don't want to affect other threads that may be running at this time
1732 */
1733 var frameworkCache = { };
1734 var framework = { };
1735 var isReload = true;
1736 frameworkCache.lastReload = now();
1737 frameworkCache.fileExists = { };
1738 frameworkCache.controllers = { };
1739 frameworkCache.services = { };
1740 lock name="fw1_#application.applicationName#_#variables.framework.applicationKey#_initialization" type="exclusive" timeout="10" {
1741 if ( structKeyExists( application, variables.framework.applicationKey ) ) {
1742 // application is already loaded, just reset the cache and trigger re-initialization of subsystems
1743 application[variables.framework.applicationKey].cache = frameworkCache;
1744 application[variables.framework.applicationKey].subsystems = { };
1745 } else {
1746 // must be first request so we need to set up the entire structure
1747 isReload = false;
1748 framework.cache = frameworkCache;
1749 framework.subsystems = { };
1750 framework.subsystemFactories = { };
1751 application[variables.framework.applicationKey] = framework;
1752 }
1753 }
1754
1755 // this will recreate the main bean factory on a reload:
1756 frameworkTrace( 'setupApplication() called' );
1757 setupApplication();
1758
1759 if ( isReload ) {
1760 /*
1761 it's possible that the cache got populated by another thread between resetting the cache above
1762 and the factory getting recreated by the user code in setupApplication() so we flush the cache
1763 again here to be safe / paranoid!
1764 */
1765 frameworkCache = { };
1766 frameworkCache.lastReload = now();
1767 frameworkCache.fileExists = { };
1768 frameworkCache.controllers = { };
1769 frameworkCache.services = { };
1770 application[variables.framework.applicationKey].cache = frameworkCache;
1771 application[variables.framework.applicationKey].subsystems = { };
1772 }
1773
1774 }
1775
1776 private void function setupFrameworkDefaults() {
1777
1778 // default values for Application::variables.framework structure:
1779 if ( !structKeyExists(variables, 'framework') ) {
1780 variables.framework = { };
1781 }
1782 if ( !structKeyExists(variables.framework, 'action') ) {
1783 variables.framework.action = 'action';
1784 }
1785 if ( !structKeyExists(variables.framework, 'base') ) {
1786 variables.framework.base = getDirectoryFromPath( variables.cgiScriptName );
1787 } else if ( right( variables.framework.base, 1 ) != '/' ) {
1788 variables.framework.base = variables.framework.base & '/';
1789 }
1790 variables.framework.base = replace( variables.framework.base, chr(92), '/', 'all' );
1791 if ( !structKeyExists(variables.framework, 'cfcbase') ) {
1792 if ( len( variables.framework.base ) eq 1 ) {
1793 variables.framework.cfcbase = '';
1794 } else {
1795 variables.framework.cfcbase = replace( mid( variables.framework.base, 2, len(variables.framework.base)-2 ), '/', '.', 'all' );
1796 }
1797 }
1798 if ( !structKeyExists(variables.framework, 'usingSubsystems') ) {
1799 variables.framework.usingSubsystems = structKeyExists(variables.framework,'defaultSubsystem') || structKeyExists(variables.framework,'sitewideLayoutSubsystem');
1800 }
1801 if ( !structKeyExists(variables.framework, 'defaultSubsystem') ) {
1802 variables.framework.defaultSubsystem = 'home';
1803 }
1804 if ( !structKeyExists(variables.framework, 'defaultSection') ) {
1805 variables.framework.defaultSection = 'main';
1806 }
1807 if ( !structKeyExists(variables.framework, 'defaultItem') ) {
1808 variables.framework.defaultItem = 'default';
1809 }
1810 if ( !structKeyExists(variables.framework, 'subsystemDelimiter') ) {
1811 variables.framework.subsystemDelimiter = ':';
1812 }
1813 if ( !structKeyExists(variables.framework, 'siteWideLayoutSubsystem') ) {
1814 variables.framework.siteWideLayoutSubsystem = 'common';
1815 }
1816 if ( !structKeyExists(variables.framework, 'home') ) {
1817 if (usingSubsystems()) {
1818 variables.framework.home = variables.framework.defaultSubsystem & variables.framework.subsystemDelimiter & variables.framework.defaultSection & '.' & variables.framework.defaultItem;
1819 } else {
1820 variables.framework.home = variables.framework.defaultSection & '.' & variables.framework.defaultItem;
1821 }
1822 }
1823 if ( !structKeyExists(variables.framework, 'error') ) {
1824 if (usingSubsystems()) {
1825 variables.framework.error = variables.framework.defaultSubsystem & variables.framework.subsystemDelimiter & variables.framework.defaultSection & '.error';
1826 } else {
1827 variables.framework.error = variables.framework.defaultSection & '.error';
1828 }
1829 }
1830 if ( !structKeyExists(variables.framework, 'reload') ) {
1831 variables.framework.reload = 'reload';
1832 }
1833 if ( !structKeyExists(variables.framework, 'password') ) {
1834 variables.framework.password = 'true';
1835 }
1836 if ( !structKeyExists(variables.framework, 'reloadApplicationOnEveryRequest') ) {
1837 variables.framework.reloadApplicationOnEveryRequest = false;
1838 }
1839 if ( !structKeyExists(variables.framework, 'preserveKeyURLKey') ) {
1840 variables.framework.preserveKeyURLKey = 'fw1pk';
1841 }
1842 if ( !structKeyExists(variables.framework, 'maxNumContextsPreserved') ) {
1843 variables.framework.maxNumContextsPreserved = 10;
1844 }
1845 if ( !structKeyExists(variables.framework, 'baseURL') ) {
1846 variables.framework.baseURL = 'useCgiScriptName';
1847 }
1848 if ( !structKeyExists(variables.framework, 'generateSES') ) {
1849 variables.framework.generateSES = false;
1850 }
1851 if ( !structKeyExists(variables.framework, 'SESOmitIndex') ) {
1852 variables.framework.SESOmitIndex = false;
1853 }
1854 // NOTE: unhandledExtensions is a list of file extensions that are not handled by FW/1
1855 if ( !structKeyExists(variables.framework, 'unhandledExtensions') ) {
1856 variables.framework.unhandledExtensions = 'cfc';
1857 }
1858 // NOTE: you can provide a comma delimited list of paths. Since comma is the delim, it can not be part of your path URL to exclude
1859 if ( !structKeyExists(variables.framework, 'unhandledPaths') ) {
1860 variables.framework.unhandledPaths = '/flex2gateway';
1861 }
1862 if ( !structKeyExists( variables.framework, 'unhandledErrorCaught' ) ) {
1863 variables.framework.unhandledErrorCaught = false;
1864 }
1865 // convert unhandledPaths to regex:
1866 variables.framework.unhandledPathRegex = replaceNoCase(
1867 REReplace( variables.framework.unhandledPaths, '(\+|\*|\?|\.|\[|\^|\$|\(|\)|\{|\||\\)', '\\\1', 'all' ),
1868 ',', '|', 'all' );
1869 if ( !structKeyExists(variables.framework, 'applicationKey') ) {
1870 variables.framework.applicationKey = 'org.corfield.framework';
1871 }
1872 if ( !structKeyExists( variables.framework, 'suppressImplicitService' ) ) {
1873 variables.framework.suppressImplicitService = true;
1874 }
1875 if ( !structKeyExists( variables.framework, 'cacheFileExists' ) ) {
1876 variables.framework.cacheFileExists = false;
1877 }
1878 if ( !structKeyExists( variables.framework, 'routes' ) ) {
1879 variables.framework.routes = [ ];
1880 }
1881 if ( !structKeyExists( variables.framework, 'noLowerCase' ) ) {
1882 variables.framework.noLowerCase = false;
1883 }
1884 if ( !structKeyExists( variables.framework, 'subsystems' ) ) {
1885 variables.framework.subsystems = { };
1886 }
1887 if ( !structKeyExists( variables.framework, 'trace' ) ) {
1888 variables.framework.trace = false;
1889 }
1890 variables.framework.version = '2.2_snapshot';
1891 setupFrameworkEnvironments();
1892 }
1893
1894 private void function setupFrameworkEnvironments() {
1895 var env = getEnvironment();
1896 if ( structKeyExists( variables.framework, 'environments' ) ) {
1897 var envs = variables.framework.environments;
1898 var tier = listFirst( env, '-' );
1899 if ( structKeyExists( envs, tier ) ) {
1900 structAppend( variables.framework, envs[ tier ] );
1901 }
1902 if ( structKeyExists( envs, env ) ) {
1903 structAppend( variables.framework, envs[ env ] );
1904 }
1905 }
1906 setupEnvironment( env );
1907 }
1908
1909 private void function setupRequestDefaults() {
1910 if ( !request._fw1.requestDefaultsInitialized ) {
1911 var pathInfo = variables.cgiPathInfo;
1912 request.base = variables.framework.base;
1913 request.cfcbase = variables.framework.cfcbase;
1914
1915 if ( !structKeyExists(request, 'context') ) {
1916 request.context = { };
1917 }
1918 // SES URLs by popular request :)
1919 if ( len( pathInfo ) > len( variables.cgiScriptName ) && left( pathInfo, len( variables.cgiScriptName ) ) == variables.cgiScriptName ) {
1920 // canonicalize for IIS:
1921 pathInfo = right( pathInfo, len( pathInfo ) - len( variables.cgiScriptName ) );
1922 } else if ( len( pathInfo ) > 0 && pathInfo == left( variables.cgiScriptName, len( pathInfo ) ) ) {
1923 // pathInfo is bogus so ignore it:
1924 pathInfo = '';
1925 }
1926 pathInfo = processRoutes( pathInfo );
1927 try {
1928 // we use .split() to handle empty items in pathInfo - we fallback to listToArray() on
1929 // any system that doesn't support .split() just in case (empty items won't work there!)
1930 if ( len( pathInfo ) > 1 ) {
1931 // Strip leading "/" if present.
1932 if ( left( pathInfo, 1 ) EQ '/' ) {
1933 pathInfo = right( pathInfo, len( pathInfo ) - 1 );
1934 }
1935 pathInfo = pathInfo.split( '/' );
1936 } else {
1937 pathInfo = arrayNew( 1 );
1938 }
1939 } catch ( any exception ) {
1940 pathInfo = listToArray( pathInfo, '/' );
1941 }
1942 var sesN = arrayLen( pathInfo );
1943 if ( ( sesN > 0 || variables.framework.generateSES ) && getBaseURL() != 'useRequestURI' ) {
1944 request._fw1.generateSES = true;
1945 }
1946 for ( var sesIx = 1; sesIx <= sesN; sesIx = sesIx + 1 ) {
1947 if ( sesIx == 1 ) {
1948 request.context[variables.framework.action] = pathInfo[sesIx];
1949 } else if ( sesIx == 2 ) {
1950 request.context[variables.framework.action] = pathInfo[sesIx-1] & '.' & pathInfo[sesIx];
1951 } else if ( sesIx mod 2 == 1 ) {
1952 request.context[ pathInfo[sesIx] ] = '';
1953 } else {
1954 request.context[ pathInfo[sesIx-1] ] = pathInfo[sesIx];
1955 }
1956 }
1957 // certain remote calls do not have URL or form scope:
1958 if ( isDefined('URL') ) structAppend(request.context,URL);
1959 if ( isDefined('form') ) structAppend(request.context,form);
1960 // figure out the request action before restoring flash context:
1961 if ( !structKeyExists(request.context, variables.framework.action) ) {
1962 request.context[variables.framework.action] = variables.framework.home;
1963 } else {
1964 request.context[variables.framework.action] = getFullyQualifiedAction( request.context[variables.framework.action] );
1965 }
1966 if ( variables.framework.noLowerCase ) {
1967 request.action = validateAction( request.context[variables.framework.action] );
1968 } else {
1969 request.action = validateAction( lCase(request.context[variables.framework.action]) );
1970 }
1971 request._fw1.requestDefaultsInitialized = true;
1972 }
1973 }
1974
1975 private void function setupRequestWrapper( boolean runSetup ) {
1976
1977 request.subsystem = getSubsystem( request.action );
1978 request.subsystembase = request.base & getSubsystemDirPrefix( request.subsystem );
1979 request.section = getSection( request.action );
1980 request.item = getItem( request.action );
1981
1982 if ( runSetup ) {
1983 rc = request.context;
1984 if ( usingSubsystems() ) {
1985 controller( variables.magicApplicationSubsystem & variables.framework.subsystemDelimiter &
1986 variables.magicApplicationController & '.' & variables.magicApplicationAction );
1987 } else {
1988 controller( variables.magicApplicationController & '.' & variables.magicApplicationAction );
1989 }
1990 setupSubsystemWrapper( request.subsystem );
1991 frameworkTrace( 'setupRequest() called' );
1992 setupRequest();
1993 }
1994
1995 controller( request.action );
1996 if ( !variables.framework.suppressImplicitService ) {
1997 service( request.action, getServiceKey( request.action ), { }, false );
1998 }
1999 }
2000
2001 private void function setupResponseWrapper() {
2002 frameworkTrace( 'setupResponse() called' );
2003 setupResponse();
2004 }
2005
2006 private void function setupSessionWrapper() {
2007 frameworkTrace( 'setupSession() called' );
2008 setupSession();
2009 }
2010
2011 private void function setupSubsystemWrapper( string subsystem ) {
2012 if ( !usingSubsystems() ) return;
2013 lock name="fw1_#application.applicationName#_#variables.framework.applicationKey#_subsysteminit_#subsystem#" type="exclusive" timeout="30" {
2014 if ( !isSubsystemInitialized( subsystem ) ) {
2015 application[ variables.framework.applicationKey ].subsystems[ subsystem ] = now();
2016 frameworkTrace( 'setupSubsystem() called', subsystem );
2017 setupSubsystem( subsystem );
2018 }
2019 }
2020 }
2021
2022 private string function validateAction( string action ) {
2023 // check for forward and backward slash in the action - using chr() to avoid confusing TextMate (Hi Nathan!)
2024 if ( findOneOf( chr(47) & chr(92), action ) > 0 ) {
2025 raiseException( type='FW1.actionContainsSlash', message="Found a slash in the action: '#action#'.",
2026 detail='Actions are not allowed to embed sub-directory paths.');
2027 }
2028 return action;
2029 }
2030
2031 private void function viewNotFound() {
2032 raiseException( type='FW1.viewNotFound', message="Unable to find a view for '#request.action#' action.",
2033 detail="'#request.missingView#' does not exist." );
2034 }
2035
2036}