Reputation: 41213
My Spring config looks like this:
<jee:remote-slsb id="ejb1"
jndi-name="org.example.Ejb1"
business-interface="org.example.Ejb1"
environment-ref="ejb1Properties">
</jee:remote-slsb>
<util:properties id="ejb1Properties" location="classpath:ejb1.properties"/>
<jee:remote-slsb id="ejb2"
jndi-name="org.example.Ejb2"
business-interface="org.example.Ejb2"
environment-ref="ejb2Properties">
</jee:remote-slsb>
<util:properties id="ejb2Properties" location="classpath:ejb2.properties"/>
... because the two EJBs may use different JNDI URLs, different context factories and authentication credentials. ejb1.properties and ejb2.properties have properties of the same name, with different values:
ejb1.properties:
java.naming.factory.initial=weblogic.jndi.WLInitialContextFactory
java.naming.provider.url=t3://example1:7101
java.naming.security.principal=id1
java.naming.security.credential=foo
ejb2.properties:
java.naming.factory.initial=weblogic.jndi.WLInitialContextFactory
java.naming.provider.url=t3://example2:7101
java.naming.security.principal=id2
java.naming.security.credential=bar
However, I would like my users to have one properties file to maintain, not two.
Clearly it's easy to write a startup script that generates ejb1.properties and ejb2.properties from a core properties file. But is there a way to have Spring get properties from a single file, mapping the names appropriately?
Upvotes: 4
Views: 982
Reputation: 10974
AFAIK, there is nothing in Spring that handles your situation. However, one straight forward solution would be to extend PropertiesFactoryBean and override the mergeProperties() method. Here is an example of such a extension that filters property entries based on a name prefix:
public class FilteringPropertiesFactoryBean extends PropertiesFactoryBean {
private String namePrefix;
@Override
protected Properties mergeProperties() throws IOException {
Properties unfilteredProperties = super.mergeProperties();
Properties filteredProperties = new Properties();
// iterator over keys
// discard entries whose key doesn't start with prefix
for (Object key : unfilteredProperties.keySet()) {
String name = key.toString();
// trim the property name by removing the target prefix.
String trimmedName = trimName(name);
if (trimmedName != null) {
// add the property to the filtered collection
String value = unfilteredProperties.getProperty(name);
filteredProperties.setProperty(trimmedName, value);
}
}
return filteredProperties;
}
public void setNamePrefix(String value) {
this.namePrefix = value;
}
private String trimName(String name) {
// does name start with the prefix and is the name longer than the prefix
if (name.startsWith(namePrefix) && name.length() > namePrefix.length()) {
return name.substring(namePrefix.length());
}
return null;
}
}
Configuring the factory bean would be something like:
<bean id="ejb1Properties" class="example.FilteringPropertiesFactoryBean">
<property name="location" value="classpath:merged.properties"/>
<property name="namePrefix" value="ejb1."/>
</bean>
With the above configuration and a merged.properties file containing:
ejb1.java.naming.factory.initial=weblogic.jndi.WLInitialContextFactory
ejb1.java.naming.provider.url=t3://example1:7101
ejb1.java.naming.security.principal=id1
ejb1.java.naming.security.credential=foo
ejb2.java.naming.factory.initial=weblogic.jndi.WLInitialContextFactory
ejb2.java.naming.provider.url=t3://example2:7101
ejb2.java.naming.security.principal=id2
ejb2.java.naming.security.credential=bar
The resulting properties returned by FilteringPropertiesFactoryBean#mergeProperties() is (note the prefix is stripped from the final property names):
java.naming.factory.initial = weblogic.jndi.WLInitialContextFactory
java.naming.provider.url = t3://example1:7101
java.naming.security.principal = id1
java.naming.security.credential = foo
Upvotes: 6