This is a bit more work but it's very flexible:

Write an "environment service" component that is initialized with a
map in ColdSpring that contains the settings for all tiers with host
name matches for each (and a default development map). The environment
service gets the server hostname and finds the matching map at
startup. All code that depends on environment values has the
environment service wired in as a dependency and fetches configuration
values from it.

Here's some snips of the way we had it set up at Broadchoice:

        <!--
                Environment definitions:
        -->
        <bean id="environmentService"
class="bc.common.model.service.EnvironmentService">
                <constructor-arg name="encryptService"><ref
bean="encryptService"/></constructor-arg>
                <constructor-arg name="environments">
                        <list>
                                <!--
                                        tier = deployment tier (production, 
shared-dev, localhost etc) - required
                                        rootDomain = .subdomain.com for 
workshop/portal - required
                                        clustered = true | false (default false)
                                        workshopDomainPrefix = workshop 
(default; or appropriate prefix,
e.g., workshop-dev)
                                        workshopProtocol = http | https 
(default http)
                                        portalDomainPrefix = portal (default; 
or appropriate prefix,
e.g., portal-dev)
                                        portalProtocol = http | https (default 
http)
                                        fromAddress = [email protected] 
(default; or some alternative
email address)
                                        newAccountNotifyAddress = 
[email protected] (default; or some
alternative email address)
                                        errorNotifyAddress = 
[email protected] (default; or some
alternative email address)
                                        sfUserName = Broadchoice SalesForce.com 
