Digamos que você tenha um arquivo tomcat/conf/context.xml que se parece com isso:
<?xml version="1.0" encoding="utf-8"?>
<Context>
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<Resource
name="jdbc/MyDB"
auth="Container"
type="javax.sql.DataSource"
removeAbandoned="true"
removeAbandonedTimeout="15"
maxActive="5"
maxIdle="5"
maxWait="7000"
username="${db.mydb.uid}"
password="${db.mydb.pwd}"
driverClassName="${db.mydb.driver}"
url="${db.mydb.url}${db.mydb.dbName}?autoReconnectForPools=true&characterEncoding=UTF-8"
factory="com.mycompany.util.configuration.CustomDataSourceFactory"
validationQuery="SELECT '1';"
testOnBorrow="true"/>
</Context>
O que queremos substituir neste caso é qualquer coisa no material ${.*} nesta definição de recurso. Com uma pequena modificação no código abaixo, no entanto, você pode realizar essas substituições em praticamente qualquer critério que desejar.
Observe a linha
factory="com.mycompany.util.configuration.CustomDataSourceFactory"
O que isso significa é que o Tomcat tentará usar essa fábrica para processar esse recurso. Deve ser mencionado que isso significa que esta fábrica terá que estar no classpath do Tomcat na inicialização (Pessoalmente, eu coloquei o meu em um JAR no Tomcat
lib
diretório). Veja como está minha fábrica:
package com.mycompany.util.configuration;
import java.util.Hashtable;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.RefAddr;
import javax.naming.Reference;
import javax.naming.StringRefAddr;
import javax.naming.spi.ObjectFactory;
import org.apache.commons.dbcp.BasicDataSourceFactory;
public class CustomDataSourceFactory extends BasicDataSourceFactory implements ObjectFactory {
private static final Pattern _propRefPattern = Pattern.compile("\\$\\{.*?\\}");
//http://tomcat.apache.org/tomcat-6.0-doc/jndi-resources-howto.html#Adding_Custom_Resource_Factories
@Override
public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment) throws Exception {
if (obj instanceof Reference) {
Reference ref = (Reference) obj;
System.out.println("Resolving context reference values dynamically");
for(int i = 0; i < ref.size(); i++) {
RefAddr addr = ref.get(i);
String tag = addr.getType();
String value = (String) addr.getContent();
Matcher matcher = _propRefPattern.matcher(value);
if (matcher.find()) {
String resolvedValue = resolve(value);
System.out.println("Resolved " + value + " to " + resolvedValue);
ref.remove(i);
ref.add(i, new StringRefAddr(tag, resolvedValue));
}
}
}
// Return the customized instance
return super.getObjectInstance(obj, name, nameCtx, environment);
}
private String resolve(String value) {
//Given the placeholder, do stuff to figure out what it's true value should be, and return that String.
//This could be decryption, or maybe using a properties file.
}
}
Então, quando esse código estiver no caminho de classe, reinicie o Tomcat e observe catalina.out para as mensagens de log. NOTA:O
System.out.println
As instruções provavelmente acabarão imprimindo informações confidenciais em seus logs, portanto, você pode removê-las assim que terminar a depuração. Em uma nota lateral, escrevi isso porque descobri que muitos exemplos eram muito específicos para um tópico específico (como a utilização de criptografia) e queria mostrar como isso pode ser feito genericamente. Além disso, algumas das outras respostas a essa pergunta não se explicam muito bem, e eu tive que pesquisar para descobrir o que precisava ser feito para que isso funcionasse. Eu queria compartilhar minhas descobertas com vocês. Sinta-se à vontade para comentar sobre isso, fazer perguntas ou fazer correções se encontrar problemas, e com certeza incluirei as correções em minha resposta.