2010-07-09 5 views
10

Je suis en train de programmer une application web en utilisant weblogic et oracle. La source de données est configurée via JNDI, avec un utilisateur de base de données restreint qui peut utiliser DML dans des tables, mais ne peut pas DDL. Comme vous pouvez le deviner, cet utilisateur n'est pas le propriétaire de ces tables, mais il a accès.JPA - EclipseLink - Comment changer le schéma par défaut

Disons qu'il est GUEST_USER

L'application utilise JPA + EclipseLink, et ont beaucoup d'entités déjà définies. Je ne veux pas écrire dans chaque classe d'entité l'attribut pour changer de schéma. J'ai essayé un SessionCustomizer, avec ce code.

public class MyCustomizer implements SessionCustomizer{ 

    @Override 
    public void customize(Session session) throws Exception { 

    session.executeNonSelectingSQL("ALTER SESSION SET CURRENT_SCHEMA = OWNERS_SCHEMA"); 
    } 
} 

Il semble qu'il y ait quelque chose uninitiallized, je reçois une exception de pointeur nul, je ne suis même pas sûr que ce soit la façon de modifier le schéma des connexions avant leur utilisation. Des échantillons ou des idées?

Merci d'avance pour votre aide!

Répondre

16

Si toutes les entités utilisent le même schéma, vous pouvez utiliser un fichier de mappage XML pour définir un schéma par défaut.

Quelque chose comme cela devrait fonctionner (exemple pour JPA 2.0, changer le schemaLocation pour 1.0)

orm.xml:

<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm orm_2_0.xsd" 
    version="2.0"> 
    <persistence-unit-metadata> 
     <persistence-unit-defaults> 
      <schema>OWNERS_SCHEMA</schema> 
     </persistence-unit-defaults> 
    </persistence-unit-metadata> 
    . . . 
</entity-mappings> 

persistence.xml:

<persistence 
    xmlns="http://java.sun.com/xml/ns/persistence" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" 
    version="2.0" > 
    <persistence-unit name="foo"> 
     . . . 
     <mapping-file>orm.xml</mapping-file> 
     . . . 
    </persistence-unit> 
</persistence> 
+0

+1 Cela semble bien –

+2

c'est bon mais toujours pas dynamique, et si j'ai besoin de changer le schéma pour deux versions de la même application pointant vers deux instances de diff db? –

+0

De plus, si je mets le schéma pour un EntityManager particulier avec un 'SET search_path TO ...', le passage du gestionnaire d'entités à d'autres méthodes n'a aucun effet. Je suppose que Wildfly (dans mon cas) prend l'une des connexions du pool précédemment créées avec le schéma par défaut public – Chris

3

Vous pouvez faites-le par programmation. Vous pouvez configurer la valeur de schéma par défaut pour chaque session.

public class MySessionCustomizer implements SessionCustomizer { 

    private static String schemaName; 

    public static void setSchemaName(String schemaName) { 
     MySessionCustomizer.schemaName = schemaName; 
    } 

    @Override 
    public void customize(Session session) throws Exception { 
     if (StringUtils.hasText(this.schemaName)) { 
      session.getLogin().setTableQualifier(this.schemaName); 
     } 
    } 
} 

Définissez ensuite la session customizer aux propriétés de l'usine de gestionnaire d'entités:

PersistenceUnitProperties.SESSION_CUSTOMIZER 

par exemple

propertiesMap.put(PersistenceUnitProperties.SESSION_CUSTOMIZER, MySessionCustomizer.class.getName()); 
+1

Y a-t-il une manière standard de faire cela? –

+0

Une méthode standard JPA utilise le schéma de paramètres dans l'annotation ['@ Table'] (http://docs.oracle.com/javaee/7/api/javax/persistence/Table.html) – Ati

0

J'utilise EJB juste avant interrogation de la base, donc à l'aide Interceptors je suis en mesure de définir le schéma dans le contexte EJB en regardant l'utilisateur en cours authentifié.

Puis, quand je construis le gestionnaire d'entités, je peux définir le bon schéma. De cette manière, en ne spécifiant pas le schéma avant le nom de la table, PostgreSQL cherchera le search_path pour déterminer le schéma à interroger. Ensuite, lorsque vous générez le gestionnaire d'entités, vous pouvez définir le schéma souhaité.

<!-- language: lang-java --> 

public class Interceptor { 

    Logger logger = Logger.getLogger(Interceptor.class); 

    /** 
    * 
    * @param ctx is always null before being passed to EJB implementation. We always query database 
    * for populating context data, making user's session accessible to all EJB implementations 
    * @return 
    * @throws Exception 
    */ 
    @SuppressWarnings({ "unchecked", "unused" }) 
    @AroundInvoke 
    public Object intercept(InvocationContext ctx) throws Exception { 
     Authentication auth = SecurityContextHolder.getContext().getAuthentication(); 

     String ejbName = ctx.getMethod().getDeclaringClass().getSimpleName(); 
     String methodName = ctx.getMethod().getName(); 
     Boolean override_schema = false; 
     String overridden_schema = ""; 

     logger.info("Intercepting " + ejbName + "." + methodName); 

     if(auth != null) { 

      UserDetails userDetails = (UserDetails)auth.getPrincipal(); 
      String username = userDetails.getUsername(); 

      Collection<SimpleGrantedAuthority> permList = (Collection<SimpleGrantedAuthority>) auth.getAuthorities(); 
      List<String> permissions = new ArrayList<String>(); 

      for (SimpleGrantedAuthority authority : permList) { 
       permissions.add(authority.getAuthority()); 
      } 


      Query query = getMasterEntityManager() 
          .createNativeQuery(
       "SQL for retrieving the schema by the current logged in user"); 

      query.setParameter("username", username); 
      List<Object[]> result = null; //query.getResultList(); 

      if(result != null) { 
       logger.info("Interceptor: context set for " + username); 
       Object[] userObj = result.get(0); 

       getContext().getContextData().put("username", username); 
       getContext().getContextData().put("schema_name",(String)userObj[1]); 
      } 
     } 

     return ctx.proceed(); 
     } 
    } 

Questions connexes