username (default is
Patrick's eTek account)
                                        sfPassword = Broadchoice SalesForce.com 
password (default is
Patrick's eTek account)
                                        sfToken = Broadchoice SalesForce.com 
token (default is Patrick's
eTek account)
                                        nsUserName = Broadchoice NetSuite.com 
username (default is
Robert's development account)
                                        nsPassword = Broadchoice NetSuite.com 
password (default is
Robert's development account)
                                        nsAccount = Broadchoice NetSuite.com 
token (default is Robert's
development account)
                                        localhostMatch = list of regex to match 
actual server names or IP
addresses (defaults to .*)
                                                (note: locahost IP address is 
normally 127.0.0.1 so try to match
by hostname!)
                                -->
                                <!-- production -->
                                <map>
                                        <entry 
key="tier"><value>production</value></entry>
                                        <entry 
key="rootDomain"><value>.broadchoice.com</value></entry>
                                        <entry 
key="clustered"><value>true</value></entry>
                                        <entry 
key="portalDomainPrefix"><value>dmm</value></entry>
                                        <entry 
key="fromAddress"><value>...</value></entry>
                                        <entry 
key="newAccountNotifyAddress"><value>...</value></entry>
                                        <entry 
key="errorNotifyAddress"><value>...</value></entry>
                                        <entry 
key="sfUserName"><value>...</value></entry>
                                        <entry 
key="sfPassword"><value>...</value></entry>
                                        <entry 
key="sfToken"><value>...</value></entry>
                                        <entry 
key="nsUserName"><value>...</value></entry>
                                        <entry 
key="nsPassword"><value>...</value></entry>
                                        <entry 
key="nsAccount"><value>...</value></entry>
                                        <entry key="localhostMatch"><value> 
domU-.*-compute</value></entry>
                                </map>
                                <!-- staging servers -->
                                <map>
                                        <entry 
key="tier"><value>staging</value></entry>
                                        <entry 
key="rootDomain"><value>.broadchoice.com</value></entry>
                                        <entry 
key="workshopDomainPrefix"><value>workshop-stage</value></entry>
                                        <entry 
key="portalDomainPrefix"><value>dmm-stage</value></entry>
                                        <entry 
key="newAccountNotifyAddress"><value>...</value></entry>
                                        <entry 
key="errorNotifyAddress"><value>...</value></entry>
                                        <entry 
key="localhostMatch"><value>apps2.broadchoice.com</value></entry>
                                </map>
                                <!-- shared-dev -->
                                <map>
                                        <entry 
key="tier"><value>shared-dev</value></entry>
                                        <entry 
key="rootDomain"><value>.broadchoice.com</value></entry>
                                        <entry 
key="workshopDomainPrefix"><value>workshop-dev</value></entry>
                                        <entry 
key="portalDomainPrefix"><value>portal-dev</value></entry>
                                        <entry 
key="newAccountNotifyAddress"><value>...</value></entry>
                                        <entry 
key="errorNotifyAddress"><value>...</value></entry>
                                        <entry 
key="localhostMatch"><value>apps.broadchoice.com</value></entry>
                                </map>
                                <!-- sean's localhost - if you copy this, 
please *change the email
addresses*! -->
                                <map>
                                        <entry 
key="tier"><value>localhost</value></entry>
                                        <entry 
key="clustered"><value>false</value></entry>
                                        <entry 
key="rootDomain"><value>.local.broadchoice.com</value></entry>
                                        <entry 
key="fromAddress"><value>[email protected]</value></entry>
                                        <entry 
key="newAccountNotifyAddress"><value>[email protected]</value></entry>
                                        <entry 
key="errorNotifyAddress"><value>[email protected]</value></entry>
                                        <entry 
key="localhostMatch"><value>scorfield-macintel</value></entry>
                                </map>
                                <!-- generic localhost - this *must* be the 
last entry! -->
                                <map>
                                        <entry 
key="tier"><value>localhost</value></entry>
                                        <entry 
key="rootDomain"><value>.local.broadchoice.com</value></entry>
                                </map>
                        </list>
                </constructor-arg>
        </bean>

EnvironmentService.cfc looks like this (relevant parts):

<cfcomponent output="false">
        
        <cffunction name="init" returntype="any" access="public"
output="false" hint="I am the constructor.">
                <cfargument name="encryptService" type="any" required="true" />
                <cfargument name="environments" type="array" required="true" />
                
                <cfset var localhost = getLocalHostname() />
                <cfset var matches = "" />
                <cfset var env = 0 />
                <cfset var regex = "" />
                
                <cflog application="true" log="application"
text="EnvironmentService.init() : localhost = #localhost#"
type="information" />
                
                <cfloop index="env" array="#arguments.environments#">
                
                        <cfif structKeyExists(env,"localhostMatch")>
                                <cfset matches = env.localhostMatch />
                        <cfelse>
                                <cfset matches = ".*" />
                        </cfif>
                
                        <cfloop index="regex" list="#matches#">
                        
                                <cfif REFind(regex,localhost) neq 0>
                                        
                                        <!--- found a match, set our parameters 
and exit --->
                                        <cfset variables.tier = env.tier />
                                        <cfset variables.rootDomain = 
env.rootDomain />
                                        <cfif left(variables.rootDomain,1) is 
not ".">
                                                <cfset variables.rootDomain = 
"." & variables.rootDomain />
                                        </cfif>
                                        <cfif structKeyExists(env,"clustered")>
                                                <cfset variables.clustered = 
env.clustered />
                                        <cfelse>
                                                <cfset variables.clustered = 
false />
                                        </cfif>

... etc for all the safe built-in default values for each optional
environment key ...
... throw exceptions for missing required keys ...

                                        <!--- now make the actual URLs --->
                                        <cfset variables.portalDomain = 
variables.portalDomainPrefix &
variables.rootDomain />
                                        <cfset variables.workshopURL = 
variables.workshopProtocol & "://"
& variables.workshopDomainPrefix & variables.rootDomain />
                                        <cfset variables.portalURL = 
variables.portalProtocol & "://" &
variables.portalDomain />
                                        <cflog log="console" text="workshopURL: 
#variables.workshopURL#" />
                                        <cflog log="console" text="portalURL: 
#variables.portalURL#" />
                                
                                        
                                        <cfreturn this />
                                        
                                </cfif>
                        
                        </cfloop>
                
                </cfloop>
                
                <!--- uh-oh! no matching localhost server --->
                <cfthrow type="bc.environment.not_found" message="Unknown
environment" detail="Localhost #localhost# is not recognized - unable
to initialize!" />

        </cffunction>

        <cffunction name="getLocalHostname" returntype="string"
access="public" output="false" hint="I return the actual server
hostname / IP">
        
                <!--- figure out the localhost server name --->
                <cfset var inet = createObject("java","java.net.InetAddress") />
                
                <!--- this is servername/ipaddress: --->
                <cfreturn inet.getLocalHost() />

        </cffunction>

        <cffunction name="getRemoteIP" returntype="string" access="public"
output="false" hint="I return the actual REMOTE_ADDR allowing for F5
load balancer.">
                
                <cfset var headers = getHttpRequestData().headers />
                <!--- if a load balancer has swapped the IP, retrieve the 
extended header --->
                <cfif structKeyExists(headers, "X-Forwarded-For")>
                        <cfreturn headers["X-Forwarded-For"] />
                <cfelse>
                        <!--- looks like the CGI variable is the truth, so 
return that directly --->
                        <cfreturn CGI.REMOTE_ADDR />
                </cfif>
                
        </cffunction>

        <cffunction name="getClustered" returntype="boolean" access="public"
output="false" hint="I return the indicator for whether this tier is
clustered.">
        
                <cfreturn variables.clustered />
        
        </cffunction>

... etc for each of the properties ...

</cfcomponent>

I've left getLocalHostname() and getRemoteIP() in because they're
useful to know about.

FWIW, Mach-II has something very similar to this coming in 1.8 and
ColdBox already has support for it as an interceptor.

Hope this code / example is useful for folks.

Sean

On Wed, Apr 22, 2009 at 6:46 AM, Al <[email protected]> wrote:
>
> I'm wondering how people manage differing configuration settings for
> the same app in different environments.
>
> Let me expand on what I mean.
>
> We have three tiers of servers: DEVELOPMENT, TEST, and PRODUCTION
> (hereafter D, T, P). For each of our applications we will have
> settings that vary based on environment. For instance, we may have a
> "test e-mail" to trap any outgoing e-mail and re-route it to the
> address in the setting rather than letting it go to the actual
> recipient. (Helps prevent messages being sent to live people from an
> app being tested.) In D that would probably be set to the development
> team, in T it would be set to the test team, and in P it would be
> NULL. Every app has a couple or half-dozen such settings.

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google
Groups "model-glue" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/model-glue?hl=en

For more about Model-Glue, check http://www.model-glue.com .
-~----------~----~----~----~------~----~------~--~---

Reply via email to