SCBCD - Referencias EJB en el Descriptor de Despliegue

(Imagen: Francisco de Goya - La familia de Carlos IV)

XML y yo no nos llevamos bien... por eso me gustó tanto que EJB 3 habilitara la configuración mediante anotaciones. Pero, como ya sabe, a Sun le encanta poner preguntas de las cosas feas de la tecnología en el examen (i.e Threads, Generics, Filters), así que debido a eso vamos a hacer un repaso práctico de como declarar referencias EJB en el DD.

Creo que este ejemplillo se explica por si solo:


<enterprise-beans>
<session>
<ejb-name>EmployeeService</ejb-name>
<ejb-class>com.wombat.empl.EmployeeServiceBean</ejb-class>
<ejb-ref>
<description>Esta es una referencia a un EJB 2.1 entity bean</description>
<ejb-ref-name>ejb/Emplrecord</ejb-ref-name>
<ejb-ref-type>Entity</ejb-ref-type>
<home>com.wombat.empl.EmployeeRecordHome</home>
<remote>com.wombat.empl.EmployeeRecord</remote>
</ejb-ref>

<ejb-local-ref>
<description>Esta es una referencia a la interfaz de negocio local de un session bean EJB 3.0 </description>
<ejb-ref-name>ejb/Payroll</ejb-ref-name>
<local>com.aardvark.payroll.Payroll</local>
</ejb-local-ref>

<ejb-local-ref>
<description>Otra referencia a una interfaz de negocio local de un session bean EJB 3.0</description>
<ejb-ref-name>ejb/PensionPlan</ejb-ref-name>
<local>com.wombat.empl.PensionPlan</local>
</ejb-local-ref>
</session>

</enterprise-beans>

Aunque... siempre son necesarias cierta aclaraciones:
  • Para declarar referencias EJB, se utilizan los elementos ejb-ref y ejb-local-ref. Usamos ejb-ref para acceder al EJB mediante su interfaz de negocio remota, o remote home; mientras ejb-local-ref es usada para acceder mediante la interfaz de negocio local o local home
  • El elemento ejb-ref-name es obligatorio, y su valor es la entrada en el entorno EJB usada en el código EJB
  • El elemento ejb-ref-type es opcional, y sirve para indicarnos el tipo de EJB esperado: Entity o Session
  • El elemento local de ejb-local-ref, se refiere a la clase/ tipo de la interfaz de negocio
  • Recordando siempre que las referencias EJB no son accessibles por otros EJB's en tiempo de ejecución. Cada EJB debe definir sus propias referencias EJB 's porque estas no se comparten.
Un ejemplito más... para terminar con el asunto:

<enterprise-beans>
<session>
<ejb-name>EmployeeService</ejb-name>
<ejb-class>com.wombat.empl.EmployeeServiceBean</ejb-class>
...
<ejb-ref>
<ejb-ref-name>ejb/EmplRecord</ejb-ref-name>
<ejb-ref-type>Entity</ejb-ref-type>
<home>com.wombat.empl.EmployeeRecordHome</home>
<remote>com.wombat.empl.EmployeeRecord</remote>
<ejb-link>EmployeeRecord</ejb-link>
</ejb-ref>
</session>

<entity>
<ejb-name>EmployeeRecord</ejb-name>
<home>com.wombat.empl.EmployeeRecordHome</home>
<remote>com.wombat.empl.EmployeeRecord</remote>
...
</entity>
...
</enterprise-beans>

Recordemos que una referencia es simplemente una referencia. Simplemente nos dice "aquí debería haver un EJB, y yo debería poder usarlo", lo cuál, en tiempo de ejecución, no es suficiente. Para suerte nuestra, nuestro amigo el ensamblador de aplicaciones tiene entre sus funciones el asignarle a la referencia EJB un EJB objetivo, de modo que ahora sí sea utilizable desde el EJB que contiene la referencia. Y para eso, utiliza el elemento ejb-link del descriptor de despliegue.

Como vemos en el ejemplo de arriba, se utiliza ejb-link dento de ejb-ref o ejb-local-ref para hacer referencia a un EJB en concreto. El valor del elemento ejb-link debe coincidir con el elemento name del enterprise bean objetivo.

Tenemos que seguir con esto del entorno EJB, pero ya será en otra ocasión. Hasta otra..!!

Tiene 12 años, se llama Allwell y es SCJP

