3.2.11. Cambios de EJB 2.x

3.2.11.1. Actualización de aplicaciones que utilizan EJB 2.x

JBoss EAP 6 se construyó sobre estándares abiertos y cumple con los requerimientos de la especificación de la edición empresarial de Java 6. Mientras que el servidor de aplicaciones proporciona soporte para EJB 2.x, puede que ya no soporte funcionalidades que van más allá de la especificación. Tenga en mente que la especificación Java EE 7 ha marcado EJB 2.x como opcional así que se le recomienda con mucho énfasis que reescriba el código de su aplicación en la especificación EJB 3.x.
Si todavía quiere migrar su código EJB 2.x en la mayoría de los casos necesitará realizar algunas modificaciones para ejecutar en JBoss EAP 6. Este tema describe algunos de los cambios que puede necesitar para ejecutar EJB 2.x en JBoss EAP 6.
Cambios en la configuración requeridos para ejecutar EJB 2.x en JBoss EAP 6

Iniciar el servidor con el perfil completo
Los beans CMP (del inglés Container Managed Persistence) EJB 2.x requieren el perfil completo de la edición empresarial de Java 6. Este perfil contiene elementos de configuración que se necesitan para ejecutar CMP EJBs.
Este perfil de configuración contiene el módulo de extensión org.jboss.as.cmp:
<extensions>
    ...
    <extension module="org.jboss.as.cmp"/>
    ...
</extensions>
También contiene el subsistema cmp:
<profiles>
    ...
    <subsystem xmlns="urn:jboss:domain:cmp:1.1"/>
    ...
</profiles>
.
Para iniciar un servidor autónomo JBoss EAP 6 con el perfil completo pase el argumento -c standalone-full.xml or -c standalone-full-ha.xml en la línea de comandos cuando inicie el servidor.
La configuración de contenedor ya no se soporta
En versiones anteriores de JBoss EAP era posible configurar un contenedor diferente para entidades CMP y otros beans y utilizarlo estableciendo referencias dentro del archivo descriptor de implementación de la aplicación jboss.xml. Por ejemplo, había diferentes configuraciones para SLSB para poner los beans en sesiones en general.
En JBoss EAP 6.x, es posible utilizar beans de entidad EJB 2 con un contenedor estándar. Sin embargo, ya no se soportan las diferentes configuraciones del contenedor. El enfoque recomendado es migrar los beans de sesión con estado EJB2 (SFSB del inglés Stateful Session Beans), los beans de sesión sin estado (SLSB ddel inglés Stateless Session Beans), beans dirigidos por mensajes (MDB del inglés Message Driven Beans) a EJB 3 y para la persistencia administrada por el contenedor (CMP del inglés Container-Managed Persistence) y los beans de entidad de persistencia administrada por beans (BMP del inglés Bean-Managed Persistence) utilizar la API de persistencia Java (JPA del inglés Java Persistence API) de acuerdo con la especificación EJB 3.
La configuración predeterminada del contenedor en JBoss EAP 6 contiene varios cambios para los beans EJB 2 CMP:
  • El bloqueo pesimista está activado por defecto. Esto puede generar puntos muertos.
  • El código de detección de deadLock que se encontraba en la capa CMP en JBoss EAP 5.x ya no está en JBoss EAP 6.
En JBoss EAP 5.x, también era posible el personalizar el caché, el agrupamiento, commit-options y la pila de interceptores. En JBoss EAP 6, esto ya no es posible. Hay solo una implementación, la cual es similar a la política Instance Per Transaction con commit-option C. Si migra una aplicación que usa la configuración del contenedor del bean de entidades cmp2.x jdbc2 pm, el cual usa un administrador de persistencia basado en JDBC compatible con CMP2.x , entonces tendrá impacto en el rendimiento. Este contenedor se optimizó para rendimiento. Se recomienda que migre estas entidades a EJB 3 antes de migrar la aplicación.
Configuración del interceptor del lado del servidor
JBoss EAP 6 soporta el Interceptor Java EE estándar utilizando las anotaciones @Interceptors y @AroundInvoke. Sin embargo, esto no permite la manipulación por fuera de la transacción o la seguridad.
En versiones anteriores de JBoss EAP era posible modificar la pila de interceptores para tener interceptores personalizados para cada invocación EJB. Esto se utilizaba con frecuencia para implementar seguridad personalizada o mecanismos de reintento antes de chequeos de seguridad o chequeos de transacciones o creación. JBoss EAP 6.1 introdujo interceptores de contenedor para brindar una funcionalidad similar. Para mayor información sobre interceptores de contenedor consulte el capítulo titulado Interceptores de contenedor en la Guía de desarrollo para JBoss EAP.
Otro enfoque para brindar más control antes, durante o después de la fase de guardado de una transacción siguiendo la especificación Java EE es utilizar el registro de sincronización de transacciones para agregar un escucha.
El recurso se puede recuperar usando uno de los siguientes métodos:
  • Use el InitialContext
    TransactionSynchronizationRegistry tsr = (TransactionSynchronizationRegistry) 
    		new InitialContext().lookup("java:jboss/TransactionSynchronizationRegistry");
    tsr.registerInterposedSynchronization(new MyTxCallback());
    
  • Use inyección
    @Resource(mappedName = "java:comp/TransactionSynchronizationRegistry")
    TransactionSynchronizationRegistry tsr;
    ...
    tsr.registerInterposedSynchronization(new MyTxCallback());
    
