AppFactory

Package: MachII.framework
Factory class for creating instances of AppManager.
Method Summary
public AppFactory init()

Used by the framework for initialization. Do not override.

private void appendConfigFilePath(string configFilePath)

Appends a config file path to be used by AppLoader to check if reloading is necessary when in dynamic mode.

private void checkIfAlreadyIncluded(struct alreadyLoaded, string includeFilePath)

Checks if the include has already been processed.

public AppManager createAppManager(string configXmlPath, string configDtdPath, string appkey, [boolean validateXml="false"], [any parentAppManager=""], [any overrideXml=""], [string moduleName=""])

Creates the AppManager and reads (and optionally validates) the XML configuration file.

public array getConfigFilePaths()

Returns an array of config file paths.

private array loadIncludes(array configFiles, string configXML, boolean validateXml, string configDtdPath, string parentConfigFilePathDirectory, [boolean overrideIncludeType="false"], [struct alreadyLoaded="#StructNew()#"])

Loads files to be included into the config xml array.

private void resetConfigFilePaths()

Resets the config file paths to a zero element array.

private void validateConfigXml(boolean validateXml, any configXml, string configXmlPath, string configDtdPath)

Validates an xml file.

Method Detail
appendConfigFilePath

private void appendConfigFilePath( string configFilePath )

Appends a config file path to be used by AppLoader to check if reloading is necessary when in dynamic mode.

Parameters:
string configFilePath

Code:

	<cffunction name="appendConfigFilePath" access="private" returntype="void" output="false"
		hint="Appends a config file path to be used by AppLoader to check if reloading is necessary when in dynamic mode.">
		<cfargument name="configFilePath" type="string" required="true" />
		<cfset ArrayAppend(variables.configFilePaths, arguments.configFilePath) />
	</cffunction> 

checkIfAlreadyIncluded

private void checkIfAlreadyIncluded( struct alreadyLoaded, string includeFilePath )

Checks if the include has already been processed.

Parameters:
struct alreadyLoaded
string includeFilePath

Code:

	<cffunction name="checkIfAlreadyIncluded" access="private" returntype="void" output="false"
		hint="Checks if the include has already been processed.">
		<cfargument name="alreadyLoaded" type="struct" required="true" />
		<cfargument name="includeFilePath" type="string" required="true" />
		
		<cfset var includeFilePathHash = Hash(arguments.includeFilePath) />
		
		<cfif StructKeyExists(arguments.alreadyLoaded, includeFilePathHash)>
			<cfthrow type="MachII.framework.IncludeAlreadyDefined"
				message="An include located at '#arguments.includeFilePath#' has already been included. You cannot define an include more than once." />
		<cfelse>
			<cfset arguments.alreadyLoaded[includeFilePathHash] = true />
		</cfif>
	</cffunction> 

createAppManager

public AppManager createAppManager( string configXmlPath, string configDtdPath, string appkey, [boolean validateXml="false"], [any parentAppManager=""], [any overrideXml=""], [string moduleName=""] )

Creates the AppManager and reads (and optionally validates) the XML configuration file.

Parameters:
string configXmlPath
string configDtdPath
string appkey
[boolean validateXml="false"]
[any parentAppManager=""]
[any overrideXml=""]
[string moduleName=""]

