Foro de elhacker.net

Programación => Java => Mensaje iniciado por: routerico en 31 Enero 2015, 13:19 pm



Título: Controlar Timeout mediante un EJB
Publicado por: routerico en 31 Enero 2015, 13:19 pm
Hola qué tal, estoy intentando controlar un TimeOut mediante un EJB.


Ésta es la clase que tiene mi EJB:

import javax.ejb.Stateless;
import javax.ejb.Timeout;
 
@Stateless
public class TimeoutRespuesta {
   
 
    @Timeout
    public int sumador(int resultado){
 
        return resultado;
 
    }
}




Exporto el EJB mediante un .jar, me creo un proyecto Java y me creo una clase de pruebas:


public class Suma {
 
    public static void main(String[] args) {
       
       
        int res = (new TimeoutRespuesta()).sumador(sumar(1,2));
       
        System.out.println(res);
       
    }
 
    public static int sumar(int a, int b){
       
        return a+b;
    }
}



Aunque es un ejemplo muy sencillo, pero mi idea es controlar el Timeout mediante EJB, si fuese un método más complejo que no deje la aplicación bloqueada, que salte el Timeout del EJB y salga del método.

¿Estaría bien así?.

¿Cuál es el tiempo por defecto del Timeout del EJB?.


Un saludo y muchas gracias.


Título: Re: Controlar Timeout mediante un EJB
Publicado por: Usuario Invitado en 31 Enero 2015, 15:42 pm
Cuando se utiliza un método timeout anotado con @timeout, la especificación nos dice que el método debe retornar void y sólo recibir como parámetro un objeto javax.ejb.TimerService o en su defecto, no debe recibir parámetros.

Para registrar un timeout podemos hacerlo de la siguiente manera (de acuerdo a la tercera forma):

Código
  1. createTimer(long duracionInicial, long duracionIntervalo, serializable objetoAsociado);

Así que puedes crearlo así:

Código
  1. @Resource TimerService timer; // opcional, aquí inyectamos al objeto TimerService
  2.  
  3. public void doSomething(Objeto obj) {
  4.    timer.createTimer(15*60*1000, 15*60*1000, obj);
  5. }

Lo que se ha hecho es crear un TimerService cuya primera véz de ejecución será un timeout de 15 minutos y el intérvalo entre ejecuciones será de 15 minutos también. Así mismo, hemos asociado al TimerService un objeto que debe implementar Serializable.

Bien, ahora el método que se ejecutará luego del registro del TimerService será:

Código
  1. @timeout doOtherThing(Timer timer)  {
  2.    Objeto obj = (Objeto) timer.getInfo();
  3.    // hacer otras cosas...
  4. }

El método getInfo() retorna el objeto asociado al TimerService. Si al momento de crear el TimerService en lugar de un objeto se declara null, el valor devuelto será null también.

Ahora, si estoy en lo correcto, podemos cancelar un TimerService. Por ejemplo si en lugar de un objeto le hemos asociado un nombre, podríamos detenerlo así:

Código
  1. public void stop(String timerName) {
  2.    for(Object obj : timerService.getTimers()) {
  3.        Timer t = (Timer)obj;
  4.        if (t.getInfo().equals(timerName)) {
  5.        t.cancel();
  6.        }
  7.    }
  8. }

Pero si no hemos asociado un nombre, podemos detenerlos iterando el conjunto de TimerService:

Código
  1. public void stop() {  
  2.        List<Timer> timers = timerService.getTimers();  
  3.        if (timers != null)  
  4.        {  
  5.            for(Timer t : timers) {
  6.                t.cancel();
  7.            }
  8.        }  
  9. }

Salu2.

PD: Usa las etiquetas Geshi para colocar código.


Título: Re: Controlar Timeout mediante un EJB
Publicado por: routerico en 31 Enero 2015, 18:14 pm
Cuando se utiliza un método timeout anotado con @timeout, la especificación nos dice que el método debe retornar void y sólo recibir como parámetro un objeto javax.ejb.TimerService o en su defecto, no debe recibir parámetros.

Para registrar un timeout podemos hacerlo de la siguiente manera (de acuerdo a la tercera forma):

