views:

241

answers:

4

Hi StackOverflow,

Lets assume we've build a system with a DI framework which is working quite fine. This system currently uses JMS to "talk" with other systems not maintained by us. The majority of our customers like the JMS approach and uses it according to our specification. The component which does all the messaging is injected with Spring into the rest of the application.

Now we got the case that one customer cannot implement the JMS solution and want to use another messaging technology. Thats not a problem because we can simply implement a messaging service using this technology and inject it in the rest of the application.

But how are we supposed to handle the deployment and maintenance of the configuration? Since the application uses Spring i could imagine to check in all the configurations i have for this application and the system administrator could start the application and passing the name of the DI XML file to specify which configuration should be loaded. But... it just don't feel right. Are there any solutions for such cases available? What are the best-practices you use? I could even imagine more complex scenarios which do not contain only one service substitution...

Thanks a lot!

+2  A: 

One solution is to use a PropertyOverrideConfigurer in your Spring config. This allows you to provide a separate properties file which can override values in the Spring configuration when the Application Context is started up. That way, you have your standard config in your applicationContext.xml (which you ship to everyone), and an additional properties file which allows you to customize the config on a per-deployment basis, without changing your main config file.

<bean class="org.springframework.beans.factory.config.PropertyOverrideConfigurer">
  <property name="location"><value>file:${config.dir}/config.properties</value></property>   
</bean>
alasdairg
Yeah, i know and use this already for all the bean configurations. But what happens if i need to change a bean class completely only for one deployed instance? With new dependencies, etc, etc. Thats what im asking about. :-)
Malax
A: 

I think, you either have the choice to ship different versions of the product or stay with one product that supports both messaging systems.

I'd tend to the single product. If you don't want the customers admin to set the parameter that defines the messaging system, then you could provide a customer specific configuration file or append that information to your license file (if any) so that you can make sure, the customer uses the right version.

Only if the messaging systems depend on non-free third-party libraries, then I'd build different products, just to prevent license trouble.

Andreas_D
We do not ship this product in a traditional manner. All the application instances run on our infrastructure. :-) But i want something that the system administrators can use easily whitout know all the DI stuff that have to be configured for one specific customer. (All general configuration is done by property files like alasdarig said)
Malax
+2  A: 

Another suggestion then: How about splitting your spring config into two parts: a common file which is shipped to everyone, and a deployment-specific file which holds the varying bean definitions. So you could have:

applicationCommon.xml
deploymentJMS.xml
deploymentOtherMessaging.xml
deploymentDifferentAgainMessaging.xml

Then when your sys admins deploy, they select one of the deployment???.xml files, depending on the scenario and drop it into a config directory

Your application would be configured to use a wildcard expression to load the applicationCommon.xml file and any other xml file in the config directory, using them together to build the Application Context (without caring specifically which actual files they were).

The different deployment XML files would live in source control, and sys admins would not need any detailed knowledge beyond knowing that they always deploy the named deployment???.xml file that suits the scenario.

(If its a web application, you might want to have the "config" directory separate from the Web app itself, so that a re-deployment of the app did not overwrite the deployment-specific config)

And this deployment could all be scripted, of course, so that the correct file was selected by a command line parameter, for example ...

alasdairg
A: 

We have this same exact use case for one of our products.

We've created different sets of applicationContext files for each set of configurations. Our context files are already split into four different files (-servlet.xml, -services.xml, -dao.xml, etc.), and each file in the same "configuration suite" shares the same prefix in it's filename.

In this product we are using Ant to build the deployment files (.war). We set up our build.xml so we can pass in a different parameter to the build script to control which prefix is used when packaging the files. For example, we run

ant dist -DtargetApp=app1

to have a deployment file built with app1-dao.xml, app1-services.xml, etc., packaged.

Within Ant, we have logic that looks something like this to set the property to use for the "configuration suite" name:

<target name="set-environment">
    <!-- If the targetApp property is not set, default to "app1" -->
    <condition property="targetApp" value="app1">
        <not>
            <isset property="targetApp"/>
        </not>
    </condition>
    <echo>Using targetApp: ${targetApp}</echo>
<target>

Since this product is a web application, the value of the ${targetApp} property is then used to filter a value in the web.xml to tell Spring which application context files to load.

matt b