La rutina callback debe implementar la interfaz javax.transaction.Synchronization. Use el método beforeCompletion{} para realizar cualquier chequeo antes de que la transacción se guarde o se deshaga. Si este método presenta una RuntimeException entonces la transacción se deshace y se le informa al cliente con una EJBTransactionRolledbackException. En el caso de una XA-Transaction, todos los recursos se desharán de acuerdo con el contrato XA. También es posible para la lógica empresarial habilitada el depender del estado de la transacción utilizando el método afterCompletion(int txStatus). Si este método presenta una RuntimeException entonces la transacción permanece en el estado anterior ya sea con lo cambios guardados o deshechos y no se le informa al cliente. Solo el administrador de transacciones muestra una advertencia dentro del los archivos de registro del servidor.
Configuración del lado del servidor para interceptores del lado del cliente
En versiones anteriores de JBoss EAP era posible configurar los interceptores clientes dentro de la configuración del servidor y proporcionar solo las clases con el API cliente.
En JBoss EAP 6, esto ya no es posible ya que el Proxy cliente ya no se crea en el lado del servidor ni se transmite al cliente después de la búsqueda. Ahora el proxy se genera del lado del cliente. Esta optimización evita una invocación del servidor para la búsqueda y carga de clases,
Configuración del pool de beans de entidades
En JBoss EAP 6 no se recomienda la configuración del pool de beans de entidades. Ya que se limita a la configuración del elemento <strict-max-pool> pueden tener lugar puntos muertos y otros problemas si el pool es demasiado pequeño para cargar todas las entidades en el grupo de resultados. Los beans de entidad no tienen métodos largos del ciclo de vida durante la inicialización así que el crear la y el contenedor que lo rodea no es más lento que cuando se utiliza una instancia de bean de entidad en pool.
Reemplace el archivo descriptor de implementación jboss.xml
El descriptor de implementación jboss-ejb3.xml reemplaza el archivo descriptor de implementación jboss.xml. Este archivo se utiliza para sobreescribir y agregar a las funcionalidades proporcionadas por el descriptor de implementaciónejb-jar.xml de la edición empresarial Java (EE). El nuevo archivo es incompatible con jboss.xml y el jboss.xml ahora se ignora en las implementaciones.
Por ejemplo, en lanzamientos anteriores de JBoss EAP, si definía una <resource-ref> en el archivo ejb-jar.xml necesitaba una definición de recursos correspondiente para el nombre JNDI en el archivo jboss.xml. XDoclet automáticamente generaba ambos archivos descriptores de implementación. En JBoss EAP 6, la información de mapeo JNDI ahora se define en el archivo jboss-ejb3.xml. Asuma que la fuente de datos se define en el código fuente Java así:
DataSource ds1 = (DataSource) new InitialContext().lookup("java:comp/env/jdbc/Resource1");
DataSource ds2 = (DataSource) new InitialContext().lookup("java:comp/env/jdbc/Resource2");
El ejb-jar.xml define las siguientes referencias de recursos.
<resource-ref >
    <res-ref-name>jdbc/Resource1</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
</resource-ref>
<resource-ref >
    <res-ref-name>java:comp/env/jdbc/Resource2</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
</resource-ref>
El archivo jboss-ejb3.jxml mapea los nombres JNDI a las referencias usando la siguiente sintaxis XML.
<resource-ref>
    <res-ref-name>jdbc/Resource1</res-ref-name>
    <jndi-name>java:jboss/datasources/ExampleDS</jndi-name>
</resource-ref>
<resource-ref>
    <res-ref-name>java:comp/env/jdbc/Resource2</res-ref-name>
    <jndi-name>java:jboss/datasources/ExampleDS</jndi-name>