Code:

	<cffunction name="createAppManager" access="public" returntype="MachII.framework.AppManager" output="false"
		hint="Creates the AppManager and reads (and optionally validates) the XML configuration file.">
		<cfargument name="configXmlPath" type="string" required="true"
		 	hint="The full path to the configuration XML file." />
		<cfargument name="configDtdPath" type="string" required="true"
		 	hint="The full path to the configuration DTD file." />
		<cfargument name="appkey" type="string" required="true"
			hint="Unqiue key for this application.">
		<cfargument name="validateXml" type="boolean" required="false" default="false"
			hint="Should the XML be validated before parsing." />
		<cfargument name="parentAppManager" type="any" required="false" default=""
			hint="Optional argument for a parent app manager. Defaults to empty string." />
		<cfargument name="overrideXml" type="any" required="false" default=""
			hint="Optional argument for override Xml for a module. Defaults to empty string." />
		<cfargument name="moduleName" type="string" required="false" default=""
			hint="Optional argument for the name of a module. Defaults to empty string." />
			
		<cfset var appManager = "" />
		<cfset var utils = "" />
		<cfset var propertyManager = "" />
		<cfset var parentPropertyManager = "" />
		<cfset var requestManager = "" />
		<cfset var listenerManager = "" />
		<cfset var parentListenerManager = "" />
		<cfset var filterManager = "" />
		<cfset var parentFilterManager = "" />
		<cfset var subroutineManager = "" />
		<cfset var parentSubroutineManager = "" />
		<cfset var eventManager = "" />
		<cfset var viewManager = "" />
		<cfset var parentViewManager = "" />
		<cfset var pluginManager = "" />
		<cfset var parentPluginManager = "" />
		<cfset var parentEventManager = "" />
		<cfset var moduleManager = "" />
		<cfset var configXml = "" />
		<cfset var configXmlFile = "" />
		<cfset var configXmls = ArrayNew(1) />
		<cfset var overrideIncludeNodes  = "" />
		<cfset var overrideIncludes = ArrayNew(1) />
		<cfset var temp = StructNew() />
		<cfset var i = "" />
		
		
		<cfset resetConfigFilePaths() />
		
		
		<cfif IsObject(arguments.parentAppManager)>
			<cfset utils = arguments.parentAppManager.getUtils() />
		<cfelse>
			<cfset utils = CreateObject("component", "MachII.util.Utils").init() />
		</cfif>
		
		
		<cfset variables.utils = utils />
		
		
		<cftry>
			<cffile 
				action="READ" 
				file="#arguments.configXmlPath#" 
				variable="configXmlFile" />
			<cfcatch type="any">
				<cfthrow type="MachII.framework.CannotFindBaseConfigFile"
					message="Unable to find the base config file for module '#arguments.moduleName#'."
					detail="configPath=#arguments.configXmlPath#" />
			</cfcatch>
		</cftry>
		
		
		<cfset appendConfigFilePath(arguments.configXmlPath) />

		
		<cfset temp.configXml = XmlParse(configXmlFile) />
		<cfset temp.override = false />
		
		
		<cfset validateConfigXml(arguments.validateXml, temp.configXml, arguments.configXmlPath, arguments.configDtdPath) />

		
		<cfset ArrayAppend(configXmls, temp) />

		
		<cfset configXmls = loadIncludes(configXmls, temp.configXml, arguments.validateXml, arguments.configDtdPath, GetDirectoryFromPath(arguments.configXmlPath)) />

		
		<cfif Len(arguments.overrideXml)>
			<cfset configXmls = loadIncludes(configXmls, arguments.overrideXml, arguments.validateXml, arguments.configDtdPath, true) />
		</cfif>
		
		
		<cfset appManager = CreateObject("component", "MachII.framework.AppManager").init() />
		<cfset appManager.setAppKey(arguments.appkey) />
		<cfif Len(arguments.moduleName)>
			<cfset appManager.setModuleName(arguments.moduleName) />
		</cfif>
		
		
		<cfif IsObject(arguments.parentAppManager)>
			<cfset appManager.setParent(arguments.parentAppManager) />
			<cfset parentPropertyManager = appManager.getParent().getPropertyManager() />
			<cfset parentListenerManager = appManager.getParent().getListenerManager() />
			<cfset parentFilterManager = appManager.getParent().getFilterManager() />
			<cfset parentSubroutineManager = appManager.getParent().getSubroutineManager() />
			<cfset parentEventManager = appManager.getParent().getEventManager() />
			<cfset parentViewManager = appManager.getParent().getViewManager() />
			<cfset parentPluginManager = appManager.getParent().getPluginManager() />
		</cfif>
		
		
		
		
		<cfset appManager.setUtils(utils) />
		
		<cfset propertyManager = CreateObject("component", "MachII.framework.PropertyManager").init(appManager, parentPropertyManager) />
		<cfloop from="1" to="#ArrayLen(configXmls)#" index="i">
			<cfset propertyManager.loadXml(configXmls[i].configXml, configXmls[i].override) />
		</cfloop>
		<cfif Len(arguments.overrideXml)>
			<cfset propertyManager.loadXml(arguments.overrideXml, true) />
		</cfif>
		<cfset appManager.setPropertyManager(propertyManager) />
		
		
		<cfif IsObject(arguments.parentAppManager)>
			<cfset requestManager = arguments.parentAppManager.getRequestManager() />
		<cfelse>
			<cfset requestManager = CreateObject("component", "MachII.framework.RequestManager").init(appManager) />
		</cfif>
		<cfif isObject(appManager.getParent())>
			<cfset appManager.setRequestManager(appManager.getParent().getRequestManager()) />
		<cfelse>
			<cfset appManager.setRequestManager(requestManager) />
		</cfif>

		<cfset listenerManager = CreateObject("component", "MachII.framework.ListenerManager").init(appManager, parentListenerManager) />
		<cfloop from="1" to="#ArrayLen(configXmls)#" index="i">
			<cfset listenerManager.loadXml(configXmls[i].configXml, configXmls[i].override) />
		</cfloop>
		<cfif Len(arguments.overrideXml)>
			<cfset listenerManager.loadXml(arguments.overrideXml, true) />
		</cfif>
		<cfset appManager.setListenerManager(listenerManager) />
		
		<cfset filterManager = CreateObject("component", "MachII.framework.EventFilterManager").init(appManager, parentFilterManager) />
		<cfloop from="1" to="#ArrayLen(configXmls)#" index="i">
			<cfset filterManager.loadXml(configXmls[i].configXml, configXmls[i].override) />
		</cfloop>
		<cfif Len(arguments.overrideXml)>
			<cfset filterManager.loadXml(arguments.overrideXml, true) />
		</cfif>
		<cfset appManager.setFilterManager(filterManager) />

		<cfset subroutineManager = CreateObject("component", "MachII.framework.SubroutineManager").init(appManager, parentSubroutineManager) />
		<cfloop from="1" to="#ArrayLen(configXmls)#" index="i">
			<cfset subroutineManager.loadXml(configXmls[i].configXml, configXmls[i].override) />
		</cfloop>
		<cfif Len(arguments.overrideXml)>
			<cfset subroutineManager.loadXml(arguments.overrideXml, true) />
		</cfif>
		<cfset appManager.setSubroutineManager(subroutineManager) />
				
		<cfset eventManager = CreateObject("component", "MachII.framework.EventManager").init(appManager, parentEventManager) />
		<cfloop from="1" to="#ArrayLen(configXmls)#" index="i">
			<cfset eventManager.loadXml(configXmls[i].configXml, configXmls[i].override) />
		</cfloop>
		<cfif Len(arguments.overrideXml)>
			<cfset eventManager.loadXml(arguments.overrideXml, true) />
		</cfif>
		<cfset appManager.setEventManager(eventManager) />
		
		<cfset viewManager = CreateObject("component", "MachII.framework.ViewManager").init(appManager, parentViewManager) />
		<cfloop from="1" to="#ArrayLen(configXmls)#" index="i">
			<cfset viewManager.loadXml(configXmls[i].configXml, configXmls[i].override) />
		</cfloop>
		<cfif Len(arguments.overrideXml)>
			<cfset viewManager.loadXml(arguments.overrideXml, true) />
		</cfif>
		<cfset appManager.setViewManager(viewManager) />
		
		<cfset pluginManager = CreateObject("component", "MachII.framework.PluginManager").init(appManager, parentPluginManager) />
		<cfloop from="1" to="#ArrayLen(configXmls)#" index="i">
			<cfset pluginManager.loadXml(configXmls[i].configXml, configXmls[i].override) />
		</cfloop>
		<cfif Len(arguments.overrideXml)>
			<cfset pluginManager.loadXml(arguments.overrideXml, true) />
		</cfif>
		<cfset appManager.setPluginManager(pluginManager) />
		
		
		<cfif NOT IsObject(arguments.parentAppManager)>
			<cfset moduleManager = CreateObject("component", "MachII.framework.ModuleManager").init(appManager, GetDirectoryFromPath(arguments.configXmlPath), arguments.configDtdPath, arguments.validateXML) />
			<cfloop from="1" to="#ArrayLen(configXmls)#" index="i">
				<cfset moduleManager.loadXml(configXmls[i].configXml, configXmls[i].override) />
			</cfloop>
		<cfelse>
			<cfset moduleManager = arguments.parentAppManager.getModuleManager() />
		</cfif>
		<cfset appManager.setModuleManager(moduleManager) />
		
		
		<cfset appManager.configure() />
		
		<cfreturn appManager />
	</cffunction> 