Este post tiene un fin motivacional, y demostrarle a mis queridos y silenciosos lectores que el examen no es la gran cosa y que, literalmente, hasta un niño puede hacerlo.

Según lo publicado en ngbd , el crío de la hazaña se llama Nyemahame Allwell Worgu, es nigeriano y se hizo Sun Certified Java Programmer con un puntaje de 72%. Y por si acaso, no es el único niño con certificación: El 2001 la niña Pakistaní Afsah Shafqat, de doce años también, hizo lo mismo.

Además, Alwell es un ejemplo de modestia y humildad. Según sus palabras, después del exámen: "me sentí normal, no sentí alegría dado que el examen era bastante sencillo y yo me encontraba listo para darlo.". Asimismo, nos demuestra su buen juicio y criterio afirmando que "la gente de raza negra es más inteligente que la gente de raza blanca"

Bueno, Alwell es un niño, todavía está en formación y ha logrado un credencial importantísimo como es una certificación Sun, por lo que desde acá mis felicitaciones. Alwell quiere estudiar en el MIT o en Cambridge, y a mi criterio tiene todo el potencial para hacerlo. Ahora, lectores adultos y contemporáneos míos; ponganle fuerza y ganas a esto de la certificación, que en el fondo no es más que un juego de niños.

Hasta otra!!


PS: Que quede en actas, que mi puntaje es superior al del chiquillo xD

SCBCD : Referencias EJB

(Imagen: Francisco de Goya - El tres de mayo)

Ahora nos vamos a poner un poco más "concretos" con lo del entorno EJB, y veremos un poco de inyección de referencias EJB. Puesto en otras palabras, veremos como utilizar una instancia EJB dentro de otra instancia EJB, mediante entradas en el entorno del bean.

Para inyectar una referencia EJB utilizamos la anotación @EJB en un campo o en un método setter; y esta referencia puede ser la interfaz de negocio de un Session Bean, entre otras posibilidades. Pero dejemos lo abstracto y vayamos a lo concreto:

package com.acme.example;

@Stateless
public class ExampleBean implements Example {
@EJB
ShoppingCart myCart;
...
}

Aquí, en el contexto JNDI de ExampleBean se ha agregado la entrada java:comp/env/com.acme.example.ExampleBean/myCart, que corresponde a una instancia EJB de ShoppingCart. El nombre largo y complejo es definido por el contenedor, no es que me haya puesto creativo. La instancia a la que se refiera esta referencia (disculpen la redundancia) debe ser definida por el deployer. Aquí va otra:

@EJB(
name="ejb/shopping-cart"
beanInterface=ShoppingCart.class
beanName="cart1"
description="The shopping cart for this application"
)
private ShoppingCart myCart;

Aprovechando las propiedades de la anotación, ahora el nombre de la referencia en el contexto JNDI del bean sería java:comp/env/ejb/shopping-cart; que no es tan horroroso como el nombre por defecto del contenedor. Notar que ahora se hace referencia a un bean en específico, denominado "cart1". Y para terminar el post, otro snippet donde nos ponemos más concretos todavía:

@EJB
(name="ejb/EmplRecord",
beanInterface=EmployeeRecordHome.class
)
@Stateless
public class EmployeeServiceBean implements EmployeeService{
public void changePhoneNumber(...){
Context initCtx = new InitialContext();
Object result = initCtx.lookup("java:comp/env/ejb/EmplRecord");
EmployeeRecordHome emplRecordHome = (EmployeeRecordHome) javax.rmi-PortableRemoteObject.narrow(result, EmployeeRecordHome.class);
}

Lo primero que se hace asignar una entrada en el entorno del EJB, mediante la anotación @EJB. Como no la hemos utilizado en un campo o método, no se ha realizado inyección de dependencia. Una vez que tenemos la entrada en el entorno utilizamos el API JNDI para localizar la referencia EJB a la interfaz remote home. Notar que el lookup se utiliza como parámetro java:comp/env/ejb/EmplRecord, que fue definido en el atributo name de la anotación EJB.

Y creo que eso es suficiente por este post. Mañana la seguimos.

La pregunta SCJP del día: Modificador static


(Imagen: Pancho Fierro - Zamacueca de salón)

Una fácil, para que no se me asusten xD
  1. Which of the following statements is true about the static modifier?
    1. A static variable cannot change it's value
    2. A static method cannot be overriden to be non-static
    3. A static method is often written in a non-Java language and exists outside the JVM
    4. The static code lies outside of any class
La idea detrás de un campo o método estático es todas las instancias de la clase accederán al mismo campo u objeto según sea el caso. De declarar una variable de instancia estática, todas las instancias de la clase accederán a la misma variable de instancia.

Para el caso de métodos estáticos, estos pueden ser ejecutados sin necesidad de instanciar la clase, a través del nombre de la clase. Volviendo a la pregunta, lo primero corresponde al modificador final, la tercera al modificador native y la cuarta es incorrecta debido a que el código estático está dentro de la clase.

Por ende, la respuesta es la segunda. Ya que los métodos estáticos no pueden ser sobre -escritos (overriden), pero pueden ser ocultos. Más información aquí

Pregunta tomada de SCJP Exam for J2SE 5 de Paul Sanghera

SCBCD - Entorno del Bean como contexto JNDI

(Imagen: Salvador Dalí - Persistencia de la memoria)

El entorno del bean (enterprise bean environment, para el examen) es un mecanismo que nos permite personalizar la lógica de negocio contenida en el EJB durante el despliegue o ensamble, y esto se realiza mediante anotaciones o en su defecto mediante el descriptor de despliegue.

Es el contenedor el que implementa el entorno del EJB, y lo hace disponible mediante un contexto JNDI. Este entorno EJB puede ser usado de diferentes maneras:
  • El EJB hace uso de las entradas del entorno, que pueden ser inyectadas a campos o métodos o mediante el método lookup de EJBContext. O si te gusta la antigua mediante interfaces JNDI
  • El contenedor provee la implementación del contexto JNDI que almacena el entorno EJB
  • El implementador crea e inicializa las entradas del entorno, declaradas mediante anotaciones o elementos del descriptor de despliegue (DD)
  • El contenedor inyecta entradas del entorno en los campos o métodos del EJB.
  • El contenedor hace disponible en contexto JNDI del entorno para todas las instancias EJB en tiempo de ejecución. Los instancias EJB pueden obtener las entradas del entorno mediante el método lookup de EJBContext o las interfaces JNDI (ya lo dije antes...pero quiero que quede claro)
Cada EJB define sus propias entradas de entorno, y todas las instancias de un EJB comparten las mismas entradas de entorno (por si suena raro... en inglés es environment entries) ; pero las entradas de entorno no son compartidas con otros EJB's.

Por lo general, al realizar un lookup al contexto obtenemos una nueva instancia del objeto solicitado; a menos que el objeto sea inmutable (java.lang.String ... la gente que estudia para el SCJP lo sabe bien) o el objeto es definido como un singleton (sólo puede existir una instancia de dicho objeto en la JVM. Para más información consultar Wikipedia). Recordar también que la inyección de un objeto se traduce en un lookup JNDI.

Anotaciones y variable de entorno: Un campo o un método EJB pueden ser anotados para solicitar la inyección de un aentrada del entorno EJB. El campo / método pueden tener cualquier modificador de acceso (recordando SCJP : public, private, protected, default) pero no deben ser estáticos (static).
  • Si se trata de un campo, el campo no puede ser final
  • Si se trata de un método, el método debe seguir las convenciones de nombres de propiedades JavaBean (setters, getters, etc...)
Cada recurso puede ser inyectado una sóla vez en el EJB. Por ejemplo, si solicitamos la inyección de java:comp:/env/com.example.MySessionBean/myDatabase en el método setMyDatabase y en la variable de instancia myDatabase obtendremos un error.

Las anotaciones pueden aplicarse a la clase, en vez de ser aplicadas en métodos o campos. En este caso, se declara una entrada en el entorno del bean pero el recurso no es inyectado; a diferencia de una anotación de campo o método. En este caso, el bean debe usar el método lookup de EJBContext o el API JNDI para obtener una entrada del entorno.

Este temita tiene para rato..así que la seguiremos en otro post. Al menos ya no son interceptores xD

SCBCD - Interceptores a la XML

(Imagen: Salvador Dalí - Leda Atómica)

Señores, este es el último post de interceptores y no pienso verlos hasta el día del examen. En fin, este post trata sobre la definición de interceptores en nuestro archivo XML favorito: el descriptor de despliegue.

Pero en vez de ponerme a hablar de cada elemento XML (lo que sería aburridísimo), vemos un poco de código:

  • Aquí definimos dos interceptores por defecto para todos los componentes del ejb-jar: MyDefaultIC y MyDefaultIC2

<interceptor-binding>
<ejb-name>*</ejb-name>
<interceptor-class>org.acme.MyDefaultIC</interceptor-class>
<interceptor-class>org.acme.MyDefaultIC2</interceptor-class>
</interceptor-binding>
  • Ahora, se aplica el interceptor MyIC al método myMethod del bean EmployeeService. Usamod method-params para identificar el método si es que se encuentra sobrecargado (overloaded... se acuerdan?). Los interceptores de métodos de negocio se invocan después de los interceptores por defecto y de los interceptores de clase.
<interceptor-binding>
<ejb-name>EmployeeService</ejb-name>
<interceptor-class>org.acme.myIC</interceptor-class>
<method-name>myMethod</method-name>
<method-params>
<method-param>java.lang.String</method-param>
<method-param>java.lang.String</mehtod-param>
</method-params>
</interceptor-binding>
  • Aquí definimos dos interceptores de clase para EmployeeService: MyIC y MyIC2. Estos se invocarán en el orden definido, después de los interceptores por defecto.

<interceptor-binding >
<ejb-name>EmployeeService</ejb-name>
<interceptor-class>org.acme.MyIC2 </interceptor-class>
<intercetor-class>org.acme.MyIC2 </intercetor-class>
</interceptor-binding>

NOTA PARA EL EXAMEN: Recordar, porque creo haberlo dicho antes, que una clase interceptora sólo puede definirse UN método around-invoke, UN método pre-construct, UN método post-destroy, UN método pre-passivate y UN método post-activate (y no he puesto UN en mayúsculas por las puras). Esto es contando los interceptores definidos por anotaciones y por descriptor de despliegue.

Trabajo en una consultora*, y eso es bueno


*Antes que nada, quería aclarar el término "consultora" del título, dado que he visto que tengo cierta lectoría internacional (modestia aparte). Una consultora, en el mundo del software peruano, aplica a una compañía dedicada a hacer software para terceros. Los gringos las llaman contractors .

El destino ha querido que me encuentre trabajando en una consultora, y a pesar del sueldo xD , me encuentro bastante cómodo. El equipo es bastante capaz, y sobre todo ameno y amigable; la aplicación a desarrollar es interesante y la vista desde mi escritorio es encantadora.

Así como yo, parece que Max Pool de Javalobby también se encuentra bastante a gusto; por lo que en su último post enumera las ventajas de trabajar en una empresa de este tipo cuando recién empiezas en el mundo del desarrollo. A mí me convenció, a ver que les parece a ustedes:

  • Mucho proyectos nuevos: Cuando trabajas para una empresa/corporación, una vez que aprendes la arquitectura tecnológica de la compañía, pues se acabo el aprendizaje. Después tu trabajo se va a limitar a realizarle cambios o agregar funcionalidad a lo que ya está funcionando. Pasado un año, serás oficialmente un desarrollador legacy (lo que por cierto, está muy bien remunerado) En cambio, en una consultora te vas a mantener viendo proyectos nuevos todo el tiempo, cada uno con una arquitectura particular por lo que el aprendizaje de tecnologías va a ser constante y continuo. Cada dos o tres meses arrancas en un proyecto nuevo, con requerimientos nuevos y tecnologías nuevas.
    • Ejemplo practico: En la primera compañía donde empecé a trabajar, las aplicaciones estaban sobre struts/EJB2.0 . Ya han pasado dos años, y todavía siguen en eso.
  • Diferentes dominios: Siempre he tratado de aprender lo mínimo necesario y suficiente del dominio del problema (o sea...el negocio) para programar. No sé si será bueno o malo, pero ponerme a aprender todo lo que el usuario ya sabe, y mucho mejor que yo, se me hace innecesario. Si trabajas para una empresa vas a estar tan metido en el dominio que hasta vas a poder refutar al usuario. Cuando trabajaba en una compañía de seguros tenía un compañero que solía decirles a los corredores como hacer su trabajo. El trabajar en una consultora te da más versatilidad, dado que cada proyecto es un dominio diferente.
  • Responsabilidades en arquitectura: En esta compañia de seguros que menciono, el departamento de arquitectura estaba compuesto por tres tíos que decidían que podían y que no podían hacer los desarrolladores (es decir, la plebe). Si querías utilizar un nuevo API, o agregarle una capa más a la aplicación necesitabas su visto bueno para proceder. Ahora en cambio, en la consultora todo es más horizontal. Somos 5 "analistas-programadores", que en la práctica somos Desarrolladores, Analistas, Arquitectos y Control de Calidad; y el asumir todos esos roles definitavemente es provechoso en cuanto a aprendizaje. En una compañía todo es más rígido, y tanto arquitectura como Control de Calidad son áreas bien definidas y tienen personal asignado. Volviendo a la arquitectura, el ser tu propio arquitecto te permite aplicar todos los tutoriales que te has leído de la web en una aplicación empresarial real...y eso, no tiene precio xD.
  • Interacción con el usuario final: Volviendo a la referencia de la compañía de seguros, estuve más o menos año y medio y vi al usuario final en vivo y en directo una sóla vez: fue para unas pruebas con control de calidad. Después, era el Jefe de Línea (el Analista..en otros términos) en que hablaba con el usuario, traducía lo que el quería y me lo decía para que yo programara . En una consultora, dado que uno también asume el rol de analista, la interacción con el usuario es más frecuente; lo que te permite pulir tus "habilidades interpersonales".
Recapitulando, si estás buscando prácticas pre profesionales o tu primer trabajo sería bastante conveniente que lo hicieras en este tipo de empresas, debido a su potencial en aprendizaje. En lo referente a la remuneración... ya lo hablaremos en otro post xD.

SCBCD - Interceptores (aún más ...)

(Imagen: Claude Monet - Amanecer)

Interceptores a nivel de método: Este es el tipo de cosas que no están en el libro pero que te toman en el examen :S. Un interceptor de métodos de negocio se aplica a un método específico del bean, en lo lugar de interceptar todos los métodos del bean con los interceptores que vimos antes. Para asignarle un interceptor a un método, usamos la anotación @Interceptors , que ya es una vieja conocida; o también con el descriptor de despliegue mediante el elemento interceptor-binding.

Como siempre, me emociono con las palabras y no recurro al código. Pero prometo enmendarme; por lo que ahora les presento un bean donde dos métodos son inteceptados por la misma clase interceptora:

@Stateless
public class MyBean ... {
public void notIntercepted (){}

@Interceptors(org.acme.MyInterceptor.class)
public void someMethod(){
...
}

@Interceptors(org.acme.MyInterceptor.class)
public void anotherMethod(){
...
}
}

En el snipet, tanto someMethod como another Method son interceptados por la clase MyInterceptor. Como recordatorio, siempre se crea una instancia de interceptor por instancia de bean , por lo que a pesar que el mismo interceptor ha sido aplicado a varios métodos en memoria sólamente habrá una solitaria instancia de ese interceptor (si se definen más interceptores para este bean, también de estos se mantiene una instancia).

En el post anterior vimos a los interceptores por defecto, que se aplican a todos los componentes de un ejb-jar. Ahora, esto no siempre es conveniente; por lo que tener la capacidad de definir excepciones a esta regla, dada por la anotación @ExcludeDefaultInterceptors y el elemento exclude-default-interceptors, es de bastante utilidad. A nivel de método, también se puede decidir obviar los interceptores de clase por medio de la anotación @ExcludeClassInterceptors (y el elemento de DD exclude-class-interceptors); pero mejor veámoslo con un poco de código, que nos es más familiar:

De no definirse interceptores por defecto, sólamente se invoca el interceptor en MyInterceptor al llamar a someMethod. El interceptor de clase AnotherInterceptor no es invocado debido a la presencia de la notación @ExcludeClassInterceptors:

@Stateless
@Interceptors (org.acme.AnotherInterceptor.class)
public class MyBean ... {
...
@Interceptors(org.acmeMyInterceptor.class)
@ExcludeClassInterceptors
public void someMethod(){
...
}
}

Ahora, si tuvieramos también interceptores por defecto, y no quisieramos que intercepten a someMethod, el bean quedaría así:

@Stateless
@Interceptors (org.acme.AnotherInterceptor.class)
public class MyBean ... {
...
@ExcludeDefaultInterceptors
@ExcludeClassInterceptors
@Interceptors (org.acme.MyInterceptor.class)
public void someMethod(){
...
}
}

Y hasta aquí la dejamos en este post. Lamentablemente, el siguiente también es de interceptores (pero prometo que es el último!!)