PDA

View Full Version : Placeholder values from an object and/or non app.config


innes
09-07-2005, 01:51 PM
From the documentation, I can see that Spring supports replacing ${placeholders} with values in specified namevalue sections of [App].config.

Is there any way for me to instruct Spring to replace placeholders from an instance of an object I provide (I am thinking of something implementing a hypothetical interface called IPlaceholderSource which might or might not exist in reality)? For example, I would like to replace '${machinename}' with the value of Environment.MachineName, and this would need some code to provide the replacement value dynamically.

I would also like to specify other placeholder values in a file, but not [App].config, so the settings are accessible to all applications in the same directory. If the placeholder values can only be loaded from app.config, I have to duplicate the values in a number of app config files - one for each application in the directory.

Alternatively, is there a way for me to just define an object in the context which is a namevaluecollection (I can see that setting properties to namevaluecollections is possible), and use some syntax to set properties of other objects to values in this namevaluecollection?

This is probably incomprehensible - I hope somebody can understand what I'm on about!

Rick Evans
09-07-2005, 02:58 PM
Hiya

I would also like to specify other placeholder values in a file, but not [App].config, so the settings are accessible to all applications in the same directory. If the placeholder values can only be loaded from app.config, I have to duplicate the values in a number of app config files - one for each application in the directory.

You can have any number of arbitrary XML files for supplying name-value pairs. See the API documentation (http://www.springframework.net/doc/api/html/Spring.Objects.Factory.Config.PropertyPlaceholderC onfigurer.html) for the PropertyPlaceHolderConfigurer (http://www.springframework.net/doc/api/html/Spring.Objects.Factory.Config.PropertyPlaceholderC onfigurer.html) class.

You can supply any old resource location to the 'locations' property of the PropertyPlaceHolderConfigurer (http://www.springframework.net/doc/api/html/Spring.Objects.Factory.Config.PropertyPlaceholderC onfigurer.html) class. If your arbitrary name-value pairs are not in your [web]apps .config file, you will have to create a file like this (lets call it dao.config)...

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="DaoConfiguration" type="System.Configuration.NameValueSectionHandler, System" />
</configSections>
<DaoConfiguration>
<add key="connection.string" value="dsn=MyDSN;uid=sa;pwd=myPassword;" />
</DaoConfiguration>
</configuration>

The corresponding .config file would look like this...

<objects xmlns="http://www.springframework.net"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.net http://www.springframework.net/xsd/spring-objects.xsd">

<object name="testObjectDao" type="Spring.Objects.TestObjectDAO, Spring.Core.Tests ">
<property name="maxResults" value="${maxResults}"/>
<property name="dbConnection" ref="myConnection"/
</object>

<object name="myConnection" type="System.Data.Odbc.OdbcConnection, System.Data">
<property name="connectionstring" value="${connection.string}"/>
</object>

<object name="appConfigPropertyHolder"
type="Spring.Objects.Factory.Config.PropertyPlaceholderC onfigurer, Spring.Core">
<property name="locations">
<list>
<value>file://myApp/daoconfig.xml</value>
</list>
</property>
<property name="configSections">
<value>DaoConfiguration</value>
</property>
</object>

</objects>

If you have the full source codebase, you may wish to check out the unit tests for the relevant classes, which demonstrate how to use this feature. I will amend the reference documentation to include an example of this.

For example, I would like to replace '${machinename}' with the value of Environment.MachineName, and this would need some code to provide the replacement value dynamically.

Well, hopefully I'm not going slightly outfield on this response to your question, but environment variable expansion is supported out of the box on the PropertyPlaceHolderConfigurer (http://www.springframework.net/doc/api/html/Spring.Objects.Factory.Config.PropertyPlaceholderC onfigurer.html) class. See the API documentation for the above class, and consult the EnvironmentVariableMode (http://www.springframework.net/doc/api/html/Spring.Objects.Factory.Config.PropertyPlaceholderC onfigurer.EnvironmentVariableMode.html) property.

Is there any way for me to instruct Spring to replace placeholders from an instance of an object I provide (I am thinking of something implementing a hypothetical interface called IPlaceholderSource which might or might not exist in reality)?

Good point. I agree that the current implementation (which mandates the use of XML-based name-value pair configuration files) is poor. The class that sources the NameValueCollection should not be coupled to the class that consumes said NameValueCollection... its only done this way to be compliant with the Spring.Java codebase. I don't like this though, and I will change it... a JIRA issue (http://opensource2.atlassian.com/projects/spring/browse/SPRNET-140) has been pending for some weeks now.

Ciao
Rick

innes
09-08-2005, 02:00 PM
Thanks Rick - I didnt notice the Location property. After finding a chunk of code for using the placeholder configurer with IObjectFactory, my config file is back from a spring object definition file, to its old self. :)
I am not using a placeholder to replace MACHINENAME, because the placeholder in this case is in the 'replacement value' of another placeholder - a SQL connection string. So I'll stick with replacing programmatically in my code for the time being.

Rick Evans
09-08-2005, 04:07 PM
Hiya

After finding a chunk of code for using the placeholder configurer with IObjectFactory, my config file is back from a spring object definition file, to its old self.

Cool.

I am not using a placeholder to replace MACHINENAME, because the placeholder in this case is in the 'replacement value' of another placeholder - a SQL connection string.

Mmm... well, I'm not trying to be obscene here :) but perhaps you can take advantage of the fact that the PropertyPlaceHolderConfigurer implements the IOrdered (http://www.springframework.net/doc/api/html/Spring.Core.IOrdered.html) interface to address this issue.

You could have two PropertyPlaceHolderConfigurers in your context. One of them is pretty much the same one that you have now. The second one (lets call it 'environmentPropertyPlaceHolderConfigurer') is tasked with replacing only environment variables. You make the first configurer (your current one) fire off first by setting its Order (http://www.springframework.net/doc/api/html/Spring.Core.IOrdered.Order.html) property to lets say 0; you then set the same property on the 'environmentPropertyPlaceHolderConfigurer' object to 1. This makes the 'environmentPropertyPlaceHolderConfigurer' object do its property replacing after the first one.

So then lets say your current properties file contains an entry ...

<name-values>
<add key="connectionstring" value="san=Foo;uid=bill;password=ben;server=${MACHINENAME }" />
</name-values>

So the first configurer kicks in and replaces all instances of ${connectionstring} with the value 'san=Foo;uid=bill;password=ben;server=${MACHINENAM E}'. The second configurer then gets its chance, and it resolves the placeholder value of '$MACHINENAME}' with well, whatever the value of the MACHINENAME environment variable is on your er, machine.

Mmm... my explanation seems a bit rough. I'll polish it up (hopefully you get where I'm going), and I'll include an example of this kind of double tap configuration in the reference documentation :)

Ciao
Rick