Desenvolvimento - Java
Detectando tempo ocioso
Este artigo se propõe a demonstrar uma maneira de detectar inatividade de um sistema feito em AWT ou Swing.
por Hamilton LimaImagine também que desejamos que se o usuário deixar o sistema aberto por mais de N minutos, queremos bloquear o usuário, ou sair do sistema, ou ainda registrar esta inatividade em algum tipo de log, seja no banco de dados ou em outra estrutura de armazenamento.
Este artigo se propõe a demonstrar uma maneira de detectar inatividade de um sistema feito em AWT ou Swing.
A idéia
Na verdade a idéia é bem simples, usar a arquitetura de delegação de tratamento de eventos, e criar uma super classe para todas as janelas, que ao ser exibida garanta que sejam atribuidos tratadores de evento adicionais para o controle do tempo, e a criação de uma classe que seja executada em um thread separado, para verificar os eventos relacionados ao tempo.
A implementação
o diagrama de classes abaixo descreve as classes envolvidas
app |
principal para execução do teste |
Timer |
implementação básica do controle do tempo |
InactivityMonitor |
filha de Timer que realiza alguma tarefa após determinado tempo de inatividade |
ShowInactivity |
filha de Timer que exeibe em um label o número de segundos de inatividade |
SuperFrame |
Deve ser superclasse de todas as janelas do sistema, executa método do InactivityListener para adicionar os listeners adicionais |
MainFrame |
Tela principal do exemplo |
FrameTest |
Tela de exemplo com diversos componentes |
Observe a classe SuperFrame abaixo
package
com.athanazio.timeout;
import javax.swing.JFrame;
public class SuperFrame extends JFrame {
private
boolean init = false;
public void show(){
super.show();
if (!init) {
InactivityListener.addListener(this);
}
}
}
Quando chama o método addListener( ) da classe
InactivityListener, faz com que a janela e todos os componentes
que estejam incluidos nela, recebam tratadores de eventos
adicionais para os eventos de Mouse e teclado, e a janela recebe
tratadores de eventos para eventos de janela.
O cõdigo do método addListener( )
public static void addListener(Window main)
{
main.addWindowStateListener(InactivityListener.getInstance());
Stack stack = new Stack();
stack.push(main);
while (!stack.empty()) {
Container container = (Container) stack.pop();
container.addKeyListener(InactivityListener.getInstance());
container.addMouseListener(InactivityListener.getInstance());
Component[] components =
container.getComponents();
for (int i = 0; i < components.length; i++) {
if (components[i] instanceof Container) {
stack.push(components[i]);
} else {
components[i].addKeyListener(InactivityListener.getInstance());
components[i].addMouseListener(InactivityListener.getInstance());
}
}
}
}
Este método
adiciona uma instância da prória classe como tratador dos
eventos:
components[i].addKeyListener(InactivityListener.getInstance());
components[i].addMouseListener(InactivityListener.getInstance());
de mudança de estado de janela (WindowStateListener), de mouse
(MouseListener) e de teclado (KeyListener), pois a classe
InactivityListener implementa os métodos necessários ao
tratamento destes diversos métodos, e todos eles, na verdade
marcam o momento em que houve algum destes eventos, mantendo
assim o momento em que ocorreu algum evento.
private
void setLastAction() {
lastAction =
System.currentTimeMillis();
}
Para garantir que todos os subcomponentes sejam alcançados, o método percorre a lista de componentes a partir da janela verificando quais são da classe Container (que podem possuir subcomponentes) e adiciona os mesmos em uma pilha para que sejam verificados, e todo subcomponente encontrado recebe um instância da classe como tratador de eventos.
Desta forma armazenamos o ultimo instante quando algum evento ocorreu, o próximo passo é verificar quando o tempo decorrido desde o último evento chega a alguma condição pré estabelecida, para tal criamos filhos da classe Timer, que é uma classe abstrata que executa o conteúdo do método doIt( ) a cada N segundos.
As classes filhas de Timer devem implementar este método e chamar em seus contrutores o construtor da classe Timer indicando de quantos em quantos segundos a execução deve ocorrer, veja por exemplo a classe InactivityMonitor que verifica se o tempo inativo passou de 15 segundos
package com.athanazio.timeout;
import javax.swing.JOptionPane;
public class InactivityMonitor extends Timer
{
public InactivityMonitor() {
super(2);
}
public void
doIt() {
if (InactivityListener.getInstance().getInactivitySeconds() > 15) {
JOptionPane.showMessageDialog(
null,
"15 segundos fazendo nada ...",
"monitor de ociosidade",
JOptionPane.WARNING_MESSAGE);
}
}
}
}
Simplemente a cada 2 segundos verifica se o tempo já chegou a 15 segundos de inatividade, e caso tenha chegado, exibe mansagem, podendo é clarro realizar qualquer tarefa necessária.
A classe principal só faz exibir as duas janelas, uma para exibir o tempo inativo, e outra de teste, e disparar os processamentos paralelos para verificação de tempo. Para testar execute a aplicação e realize algum evento na segunda janela e o tempo de inatividade na primeira será zerado.
baixe aqui os fontes e o arquivo do diagrama (feito no jude)
Aproveite
Hamilton Lima (athanazio)
Dezembro 2003