Código
  1. createTimer(long duracionInicial, long duracionIntervalo, serializable objetoAsociado);

Así que puedes crearlo así:

Código
  1. @Resource TimerService timer; // opcional, aquí inyectamos al objeto TimerService
  2.  
  3. public void doSomething(Objeto obj) {
  4.    timer.createTimer(15*60*1000, 15*60*1000, obj);
  5. }

Lo que se ha hecho es crear un TimerService cuya primera véz de ejecución será un timeout de 15 minutos y el intérvalo entre ejecuciones será de 15 minutos también. Así mismo, hemos asociado al TimerService un objeto que debe implementar Serializable.

Bien, ahora el método que se ejecutará luego del registro del TimerService será:

Código
  1. @timeout doOtherThing(Timer timer)  {
  2.    Objeto obj = (Objeto) timer.getInfo();
  3.    // hacer otras cosas...
  4. }

El método getInfo() retorna el objeto asociado al TimerService. Si al momento de crear el TimerService en lugar de un objeto se declara null, el valor devuelto será null también.

Ahora, si estoy en lo correcto, podemos cancelar un TimerService. Por ejemplo si en lugar de un objeto le hemos asociado un nombre, podríamos detenerlo así:

Código
  1. public void stop(String timerName) {
  2.    for(Object obj : timerService.getTimers()) {
  3.        Timer t = (Timer)obj;
  4.        if (t.getInfo().equals(timerName)) {
  5.        t.cancel();
  6.        }
  7.    }
  8. }

Pero si no hemos asociado un nombre, podemos detenerlos iterando el conjunto de TimerService:

Código
  1. public void stop() {  
  2.        List<Timer> timers = timerService.getTimers();  
  3.        if (timers != null)  
  4.        {  
  5.            for(Timer t : timers) {
  6.                t.cancel();
  7.            }
  8.        }  
  9. }

Salu2.

PD: Usa las etiquetas Geshi para colocar código.

Muchas gracias por tu ayuda, pero tengo algunas dudas de implementación.

Si quisiera controlar el timeout de un método como el anterior, ¿sería algo así?


Código
  1.  
  2. import java.io.Serializable;
  3. import javax.annotation.Resource;
  4. import javax.ejb.Stateless;
  5. import javax.ejb.Timeout;
  6. import javax.ejb.Timer;
  7. import javax.ejb.TimerService;
  8.  
  9.  
  10. @Stateless
  11. public class TimeoutRespuesta {
  12.  
  13.  
  14. @Resource TimerService timer;
  15.  
  16. public void doSomething(Object obj) {
  17.    timer.createTimer(1000, 1000, (Serializable) obj);
  18. }
  19.  
  20. @Timeout void doOtherThing(Timer timer)  {
  21.    Object obj = (Object) timer.getInfo();
  22.  
  23. }
  24.  
  25. public int sum(int i){
  26. return i;
  27. }
  28.  
  29. }
  30.  
  31.  



Código
  1. import timeout.TimeoutRespuesta;
  2.  
  3.  
  4. public class Suma {
  5.  
  6. public static void main(String[] args) {
  7.  
  8.  
  9. int res = (new TimeoutRespuesta()).sum(sumar(1,2));
  10.  
  11. System.out.println(res);
  12.  
  13. }
  14.  
  15. public static int sumar(int a, int b){
  16. return a+b;
  17. }
  18. }
  19.  
  20.  
  21.  


Gracias.


Título: Re: Controlar Timeout mediante un EJB
Publicado por: Usuario Invitado en 1 Febrero 2015, 00:08 am
No te entiendo. ¿Dices que quieres controlar el timeout dinámicamente?

Si es así, puedes controlarlo cancelándolo y volviendo a crearlo. Por ejemplo:

Código
  1. public void startOrModifyTimer(long initialExpiration, long interval, String name){      
  2.        for (Timer timer: timer.getTimers()) {
  3.            if (timer.getInfo().equals(name)) {
  4.                timer.cancel();
  5.            }
  6.        }
  7.        TimerConfig config = new TimerConfig();
  8.        config.setInfo(name);
  9.        config.setPersistent(false);
  10.        timerService.createIntervalTimer(initialExpiration, interval, config);
  11. }


