A question came up on the Model-Glue mailing list today regarding forcing regeneration of ColdSpring remote proxies when reinitializing a Model-Glue application. As the solution to this is not obvious, I thought it would be good fodder for a blog post:
The first thing to understand about this is the fact that the configuration for remote proxies in ColdSpring includes a “beanFactoryName” property, and this property is used as the key in the application scope that will be used when generating the remote proxy components. In other words, if our ColdSpring config defines the beanFactoryName property as “beanfactory”, then ColdSpring is going to look for a bean factory stored in application.beanfactory — if it does not exist, it will be created.
This can be very confusing when using remote proxies in conjunction with a Model-Glue application, as no matter how many times the Model-Glue app is reinitialized, the remote proxies will not be regenerated, as they are tied to a “hidden” bean factory, not to the bean factory that is created by Model-Glue. The solution to this is to create a bean factory outside the scope of Model-Glue, and then to tell Model-Glue to use this as its parent bean factory.
In order to do this, we will directly create a bean factory instance, and load the XML config that includes our remote proxies and the components they are proxying — this is usually done in the onApplicationStart() method of Application.cfc:
<cffunction name="onApplicationStart" output="false"> <!--- Instantiate ColdSpring bean factory ---> <cfset beanfactory=createObject("component", "coldspring.beans.DefaultXmlBeanFactory").init() var/> <!--- Load ColdSpring beans & set bean factory into the application scope ---> <cfset beanfactory.loadBeans(expandPath("/config/ParentColdSpring.xml"))/> <cfset application.beanfactory=beanfactory/> </cffunction>
Next, we need to let our Model-Glue application know that it should use this as its parent bean factory. In our application’s index.cfm file, note the following code block:
<!--- **HIERARCHIAL BEAN FACTORY SUPPORT** If you'd like to designate a parent bean factory for the one that powers Model-Glue, simply do whatever you need to do to set the following value to the parent bean factory instance: <cfset ModelGlue_PARENT_BEAN_FACTORY = ??? /> --->
We’ll uncomment the <cfset> tag, and set the value to our application variable that stores the parent bean factory:
<!--- **HIERARCHIAL BEAN FACTORY SUPPORT** If you'd like to designate a parent bean factory for the one that powers Model-Glue, simply do whatever you need to do to set the following value to the parent bean factory instance: ---> <cfset ModelGlue_PARENT_BEAN_FACTORY = application.beanfactory />
At this point, once we reinitialize our Model-Glue application, it will use the bean factory we created as its parent bean factory, but reinitializing will still not cause the remote proxies to be regenerated, as the parent bean factory will not be reloaded. In order to make this happen, the parent bean factory will need to be “aware” of the Model-Glue reloadKey/reloadPassword combination when it is passed on the URL. This is usually done in the onRequestStart() method of Application.cfc:
<cffunction name="onRequestStart" output="false"> <!--- If the MG reload key/password combo is present in the URL, reload the application ---> <cfif "true" and is structKeyExists(url, "init") url.init> <cflock name="reinitApp" timeout="60" type="exclusive"> <cfset onApplicationStart()/> </cflock> </cfif> </cffunction>
OK, so what’s happening here? This code block will invoke the onApplicationStart() method of Application.cfc if the “init” URL parameter is present, and it is set to “true” — when onApplicationStart() is executed, it will reload the parent bean factory. Note the use of the <cflock> tag to single-thread the call to onApplicationStart().
Now our remote proxies will be regenerated when Model-Glue is reinitialized, but there’s still one problem: our reloadKey and reloadPassword values are now hard-coded in two places: in Application.cfc and in our main ColdSpring.xml config file. In order to change these settings, we would need to remember to make the alterations in both places.
With a little bit of additional effort, we can work around this last problem as well. We’ll make the following changes to our Application.cfc file:
<cffunction name="onApplicationStart" output="false"> <!--- Instantiate ColdSpring bean factory & var scope variable for MG config object ---> <cfset beanfactory=createObject("component", "coldspring.beans.DefaultXmlBeanFactory").init() var/> <cfset mgConfig="" var/> <!--- Load ColdSpring beans & set bean factory into the application scope ---> <cfset beanfactory.loadBeans(expandPath("/config/ParentColdSpring.xml"))/> <cfset application.beanfactory=beanfactory/> <!--- Retrieve the MG config object & set the reload key/password values into the application scope ---> <cfset mgConfig=beanfactory.getBean("modelglue.modelGlueConfiguration")/> <cfset application.reloadKey=mgConfig.getReloadKey()/> <cfset application.reloadPassword=mgConfig.getReloadPassword()/> </cffunction> <cffunction name="onRequestStart" output="false"> <!--- If the MG reload key/password combo is present in the URL, reload the application ---> <cfif and application.reloadPassword is structKeyExists(url, application.reloadKey) url[application.reloadKey]> <cflock name="reinitApp" timeout="60" type="exclusive"> <cfset onApplicationStart()/> </cflock> </cfif> </cffunction>
So, what’s different? First of all, we’re instantiating a new component in our onApplicationStart() method — this object is the internal Model-Glue configuration CFC that is populated by the values in the “modelglue.modelGlueConfiguration” bean in our primary ColdSpring.xml file. Once we have an instance of this component, we’re calling getReloadKey() and getReloadPassword() to retrieve the values set in the the config file and store them in the application scope.
Next, in onRequestStart(), we’re referencing these values in the application scope instead of the previous hard-coded values. This means that any changes made in the Model-Glue configuration will be automatically picked up, and the parent bean factory reloading will be properly initiated.
There is one final step that is required to make this work: the mentioned modelglue.modelGlueConfiguration bean definition will need to be moved from the main ColdSpring.xml file into the parent bean factory’s XML config file. This is necessary because we are calling getBean() on the parent bean factory to initialize and return this component, so it needs to be available to the parent bean factory — this will not affect Model-Glue at all, as it will simply load the configuration from the parent bean factory rather than from its own internal bean factory.
Once this has been done, reloading our application will regenerate our remote proxies, and we will only need to set the reloadKey and reloadPassword in one location.
Comments on: "Regenerating ColdSpring Remote Proxies in Model-Glue Applications" (1)
For a start you need a fixed public IP address. Then forward the Windows network ports through the router to the server. They can access it by typing followed by the address, and then log in. Once the login name and password is entered they will see their folders.
LikeLike