2010-07-09 20 views
10

Estoy programando una aplicación web usando weblogic y oracle. el origen de datos se configura a través de JNDI, con un usuario de base de datos restringido que puede DML en tablas, pero no puede DDL. Como puede adivinar, ese usuario no es el propietario de esas tablas, pero se le ha otorgado acceso.JPA - EclipseLink - Cómo cambiar el esquema predeterminado

Digamos que es GUEST_USER

La aplicación utiliza JPA + EclipseLink, y tienen un montón de entidades ya definidos. No quiero escribir en cada clase de entidad el atributo para cambiar el esquema. He intentado un SessionCustomizer, con este código.

public class MyCustomizer implements SessionCustomizer{ 

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

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

Parece que hay algo uninitiallized, me estoy haciendo una excepción de puntero nulo, ni siquiera estoy seguro si esto es la manera de cambiar el esquema de las conexiones antes de ser utilizados. ¿Alguna muestra o idea?

Gracias de antemano por su ayuda!

Respuesta

16

Si todas las entidades usan el mismo esquema, puede usar un archivo de asignación xml para definir un esquema predeterminado.

Algo como esto debería funcionar (por ejemplo es JPA 2.0, cambie el schemaLocation de 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 Esto suena bien –

+2

esto es bueno pero aún no es dinámico, ¿qué sucede si necesito cambiar el esquema de dos versiones de la misma aplicación que apuntan a dos instancias de db diff? –

+0

Además, si configuro el esquema para un EntityManager particular con un 'SET search_path TO ...', pasar el administrador de entidades a otros métodos no tiene efectos. Supongo que Wildfly (en mi caso) toma una de las conexiones del grupo creadas previamente con el esquema público predeterminado – Chris

3

Puede hazlo programáticamente Puede configurar el valor de esquema predeterminado para cada sesión.

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); 
     } 
    } 
} 

asentando después el personalizador sesión a las propiedades de fábrica gestor de la entidad:

PersistenceUnitProperties.SESSION_CUSTOMIZER 

por ejemplo,

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

¿Hay una forma estándar de JPA de hacer esto? –

+0

Una forma estándar de JPA es usar el esquema de parámetros en la anotación ['@ Table'] (http://docs.oracle.com/javaee/7/api/javax/persistence/Table.html) – Ati

0

utilizo EJB justo antes de consultar la base de datos, por lo que mediante el uso de Interceptors soy capaz de establecer el esquema en el contexto de EJB mirando el usuario autenticado actual.

Luego, cuando construyo el administrador de entidades, puedo establecer el esquema correcto. De esta forma, al no especificar el esquema antes del nombre de la tabla, PostgreSQL observará el search_path para determinar qué esquema consultar.

<!-- 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(); 
     } 
    } 

Luego, cuando crea el administrador de entidades, puede establecer el esquema que desee.

Cuestiones relacionadas