Título: Re: Controlar Timeout mediante un EJB
Publicado por: routerico en 1 Febrero 2015, 17:16 pm
No te entiendo. ¿Dices que quieres controlar el timeout dinámicamente?

Si es así, puedes controlarlo cancelándolo y volviendo a crearlo. Por ejemplo:

Código
  1. public void startOrModifyTimer(long initialExpiration, long interval, String name){      
  2.        for (Timer timer: timer.getTimers()) {
  3.            if (timer.getInfo().equals(name)) {
  4.                timer.cancel();
  5.            }
  6.        }
  7.        TimerConfig config = new TimerConfig();
  8.        config.setInfo(name);
  9.        config.setPersistent(false);
  10.        timerService.createIntervalTimer(initialExpiration, interval, config);
  11. }


Hola, muchas gracias. Ésto es lo que quiero hacer, pongo un ejemplo:

Tengo un proyecto web en Java, ahora bien, tengo un método que hace una consulta a la base de datos, pues imagínate que se queda pillado el método y no devuelve nunca el resultado de la consulta, en vez de quedarse bloqueado, lo que quiero es mediante el timeout de un EJB, controlar y decir si se invoca el método y pasan 20 segundos y no se recibe respuesta que se salga del método y no se quede pillado ahí.


Saludos.


Título: Re: Controlar Timeout mediante un EJB
Publicado por: Usuario Invitado en 1 Febrero 2015, 17:52 pm
Yo lo haría así:

1.- Hacer la consulta en un Thread.
2.- Haces la consulta.
3.- Registras el Timer a 20 segundos.
4.- En el método @Timeout cancelas el Thread y por consiguiente la consulta.


Título: Re: Controlar Timeout mediante un EJB
Publicado por: routerico en 1 Febrero 2015, 18:29 pm
Yo lo haría así:

1.- Hacer la consulta en un Thread.
2.- Haces la consulta.
3.- Registras el Timer a 20 segundos.
4.- En el método @Timeout cancelas el Thread y por consiguiente la consulta.

Vale gracias, hice los pasos:


1.- Hacer la consulta en un Thread.

Código
  1.  
  2. public class ConsultaBBDD implements Runnable{
  3.  
  4. public void run() {
  5. String datos = consultarBBDD();
  6.  
  7. }
  8.  
  9. public String consultarBBDD(){
  10. return "datosBBDD";
  11. }
  12. }
  13.  
  14.  






2.- Haces la consulta.


Código
  1. public class ClasePrincipal {
  2.  
  3. public String obtenerDatos(){
  4. Thread t = new Thread(new ConsultaBBDD());
  5. t.start();
  6.  
  7. return "";
  8. }
  9.  
  10. }
  11.  
  12.  



3.- Registras el Timer a 20 segundos.
4.- En el método @Timeout cancelas el Thread y por consiguiente la consulta.


Código
  1. import java.io.Serializable;
  2. import javax.annotation.Resource;
  3. import javax.ejb.Stateless;
  4. import javax.ejb.Timeout;
  5. import javax.ejb.Timer;
  6. import javax.ejb.TimerService;
  7.  
  8.  
  9. @Stateless
  10. public class TimeoutRespuesta {
  11.  
  12. @Resource TimerService timer;
  13.  
  14. public void doSomething(Object obj) {
  15.    timer.createTimer(20000, 20000, (Serializable) obj);
  16. }
  17.  
  18. @Timeout void doOtherThing(Timer timer)  {
  19.    Thread t = new Thread();
  20.    t.stop();
  21. }
  22. }
  23.  




¿Sería algo parecido a lo que puse?. Lo que me falta sería la invocación del EJB dentro de la ClasePrincipal, pero es que no sé exactamente cómo sería, ¿qué método suyo tendrían que invocar?.


Muchas gracias.

Saludos.



Título: Re: Controlar Timeout mediante un EJB
Publicado por: Usuario Invitado en 1 Febrero 2015, 19:18 pm
Exactamente. Me captaste la idea  ;D