</resource-ref>
Algunas de las opciones de configuración que estaban disponibles en el archivo jboss.xml JBoss EAP 5.x no se implementaron en JBoss EAP 6. La siguiente lista describe algunos de los atributos utilizados comúnmente en el archivo jboss.xml y si hay una manera opcional de alcanzarlos en JBoss EAP 6.
  • El elemento method-attribute se utilizaba para configurar métodos de beans de sesión y entidades individuales.
    • Las opciones de configuración read-only y idempotent no se llevaron a JBoss EAP 6.
    • La opción transaction-timeout ahora se configura en el archivo jboss-ejb3.xml.
  • El atributo missing-method-permission-exclude-mode cambió el comportamiento de los métodos sin implementar metadatos de seguridad explícitos en un bean asegurado. En JBoss EAP 6, la ausencia de una anotación @RolesAllowed se trata de manera similar a @PermitAll
Configuración de mapeo del tipo de fuente de datos
En versiones anteriores de JBoss EAP, era posible configurar el mapeo del tipo de fuente de datos dentro del archivo de configuración de la implementación de la fuente de datos *-ds.xml.
En JBoss EAP 6, esto se debe hacer ahora en el archivo descriptor de implementación jbosscmp-jdbc.xml.
<defaults>  
    <datasource-mapping>mySQL</datasource-mapping>  
    <create-table>true</create-table>  
    ....  
</defaults>
En versiones anteriores de JBoss EAP, el mapeo personalizado se realizaba en el archivo standardjbosscmp-jdbc.xml. Este archivo ya no está disponible y el mapeo ahora se realiza en el archivo descriptor de implementación jbosscmp-jdbc.xml.
Cambios adicionales a la persistencia administrada por el contenedor y las relaciones administradas por el contenedor

Cambios en el iterador de relaciones administradas por el contenedor y colecciones
En lanzamientos anteriores de JBoss EAP, era posible para algunos contenedores, por ejemplo el contenedor cmp2.x jdbc2 pm el iterar colecciones CMR (del inglés Container Managed Relationship) y borrar o agregar relaciones. Debido a que la configuración del contenedor no se soporta, esto ya no es posible en JBoss EAP 6. Para obtener mayor información sobre cómo lograr esta misma funcionalidad en el código de la aplicación, consulte EJB2.1 Localizador de entidades CMP con relaciones (CMR) retorna duplicados en EAP6 en la sección de Soluciones de la base de conocimiento de soporte del Portal de clientes.
Entradas duplicadas de relaciones administradas por el contenedor para localizadores
En versiones anteriores de JBoss EAP, era posible seleccionar diferentes contenedores CMP que utilizaban diferentes estrategias de persistencia. El contenedor cmp2.x jdbc2 pm en JBoss EAP 5.x utilizaba SQL-92 optimizado para generar sintaxis LEFT OUTER JOIN optimizada para localizadores. Debido a que JBoss EAP 6.x solo soporta el contenedor estándar para CMP y CMR, la implementación no contiene estas optimizaciones. El localizador debe incluir la palabra clave DISTINCT en la declaración SELECT para evitar un producto cartesiano en el grupo de resultados. Para obtener mayor información consulte EJB2.1 Localizador para entidades CMP con relaciones (CMR) retorna duplicados en EAP6 en la sección de Soluciones de la base de conocimiento de soporte del Portal de clientes.
Cambio en el borrado predeterminado en cascada para beans de entidad CMP
El valor predeterminado del borrado en cascada cambió a false. Esto puede generar fallos de borrado en JBoss EAP 6. Si relaciones de entidades se marcan como cascade-delete debe establecer explícitamente el batch-cascade-delete como true en el archivo jbosscmp-jdbc.xml. Para obtener mayor información consulte fallo en el borrado en cascada para entidades EJB2 CMP después de la migración a EAP6 en la sección de Soluciones de la base de conocimiento de soporte del Portal de clientes.
Mapeos personalizados CMP para campos personalizados
Si utilizó las clases de mapeo de clientes tal como JDBCParameterSetter, JDBCResultSetReader y Mapper en su aplicación JBoss EAP 5.x, es posible que vea la java.lang.ClassNotFoundException cuando implementa su aplicación en JBoss EAP 6. Esto se debe a que los nombres de paquetes para las interfaces se cambiaron de org.jboss.ejb.plugins.cmp.jdbc.Mapper a org.jboss.as.cmp.jdbc.Mapper. Para obtener mayor información consulte Cómo utilizar el mapeo de campos para las clases personalizadas en una aplicación EJB2 CMP en EAP6 en la sección de Soluciones de la base de conocimiento de soporte del Portal de clientes.
Generación de llaves primarias utilizando comandos de entidad
Si su aplicación JBoss EAP 5 usa entity-commands para generar llaves primarias, por ejemplo Sequence o Auto-increment es posible que vea una ClassNotFoundException para la clase JDBCOracleSequenceCreateCommand cuando migra su aplicación a JBoss EAP 6. Esto se debe a que el paquete clase cambió de org.jboss.ejb.plugins.cmp.jdbc a org.jboss.as.cmp.jdbc.keygen. Si utiliza esta clase en su aplicación JBoss EAP 6 también debe agregar una dependencia en el módulo EAP_HOME/modules/system/layers/base/org/jboss/as/cmp.
Cambios en la aplicación