getConfigFilePaths

public array getConfigFilePaths( )

Returns an array of config file paths.

Parameters:

Code:

	<cffunction name="getConfigFilePaths" access="public" returntype="array" output="false"
		hint="Returns an array of config file paths.">
		<cfreturn variables.configFilePaths />
	</cffunction> 

init

public AppFactory init( )

Used by the framework for initialization. Do not override.

Parameters:

Code:

	<cffunction name="init" access="public" returntype="AppFactory" output="false"
		hint="Used by the framework for initialization. Do not override.">
		<cfreturn this />
	</cffunction> 

loadIncludes

private array loadIncludes( array configFiles, string configXML, boolean validateXml, string configDtdPath, string parentConfigFilePathDirectory, [boolean overrideIncludeType="false"], [struct alreadyLoaded="#StructNew()#"] )

Loads files to be included into the config xml array.

Parameters:
array configFiles
string configXML
boolean validateXml
string configDtdPath
string parentConfigFilePathDirectory
[boolean overrideIncludeType="false"]
[struct alreadyLoaded="#StructNew()#"]

Code:

	<cffunction name="loadIncludes" access="private" returntype="array" output="false"
		hint="Loads files to be included into the config xml array.">
		<cfargument name="configFiles" type="array" required="true" />
		<cfargument name="configXML" type="string" required="true" />
		<cfargument name="validateXml" type="boolean" required="true" />
		<cfargument name="configDtdPath" type="string" required="true" />
		<cfargument name="parentConfigFilePathDirectory" type="string" required="true" />
		<cfargument name="overrideIncludeType" type="boolean" required="false" default="false" />
		<cfargument name="alreadyLoaded" type="struct" required="false" default="#StructNew()#" />
		
		<cfset var includeNodes = "" />
		<cfset var temp = StructNew() />
		<cfset var includeFilePath = "" />
		<cfset var includeXmlFile = "" />
		<cfset var i = 0 />
		
		<cfset includeNodes =  XmlSearch(arguments.configXML, ".//includes/include") />
		<cfloop from="1" to="#ArrayLen(includeNodes)#" index="i">

			<cfset temp = StructNew() />
			<cfset includeFilePath = includeNodes[i].xmlAttributes["file"] />
			
			<cfif Left(includeFilePath, 1) IS ".">
				<cfset includeFilePath = variables.utils.expandRelativePath(arguments.parentConfigFilePathDirectory, includeFilePath) />
			<cfelse>
				<cfset includeFilePath = ExpandPath(includeFilePath) />
			</cfif>

			
			<cfif NOT arguments.overrideIncludeType>
				<cfif StructKeyExists(includeNodes[i].xmlAttributes, "override")>
					<cfset temp.override = includeNodes[i].xmlAttributes["override"] />
				<cfelse>
					<cfset temp.override = false />
				</cfif>
			<cfelse>
				<cfset temp.override = true />
			</cfif>
			
			
			<cfset checkIfAlreadyIncluded(arguments.alreadyLoaded, includeFilePath) />
			
			
			<cftry>
				<cffile
					action="read"
					file="#includeFilePath#"
					variable="includeXMLFile" />
				<cfcatch type="any">
					<cfthrow type="MachII.framework.CannotFindIncludeConfigFile"
						message="Unable to find the include config file. This could be due to an incorrect relative path."
						detail="includePath=#includeFilePath#" />
				</cfcatch>
			</cftry>
			
			
			<cfset temp.configXml = XmlParse(includeXmlFile) />

			
			<cfset validateConfigXml(arguments.validateXml, temp.configXml, includeFilePath, arguments.configDtdPath) />
			
			
			<cfset appendConfigFilePath(includeFilePath) />
			
			
			<cfset ArrayAppend(arguments.configFiles, temp) />
			
			
			<cfset arguments.configFiles = loadIncludes(arguments.configFiles, temp.configXml, arguments.validateXml, arguments.configDtdPath, GetDirectoryFromPath(includeFilePath), arguments.overrideIncludeType, arguments.alreadyLoaded) />
		</cfloop>
		
		<cfreturn arguments.configFiles />
	</cffunction> 