Para invocar al método @Timeout no es necesario invocar nada. En el momento en que registras un TimerService, el método @Timeout se invocará automáticamente cuando expire el tiempo de espera.

Otra cosa. Un TimerService tiene que ser usado en un servidor de aplicaciones ya que, éste será inyectado por medio de @Resource por el contenedor del servidor. Además creo que para usar un EJB Timer es necesario especificar si es un Bean local o remoto por medio de sus interfaces. Te dejo un ejemplo:

Interface local:
Código
  1. import javax.ejb.Local;
  2. import javax.ejb.Timer;
  3.  
  4. @Local
  5. public interface BeanLocal {
  6. public void start(String name);
  7. public void execute(Timer timer);
  8. public void stop(String name);
  9. }

El EJB
Código
  1. import javax.annotation.Resource;
  2. import javax.ejb.Singleton;
  3. import javax.ejb.Timeout;
  4. import javax.ejb.Timer;
  5. import javax.ejb.TimerService;
  6.  
  7. @Singleton
  8. public class TimerBean implements BeanLocal {
  9.  
  10. @Resource TimerService timer;
  11.  
  12. @Override
  13. public void start(String name) {
  14. boolean exists = false;
  15. for(Timer temp : timer.getTimers()) {
  16. if(temp.getInfo().equals(name))
  17. exists = true;
  18. }
  19. if(!exists)
  20. timer.createTimer(15000, 3000, name);
  21. }
  22.  
  23. @Override @Timeout
  24. public void execute(Timer timer) {
  25. System.out.println("M&#233;todo @Timeout invocado: "+timer.getInfo());
  26. }
  27.  
  28. @Override
  29. public void stop(String name) {
  30. for(Timer temp : timer.getTimers()) {
  31. if(temp.getInfo().equals(name))
  32. temp.cancel();
  33. }
  34. }
  35.  
  36. }

Luego, donde uses el EJB Timer lo inyectas también:

Código
  1. @Inject private BeanLocal myEJB;

Para registrar un TimerService, simplemente haría:

Código
  1. myEJB.start("identificadorTimer");

Y para cancelar un TimerService:

Código
  1. myEJB.stop("identificadorTimer");

Nota: Yo le puse @Singleton porque quería que solo exista una instancia del EJB Timer. Funciona igual con EJB Stateless y Stateful.

UPDATE

De acuerdo a la especificación de EJB 3.1, si va a ser un EJB local solamente, se puede obviar la interface @Local. Solo basta ponerle al EJB @LocalBean para indicar que es un EJB local.