Modifique el código para utilizar las nuevas reglas de espacio de nombres JNDI.
Así como con EJB 3.0, tiene que utilizar el prefijo completo JNDI con EJB 2.x. Para mayor información sobre las nuevas reglas del espacio de nombre JNDI y ejemplos del código consulte Sección 3.1.8.1, “Actualización de los nombres de espacios de nombres JNDI de la aplicación”.
Puede encontrar los ejemplos sobre cómo actualizar los espacios de nombres JNDI de lanzamientos anteriores aquí: Sección 3.1.8.5, “Ejemplos de espacios de nombres JNDI en lanzamientos anteriores y la manera en que se especifican en JBoss EAP 6”.
Modifique el descriptor de archivos jboss-web.xml
Modifique el <jndi-name> para cada <ejb-ref> para utilizar el nuevo formato de búsqueda completamente calificado JNDI.
Use XDoclet para mapear el nombre JNDI Name de interfaces locales internas
Con EJB 2 era muy común el utilizar el patrón Locator para buscar Beans. Si usted utilizaba este patrón en su aplicación, en lugar de modificar el código de la aplicación code, puede utilizar XDoclet para generar un mapa para los nuevos nombres JNDI.
Una anotación XDoclet típica se ve así:
@ejb.bean name="UserAttribute" display-name="UserAttribute" local-jndi-name="ejb21/UserAttributeEntity" view-type="local" type="CMP" cmp-version="2.x" primkey-field="id"
El nombre JNDI ejb21/UserAttributeEntity en el ejemplo anterior ya no es válido en JBoss EAP 6. Puede mapear este nombre a un nombre JNDI válido utilizando el subsistema naming en la configuración del servidor y un parche para XDoclet.
Puede crear mapeos personalizados tal como se anota en el párrafo anterior titulado Mapeos personalizados CMP para campos personalizados o puede modificar el código tal como se describe en el siguiente procedimiento.

Procedimiento 3.24. Cambie el código generado XDoclet y use el subsistema de nombrado

  1. Extraiga la plantilla XDoclet lookup.xdt que se encuentra en ejb-module.jar y modifique lookup() en lookupHome así:
    private static Object lookupHome(java.util.Hashtable environment, String jndiName, Class narrowTo) throws javax.naming.NamingException {  
        // Obtain initial context  
        javax.naming.InitialContext initialContext = new javax.naming.InitialContext(environment);  
        try { 
            // Replace the existing lookup      
            // Object objRef = initialContext.lookup(jndiName);  
            // This is the new mapped lookup
            Object objRef;  
            try {  
                // try JBoss EAP mapping  
                objRef = initialContext.lookup("global/"+jndiName);  
            } catch(java.lang.Exception e) {  
                objRef = initialContext.lookup(jndiName);  
            }  
            // only narrow if necessary  
            if (java.rmi.Remote.class.isAssignableFrom(narrowTo))  
                return javax.rmi.PortableRemoteObject.narrow(objRef, narrowTo); 
            else  
                return objRef;  
        } finally {  
            initialContext.close();  
        }  
    }
  2. Ejecute Ant, configurando el atributo plantilla para utilizar el lookup.xdt modificado para la tarea ejbdoclet.
  3. Modifique el subsistema naming en el archivo de configuración del servidor para mapear el nombre JNDI viejo al nuevo nombre JNDI válido.
    <subsystem xmlns="urn:jboss:domain:naming:1.2">  
        <bindings>  
            <lookup name="java:global/ejb21/UserAttributeEntity" lookup="java:global/ejb2CMP/ejb/UserAttribute!de.wfink.ejb21.cmp.cmr.UserAttributeLocalHome"/>  
        </bindings>  
        <remote-naming/>  
    </subsystem>
Resumen de archivos obsoletos

Los siguientes archivos ya no se soportan en JBoss EAP 6.

jboss.xml
El archivo descriptor de implementación jboss.xml ya no se soporta y se ignora si se incluye en el archivador implementado.
standardjbosscmp-jdbc.xml
El archivo de configuración standardjbosscmp-jdbc.xml ya no se soporta. Esta información de configuración ahora se incluye en el módulo org.jboss.as.cmp y ya no se puede personalizar.
standardjboss.xml
El archivo de configuración standardjboss.xml ya no se soporta. Esta información de configuración ahora se incluye en el archivo standalone.xml al ejecutar un servidor autónomo o el archivo domain.xml en un dominio administrado.