Il s'agissait de donner la possibilité à un utilisateur connecté à l'application web de changer de connexion de base de données mais rien que pour lui.
Autrement dit uniquement sur sa session web sans impacter les autres utilisateurs.
Cette fonctionnalité vient de la version précédente de l'application, une version client serveur en VB qui permettait à chaque poste client de se connecté a une base différente.
L'idée est que l'utilisateur peut vouloir se connecter à l'application pour travailler sur un base archivé qui n'est pas la base courante de travaille.
L'application doit proposer 3 bases d'archive en plus de la base courante.
Les bases d'archives sont une image de la base courante à un instant t , le mapping hibernate reste donc le même.
Très honnêtement j'ai tout de suite dit que ça me semblait irréalisable, SPRING chargeant le "DataSource" à l'initialisation de la webapp je voyais pas comment le réinitialiser dynamiquement et encore moins comment réinitialiser le data source pour une unique session web sans impacter les autres utilisateurs connecté au même moment sur la même application, tout simplement parce que le data source est unique pour toute l'application.
J'ai fini par trouvé une solution qui fonctionne plutot bien, dans le contexte de cette application.
D'abord j'ai déclaré l'ensemble des "data sources" dans le fichier de configuration de SPRING "applicationContext.xml" :
<bean id="parentDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" abstract="true"> <property name="driverClassName" value="org.postgresql.Driver" /> <property name="username" value="******" /> <property name="password" value="******" /> </bean> <bean id="courante" parent="parentDataSource"> <property name="url" value="url de connexion base courante" /> </bean> <bean id="archive1" parent="parentDataSource"> <property name="url" value="url de connexion base d'archive 1" /> </bean> <bean id="archive2" parent="parentDataSource"> <property name="url" value="url de connexion base d'archive 2" /> </bean> <bean id="archive3" parent="parentDataSource"> <property name="url" value="url de connexion base d'archive 3" /> </bean> <bean id="dataSource" class="com.capjtel.vtp.metier.datasource.BDDRoutingDataSource"> <property name="targetDataSources"> <map key-type="com.capjtel.vtp.metier.datasource.BDDType"> <entry key="COURANTE" value-ref="courante" /> <entry key="ARCHIVE1" value-ref="archive1" /> <entry key="ARCHIVE2" value-ref="archive2" /> <entry key="ARCHIVE3" value-ref="archive3" /> </map> </property> <property name="defaultTargetDataSource" ref="courante" /> </bean>On définit tous les paramètres de connexion dans la balise d'id "parentDataSource".
Ensuite je défini le dataSource à proprement parlé.
Dans l'attribut class je spécifie la classe BDDRoutingDataSource qui hérite de org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource.
Il s'agit de la classe qui indiquera à Spring quel "DataSource" utiliser parmi les "targetDataSources" de type BDDType:
public class BDDRoutingDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return BDDContextHolder.getBDDType();
}
}
public enum BDDType {
COURANTE,
ARCHIVE1,
ARCHIVE2,
ARCHIVE3
}
public class BDDContextHolder {
public static final ThreadLocal<BDDType> contextHolder = new ThreadLocal<BDDType>();
public static void setCustomerType(BDDType bddType) {
contextHolder.set(bddType);
}
public static void setCustomerType(String bddType) {
if (bddType == null) {
setCustomerType(BDDType.COURANTE);
}else if(BDDType.COURANTE.equals(bddType)){
setCustomerType(BDDType.COURANTE);
}else if(BDDType.ARCHIVE1.equals(bddType)){
setCustomerType(BDDType.ARCHIVE1);
}else if(BDDType.ARCHIVE2.equals(bddType)){
setCustomerType(BDDType.ARCHIVE2);
}else if(BDDType.ARCHIVE3.equals(bddType)){
setCustomerType(BDDType.ARCHIVE3);
}
}
public static BDDType getBDDType() {
return (BDDType) contextHolder.get();
}
public static void clearBDDType() {
contextHolder.remove();
}
}
La classe BDDContextHolder conserve le BDDType dans un ThreadLocal ainsi le BDDType est propre au thread courant.
Concretement l'utilisateur choisi sa base de travaille, elle est stocké dans la session HTTP, puis dans un servlet Filter j'initialise le BDDContextHolder pour le thread courant avec le contenue de la session HTTP, ainsi chaque requete http de l'utilisateur a son propre data source.
Aucun commentaire:
Enregistrer un commentaire