2012-07-27 7 views
8

Disons que j'ai le persistence.xml suivant avec l'URL de connexion, l'utilisateur & mot de passe tous codés en dur.Définition dynamique des propriétés de persistance JPA

Ce qui suit est pour Hibernate 3.2. Pour Hibernate 3.5 ++, nous devons remplacer "hibernate.connection" par "javax.persistence". Mais permettez-moi de poser cette question indépendamment des littéraux "hibernate.connection" ou "javax.persistence".

<persistence-unit name="obamacare" transaction-type="RESOURCE_LOCAL"> 
    <provider>org.hibernate.ejb.HibernatePersistence</provider> 
    <exclude-unlisted-classes>false</exclude-unlisted-classes> 
    <properties> 
    <property name="hibernate.archive.autodetection" value="class, hbm"/> 
    <property name="hibernate.connection.driver_class" value="oracle.jdbc.driver.OracleDriver"/> 
    <property name="hibernate.connection.url" value="blah blah blah"/> 
    <property name="hibernate.connection.username" value="careuser"/> 
    <property name="hibernate.connection.password" value="carepass"/> 
    <property name="hibernate.dialect" value="org.hibernate.dialect.OracleDialect"/> 
    <property name="hibernate.show_sql" value="true"/> 
    </properties> 
    </persistence-unit> 
</persistence> 

Cependant, nous devons définir l'URL, l'utilisateur & mot de passe dynamique. Il existe un serveur d'authentification proposé qui sert l'url, l'utilisateur & mot de passe. De sorte que nous n'avons pas besoin de configurer individuellement les myriades de webapps qui utilisent une forme de jdbc, hibernate ou JPA. Outre le problème de sécurité de ne pas vouloir stocker/gérer les mots de passe sur les fichiers texte visibles.

En ce qui concerne JPA, comment puis-je définir dynamiquement ces propriétés JPA? Je cherche deux séries de réponses:

  1. une solution qui est fournisseur JPA indépendante (TopLink, EclipseLink, mise en veille prolongée, etc.) - Y at-il des fonctionnalités de JPA qui me permettent de définir ces trois propriétés dynamiquement? Si je suis autorisé à dépendre totalement d'Hibernate, en plus de l'avenue JPA, y a-t-il un moyen d'y parvenir sans impliquer Spring framework (qui ressemble à une énorme monstruosité avec des tentacules partout)?

Je serais fou de joie si vous souhaitez également jeter dans deux cents/quids/roupies sur JNDI et comment je pourrais l'utiliser pour remplacer la fonctionnalité des propriétés persistence.xml. Cependant, ce n'est pas la priorité de la question.

+1

La plupart des choses que vous voulez accomplir peuvent être facilement réalisées avec Spring. J'utilise Spring depuis quelques semaines et je ne regrette pas du tout l'interrupteur. Le printemps semble être une grosse charge de travail, mais c'est en fait assez facile. – siebz0r

Répondre

7

Cela dépend de la façon dont vous amorcez votre EntityManagerFactory. Les deux méthodes définies par spécification vous permettent chacune de transmettre un java.util.Map de valeurs. Ces valeurs sont supposées avoir préséance sur les valeurs définies dans persistence-unit.

Dans la "approche SE" aucun problème puisque le processus d'amorçage est généralement contrôlé par votre application: javax.persistence.Persistence#createEntityManagerFactory(String puName, Map config. Maintenant, vous pourriez avoir des problèmes ici si quelque chose d'autre (ahem, Spring) est de "gérer" le EMF pour vous ...

Dans la "approche EE" je ne suis pas au courant d'une bonne approche globale. Cette carte de valeurs existe toujours dans le bootstrapping, mais le problème est que le conteneur EE est celui qui appelle cette méthode.

Une approche spécifique à Hibernate qui fonctionnerait dans les deux cas serait d'utiliser le remplacement de variables de configuration. Donc, dans votre unité de persistance, vous définiriez le nom d'utilisateur ou le mot de passe en utilisant ${some.key} et Hibernate les remplacerait pour vous. Cela dépend vraiment de la façon dont vous voulez définir ces valeurs en fin de compte; Hibernate a toujours besoin d'accéder à une valeur de configuration nommée some.key pour que cela fonctionne ...

