Sorcerer's IsleCode QueryParam Scanner / files

     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}