Capturar eventos em outra classe

Pessoal, tenho uma classe java que fica monitorando a porta serial. Na verdade há um sensor (ligado via arduíno) e essa classe fica lendo as informações.

Preciso saber se é possível e como fazer para que uma outra classe consiga “ouvir” que foi lido um valor na porta serial.

Isso que você quer fazer é perfeitamente possível. Seguindo os “bons costumes”, você precisa criar uma interface SensorListener mais ou menos assim:

public interface SensorListener {
	public void init();

	public void informacaoLida(String informacao);

	public void finish();
}

Dentro da classe que lê a informação você faz o seguinte:

import java.util.ArrayList;
import java.util.List;

public class SensorLeitor {
	private List<SensorListener> ouvintes = new ArrayList<SensorListener>();

	// Esse método precisa ser chamado logo após a criação de SensorLeitor
	// passando um SensorLogger
	public void addListener(SensorListener ouvinte) {
		ouvintes.add(ouvinte);
	}

	public void lerInformacoes() {
		init();
		// seus métodos de leitura normais, passando a informação lida para
		// String "resultadoLeitura"
		String resultadoLeitura = "Teste";
		for (SensorListener sl : ouvintes) {
			sl.informacaoLida(resultadoLeitura);
		}
		finish();
	}

	private void init() {
		for (SensorListener sl : ouvintes) {
			sl.init();
		}
	}

	private void finish() {
		for (SensorListener sl : ouvintes) {
			sl.finish();
		}
	}
}

Por fim, você cria uma classe que implementa o SensorListener e que grava as informações em um arquivo.

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.Format;
import java.text.SimpleDateFormat;
import java.util.Date;

public class SensorLogger implements SensorListener {

	private FileOutputStream out;
	private Format formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

	@Override
	public void init() {
		try {
			out = new FileOutputStream(new File("D:\\sensor.log"));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}

	}

	@Override
	public void informacaoLida(String informacao) {
		try {
			String log = formatter.format(new Date()) + ": " + informacao;
			out.write(log.getBytes());
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	@Override
	public void finish() {
		try {
			out.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}

Exemplo de execução:

public class SensorMain {
	public static void main(String[] args) {
		SensorLogger logger = new SensorLogger();
		SensorLeitor leitor = new SensorLeitor();
		leitor.addListener(logger);
		leitor.lerInformacoes();
	}
}

Saída:
> 2016-01-10 15:48:23: Teste

Baseado nessa postagem:

Se você quiser que as classes que implementam SensorListener sejam adicionadas automaticamente, sem ter que chamar addListener(SensorListener), pode ser importada a biblioteca org.reflections (exemplo no Maven):

     <dependency>
         <groupId>org.reflections</groupId>
         <artifactId>reflections</artifactId>
         <version>0.9.9-RC1</version>
     </dependency>

E na inicialização do leitor:

	public SensorLeitor() {
		Reflections reflections = new Reflections(ClasspathHelper.forPackage("br.com.guj.gpassero"),
				new SubTypesScanner());
		Set<Class<? extends SensorListener>> classesOuvintes = reflections.getSubTypesOf(SensorListener.class);
		for (Iterator<Class<? extends SensorListener>> iterator = classesOuvintes.iterator(); iterator.hasNext();) {
			Class<? extends SensorListener> classe = iterator.next();
			try {
				ouvintes.add(classe.newInstance());
			} catch (InstantiationException | IllegalAccessException e) {
				e.printStackTrace();
			}
		}
	}

https://code.google.com/p/reflections/

Boa Tarde,Será que alguém poderia me dar uma força, não funcionou pra mim, no meu caso eu tenho uma classe que escuta eventos da porta serial, eu implantei todas as etapas, porem mesmo quando acontece o evento na serial nenhum evento é disparado na classe onde implantei os metodos da classe SensorMain.

Posta o código que você escreveu.

Acabei de apagar tudo, estou tentando uma nova abordagem, mas assim que terminar eu posto aqui, muito obrigado @staroski

Deu certo, vou deixar minha solução aqui, ode ajudar mais alguém.

Inicialmente tenho que explicar melhor a ideia.
Eu criei um projeto para comunicação serial com alguns equipamentos e cada um deles responde em um protocolo diferente, então minha ideia foi a seguinte, desenvolver um .jar que faça esta comunicação com a serial e traduza o protocolo.
Ate a parte da comunicação serial tranquilo, meu problema foi quando eu estava em outro .jar.
Minha solução foi a seguinte:
Criei na classe que controla a comunicação serial um array para responder a todas as chamadas.

private List<ActionListener> listeners = new ArrayList<ActionListener>(0);

e criei um método de acesso a este array para adicionar ouvidores:

public void addActionListener(ActionListener listener) {
		this.listeners.add(listener);
	}

em seguida criei um método para disparar os eventos:

public void dadosRecebidos(){
	for(ActionListener listener : listeners) {
		listener.actionPerformed(new ActionEvent(this,1,"DADOS RECEBIDOS"));
	}
}

este metodo é chamado dentro do evento que é disparado ao receber dados na porta serial.

@Override
    public void serialEvent(SerialPortEvent spe) {
        //metodo que recebe os dados da serial
        try {
            switch(spe.getEventType()){
                case SerialPortEvent.DATA_AVAILABLE:
                    if(input == null){
                        input = new BufferedReader(new InputStreamReader(serialPort.getInputStream()));
                    }                    
                    dadosSerial = input.readLine();
                    System.out.println(dadosSerial); 
                    //Sinalizar evento na porta serial
                    dadosRecebidos(); //aqui comunica o recebimento de dados
                    input=null;
                    break;
                default:
                    break;
            }
        } catch (IOException e) {
        }
        
    }

Agora dentro já posso receber este evento dentro de outro .jar, bastou criar uma classe.

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;


    public class DadosSerial implements ActionListener{

        @Override
        public void actionPerformed(ActionEvent e) {
            System.out.println("Dados Serial : "+e.getID()+" > "+e.getActionCommand());
        }
        
    }

Agora dentro do meu JFrame eu Declarei minha classe de comunicação e instanciei a classe que associa o evento.

public class FramePrincipal extends javax.swing.JFrame {
    Serial.SerialTxRx serial = new Serial.SerialTxRx();
    
    /**
     * Creates new form FramePrincipal
     */
    public FramePrincipal() {                            
        initComponents();        
        serial.addActionListener(new DadosSerial());
        
    }

Grande abraço, e espero também poder ajudar alguém e me desculpem qualquer erro este é meu primeiro post.

1 curtida

Então tu tens um JAR rodando em uma instância da JVM e esse JAR trata os eventos recebidos pela porta serial.

E você quer que ele notifique outro JAR que esté rodando em outra instância da JVM.

É isso?

Pra implementar listeners em diferentes programas, creio que o mais simples será você implementar objetos distribuídos com RMI.

Provavelmente é o mais certo, mas já funcionou aqui, vou aproveitar e ver como funcionam estes objetos distribuídos com RMI.