root / framework / tags / fusebox5A2 / fuseboxCircuit.cfc

Revision 99, 16.0 kB (checked in by scorfield, 3 years ago)

Fixes for loadclean, parseall, development-no-load modes/flags.

Line 
1<!---
2Fusebox Software License
3Version 1.0
4
5Copyright (c) 2003, 2004, 2005, 2006 The Fusebox Corporation. All rights reserved.
6
7Redistribution and use in source and binary forms, with or without modification, are permitted
8provided that the following conditions are met:
9
101. Redistributions of source code must retain the above copyright notice, this list of conditions
11   and the following disclaimer.
12
132. Redistributions in binary form or otherwise encrypted form must reproduce the above copyright
14   notice, this list of conditions and the following disclaimer in the documentation and/or other
15   materials provided with the distribution.
16
173. The end-user documentation included with the redistribution, if any, must include the following
18   acknowledgment:
19
20   "This product includes software developed by the Fusebox Corporation (http://www.fusebox.org/)."
21
22   Alternately, this acknowledgment may appear in the software itself, if and wherever such
23   third-party acknowledgments normally appear.
24
254. The names "Fusebox" and "Fusebox Corporation" must not be used to endorse or promote products
26   derived from this software without prior written (non-electronic) permission. For written
27   permission, please contact fusebox@fusebox.org.
28
295. Products derived from this software may not be called "Fusebox", nor may "Fusebox" appear in
30   their name, without prior written (non-electronic) permission of the Fusebox Corporation. For
31   written permission, please contact fusebox@fusebox.org.
32
33If one or more of the above conditions are violated, then this license is immediately revoked and
34can be re-instated only upon prior written authorization of the Fusebox Corporation.
35
36THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38DISCLAIMED. IN NO EVENT SHALL THE FUSEBOX CORPORATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY
39DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
40LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
41BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
42STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
43OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
44
45-------------------------------------------------------------------------------
46
47This software consists of voluntary contributions made by many individuals on behalf of the
48Fusebox Corporation. For more information on Fusebox, please see <http://www.fusebox.org/>.
49
50--->
51<cfcomponent extends="fuseboxBaseCircuit" output="false">
52       
53        <cffunction name="init" returntype="fuseboxCircuit" access="public" output="false">
54                <cfargument name="fbApp" type="fuseboxApplication" required="true" />
55                <cfargument name="alias" type="string" required="true" />
56                <cfargument name="path" type="string" required="true" />
57                <cfargument name="parent" type="string" required="true" />
58               
59                <cfset var circuitXML = "" />
60                <cfset var circuitCode = "" />
61                <cfset var aLex = "" />
62               
63                <cfset super.init(arguments.fbApp,arguments.alias) />
64               
65                <cfset variables.originalPath = arguments.path />
66                <cfset this.parent = arguments.parent />
67                <cfset variables.appPath = getApplication().getApplicationRoot() />
68                <cfset variables.lexicons = structNew() />
69               
70                <cfset variables.relativePath = replace(arguments.path,"\","/","all") />
71                <cfif len(variables.relativePath) and right(variables.relativePath,1) is not "/">
72                        <cfset variables.relativePath = variables.relativePath & "/" />
73                </cfif>
74                <cfset this.path = variables.relativePath />
75                <cfset variables.fullPath = variables.appPath & variables.relativePath />
76                <!--- remove pairs of directory/../ to form canonical path: --->
77                <cfloop condition="find('/../',variables.fullPath) gt 0">
78                        <cfset variables.fullPath = REreplace(variables.fullPath,"[^\.:/]*/\.\./","") />
79                </cfloop>
80                <cfset this.rootPath = getApplication().relativePath(variables.fullPath,variables.appPath) />
81               
82                <!--- attempt to load circuit.xml(.cfm): --->
83                <cftry>
84                       
85                        <cffile action="read" file="#variables.fullPath#circuit.xml.cfm" variable="circuitXML" />
86                        <cfset variables.circuitPath = variables.fullPath & "circuit.xml.cfm" />
87                       
88                        <cfcatch type="any">
89                                <cftry>
90                               
91                                        <cffile action="read" file="#variables.fullPath#circuit.xml" variable="circuitXML" />
92                                        <cfset variables.circuitPath = variables.fullPath & "circuit.xml" />
93                                       
94                                        <cfcatch type="any">
95                                                <!--- missing fusebox xml file --->
96                                        </cfcatch>
97                               
98                                </cftry>
99                        </cfcatch>
100                       
101                </cftry>
102               
103                <cftry>
104                       
105                        <cfset circuitCode = xmlParse(circuitXML) />
106                       
107                        <cfcatch type="any">
108                                <!--- illformed XML --->
109                        </cfcatch>
110                       
111                </cftry>
112
113                <cfif circuitCode.xmlRoot.xmlName is not "circuit">
114                        <cfthrow type="fusebox.badGrammar.badCircuitFile"
115                                        detail="Circuit file does contain 'circuit' XML"
116                                        message="Circuit file #variables.circuitPath# does not contain 'circuit' as the root XML node." />
117                </cfif>
118                <cfif structKeyExists(circuitCode.xmlRoot.xmlAttributes,"access")>
119                        <cfif listFind("private,internal,public",circuitCode.xmlRoot.xmlAttributes.access) eq 0>
120                                <cfthrow type="fusebox.badGrammar.illegalAccess"
121                                                message="Circuit access illegal"
122                                                detail="The 'access' value '#circuitCode.xmlRoot.xmlAttributes.access#' is illegal in Circuit #getAlias()#. 'private', 'internal' or 'public' are the only legal values." />
123                        </cfif>
124                        <cfset this.access = circuitCode.xmlRoot.xmlAttributes.access />
125                <cfelse>
126                        <cfset this.access = "internal" />
127                </cfif>
128                <cfif structKeyExists(circuitCode.xmlRoot.xmlAttributes,"permissions")>
129                        <cfset this.permissions = circuitCode.xmlRoot.xmlAttributes.permissions />
130                <cfelse>
131                        <cfset this.permissions = "" />
132                </cfif>
133
134                <cfset loadLexicons(circuitCode) />             
135                <cfset loadPreAndPostFuseactions(circuitCode) />
136                <cfset loadFuseactions(circuitCode) />
137               
138                <cfreturn this />
139
140        </cffunction>
141       
142        <cffunction name="reload" returntype="void" access="public" output="false">
143                <cfargument name="appKey" type="string" required="true" />
144
145                <!--- lock using the same lock as load process in fusebox5.cfm --->             
146                <cflock name="#application.ApplicationName#_fusebox_#arguments.appKey#" type="exclusive" timeout="300">
147                        <cfset init(getApplication(),getAlias(),variables.originalPath,this.parent) />
148                </cflock>       
149
150        </cffunction>
151
152        <cffunction name="compile" returntype="void" access="public" output="false">
153                <cfargument name="writer" type="fuseboxWriter" required="true" />
154                <cfargument name="fuseaction" type="string" required="true" />
155       
156                <cfset var f = "" />
157                <cfset var i = 0 />
158                <cfset var n = 0 />
159
160                <cfset f = arguments.writer.setFuseaction(arguments.fuseaction) />
161
162                <cfset compilePreOrPostFuseaction(arguments.writer,"pre") />
163               
164                <cfif not structKeyExists(this.fuseactions,arguments.fuseaction)>
165                        <cfthrow type="fusebox.undefinedFuseaction"
166                                        message="undefined Fuseaction"
167                                        detail="You specified a Fuseaction of #arguments.fuseaction# which is not defined in Circuit #getAlias()#." />
168                </cfif>
169                <cfset this.fuseactions[arguments.fuseaction].compile(arguments.writer) />
170               
171                <cfset compilePreOrPostFuseaction(arguments.writer,"post") />
172
173                <cfset arguments.writer.setFuseaction(f) />
174               
175        </cffunction>
176       
177        <cffunction name="compilePreOrPostFuseaction" returntype="void" access="public" output="false">
178                <cfargument name="writer" type="fuseboxWriter" required="true" />
179                <cfargument name="preOrPost" type="string" required="true" />
180       
181                <cfset var c = "" />
182
183                <cfif variables.hasAction[arguments.preOrPost]>
184                        <cfif arguments.preOrPost is "pre" and variables.callsuper["pre"] and hasParent()>
185                                <cfset getParent().compilePreOrPostFuseaction(arguments.writer,arguments.preOrPost) />
186                        </cfif>
187                        <cfset c = arguments.writer.setCircuit(getAlias()) />
188                        <cfset variables.action[arguments.preOrPost].compile(arguments.writer) />
189                        <cfset arguments.writer.setCircuit(c) />
190                        <cfif arguments.preOrPost is "post" and variables.callsuper["post"] and hasParent()>
191                                <cfset getParent().compilePreOrPostFuseaction(arguments.writer,arguments.preOrPost) />
192                        </cfif>
193                </cfif>
194       
195        </cffunction>
196       
197        <cffunction name="buildCircuitTrace" returntype="void" access="public" output="false">
198       
199                <cfset var c = getParentName() />
200                <cfset var seen = structNew() />
201               
202                <cfset seen[getAlias()] = true />
203                <cfset this.circuitTrace = arrayNew(1) />
204                <cfset arrayAppend(this.circuitTrace,getAlias()) />
205                <cfloop condition="c is not ''">
206                        <cfif structKeyExists(seen,c)>
207                                <cfthrow type="fusebox.badGrammar.circularParent"
208                                                message="Circular parent for Circuit"
209                                                detail="You specified a parent Circuit of #c# (for Circuit #getAlias()#) which creates a circular dependency." />
210                        </cfif>
211                        <cfset seen[c] = true />
212                        <cfif not structKeyExists(getApplication().circuits,c)>
213                                <cfthrow type="fusebox.undefinedCircuit"
214                                                message="undefined Circuit"
215                                                detail="You specified a parent Circuit of #c# (for Circuit #getAlias()#) which is not defined." />
216                        </cfif>
217                        <cfset arrayAppend(this.circuitTrace,c) />
218                        <cfset c = getApplication().circuits[c].getParentName() />
219                </cfloop>
220               
221        </cffunction>
222       
223        <cffunction name="getParentName" returntype="string" access="public" output="false">
224       
225                <cfreturn this.parent />
226       
227        </cffunction>
228
229        <cffunction name="hasParent" returntype="boolean" access="public" output="false">
230       
231                <cfreturn getParentName() is not "" />
232       
233        </cffunction>
234
235        <cffunction name="getParent" returntype="fuseboxBaseCircuit" access="public" output="false">
236       
237                <!---
238                        note that this will throw an exception if the circuit has no parent
239                        code should call hasParent() first
240                --->
241                <cfreturn getApplication().circuits[getParentName()] />
242       
243        </cffunction>
244
245        <cffunction name="getPermissions" returntype="string" access="public" output="false">
246                <cfargument name="useCircuitTrace" type="boolean" default="false" />
247       
248                <cfif this.permissions is "" and arguments.useCircuitTrace and hasParent()>
249                        <cfreturn getParent().getPermissions(arguments.useCircuitTrace) />
250                <cfelse>
251                        <cfreturn this.permissions />
252                </cfif>
253       
254        </cffunction>
255       
256        <cffunction name="getRelativePath" returntype="string" access="public" output="false">
257       
258                <cfreturn variables.relativePath />
259       
260        </cffunction>
261       
262        <cffunction name="getFuseactions" returntype="struct" access="public" output="false">
263               
264                <cfreturn this.fuseactions />
265               
266        </cffunction>
267       
268        <cffunction name="getLexiconDefinition" returntype="struct" access="public" output="false">
269                <cfargument name="namespace" type="string" required="true" />
270               
271                <cfif arguments.namespace is getFuseboxLexicon().namespace>
272                        <cfreturn getFuseboxLexicon() />
273                <cfelse>
274                        <cfreturn variables.lexicons[arguments.namespace] />
275                </cfif>
276
277        </cffunction>
278       
279        <cffunction name="getAccess" returntype="string" access="public" output="false">
280       
281                <cfreturn this.access />
282       
283        </cffunction>
284       
285        <cffunction name="loadLexicons" returntype="void" access="private" output="false">
286                <cfargument name="circuitCode" type="any" required="true" />
287               
288                <cfset var attributes = circuitCode.xmlRoot.xmlAttributes />
289                <cfset var attr = "" />
290                <cfset var aLex = "" />
291                <cfset var ns = "" />
292               
293                <!--- pass 1: pull out any namespace declarations --->
294                <cfloop collection="#attributes#" item="attr">
295                        <cfif len(attr) gt 6 and left(attr,6) is "xmlns:">
296                                <!--- found a namespace declaration, pull it out: --->
297                                <cfset aLex = structNew() />
298                                <cfset aLex.namespace = listLast(attr,":") />
299                                <cfif aLex.namespace is getFuseboxLexicon().namespace>
300                                        <cfthrow type="fusebox.badGrammar.reservedName"
301                                                        message="Attempt to use reserved namespace"
302                                                        detail="You have attempted to declare a namespace '#aLex.namespace#' (in Circuit #getAlias()#) which is reserved by the Fusebox framework." />
303                                </cfif>
304                                <cfset aLex.path = getApplication().getCoreToAppRootPath() & getApplication().lexiconPath & attributes[attr] />
305                                <cfset variables.lexicons[aLex.namespace] = aLex />
306                                <cfset variables.customAttributes[aLex.namespace] = structNew() />
307                        </cfif>
308                </cfloop>
309               
310                <!--- pass 2: pull out any custom attributes --->
311                <cfloop collection="#attributes#" item="attr">
312                        <cfif listLen(attr,":") eq 2>
313                                <!--- looks like a custom attribute: --->
314                                <cfset ns = listFirst(attr,":") />
315                                <cfif ns is "xmlns">
316                                        <!--- special case - need to ignore xmlns:foo="bar" --->
317                                <cfelseif structKeyExists(variables.customAttributes,ns)>
318                                        <cfset variables.customAttributes[ns][listLast(attr,":")] = attributes[attr] />
319                                <cfelse>
320                                        <!--- TODO: error: undeclared namespace --->
321                                </cfif>
322                        </cfif>
323                </cfloop>
324                               
325        </cffunction>
326       
327        <cffunction name="loadPreAndPostFuseactions" returntype="void" access="private" output="false">
328                <cfargument name="circuitCode" type="any" required="true" />
329               
330                <cfset variables.hasAction = structNew() />
331                <cfset variables.action = structNew() />
332                <cfset variables.callsuper = structNew() />
333                <cfset loadPrePostFuseaction(arguments.circuitCode,"pre") />
334                <cfset loadPrePostFuseaction(arguments.circuitCode,"post") />
335                               
336        </cffunction>
337       
338        <cffunction name="loadPrePostFuseaction" returntype="void" access="private" output="false">
339                <cfargument name="circuitCode" type="any" required="true" />
340                <cfargument name="prePost" type="string" required="true" />
341               
342                <cfset var children = xmlSearch(arguments.circuitCode,"/circuit/#arguments.prePost#fuseaction") />
343                <cfset var i = 0 />
344                <cfset var n = arrayLen(children) />
345               
346                <cfif n eq 0>
347                        <cfset variables.hasAction[arguments.prePost] = false />
348                <cfelseif n eq 1>
349                        <cfset variables.hasAction[arguments.prePost] = true />
350                        <cfparam name="children[1].xmlAttributes.callsuper" type="boolean" default="false" />
351                        <cfset variables.callsuper[arguments.prePost] = children[1].xmlAttributes.callsuper />
352                        <cfset variables.action[arguments.prePost] =
353                                        createObject("component","fuseboxAction")
354                                                .init(this,
355                                                        "$#arguments.prePost#fuseaction",
356                                                                "internal",
357                                                                        children[1].xmlChildren) />
358                <cfelse>
359                        <!--- TODO: ought to check there is only one prefuseaction? --->
360                </cfif>
361               
362        </cffunction>
363       
364        <cffunction name="loadFuseactions" returntype="void" access="private" output="false">
365                <cfargument name="circuitCode" type="any" required="true" />
366               
367                <cfset var children = xmlSearch(arguments.circuitCode,"/circuit/fuseaction") />
368                <cfset var i = 0 />
369                <cfset var n = arrayLen(children) />
370                <cfset var attribs = 0 />
371                <cfset var attr = "" />
372                <cfset var ns = "" />
373                <cfset var customAttribs = 0 />
374               
375                <cfset this.fuseactions = structNew() />
376               
377                <cfloop from="1" to="#n#" index="i">
378                        <cfset attribs = children[i].xmlAttributes />
379
380                        <!--- scan for custom attributes --->
381                        <cfset customAttribs = structNew() />
382                        <cfloop collection="#attribs#" item="attr">
383                                <cfif listLen(attr,":") eq 2>
384                                        <!--- looks like a custom attribute: --->
385                                        <cfset ns = listFirst(attr,":") />
386                                        <cfif structKeyExists(variables.customAttributes,ns)>
387                                                <cfset customAttribs[ns][listLast(attr,":")] = attribs[attr] />
388                                        <cfelse>
389                                                <!--- TODO: error: undeclared namespace --->
390                                        </cfif>
391                                </cfif>
392                        </cfloop>
393
394                        <cfif structKeyExists(attribs,"access")>
395                                <cfif listFind("private,internal,public",attribs.access) eq 0>
396                                        <cfthrow type="fusebox.badGrammar.illegalAccess"
397                                                        message="Fuseaction access illegal"
398                                                        detail="The 'access' value '#attribs.access#' is illegal on Fuseaction #attribs.name# in Circuit #getAlias()#. 'private', 'internal' or 'public' are the only legal values." />
399                                </cfif>
400                        <cfelse>
401                                <!--- default fuseaction access to circuit access --->
402                                <cfset attribs.access = this.access />
403                        </cfif>
404                        <cfset this.fuseactions[attribs.name] =
405                                        createObject("component","fuseboxAction")
406                                                .init(this,attribs.name,attribs.access,children[i].xmlChildren,false,customAttribs) />
407
408                        <!--- FB41 compatibility for security plugins --->
409                        <cfif structKeyExists(attribs,"permissions")>
410                                <cfset this.fuseactions[attribs.name].permissions = attribs.permissions />
411                        <cfelse>
412                                <cfset this.fuseactions[attribs.name].permissions = "" />
413                        </cfif>
414                </cfloop>
415               
416        </cffunction>
417       
418</cfcomponent>
Note: See TracBrowser for help on using the browser.