Encore une autre "approche globale" ... La "approche EE" pour amorcer la fonction EMF consiste pour le conteneur à instancier la javax.persistence. spi.PersistenceProvider et appelez son javax.persistence.spi.PersistenceProvider # createContainerEntityManagerFactory. createContainerEntityManagerFactory a une signature intéressante ici. Essentiellement, il est passé un javax.persistence.spi.PersistenceUnitInfo qui est une représentation d'objet de l'unité de persistance analysée plus quelques autres choses. Une option serait d'utiliser cette approche pour bootstrap et passer dans une instance de javax.persistence.spi.PersistenceUnitInfo que vous construisez vous-même. javax.persistence.spi.PersistenceProvider est une interface. Pour l'instancier, vous devez connaître le fournisseur que vous souhaitez utiliser et le FQN pour leur impl. Mais ce n'est généralement pas un problème car ceux-ci sont assez bien connus.

Vous vous interrogez spécifiquement sur la création/la mise en pool de connexions JDBC. Vous avez des options supplémentaires ici spécifiquement. Vous pourriez avoir votre "service d'identification" créer DataSources et votre fournisseur JPA simplement utiliser cette DataSource. Tous les fournisseurs JPA prennent en charge la localisation de DataSources via la recherche JNDI. Dans "EE bootstrapping", les fournisseurs peuvent également recevoir une DataSource à utiliser via PersistenceUnitInfo # getJtaDataSource et/ou PersistenceUnitInfo # getNonJtaDataSource. Hibernate accepte alternativement une instance DataSource à la place du paramètre de nom JNDI DataSource typique. Si vous ne voulez pas utiliser DataSource (pour une raison étrange), une alternative spécifique à Hibernate est d'implémenter vous-même le contrat ConnectionProvider de Hibernate, c'est le contrat (interface) que Hibernate utilise pour obtenir et libérer des connexions JDBC quand il le faut. En implémentant ConnectionProvider, vous pouvez configurer les connexions sous-jacentes comme vous le souhaitez.

Beaucoup d'options :)

+0

Encore une autre "approche globale" ... L'approche "EE" pour amorcer le fichier EMF consiste à instancier le fichier javax.persistence.spi.PersistenceProvider et à appeler son fichier javax.persistence.spi.PersistenceProvider # createContainerEntityManagerFactory. createContainerEntityManagerFactory a une signature intéressante ici. Essentiellement, il est passé un javax.persistence.spi.PersistenceUnitInfo qui est une représentation d'objet de l'unité de persistance analysée plus quelques autres choses. Sur option serait d'utiliser cette approche à bootstrap et passer dans le javax.persistence.spi.PersistenceUnitInfo que vous construisez votre auto –

+0

Ran hors de l'espace dans le dernier commentaire :) javax.persistence.spi.PersistenceProvider est une interface. Pour l'instancier, vous devez connaître le fournisseur que vous souhaitez utiliser et le FQN pour leur impl. Mais ce n'est généralement pas un problème car ceux-ci sont assez bien connus. –

+0

Steve, merci pour vos efforts. Serait-il possible que vous puissiez transférer vos commentaires dans la zone de réponse? La méthode de substitution $ {some.key} est exactement ce que je cherche. Pourriez-vous me donner un exemple de comment le faire sur persistence.xml d'hibernate. Parce que notre boîte de production est jboss 4.x, nous devons utiliser hibernate 3.2 plutôt que hibernate 3.6 - donc beaucoup de nouvelles fonctions d'hibernation ne sont pas applicables. –

3

Pour votre deuxième question, je peux vous fournir une solution Hibernate seulement.

package dev.stackoverflow; 

import java.util.Properties; 

import org.hibernate.Session; 
import org.hibernate.SessionFactory; 
import org.hibernate.cfg.Configuration; 

public class DynamicHibernateSessionFactory { 
    public Session setProperties(final String provider, 
           final Boolean excludeUnlisted, 
           final Properties properties) { 
     properties.setProperty("provider", provider); 
     properties.setProperty("exclude-unlisted-classes", excludeUnlisted.toString()); 
     Configuration configuration = new Configuration(); 
     configuration.setProperties(properties); 
     SessionFactory sessionFactory = configuration.configure().buildSessionFactory(); 
     return sessionFactory.openSession(); 
    } 
} 
Questions connexes