Sorcerer's IsleCode QueryParam Scanner / files

     1<!---
     2Copyright 2006-2007 TeraTech, Inc. http://teratech.com/
     3
     4Licensed under the Apache License, Version 2.0 (the "License");
     5you may not use this file except in compliance with the License.
     6You may obtain a copy of the License at
     7
     8http://www.apache.org/licenses/LICENSE-2.0
     9
    10Unless required by applicable law or agreed to in writing, software
    11distributed under the License is distributed on an "AS IS" BASIS,
    12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13See the License for the specific language governing permissions and
    14limitations under the License.
    15--->
    16<cfcomponent output="false" hint="I represent a circuit.">
    17	
    18	<cffunction name="init" returntype="fuseboxCircuit" access="public" output="false" 
    19				hint="I am the constructor.">
    20		<cfargument name="fbApp" type="fuseboxApplication" required="true" 
    21					hint="I am the fusebox application object." />
    22		<cfargument name="alias" type="string" required="true" 
    23					hint="I am the circuit alias." />
    24		<cfargument name="path" type="string" required="true" 
    25					hint="I am the path from the application root to the circuit directory." />
    26		<cfargument name="parent" type="string" required="true" 
    27					hint="I am the alias of the parent circuit." />
    28		<cfargument name="myFusebox" type="myFusebox" required="true" 
    29					hint="I am the myFusebox data structure." />
    30		<cfargument name="relative" type="boolean" required="true" 
    31					hint="I indicate whether the path is relative or absolute (mapped)." />
    32		
    33		<cfset variables.fuseboxApplication = arguments.fbApp />
    34		<cfset variables.alias = arguments.alias />
    35		<cfset variables.relative = arguments.relative />
    36
    37		<cfset variables.fuseboxLexicon = variables.fuseboxApplication.getFuseactionFactory().getBuiltinLexicon() />
    38				
    39		<cfset variables.customAttributes = structNew() />
    40		
    41		<cfset variables.originalPath = arguments.path />
    42		<cfset this.parent = arguments.parent />
    43		<cfset variables.appPath = variables.fuseboxApplication.getApplicationRoot() />
    44		<cfset variables.lexicons = structNew() />
    45		
    46		<cfset variables.relativePath = variables.fuseboxApplication.normalizePartialPath(arguments.path) />
    47		<cfset this.path = variables.relativePath />
    48		<!--- ticket 139: allow absolute path names and mappings: --->
    49		<cfif left(variables.relativePath,1) is "/">
    50			<cfif variables.relative>
    51				<!--- unintentional absolute path? --->
    52				<cfif variables.fuseboxApplication.strictMode>
    53					<cfthrow type="fusebox.badGrammar.illegalPath"
    54							message="Circuit path is not relative"
    55							detail="The 'path' value '#variables.originalPath#' for circuit #getAlias()# specifies an absolute path. Did you forget to specify 'relative=""false""'?" />
    56				</cfif>
    57				<cfset variables.fullPath = variables.appPath & variables.relativePath />
    58			<cfelse>
    59				<!--- explicit absolute / mapped path: --->
    60				<cfset variables.fullPath = replace(expandPath(variables.relativePath),"\","/","all") />
    61			</cfif>
    62		<cfelse>
    63			<cfif variables.relative>
    64				<cfset variables.fullPath = variables.appPath & variables.relativePath />
    65			<cfelse>
    66				<cfthrow type="fusebox.badGrammar.illegalPath"
    67						message="Circuit path is relative"
    68						detail="The 'path' value '#variables.originalPath#' for circuit #getAlias()# should specify an absolute path when 'relative=""false""'." />
    69			</cfif>
    70		</cfif>
    71		
    72		<cfset variables.fullPath = variables.fuseboxApplication.getCanonicalPath(variables.fullPath) />
    73
    74		<!---
    75			this was not correctly normalized prior to ticket 139 but it didn't really matter
    76			until absolute paths were allowed in that ticket:
    77		--->
    78		<cfset variables.relativePath = variables.fuseboxApplication.relativePath(variables.appPath,variables.fullPath) />
    79		<cfset this.rootPath = variables.fuseboxApplication.relativePath(variables.fullPath,variables.appPath) />
    80
    81		<cfset reload(arguments.myFusebox) />
    82				
    83		<cfreturn this />
    84
    85	</cffunction>
    86	
    87	<cffunction name="reload" returntype="fuseboxCircuit" access="public" output="false" 
    88				hint="I reload the circuit file and build the in-memory structures from it.">
    89		<cfargument name="myFusebox" type="myFusebox" required="true" 
    90					hint="I am the myFusebox data structure." />
    91
    92		<cfset var circuitFile = "circuit.xml.cfm" />
    93		<cfset var circuitFileAlt = "circuit.xml" />
    94		<cfset var circuitImplicit = false />
    95		<cfset var circuitXML = "" />
    96		<cfset var circuitCode = "" />
    97		<cfset var needToLoad = true />
    98		<cfset var circuitFiles = 0 />
    99
   100		<!---
   101			since we need to check the file, regardless of whether we load it,
   102			we might as well do the test up front and perform the strict check
   103			that just one version exists (ticket 135)
   104		--->
   105		<cfif fileExists(variables.fullPath & circuitFile)>
   106			<cfif variables.fuseboxApplication.strictMode and fileExists(variables.fullPath & circuitFileAlt)>
   107				<cfthrow type="fusebox.multipleCircuitXML" 
   108						message="Both 'circuit.xml' and 'circuit.xml.cfm' exist" 
   109						detail="'circuit.xml.cfm' will be used but 'circuit.xml' also exists in '#variables.fullPath#." />
   110			</cfif>
   111		<cfelse>
   112			<cfset circuitFile = circuitFileAlt />
   113		</cfif>
   114
   115		<cfif structKeyExists(this,"timestamp")>
   116			<!--- Java timestamp solution provided by Daniel Schmid --->
   117			<cfset needToLoad = getApplication().fileModificationDate(variables.fullPath & circuitFile) gt parseDateTime(this.timestamp) />
   118		</cfif>
   119
   120		<cfif needToLoad>
   121			<cfif variables.fuseboxApplication.debug>
   122				<cfset arguments.myFusebox.trace("Compiler","Loading #getAlias()# circuit.xml file") />
   123			</cfif>
   124
   125			<!--- attempt to load circuit.xml(.cfm): --->
   126			<cftry>
   127				
   128				<cffile action="read" file="#variables.fullPath##circuitFile#"
   129						variable="circuitXML"
   130						charset="#variables.fuseboxApplication.characterEncoding#" />
   131				<cfset variables.circuitPath = variables.fullPath & circuitFile />
   132
   133				<cfcatch type="security">
   134					<!--- cffile denied by sandbox security --->
   135					<cfthrow type="fusebox.security" 
   136							message="security error reading circuit.xml" 
   137							detail="The circuit xml file, '#circuitFile#', for circuit #getAlias()# could not be read because sandbox security has disabled the cffile tag."
   138							extendedinfo="#cfcatch.detail#" />
   139				</cfcatch>				
   140
   141				<cfcatch type="any">
   142					<cfif variables.fuseboxApplication.allowImplicitCircuits>
   143						<cfset circuitXML = "<circuit/>" />
   144						<cfset circuitImplicit = true />
   145					<cfelse>
   146						<cfthrow type="fusebox.missingCircuitXML" 
   147								message="missing circuit.xml" 
   148								detail="The circuit xml file, #circuitFile#, for circuit #getAlias()# could not be found in #variables.fullPath#."
   149								extendedinfo="#cfcatch.detail#" />
   150					</cfif>
   151				</cfcatch>
   152				
   153			</cftry>
   154<!--- 		
   155			this was initially implemented as part of ticket 135 but feedback on
   156			the mailing list seems to indicate people think it is too draconian
   157			a restriction, even in strict mode - and I agree! -- Sean Corfield
   158			
   159			<cfif variables.fuseboxApplication.strictMode and not circuitImplicit and
   160					variables.fuseboxApplication.getFuseboxFileExtension() is not listLast(circuitFile,".")>
   161				<cfthrow type="fusebox.inconsistentFuseboxCircuit"
   162						message="Inconsistent Fusebox / Circuit file extensions" 
   163						detail="The circuit xml file, #circuitFile#, in #variables.fullPath#, uses a different file extension to the application's fusebox xml file. Strict requires consistency." />
   164			</cfif>
   165 --->			
   166			<cftry>
   167				
   168				<cfset circuitCode = xmlParse(circuitXML) />
   169				
   170				<cfcatch type="any">
   171					<cfthrow type="fusebox.circuitXMLError" 
   172							message="Error reading circuit.xml" 
   173							detail="A problem was encountered while reading the circuit file #circuitFile# for circuit #getAlias()#. This is usually caused by unmatched XML tag-pairs. Close all XML tags explicitly or use the / (slash) short-cut."
   174							extendedinfo="#cfcatch.detail#" />
   175				</cfcatch>
   176				
   177			</cftry>
   178	
   179			<cfif circuitCode.xmlRoot.xmlName is not "circuit">
   180				<cfthrow type="fusebox.badGrammar.badCircuitFile"
   181						detail="Circuit file does contain 'circuit' XML" 
   182						message="Circuit file #variables.circuitPath# does not contain 'circuit' as the root XML node." />
   183			</cfif>
   184			<cfif structKeyExists(circuitCode.xmlRoot.xmlAttributes,"access")>
   185				<cfif listFind("private,internal,public",circuitCode.xmlRoot.xmlAttributes.access) eq 0>
   186					<cfthrow type="fusebox.badGrammar.illegalAccess"
   187							message="Circuit access illegal"
   188							detail="The 'access' value '#circuitCode.xmlRoot.xmlAttributes.access#' is illegal in Circuit #getAlias()#. 'private', 'internal' or 'public' are the only legal values." />
   189				</cfif>
   190				<cfset this.access = circuitCode.xmlRoot.xmlAttributes.access />
   191			<cfelse>
   192				<cfset this.access = "internal" />
   193			</cfif>
   194			<cfif structKeyExists(circuitCode.xmlRoot.xmlAttributes,"permissions")>
   195				<cfset this.permissions = circuitCode.xmlRoot.xmlAttributes.permissions />
   196			<cfelse>
   197				<cfset this.permissions = "" />
   198			</cfif>
   199	
   200			<cfset loadLexicons(circuitCode) />		
   201			<cfset loadPreAndPostFuseactions(circuitCode) />
   202			<cfset loadFuseactions(circuitCode) />
   203			<cfset variables.circuitFile = circuitFile />
   204			<cfset this.timestamp = now() />
   205		</cfif>
   206		
   207		<cfreturn this />
   208		
   209	</cffunction>
   210
   211	<cffunction name="compile" returntype="void" access="public" output="false" 
   212				hint="I compile a given fuseaction within this circuit.">
   213		<cfargument name="writer" type="any" required="false" 
   214					hint="I am the parsed file writer object. I am required but it's faster to specify that I am not required." />
   215		<cfargument name="fuseaction" type="any" required="false" 
   216					hint="I am the name of the fuseaction to compile. I am required but it's faster to specify that I am not required." />
   217	
   218		<cfset var f = arguments.writer.setFuseaction(arguments.fuseaction) />
   219
   220		<cfset compilePreOrPostFuseaction(arguments.writer,"pre") />
   221		
   222		<cfif not structKeyExists(this.fuseactions,arguments.fuseaction)>
   223			<cfthrow type="fusebox.undefinedFuseaction" 
   224					message="undefined Fuseaction" 
   225					detail="You specified a Fuseaction of #arguments.fuseaction# which is not defined in Circuit #getAlias()#." />
   226		</cfif>
   227		<cfset this.fuseactions[arguments.fuseaction].compile(arguments.writer) />
   228		
   229		<cfset compilePreOrPostFuseaction(arguments.writer,"post") />
   230
   231		<cfset arguments.writer.setFuseaction(f) />
   232		
   233	</cffunction>
   234	
   235	<cffunction name="compilePreOrPostFuseaction" returntype="void" access="public" output="false" 
   236				hint="I compile the pre/post-fuseaction for a circuit.">
   237		<cfargument name="writer" type="any" required="false" 
   238					hint="I am the parsed file writer object. I am required but it's faster to specify that I am not required." />
   239		<cfargument name="preOrPost" type="string" required="false" 
   240					hint="I am either 'pre' or 'post' to indicate whether this is a prefuseaction or a postfuseaction. I am required but it's faster to specify that I am not required." />
   241	
   242		<cfset var c = "" />
   243
   244		<cfif variables.hasAction[arguments.preOrPost]>
   245			<cfif arguments.preOrPost is "pre" and variables.callsuper["pre"] and hasParent()>
   246				<cfset getParent().compilePreOrPostFuseaction(arguments.writer,arguments.preOrPost) />
   247			</cfif>
   248			<cfset c = arguments.writer.setCircuit(getAlias()) />
   249			<cfset variables.action[arguments.preOrPost].compile(arguments.writer) />
   250			<cfset arguments.writer.setCircuit(c) />
   251			<cfif arguments.preOrPost is "post" and variables.callsuper["post"] and hasParent()>
   252				<cfset getParent().compilePreOrPostFuseaction(arguments.writer,arguments.preOrPost) />
   253			</cfif>
   254		</cfif>
   255	
   256	</cffunction>
   257	
   258	<cffunction name="buildCircuitTrace" returntype="void" access="public" output="false" 
   259				hint="I build the 'circuit trace' structure - the array of parents. Required for Fusebox 4.1 compatibility.">
   260	
   261		<cfset var c = getParentName() />
   262		<cfset var seen = structNew() />
   263		
   264		<cfset seen[getAlias()] = true />
   265		<cfset this.circuitTrace = arrayNew(1) />
   266		<cfset arrayAppend(this.circuitTrace,getAlias()) />
   267		<cfloop condition="c is not ''">
   268			<cfif structKeyExists(seen,c)>
   269				<cfthrow type="fusebox.badGrammar.circularParent" 
   270						message="Circular parent for Circuit" 
   271						detail="You specified a parent Circuit of #c# (for Circuit #getAlias()#) which creates a circular dependency." />
   272			</cfif>
   273			<cfset seen[c] = true />
   274			<cfif not structKeyExists(variables.fuseboxApplication.circuits,c)>
   275				<cfthrow type="fusebox.undefinedCircuit" 
   276						message="undefined Circuit" 
   277						detail="You specified a parent Circuit of #c# (for Circuit #getAlias()#) which is not defined." />
   278			</cfif>
   279			<cfset arrayAppend(this.circuitTrace,c) />
   280			<cfset c = variables.fuseboxApplication.circuits[c].getParentName() />
   281		</cfloop>
   282		
   283	</cffunction>
   284	
   285	<cffunction name="getOriginalPath" returntype="string" access="public" output="false" 
   286				hint="I return the original relative path specified in the circuit declaration.">
   287	
   288		<cfreturn variables.originalPath />
   289	
   290	</cffunction>
   291	
   292	<cffunction name="getCircuitRoot" returntype="string" access="public" output="false" 
   293				hint="I return the full file system path to the circuit directory.">
   294	
   295		<cfreturn variables.fullPath />
   296	
   297	</cffunction>
   298
   299	<cffunction name="getCircuitXMLFilename" returntype="string" access="public" output="false" 
   300				hint="I return the actual name of the circuit XML file: circuit.xml or circuit.xml.cfm.">
   301	
   302		<cfreturn variables.circuitFile />
   303	
   304	</cffunction>
   305
   306	<cffunction name="getOriginalPathIsRelative" returntype="string" access="public" output="false" 
   307				hint="I return true if this circuit's declaration used a relative path.">
   308	
   309		<cfreturn variables.relative />
   310	
   311	</cffunction>
   312
   313	<cffunction name="getParentName" returntype="string" access="public" output="false" 
   314				hint="I return the name (alias) of this circuit's parent.">
   315	
   316		<cfreturn this.parent />
   317	
   318	</cffunction>
   319
   320	<cffunction name="hasParent" returntype="boolean" access="public" output="false" 
   321				hint="I return true if this circuit has a parent, otherwise I return false.">
   322	
   323		<cfreturn getParentName() is not "" />
   324	
   325	</cffunction>
   326
   327	<cffunction name="getParent" returntype="any" access="public" output="false" 
   328				hint="I return this circuit's parent circuit object. I throw an exception if hasParent() returns false.">
   329	
   330		<!---
   331			note that this will throw an exception if the circuit has no parent
   332			code should call hasParent() first
   333		--->
   334		<cfreturn variables.fuseboxApplication.circuits[getParentName()] />
   335	
   336	</cffunction>
   337
   338	<cffunction name="getPermissions" returntype="string" access="public" output="false" 
   339				hint="I return the aggregated permissions for this circuit.">
   340		<cfargument name="useCircuitTrace" type="boolean" default="false" 
   341					hint="I indicate whether or not to inherit the parent circuit's permissions if this circuit has no permissions specified." />
   342	
   343		<cfif this.permissions is "" and arguments.useCircuitTrace and hasParent()>
   344			<cfreturn getParent().getPermissions(arguments.useCircuitTrace) />
   345		<cfelse>
   346			<cfreturn this.permissions />
   347		</cfif>
   348	
   349	</cffunction>
   350	
   351	<cffunction name="getRelativePath" returntype="string" access="public" output="false" 
   352				hint="I return the normalized relative path from the application root to this circuit's directory.">
   353	
   354		<cfreturn variables.relativePath />
   355	
   356	</cffunction>
   357	
   358	<cffunction name="getFuseactions" returntype="struct" access="public" output="false" 
   359				hint="I return the structure containing the definitions of the fuseactions within this circuit.">
   360		
   361		<cfreturn this.fuseactions /> 
   362		
   363	</cffunction>
   364	
   365	<cffunction name="getLexiconDefinition" returntype="any" access="public" output="false" 
   366				hint="I return the definition of the specified lexicon.">
   367		<cfargument name="namespace" type="any" required="false" 
   368					hint="I am the namespace whose lexicon is to be retrieved. I am required but it's faster to specify that I am not required." />
   369		
   370		<cfif arguments.namespace is variables.fuseboxLexicon.namespace>
   371			<cfreturn variables.fuseboxLexicon />
   372		<cfelse>
   373			<cfreturn variables.lexicons[arguments.namespace] />
   374		</cfif>
   375
   376	</cffunction>
   377	
   378	<cffunction name="getAccess" returntype="any" access="public" output="false" 
   379				hint="I return the access specified for this circuit.">
   380	
   381		<cfreturn this.access />
   382	
   383	</cffunction>
   384	
   385	<cffunction name="getAlias" returntype="any" access="public" output="false" 
   386				hint="I return the circuit alias.">
   387	
   388		<cfreturn variables.alias />
   389	
   390	</cffunction>
   391	
   392	<cffunction name="getApplication" returntype="any" access="public" output="false" 
   393				hint="I return the fusebox application object.">
   394	
   395		<cfreturn variables.fuseboxApplication />
   396	
   397	</cffunction>
   398	
   399	<cffunction name="getCustomAttributes" returntype="struct" access="public" output="false" 
   400				hint="I return any custom attributes for the specified namespace prefix.">
   401		<cfargument name="ns" type="string" required="true" 
   402					hint="I am the namespace for which to return custom attributes." />
   403		
   404		<cfif structKeyExists(variables.customAttributes,arguments.ns)>
   405			<!--- we structCopy() this so folks can't poke values back into the metadata! --->
   406			<cfreturn structCopy(variables.customAttributes[arguments.ns]) />
   407		<cfelse>
   408			<cfreturn structNew() />
   409		</cfif>
   410		
   411	</cffunction>
   412	
   413	<cffunction name="loadLexicons" returntype="void" access="private" output="false" 
   414				hint="I load the lexicon definitions and custom attributes out of the namespace declarations in the circuit tag.">
   415		<cfargument name="circuitCode" type="any" required="true" 
   416					hint="I am the XML representation of the circuit file." />
   417		
   418		<cfset var attributes = circuitCode.xmlRoot.xmlAttributes />
   419		<cfset var attr = "" />
   420		<cfset var aLex = "" />
   421		<cfset var ns = "" />
   422		<cfset var strict = variables.fuseboxApplication.strictMode />
   423		
   424		<!--- pass 1: pull out any namespace declarations --->
   425		<cfloop collection="#attributes#" item="attr">
   426			<cfif len(attr) gt 6 and left(attr,6) is "xmlns:">
   427				<!--- found a namespace declaration, pull it out: --->
   428				<cfset aLex = structNew() />
   429				<cfset aLex.namespace = listLast(attr,":") />
   430				<cfif aLex.namespace is variables.fuseboxLexicon.namespace>
   431					<cfthrow type="fusebox.badGrammar.reservedName"
   432							message="Attempt to use reserved namespace" 
   433							detail="You have attempted to declare a namespace '#aLex.namespace#' (in Circuit #getAlias()#) which is reserved by the Fusebox framework." />
   434				</cfif>
   435				<cfset attributes[attr] = variables.fuseboxApplication.normalizePartialPath(attributes[attr]) />
   436				<cfif left(attributes[attr],1) is "/">
   437					<!--- assume mapped / root-relative path --->
   438					<cfset aLex.path = attributes[attr] />
   439				<cfelseif left(variables.fuseboxApplication.lexiconPath,1) is "/">
   440					<!--- assume mapped / root-relative path --->
   441					<cfset aLex.path = variables.fuseboxApplication.lexiconPath & attributes[attr] />
   442				<cfelse>
   443					<!--- relative paths --->
   444					<cfset aLex.path = variables.fuseboxApplication.getCoreToAppRootPath() & 
   445							variables.fuseboxApplication.lexiconPath & attributes[attr] />
   446				</cfif>
   447				<cfset variables.lexicons[aLex.namespace] = aLex />
   448				<cfset variables.customAttributes[aLex.namespace] = structNew() />
   449			</cfif>
   450		</cfloop>
   451		
   452		<!--- pass 2: pull out any custom attributes --->
   453		<cfloop collection="#attributes#" item="attr">
   454			<cfif listLen(attr,":") eq 2>
   455				<!--- looks like a custom attribute: --->
   456				<cfset ns = listFirst(attr,":") />
   457				<cfif ns is "xmlns">
   458					<!--- special case - need to ignore xmlns:foo="bar" --->
   459				<cfelseif structKeyExists(variables.customAttributes,ns)>
   460					<cfset variables.customAttributes[ns][listLast(attr,":")] = attributes[attr] />
   461				<cfelse>
   462					<cfthrow type="fusebox.badGrammar.undeclaredNamespace" 
   463							message="Undeclared lexicon namespace" 
   464							detail="The lexicon prefix '#ns#' was found on a custom attribute in the <circuit> tag of Circuit #getAlias()# but no such lexicon namespace has been declared." />
   465				</cfif>
   466			<cfelseif strict and listFind("access,permissions",attr) eq 0>
   467				<cfthrow type="fusebox.badGrammar.unexpectedAttributes"
   468						message="Unexpected attributes"
   469						detail="Unexpected attributes were found in the 'circuit' tag of the '#getAlias()#' circuit.xml file." />
   470			</cfif>
   471		</cfloop>
   472				
   473	</cffunction>
   474	
   475	<cffunction name="loadPreAndPostFuseactions" returntype="void" access="private" output="false" 
   476				hint="I load the prefuseaction and postfuseaction definitions from the circuit file.">
   477		<cfargument name="circuitCode" type="any" required="true" 
   478					hint="I am the XML representation of the circuit file." />
   479		
   480		<cfset variables.hasAction = structNew() />
   481		<cfset variables.action = structNew() />
   482		<cfset variables.callsuper = structNew() />
   483		<cfset loadPrePostFuseaction(arguments.circuitCode,"pre") />
   484		<cfset loadPrePostFuseaction(arguments.circuitCode,"post") />
   485				
   486	</cffunction>
   487	
   488	<cffunction name="loadPrePostFuseaction" returntype="void" access="private" output="false" 
   489				hint="I load the either a prefuseaction or a postfuseaction definition from the circuit file.">
   490		<cfargument name="circuitCode" type="any" required="true" 
   491					hint="I am the XML representation of the circuit file." />
   492		<cfargument name="prePost" type="string" required="true" 
   493					hint="I specify whether to load a 'pre'fuseaction or a 'post'fuseaction." />
   494		
   495		<cfset var children = xmlSearch(arguments.circuitCode,"/circuit/#arguments.prePost#fuseaction") />
   496		<cfset var i = 0 />
   497		<cfset var n = arrayLen(children) />
   498		<cfset var nAttrs = 0 />
   499		
   500		<cfif n eq 0>
   501			<cfset variables.hasAction[arguments.prePost] = false />
   502		<cfelseif n eq 1>
   503			<cfset variables.hasAction[arguments.prePost] = true />
   504			<cfif structKeyExists(children[1].xmlAttributes,"callsuper")>
   505				<cfif listFind("true,false,yes,no",children[1].xmlAttributes.callsuper) eq 0>
   506					<cfthrow type="fusebox.badGrammar.invalidAttributeValue"
   507							message="Attribute has invalid value" 
   508							detail="The attribute 'callsuper' must either be ""true"" or ""false"", for a '#arguments.prePost#fuseaction' in Circuit #getAlias()#." />
   509				</cfif>
   510				<cfset nAttrs = 1 />
   511				<cfset variables.callsuper[arguments.prePost] = children[1].xmlAttributes.callsuper />
   512			<cfelse>
   513				<cfset variables.callsuper[arguments.prePost] = false />
   514			</cfif>
   515			<cfif variables.fuseboxApplication.strictMode and structCount(children[1].xmlAttributes) neq nAttrs>
   516				<cfthrow type="fusebox.badGrammar.unexpectedAttributes"
   517						message="Unexpected attributes"
   518						detail="Unexpected attributes found on '#arguments.prePost#fuseaction' in Circuit #getAlias()#." />
   519			</cfif>
   520			<cfset variables.action[arguments.prePost] =
   521					createObject("component","fuseboxAction")
   522						.init(this,
   523							"$#arguments.prePost#fuseaction",
   524								"internal",
   525									children[1].xmlChildren) />
   526		<cfelse>
   527			<cfthrow type="fusebox.badGrammar.nonUniqueDeclaration" 
   528					message="Declaration was not unique" 
   529					detail="More than one &lt;#arguments.prePost#fuseaction&gt; declaration was found in Circuit #getAlias()#." />
   530		</cfif>
   531		
   532	</cffunction>
   533	
   534	<cffunction name="loadFuseactions" returntype="void" access="private" output="false" 
   535				hint="I load all of the fuseaction definitions from the circuit file.">
   536		<cfargument name="circuitCode" type="any" required="true" 
   537					hint="I am the XML representation of the circuit file." />
   538		
   539		<cfset var children = xmlSearch(arguments.circuitCode,"/circuit/fuseaction") />
   540		<cfset var i = 0 />
   541		<cfset var n = arrayLen(children) />
   542		<cfset var attribs = 0 />
   543		<cfset var attr = "" />
   544		<cfset var ns = "" />
   545		<cfset var customAttribs = 0 />
   546		<cfset var access = "" />
   547		<cfset var permissions = "" />
   548		<cfset var strict = variables.fuseboxApplication.strictMode />
   549		
   550		<cfset this.fuseactions = structNew() />
   551		<cfloop from="1" to="#n#" index="i">
   552			<!--- default fuseaction access to circuit access --->
   553			<cfset access = this.access />
   554			<!--- default fuseaction permissions to empty string --->
   555			<cfset permissions = "" />
   556			<cfset attribs = children[i].xmlAttributes />
   557			
   558			<cfif not structKeyExists(attribs,"name")>
   559				<cfthrow type="fusebox.badGrammar.requiredAttributeMissing"
   560						message="Required attribute is missing"
   561						detail="The attribute 'name' is required, for a 'fuseaction' declaration in circuit #getAlias()#." />
   562			</cfif>
   563
   564			<!--- scan for custom attributes --->
   565			<cfset customAttribs = structNew() />
   566			<cfloop collection="#attribs#" item="attr">
   567
   568				<cfswitch expression="#attr#">
   569				<cfcase value="name">
   570					<cfif structKeyExists(this.fuseactions,attribs.name)>
   571						<cfthrow type="fusebox.overloadedFuseaction" 
   572								message="overloaded Fuseaction" 
   573								detail="You referenced a fuseaction, #attribs.name#, which has been defined multiple times in circuit #getAlias()#. Fusebox does not allow overloaded methods." />
   574					</cfif>
   575				</cfcase>
   576				<cfcase value="access">
   577					<cfset access = attribs.access />
   578					<cfif listFind("private,internal,public",access) eq 0>
   579						<cfthrow type="fusebox.badGrammar.illegalAccess"
   580								message="Fuseaction access illegal"
   581								detail="The 'access' value '#access#' is illegal on Fuseaction #attribs.name# in Circuit #getAlias()#. 'private', 'internal' or 'public' are the only legal values." />
   582					</cfif>
   583				</cfcase>
   584				<cfcase value="permissions">
   585					<cfset permissions = attribs.permissions />
   586				</cfcase>
   587				<cfdefaultcase>
   588					<cfif listLen(attr,":") eq 2>
   589						<!--- looks like a custom attribute: --->
   590						<cfset ns = listFirst(attr,":") />
   591						<cfif structKeyExists(variables.customAttributes,ns)>
   592							<cfset customAttribs[ns][listLast(attr,":")] = attribs[attr] />
   593						<cfelse>
   594							<cfthrow type="fusebox.badGrammar.undeclaredNamespace" 
   595									message="Undeclared lexicon namespace" 
   596									detail="The lexicon prefix '#ns#' was found on a custom attribute in the Fuseaction #attribs.name# in Circuit #getAlias()# but no such lexicon namespace has been declared." />
   597						</cfif>
   598	
   599					<cfelseif strict>
   600						<cfthrow type="fusebox.badGrammar.unexpectedAttributes"
   601								message="Unexpected attributes"
   602								detail="Unexpected attribute '#attr#' found on Fuseaction #attribs.name# in Circuit #getAlias()#." />
   603					</cfif>
   604				</cfdefaultcase>
   605				</cfswitch>
   606			</cfloop>
   607
   608			<cfset this.fuseactions[attribs.name] =
   609					createObject("component","fuseboxAction")
   610						.init(this,attribs.name,access,children[i].xmlChildren,false,customAttribs) />
   611			<!--- FB41 security plugin compatibility: --->
   612			<cfset this.fuseactions[attribs.name].permissions = permissions />
   613		</cfloop>
   614		
   615	</cffunction>
   616	
   617</cfcomponent>