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 am the representation of the do and fuseaction verbs.">
    17	
    18	<cffunction name="init" returntype="any" access="public" output="false" 
    19				hint="I am the constructor.">
    20		<cfargument name="action" type="any" required="true" 
    21					hint="I am the enclosing fuseaction object." />
    22		<cfargument name="attributes" type="struct" required="true" 
    23					hint="I am the attributes for this verb." />
    24		<cfargument name="children" type="any" required="true" 
    25					hint="I am the XML representation of any children this verb has." />
    26		<cfargument name="verb" type="string" required="true" 
    27					hint="I am the name of this verb." />
    28					
    29		<cfset var nAttrs = 1 />
    30		
    31		<cfset variables.action = arguments.action />
    32		<cfset variables.attributes = structNew() />
    33		<cfset variables.children = arguments.children />
    34		<cfset variables.numChildren = arrayLen(variables.children) />
    35		<cfset variables.verb = arguments.verb />
    36		
    37		<!---
    38			validate the attributes:
    39			action - required
    40			append - boolean - optional
    41			prepend - boolean - optional
    42			overwrite - boolean - optional
    43			contentvariable - optional
    44		--->
    45		<cfif structKeyExists(arguments.attributes,"action")>
    46			<cfset variables.attributes.action = arguments.attributes.action />
    47		<cfelse>
    48			<cfthrow type="fusebox.badGrammar.requiredAttributeMissing"
    49					message="Required attribute is missing"
    50					detail="The attribute 'action' is required, for a '#variables.verb#' verb in fuseaction #variables.action.getCircuit().getAlias()#.#variables.action.getName()#." />
    51		</cfif>
    52		<cfif variables.verb is "fuseaction" and listLen(variables.attributes.action,".") lt 2>
    53			<!--- illegal: there is no circuit associated with a (global) action --->
    54			<cfthrow type="fusebox.badGrammar.invalidAttributeValue"
    55					message="Attribute has invalid value" 
    56					detail="The attribute 'action' must be a fully-qualified fuseaction, for a 'fuseaction' verb in a global pre/post process." />
    57		</cfif>		
    58		
    59		<cfif structKeyExists(arguments.attributes,"append")>
    60			<cfset variables.attributes.append = arguments.attributes.append />
    61			<cfset nAttrs = nAttrs + 1 />
    62			<cfif listFind("true,false,yes,no",variables.attributes.append) eq 0>
    63				<cfthrow type="fusebox.badGrammar.invalidAttributeValue"
    64						message="Attribute has invalid value"
    65						detail="The attribute 'append' must either be ""true"" or ""false"", for a '#variables.verb#' verb in fuseaction #variables.action.getCircuit().getAlias()#.#variables.action.getName()#." />
    66			</cfif>
    67			<cfif not structKeyExists(arguments.attributes,"contentvariable")>
    68				<cfthrow type="fusebox.badGrammar.requiredAttributeMissing"
    69						message="Required attribute is missing"
    70						detail="The attribute 'contentvariable' is required when the attribute 'append' is present, for a '#variables.verb#' verb in fuseaction #variables.action.getCircuit().getAlias()#.#variables.action.getName()#." />
    71			</cfif>
    72		<cfelse>
    73			<cfset variables.attributes.append = false />
    74		</cfif>
    75
    76		<cfif structKeyExists(arguments.attributes,"prepend")>
    77			<cfset variables.attributes.prepend = arguments.attributes.prepend />
    78			<cfset nAttrs = nAttrs + 1 />
    79			<cfif listFind("true,false,yes,no",variables.attributes.prepend) eq 0>
    80				<cfthrow type="fusebox.badGrammar.invalidAttributeValue"
    81						message="Attribute has invalid value"
    82						detail="The attribute 'prepend' must either be ""true"" or ""false"", for a '#variables.verb#' verb in fuseaction #variables.action.getCircuit().getAlias()#.#variables.action.getName()#." />
    83			</cfif>
    84			<cfif not structKeyExists(arguments.attributes,"contentvariable")>
    85				<cfthrow type="fusebox.badGrammar.requiredAttributeMissing"
    86						message="Required attribute is missing"
    87						detail="The attribute 'contentvariable' is required when the attribute 'append' is present, for a '#variables.verb#' verb in fuseaction #variables.action.getCircuit().getAlias()#.#variables.action.getName()#." />
    88			</cfif>
    89		<cfelse>
    90			<cfset variables.attributes.prepend = false />
    91		</cfif>
    92
    93		<cfif structKeyExists(arguments.attributes,"overwrite")>
    94			<cfset variables.attributes.overwrite = arguments.attributes.overwrite />
    95			<cfset nAttrs = nAttrs + 1 />
    96			<cfif listFind("true,false,yes,no",variables.attributes.overwrite) eq 0>
    97				<cfthrow type="fusebox.badGrammar.invalidAttributeValue"
    98						message="Attribute has invalid value"
    99						detail="The attribute 'overwrite' must either be ""true"" or ""false"", for a '#variables.verb#' verb in fuseaction #variables.action.getCircuit().getAlias()#.#variables.action.getName()#." />
   100			</cfif>
   101			<cfif not structKeyExists(arguments.attributes,"contentvariable")>
   102				<cfthrow type="fusebox.badGrammar.requiredAttributeMissing"
   103						message="Required attribute is missing"
   104						detail="The attribute 'contentvariable' is required when the attribute 'append' is present, for a '#variables.verb#' verb in fuseaction #variables.action.getCircuit().getAlias()#.#variables.action.getName()#." />
   105			</cfif>
   106		<cfelse>
   107			<cfset variables.attributes.overwrite = true />
   108		</cfif>
   109
   110		<cfif structKeyExists(arguments.attributes,"contentvariable")>
   111			<cfset variables.attributes.contentvariable = arguments.attributes.contentvariable />
   112			<cfset nAttrs = nAttrs + 1 />
   113		</cfif>
   114
   115		<cfif variables.action.getCircuit().getApplication().strictMode and structCount(arguments.attributes) neq nAttrs>
   116			<cfthrow type="fusebox.badGrammar.unexpectedAttributes"
   117					message="Unexpected attributes"
   118					detail="Unexpected attributes were found in a '#variables.verb#' verb in fuseaction #variables.action.getCircuit().getAlias()#.#variables.action.getName()#." />
   119		</cfif>
   120		
   121		<cfreturn this />
   122		
   123	</cffunction>
   124	
   125	<cffunction name="compile" returntype="void" access="public" output="false" 
   126				hint="I compile this do/fuseaction verb.">
   127		<cfargument name="writer" type="any" required="false" 
   128					hint="I am the parsed file writer object. I am required but it's faster to specify that I am not required." />
   129
   130		<cfset var i = 0 />
   131		<cfset var n = 0 />
   132		<cfset var app = variables.action.getCircuit().getApplication() />
   133		<cfset var plugins = app.pluginPhases />
   134		<cfset var c = "" />
   135		<cfset var f = "" />
   136		<cfset var cDotF = "" />
   137		<cfset var old_c = "" />
   138		<cfset var old_f = "" />
   139		<cfset var circuits = app.circuits />
   140		<cfset var needTryOnFuseaction = false />
   141
   142		<cfif listLen(variables.attributes.action,".") gte 2>
   143			<!--- action is a circuit.fuseaction pair somewhere --->
   144			<cfset f = listLast(variables.attributes.action,".") />
   145			<cfset c = left(variables.attributes.action,len(variables.attributes.action)-len(f)-1) />
   146			<cfset cDotF = variables.attributes.action />
   147		<cfelse>
   148			<cfset c = variables.action.getCircuit().getAlias() />
   149			<cfset f = variables.attributes.action />
   150			<cfset cDotF = c & "." & f />
   151		</cfif>
   152		
   153		<cfif structKeyExists(request.__fusebox.fuseactionsDone,cDotF)>
   154			<cfthrow type="fusebox.badGrammar.recursiveDo" 
   155					message="Recursive do is illegal"
   156					detail="An attempt was made to compile a fuseaction '#cDotF#' that is already being compiled, in fuseaction #variables.action.getCircuit().getAlias()#.#variables.action.getName()#." />
   157		</cfif>
   158		<cfset request.__fusebox.fuseactionsDone[cDotF] = true />
   159		
   160		<cfset arguments.writer.rawPrintln('<!--- #variables.verb# action="#variables.attributes.action#" --->') />
   161		<cfif app.debug>
   162			<cfset arguments.writer.rawPrintln('<' & 'cfset myFusebox.trace("Runtime","&lt;#variables.verb# action=""#variables.attributes.action#""/&gt;") >') />
   163		</cfif>
   164		<cfset old_c = arguments.writer.setCircuit(c) />
   165		<cfset old_f = arguments.writer.setFuseaction(f) />
   166		
   167		<cfif structKeyExists(plugins,"fuseactionException") and
   168				arrayLen(plugins["fuseactionException"]) gt 0 and
   169				not request.__fusebox.SuppressPlugins>
   170			<cfset needTryOnFuseaction = true />
   171			<cfset arguments.writer.rawPrintln("<cftry>") />
   172		</cfif>
   173		
   174		<cfif structKeyExists(plugins,"preFuseaction")>
   175			<cfset n = arrayLen(plugins["preFuseaction"]) />
   176			<cfloop from="1" to="#n#" index="i">
   177				<cfset plugins["preFuseaction"][i].compile(arguments.writer) />
   178			</cfloop>
   179		</cfif>
   180		
   181		<cfif variables.numChildren gt 0>
   182			<cfset enterStackFrame(arguments.writer) />
   183		</cfif>
   184		
   185		<cfif structKeyExists(variables.attributes,"contentvariable")>
   186			<cfif not variables.attributes.overwrite>
   187				<cfset arguments.writer.println('<cfif not isDefined("#variables.attributes.contentvariable#")>') />
   188			</cfif>
   189			<cfif variables.attributes.append or variables.attributes.prepend>
   190				<cfset arguments.writer.println('<cfparam name="#variables.attributes.contentvariable#" default="">') />
   191			</cfif>
   192			<cfset arguments.writer.println('<cfsavecontent variable="#variables.attributes.contentvariable#">') />
   193			<cfif variables.attributes.append>
   194				<cfset arguments.writer.println('<' & 'cfoutput>###variables.attributes.contentvariable###</' & 'cfoutput>') />
   195			</cfif>
   196		</cfif>
   197
   198		<cfif listLen(variables.attributes.action,".") gte 2>
   199
   200			<cfif structKeyExists(circuits,c)>
   201
   202				<cfif structKeyExists(circuits[c].fuseactions,f)>
   203
   204					<!--- if not in the same circuit, check access is not private --->
   205					<cfif c is not variables.action.getCircuit().getAlias()>
   206
   207						<cfif circuits[c].fuseactions[f].getAccess() is "private">
   208
   209							<cfthrow type="fusebox.invalidAccessModifier" 
   210									message="invalid access modifier" 
   211									detail="The fuseaction '#c#.#f#' has an access modifier of private and can only be called from within its own circuit. Use an access modifier of internal or public to make it available outside its immediate circuit.">
   212
   213						</cfif>
   214
   215					</cfif>
   216					
   217				<!--- ticket 309 - remove fuseaction check prior to compile so that implicit circuits work --->
   218				
   219				</cfif>
   220
   221			<cfelseif not variables.action.getCircuit().getApplication().allowImplicitCircuits>
   222
   223				<cfthrow type="fusebox.undefinedCircuit" 
   224						message="undefined Circuit" 
   225						detail="You specified a Circuit of #c# which is not defined." />
   226
   227			</cfif>
   228
   229			<cfset variables.action.getCircuit().getApplication().compile(arguments.writer,c,f) />
   230
   231		<cfelse>
   232
   233			<!--- action is a fuseaction in this same circuit --->
   234			<cfif not structKeyExists(variables.action.getCircuit().fuseactions,f)>
   235				<cfthrow type="fusebox.undefinedFuseaction" 
   236						message="undefined Fuseaction" 
   237						detail="You specified a Fuseaction of #f# which is not defined in Circuit #c#." />
   238			</cfif>
   239
   240			<cfset variables.action.getCircuit().compile(arguments.writer,f) />
   241
   242		</cfif>
   243		
   244		<cfif structKeyExists(variables.attributes,"contentvariable")>
   245			<cfif variables.attributes.prepend>
   246				<cfset arguments.writer.println('<' & 'cfoutput>###variables.attributes.contentvariable###</' & 'cfoutput>') />
   247			</cfif>
   248			<cfset arguments.writer.println('</cfsavecontent>') />
   249			<cfif not variables.attributes.overwrite>
   250				<cfset arguments.writer.println('</cfif>') />
   251			</cfif>
   252		</cfif>
   253
   254		<cfif variables.numChildren gt 0>
   255			<cfset leaveStackFrame(arguments.writer) />
   256		</cfif>
   257		
   258		<cfif structKeyExists(plugins,"postFuseaction")>
   259			<cfset n = arrayLen(plugins["postFuseaction"]) />
   260			<cfloop from="1" to="#n#" index="i">
   261				<cfset plugins["postFuseaction"][i].compile(arguments.writer) />
   262			</cfloop>
   263		</cfif>
   264
   265		<cfif needTryOnFuseaction>
   266			<cfset n = arrayLen(plugins["fuseactionException"]) />
   267			<cfloop from="1" to="#n#" index="i">
   268				<cfset plugins["fuseactionException"][i].compile(arguments.writer) />
   269			</cfloop>
   270			<cfset arguments.writer.rawPrintln("</cftry>") />
   271		</cfif>
   272
   273		<cfset arguments.writer.setFuseaction(old_f) />
   274		<cfset arguments.writer.setCircuit(old_c) />
   275
   276		<cfset structDelete(request.__fusebox.fuseactionsDone,cDotF) />
   277		
   278	</cffunction>
   279	
   280	<cffunction name="enterStackFrame" returntype="void" access="private" output="false" 
   281				hint="I generate code to create a new stack frame and push the scoped variables.">
   282		<cfargument name="writer" type="any" required="false" 
   283					hint="I am the parsed file writer object. I am required but it's faster to specify that I am not required." />
   284		
   285		<cfset var i = 0 />
   286		<cfset var child = 0 />
   287		<cfset var match1 = 0 />
   288		<cfset var match2 = 0 />
   289		<cfset var nameLen = 0 />
   290		
   291		<cfset arguments.writer.rawPrintln('<cfset myFusebox.enterStackFrame() >') />
   292		<cfloop from="1" to="#variables.numChildren#" index="i">
   293			<cfset child = variables.children[i] />
   294			<!--- validate the child: it must be <parameter> and have both name= and value= --->
   295			<cfif child.xmlName is "parameter">
   296				<cfif not structKeyExists(child.xmlAttributes,"name")>
   297					<cfthrow type="fusebox.badGrammar.requiredAttributeMissing"
   298							message="Required attribute is missing"
   299							detail="The attribute 'name' is required, for a 'parameter' verb in fuseaction #variables.action.getCircuit().getAlias()#.#variables.action.getName()#." />
   300				</cfif>
   301				<cfset match1 = REFind("[A-Za-z0-9_]*",child.xmlAttributes.name,1,true) />
   302				<cfset match2 = REFind("[A-Za-z0-9_]*\.[A-Za-z0-9_]*",child.xmlAttributes.name,1,true) />
   303				<cfset nameLen = len(child.xmlAttributes.name) />
   304				<cfif match1.pos[1] eq 1 and match1.len[1] eq nameLen>
   305					<!--- simple varname: patch up XML to make leaveStackFrame() simpler --->
   306					<cfset child.xmlAttributes.name = "variables." & child.xmlAttributes.name />
   307				<cfelseif match2.pos[1] eq 1 and match2.len[1] eq nameLen>
   308					<!--- scoped varname.varname: nothing to patch up --->
   309				<cfelse>
   310					<cfthrow type="fusebox.badGrammar.invalidAttributeValue"
   311							message="Attribute has invalid value"
   312							detail="The attribute 'name' must be a simple variable name, optionally qualified by a scope name, for a 'parameter' verb in fuseaction #variables.action.getCircuit().getAlias()#.#variables.action.getName()#." />
   313				</cfif>
   314				<cfset arguments.writer.rawPrintln('<' & 'cfif isDefined("#child.xmlAttributes.name#")><' &
   315							'cfset myFusebox.stack["#child.xmlAttributes.name#"] = #child.xmlAttributes.name# ></' & 'cfif>') />
   316				<cfif structKeyExists(child.xmlAttributes,"value")>
   317					<cfset arguments.writer.rawPrintln('<' & 'cfset #child.xmlAttributes.name# = "#child.xmlAttributes.value#" >') />
   318				</cfif>
   319			<cfelse>
   320				<cfthrow type="fusebox.badGrammar.illegalVerb" 
   321						message="Illegal verb encountered" 
   322						detail="The '#child.xmlName#' verb is illegal inside a 'do' verb, in fuseaction #variables.action.getCircuit().getAlias()#.#variables.action.getName()#." />
   323			</cfif>
   324		</cfloop>
   325		
   326	</cffunction>
   327	
   328	<cffunction name="leaveStackFrame" returntype="void" access="private" output="false" 
   329				hint="I generate code to pop the scoped variables and drop the stack frame.">
   330		<cfargument name="writer" type="any" required="false" 
   331					hint="I am the parsed file writer object. I am required but it's faster to specify that I am not required." />
   332		
   333		<cfset var i = 0 />
   334		<cfset var child = 0 />
   335		<cfset var scope = "" />
   336		<cfset var qName = "" />
   337		
   338		<cfloop from="#variables.numChildren#" to="1" step="-1" index="i">
   339			<cfset child = variables.children[i] />
   340			<cfset arguments.writer.rawPrintln('<' & 'cfif structKeyExists(myFusebox.stack,"#child.xmlAttributes.name#")><' &
   341						'cfset #child.xmlAttributes.name# = myFusebox.stack["#child.xmlAttributes.name#"] ></' & 'cfif>') />
   342			<cfset scope = listFirst(child.xmlAttributes.name,".") />
   343			<cfset qName = listRest(child.xmlAttributes.name,".") />
   344			<cfset arguments.writer.rawPrintln('<' & 'cfif structKeyExists(myFusebox.stack,"#child.xmlAttributes.name#")><' &
   345							'cfset #child.xmlAttributes.name# = myFusebox.stack["#child.xmlAttributes.name#"] ><' &
   346							'cfelse><' & 
   347							'cfset structDelete(#scope#,"#qName#")></' & 'cfif>') />
   348		</cfloop>
   349		<cfset arguments.writer.rawPrintln('<cfset myFusebox.leaveStackFrame() >') />
   350		
   351	</cffunction>
   352
   353	<cffunction name="getNamespace" returntype="string" access="public" output="false"
   354				hint="I return the namespace for this verb (which will be empty).">
   355
   356		<cfreturn "" />
   357
   358	</cffunction>	
   359	
   360	<cffunction name="getVerb" returntype="string" access="public" output="false">
   361
   362		<cfreturn variables.verb />
   363
   364	</cffunction>
   365	
   366</cfcomponent>