Código
  1. @LocalBean
  2. @Singleton
  3. public class TimerBean {


Título: Re: Controlar Timeout mediante un EJB
Publicado por: routerico en 1 Febrero 2015, 19:47 pm
Exactamente. Me captaste la idea  ;D

Para invocar al método @Timeout no es necesario invocar nada. En el momento en que registras un TimerService, el método @Timeout se invocará automáticamente cuando expire el tiempo de espera.

Otra cosa. Un TimerService tiene que ser usado en un servidor de aplicaciones ya que, éste será inyectado por medio de @Resource por el contenedor del servidor. Además creo que para usar un EJB Timer es necesario especificar si es un Bean local o remoto por medio de sus interfaces. Te dejo un ejemplo:

Interface local:
Código
  1. import javax.ejb.Local;
  2. import javax.ejb.Timer;
  3.  
  4. @Local
  5. public interface BeanLocal {
  6. public void start(String name);
  7. public void execute(Timer timer);
  8. public void stop(String name);
  9. }

El EJB
Código
  1. import javax.annotation.Resource;
  2. import javax.ejb.Singleton;
  3. import javax.ejb.Timeout;
  4. import javax.ejb.Timer;
  5. import javax.ejb.TimerService;
  6.  
  7. @Singleton
  8. public class TimerBean implements BeanLocal {
  9.  
  10. @Resource TimerService timer;
  11.  
  12. @Override
  13. public void start(String name) {
  14. boolean exists = false;
  15. for(Timer temp : timer.getTimers()) {
  16. if(temp.getInfo().equals(name))
  17. exists = true;
  18. }
  19. if(!exists)
  20. timer.createTimer(15000, 3000, name);
  21. }
  22.  
  23. @Override @Timeout
  24. public void execute(Timer timer) {
  25. System.out.println("Método @Timeout invocado: "+timer.getInfo());
  26. }
  27.  
  28. @Override
  29. public void stop(String name) {
  30. for(Timer temp : timer.getTimers()) {
  31. if(temp.getInfo().equals(name))
  32. temp.cancel();
  33. }
  34. }
  35.  
  36. }

Luego, donde uses el EJB Timer lo inyectas también:

Código
  1. @Inject private BeanLocal myEJB;

Para registrar un TimerService, simplemente haría:

Código
  1. myEJB.start("identificadorTimer");

Y para cancelar un TimerService:

Código
  1. myEJB.stop("identificadorTimer");

Nota: Yo le puse @Singleton porque quería que solo exista una instancia del EJB Timer. Funciona igual con EJB Stateless y Stateful.

De acuerdo, muchísimas gracias. Mañana lo voy a probar a ver qué sucede.

Un saludo!!


Título: Re: Controlar Timeout mediante un EJB
Publicado por: routerico en 2 Febrero 2015, 20:31 pm


Código
  1. @Inject private BeanLocal myEJB;

Para registrar un TimerService, simplemente haría:

Código
  1. myEJB.start("identificadorTimer");

Y para cancelar un TimerService:

Código
  1. myEJB.stop("identificadorTimer");

Nota: Yo le puse @Singleton porque quería que solo exista una instancia del EJB Timer. Funciona igual con EJB Stateless y Stateful.

UPDATE

De acuerdo a la especificación de EJB 3.1, si va a ser un EJB local solamente, se puede obviar la interface @Local. Solo basta ponerle al EJB @LocalBean para indicar que es un EJB local.

Código
  1. @LocalBean
  2. @Singleton
  3. public class TimerBean {




Hola compañero, me está dando NullPointerException cuando en el proyecto web.


- Me creo el atributo del EJB
Código
  1. @Inject private BeanLocal myEJB;


Pero cuando invoco al método start, ahí me da NullPointerException

Código
  1. myEJB.start("identificadorTimer");


¿Cómo tendría que instanciar el EJB dentro de una clase del Proyecto Web para que no me de null?

Un saludo y muchas gracias de nuevo.


Título: Re: Controlar Timeout mediante un EJB
Publicado por: Usuario Invitado en 2 Febrero 2015, 20:47 pm
No cites mis respuestas para no hacer muy largas las mismas. Pégame el StackTrace y las clases que tienes.

PD: Para que funcione CDI (inyeción de dependencias) tienes que crear un archivo beans.xml en el directorio WEB-INF/, en donde está el web.xml.

JDK 1.7+
Código
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  3.       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4.       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
  5.       version="1.1" bean-discovery-mode="all">
  6. </beans>


Título: Re: Controlar Timeout mediante un EJB
Publicado por: routerico en 2 Febrero 2015, 21:01 pm
No cites mis respuestas para no hacer muy largas las mismas. Pégame el StackTrace y las clases que tienes.

PD: Para que funcione CDI (inyeción de dependencias) tienes que crear un archivo beans.xml en el directorio WEB-INF/, en donde está el web.xml.

JDK 1.7+
Código
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  3.       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4.       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
  5.       version="1.1" bean-discovery-mode="all">
  6. </beans>

Mi JDK es 1.6, será este el problema...


Muchas gracias.

Un saludo:


Título: Re: Controlar Timeout mediante un EJB
Publicado por: Usuario Invitado en 2 Febrero 2015, 21:04 pm
En parte. Yo te estoy hablando de Java EE 7, osea con el JDK 1.7 o el 1.8 que es el último. Tu estás usando Java EE 6.

Instala el JDK 1.8 y utiliza un servidor EE como GlassFish o WildFly. Tomcat no te servirá porque no soporta EJBs, solo EJBs lite pero eso es otra cosa.

Salu2.

PD: No cites mis respuestas en tu próxima respuesta. Solo escribe nada más.