resetConfigFilePaths

private void resetConfigFilePaths( )

Resets the config file paths to a zero element array.

Parameters:

Code:

	<cffunction name="resetConfigFilePaths" access="private" returntype="void" output="false"
		hint="Resets the config file paths to a zero element array.">
		<cfset ArrayClear(variables.configFilePaths) />
	</cffunction> 

validateConfigXml

private void validateConfigXml( boolean validateXml, any configXml, string configXmlPath, string configDtdPath )

Validates an xml file.

Parameters:
boolean validateXml
any configXml
string configXmlPath
string configDtdPath

Code:

	<cffunction name="validateConfigXml" access="private" returntype="void" output="false"
		hint="Validates an xml file.">
		<cfargument name="validateXml" type="boolean" required="true" />
		<cfargument name="configXml" type="any" required="true" />
		<cfargument name="configXmlPath" type="string" required="true" />
		<cfargument name="configDtdPath" type="string" required="true" />
		
		<cfset var validationResult = "" />
		<cfset var validationException = "" />
		
		
		<cfif arguments.validateXml AND ListFirst(server.ColdFusion.ProductVersion) GTE 7>
			<cfset validationResult = XmlValidate(arguments.configXml, arguments.configDtdPath) />
			<cfif NOT validationResult.Status>
				<cfset validationException = CreateObject("component", "MachII.util.XmlValidationException") />
				<cfset validationException.wrapValidationResult(validationResult, arguments.configXmlPath, arguments.configDtdPath) />
				<cfthrow type="MachII.framework.XmlValidationException" 
					message="#validationException.getFormattedMessage()#" />
			</cfif>
		</cfif>
	</cffunction>