Załóżmy, że masz plik tomcat/conf/context.xml, który wygląda mniej więcej tak:
<?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>
W tym przypadku chcemy zastąpić wszystko, co zawiera ${.*} w tej definicji zasobu. Jednak po niewielkich modyfikacjach poniższego kodu możesz wykonać te zamiany na praktycznie dowolnych kryteriach.
Zwróć uwagę na wiersz factory="com.mycompany.util.configuration.CustomDataSourceFactory"
Oznacza to, że Tomcat spróbuje użyć tej fabryki do przetworzenia tego zasobu. Należy wspomnieć, że oznacza to, że ta fabryka będzie musiała znajdować się na ścieżce klas Tomcata podczas uruchamiania (osobiście umieściłem swoją w JAR w lib
Tomcata informator).
Oto jak wygląda moja fabryka:
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.
}
}
Następnie, gdy ten kod znajdzie się w ścieżce klasy, uruchom ponownie Tomcata i obserwuj catalina.out w poszukiwaniu komunikatów dziennika. UWAGA:System.out.println
wyciągi prawdopodobnie spowodują wydrukowanie poufnych informacji w dziennikach, więc możesz chcieć je usunąć po zakończeniu debugowania.
Na marginesie napisałem to, ponieważ odkryłem, że wiele przykładów było zbyt specyficznych dla jednego konkretnego tematu (takiego jak wykorzystanie kryptografii) i chciałem pokazać, jak można to zrobić ogólnie. Co więcej, niektóre inne odpowiedzi na to pytanie nie wyjaśniają się zbyt dobrze i musiałem trochę kopać, aby dowiedzieć się, co należy zrobić, aby to zadziałało. Chciałem podzielić się z wami moimi odkryciami. Zachęcamy do komentowania tego, zadawania jakichkolwiek pytań lub wprowadzania poprawek, jeśli znajdziesz problemy, a na pewno wprowadzę poprawki do mojej odpowiedzi.