Changeset 1969

Show
Ignore:
Timestamp:
11/21/2009 07:02:07 AM (4 months ago)
Author:
peterfarrell
Message:

ColdSpring? autowire by "depends" no longer needs disk write access. Process now 9,500% faster according to test case. Grab a nightly #tweet closes[t:456]

Location:
framework/1-8-0/trunk
Files:
1 added
3 modified

Legend:

Unmodified
Added
Removed
  • framework/1-8-0/trunk/CHANGELOG

    r1937 r1969  
    4040    modules, and to copy and distribute the resulting executable under 
    4141    terms of your choice, provided that you also meet, for each linked 
    42     independent module, the terms and conditions of the license of that 
     42-    independent module, the terms and conditions of the license of that 
    4343    module.  An independent module is a module which is not derived from 
    4444    or based on this library.  If you modify this library, you may extend 
     
    397397------------------------------------------------ 
    398398 
     399* Remove generation of cfcs for method injection for ColdSpring "depends" integration 
     400Remove the need to generate cfcs and write them to disk for method injection for  
     401ColdSpring depends integration. This is typically a slow process because in order  
     402into instantiate the CFC we must write it to the disk, instantiate into memory  
     403and then delete it. 
     404 
     405Side by side comparison of generating a CFC, writing it to disk, instantiating it and  
     406then deleting from disk compared to this new solution is about 9,500% faster. A test  
     407case for this sub section of code (1000 iterations each) is 2359ms for  
     408generate/write/instantiate/delete process (10 tests averaged) to 25ms for the new  
     409instantiate generic bean process (10 tests averaged). 
     410 
     411Special thanks to Dave Shuck's mention of a difficulty with autowire with depends 
     412on Google App Engine due to no disk write access. This lead this a lightbulb 
     413moment on a workaround that did not involve writing to disk. 
     414 
     415For more information see: 
     416http://greatbiztoolsllc.trac.cvsdude.com/mach-ii/ticket/456 
     417(2009-11-21 peterfarrell) 
     418 
    399419* Trace Plugin reports that is has been deprecated in the trace output 
    400420https://greatbiztoolsllc.trac.cvsdude.com/mach-ii/ticket/277 
  • framework/1-8-0/trunk/README

    r1939 r1969  
    4040* Jonah (Creori) 
    4141* Shaun (Net Grow) 
     42* Dave Shuck 
    4243* Mike Rogers 
    4344* Dan Skaggs  
  • framework/1-8-0/trunk/properties/ColdspringProperty.cfc

    r1892 r1969  
    304304                <!--- Set the autowire attribute name ---> 
    305305                <cfset setAutowireAttributeName(getParameter("autowireAttributeName", "depends")) /> 
    306                  
    307                 <!--- Setup CFC generation location ---> 
    308                 <cfset setCfcGenerationLocation(ExpandPath(getParameter("cfcGenerationLocation")) 
    309                                 , GetDirectoryFromPath(GetCurrentTemplatePath())) /> 
    310                  
    311                 <!--- Setup the dot path to the CFC generation location ---> 
    312                 <cfset setDotPathToCfcGenerationLocation(getParameter("dotPathTocfcGenerationLocation"), "") /> 
    313                  
     306                                 
    314307                <!--- Get the config file path ---> 
    315308                <cfset getAssert().hasLength(getParameter("configFile") 
     
    595588                <cfset var autowireBeanNames = "" /> 
    596589                <cfset var beanName = "" /> 
     590                <cfset var targets = StructNew() /> 
    597591                <cfset var autowireCfc = "" /> 
    598592                <cfset var i = 0 /> 
     
    602596                         
    603597                        <!--- Get all of the bean names to autowire ---> 
    604                         <cfset autowireBeanNames = ListToArray(arguments.targetObjMetadata[arguments.autowireAttributeName]) /> 
     598                        <cfset autowireBeanNames = ListToArray(getUtils().trimList(arguments.targetObjMetadata[arguments.autowireAttributeName])) /> 
    605599                         
    606600                        <!--- Generate and instantiate autowire component with the getter/setter methods ---> 
    607                         <cfset autowireCfc = createAutowireDynamicMethodsComponent(autowireBeanNames) /> 
    608                          
    609                         <!--- Loop over all the methods ---> 
    610                         <cfloop from="1" to="#ArrayLen(autowireBeanNames)#" index="i"> 
    611                                  
    612                                 <cfset beanName = Trim(autowireBeanNames[i]) /> 
    613                                  
    614                                 <!--- Inject the _methodInject() so we can get the methods into the variables scope 
    615                                         in addition to the this scope of the component ---> 
    616                                 <cfset arguments.targetObj["_methodInject"] = autowireCfc["_methodInject"] /> 
    617  
    618                                 <!--- Only dynamically inject the setter if there isn't a concrete getter ---> 
    619                                 <cfif NOT StructKeyExists(arguments.targetObj, "get" & beanName)> 
    620                                         <cfset arguments.targetObj._methodInject("get" & beanName, autowireCfc["get" & beanName]) /> 
    621                                 </cfif> 
    622                                  
    623                                 <!--- Only dynamically inject the setter if there isn't a concrete setter ---> 
    624                                 <cfif NOT StructKeyExists(arguments.targetObj, "set" & beanName)> 
    625                                         <cfset arguments.targetObj._methodInject("set" & beanName, autowireCfc["set" & beanName]) /> 
    626                                 </cfif> 
    627                                                                          
    628                                 <!--- Inject appropriate bean if the factory has a bean by that name ---> 
    629                                 <cfif getAssert().isTrue(beanFactory.containsBean(beanName) 
    630                                                 , "Cannot find bean named '#beanName#' to autowire by method injection in a '#ListLast(targetObjMetadata.extends.name, '.')#' of type '#targetObjMetadata.name#' in module '#getAppManager().getModuleName()#'." 
    631                                                 , "Check that there is a bean named '#beanName#' defined in your ColdSpring bean factory.")> 
    632                                         <cfinvoke component="#arguments.targetObj#" method="set#beanName#"> 
    633                                                 <cfinvokeargument name="#beanName#" value="#beanFactory.getBean(beanName)#" /> 
    634                                         </cfinvoke> 
    635                                 </cfif> 
    636                                  
    637                                 <!--- Delete the _methodInject() from the target ---> 
    638                                 <cfset StructDelete(arguments.targetObj, "_methodInject") /> 
    639                         </cfloop> 
     601                        <cfset autowireCfc = CreateObject("component", "MachII.properties.ColdSpringProperty_InjectionMethods").init(autowireBeanNames) /> 
     602                         
     603                        <!--- Build all the targets ---> 
     604                        <cftry> 
     605                                <cfloop from="1" to="#ArrayLen(autowireBeanNames)#" index="i"> 
     606                                        <cfset beanName = autowireBeanNames[i] /> 
     607                                                                                                 
     608                                        <!--- Add appropriate bean if the factory has a bean by that name ---> 
     609                                        <cfset targets[beanName] = beanFactory.getBean(beanName) /> 
     610                                </cfloop> 
     611                                <!--- Faster to fast fail and handle a missing bean exception than to check if the bean exists in the factor ---> 
     612                                <cfcatch type="any"> 
     613                                        <cfthrow type="MachII.properties.ColdSpringProperty.NoBean" 
     614                                                message="Cannot find bean named '#beanName#' to autowire by method injection in a '#ListLast(targetObjMetadata.extends.name, '.')#' of type '#targetObjMetadata.name#' in module '#getAppManager().getModuleName()#'." 
     615                                                detail="Check that there is a bean named '#beanName#' defined in your ColdSpring bean factory." /> 
     616                                </cfcatch> 
     617                        </cftry> 
     618                         
     619                        <!--- Inject the _methodInject() so we can get the methods into the variables scope 
     620                                in addition to the this scope of the component ---> 
     621                        <cfset arguments.targetObj["_injectMethods"] = autowireCfc["_injectMethods"] /> 
     622                         
     623                        <!--- Now inject everything into the target ---> 
     624                        <cfset arguments.targetObj._injectMethods(autowireCfc, targets) /> 
     625         
     626                        <!--- Delete the _methodInject() from the target ---> 
     627                        <cfset StructDelete(arguments.targetObj, "_injectMethods") /> 
    640628                </cfif>  
    641629        </cffunction> 
     
    779767        </cffunction> 
    780768         
    781         <cffunction name="createAutowireDynamicMethodsComponent"access="private" returntype="any" output="false" 
    782                 hint="Create a component with the neccessary methods to dynamically inject into targets."> 
    783                 <cfargument name="autowireBeanNames" type="array" required="true" /> 
    784                  
    785                 <cfset var beanName = "" /> 
    786                 <cfset var cfcData = CreateObject("java", "java.lang.StringBuffer") /> 
    787                 <cfset var cfcName = "" /> 
    788                 <cfset var cfcDirectory = getCfcGenerationLocation() /> 
    789                 <cfset var autowireCfc = "" /> 
    790                 <cfset var i = "" /> 
    791                  
    792                 <!--- Add the opening cfcomponent tag and _methodInject method --->              
    793                 <!--- Used string concatenation otherwise CFEclipse marks this as bad code ---> 
    794                 <cfset cfcData.append('<cfcomponent><cffunction name="_methodInject" access="public" returntype="void" output="false"><cfargument name="methodName" type="string" required="true" /><cfargument name="method" type="any" required="true" /><cfset this[arguments.methodName] = arguments.method /><cfset variables[arguments.methodName] = arguments.method /></' & 'cffunction>') /> 
    795                                  
    796                 <!--- Create the getter/setter methods for each beanName ---> 
    797                 <cfloop from="1" to="#ArrayLen(arguments.autowireBeanNames)#" index="i"> 
    798                         <!--- Clean any spaces from the bean name ---> 
    799                         <cfset beanName = Trim(arguments.autowireBeanNames[i]) /> 
    800  
    801                         <!--- Used string concatenation otherwise CFEclipse marks this as bad code ---> 
    802                         <cfset cfcData.append('<cffunction name="set' & beanName & '" access="public" returntype="void" output="false"><cfargument name="' & beanName & '" type="any" required="true" /><cfset variables.' & beanName & ' = arguments.' & beanName & ' /></' & 'cffunction><cffunction name="get' & beanName & '" access="public" returntype="any" output="false"><cfreturn variables.' & beanName & ' /></' & 'cffunction>') /> 
    803                 </cfloop> 
    804  
    805                 <!--- Add the closing cfcomponent tag ---> 
    806                 <cfset cfcData.append('</cfcomponent>') /> 
    807                  
    808                 <!--- Create a name for the CFC using Hash() since that is faster than creating a UUID ---> 
    809                 <cfset cfcName = Hash(getTickCount() & RandRange(0, 10000) & RandRange(0, 10000)) /> 
    810                  
    811                 <!--- Write the cfc data to a temp file ---> 
    812                 <cftry> 
    813                         <cffile action="write"  
    814                                 output="#cfcData.toString()#"  
    815                                 file="#cfcDirectory#/#cfcName#.cfc" /> 
    816                         <cfcatch type="any"> 
    817                                 <cfthrow type="MachII.properties.ColdspringProperty.CFCWritePermissions" 
    818                                         message="Cannot write temporary CFC for autowiring to '#cfcDirectory#'. Does your CFML engine have write permissions to this directory?" 
    819                                         detail="#getAppManager().getUtils().buildMessageFromCfCatch(cfcatch)#" /> 
    820                         </cfcatch> 
    821                 </cftry> 
    822                  
    823                 <!--- Instantiate the component ---> 
    824                 <cftry> 
    825                         <cfset autowireCfc = CreateObject("component", getDotPathToCfcGenerationLocation() & cfcName) /> 
    826                         <cfcatch type="any"> 
    827                                 <cfif StructKeyExists(cfcatch, "missingFileName")> 
    828                                         <cfthrow type="MachII.properties.ColdspringProperty.CannotFindCFC" 
    829                                                 message="Cannot find a temporary CFC at '#getDotPathToCfcGenerationLocation() & cfcName#'." 
    830                                                 detail="Please check that the dot path location '#getDotPathToCfcGenerationLocation() & cfcName#' and cfcGenerationLocation '#cfcDirectory#' point to the same directory." /> 
    831                                 <cfelse> 
    832                                         <cfrethrow /> 
    833                                 </cfif>                                          
    834                         </cfcatch> 
    835                 </cftry> 
    836                  
    837                 <!--- Delete the temp cfc ---> 
    838                 <cffile action="delete"  
    839                         file="#cfcDirectory#/#cfcName#.cfc" /> 
    840                  
    841                 <cfreturn autowireCfc /> 
    842         </cffunction> 
    843          
    844769        <cffunction name="referenceBeansToMachIIProperties" access="private" returntype="void" output="false" 
    845770                hint="Places references to ColdSpring managed beans into the Mach-II properties."> 
     
    884809        </cffunction> 
    885810         
    886         <cffunction name="setCfcGenerationLocation" access="private" returntype="void" output="false"> 
    887                 <cfargument name="cfcGenerationLocation" type="string" required="true" /> 
    888                 <cfset variables.instance.cfcGenerationLocation = arguments.cfcGenerationLocation /> 
    889         </cffunction> 
    890         <cffunction name="getCfcGenerationLocation" access="public" returntype="string" output="false"> 
    891                 <cfreturn variables.instance.cfcGenerationLocation /> 
    892         </cffunction> 
    893          
    894         <cffunction name="setDotPathToCfcGenerationLocation" access="private" returntype="void" output="false"> 
    895                 <cfargument name="dotPathToCfcGenerationLocation" type="string" required="true" /> 
    896                  
    897                 <!--- Add a trailing dot of the path exists ---> 
    898                 <cfif Len(dotPathToCfcGenerationLocation)> 
    899                         <cfset arguments.dotPathToCfcGenerationLocation = arguments.dotPathToCfcGenerationLocation & "." /> 
    900                 </cfif> 
    901                  
    902                 <cfset variables.instance.dotPathToCfcGenerationLocation = arguments.dotPathToCfcGenerationLocation /> 
    903         </cffunction> 
    904         <cffunction name="getDotPathToCfcGenerationLocation" access="public" returntype="string" output="false"> 
    905                 <cfreturn variables.instance.dotPathToCfcGenerationLocation /> 
    906         </cffunction> 
    907          
    908811        <cffunction name="setConfigFilePaths" access="private" returntype="void" output="false"> 
    909812                <cfargument name="configFilePaths" type="array" required="true" />