DICA: Verifica se sua aplicação já está aberta

Galera, gostaria de compartilhar uma dica aqui com vocês que achei bem legal.

A classe abaixo verifica se seu sistema já está aberto, se sim apresenta a mensagem “O sistema já está aberto”, desta forma evita de o usuário ficar abrindo varias instâncias.

Em resumo ao abrir o sistema ele cria um arquivo temporário na pasta raiz do jar e ao fechar o sistema ele exclui o arquivo temporário, abaixo todo código:

No pacote main do seu projeto crie uma nova classe com o nome de “Control” e cole o código abaixo:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.text.ParseException;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javax.swing.JOptionPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

/**
 * Verifica se o app ja esta aberto e não deixa abir outra instancia *
 * @author : Fabio Argenton
 * @contato: fabio.argenton@hotmail.com
 * 
 */
public class Control {

    //Arquivo TMP
    private String appPath = System.getProperties().getProperty("user.dir");
    private File arquivo = new File(appPath + "\\meuApp.tmp");

    //Tempo em que se atualiza o arquivo TMP
    private int segundos = 2;

    /**
     * Contrutor da classe
     */
    public Control() {
    }

    ;
    
    /**
     * Cria um arquivo TMP com um unico valor, o tempo em milisegundos
     */
    public void criarTMP() {
        Date fechar = new Date();
        try {
            BufferedWriter writer = new BufferedWriter(new FileWriter(arquivo));
            writer.write(String.valueOf(fechar.getTime()));
            writer.close();
        } catch (IOException e) {
            System.err.println(e.getMessage());
        }
    }

    /**
     * Lê o arquivo TMP e retorna seu valor
     *
     *
     * @returna em LONG a quantidade de milisegundos
     */
    public long ler() {
        String linha = "0";
        BufferedReader bufferedReader;
        try {
            bufferedReader = new BufferedReader(new FileReader(arquivo));
            while (bufferedReader.ready()) {
                linha = bufferedReader.readLine();
            }
        } catch (IOException e) {
            System.err.println(e.getMessage());
        }
        return Long.valueOf(linha).longValue();
    }

    /**
     * Verifica se arquivo TMP existe, senão cria e inicia valores
     */
    public boolean verificar() throws ParseException, UnsupportedLookAndFeelException {
        if (arquivo.exists()) {
            long tempo = ler();//
            long res = reiniciaTempo(tempo);
            if (res < segundos) {
                JOptionPane.showMessageDialog(null, "O Sistema já está aberto!");
                return false;
            } else {
                job();
                return true;
            }
        } else// não existe arquivo
        {
            criarTMP();
            job();
            return true;
        }
    }

    /**
     * Expressa o tempo impresso em milisegundos
     *
     *
     * @param tempoAtual o tempo atual do sistema expressado em milisegundos
     * @returna tempo e o resultado expressado em segundos
     */
    public long reiniciaTempo(long tempoAtual) {
        Date data = new Date();
        long tempoTMP = data.getTime();
        long tempo = tempoTMP - tempoAtual;
        tempo = tempo / 1000;
        return tempo;
    }

    /**
     * Programa um processo que se repete a cada certo tempo
     */
    public void job() {
        ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
        scheduler.scheduleAtFixedRate(
                new Runnable() {
            @Override
            public void run() {
                criarTMP();
            }
        }, 1000, segundos * 1000, TimeUnit.MILLISECONDS); //começa dentro de 1 segundo e logo se repete cada N segundos

    }

    /**
     * Elimina o arquivo TMP se é que existe
     */
    public void fecharApp() {
        if (arquivo.exists()) {
            arquivo.delete();
        }
    }

}//--> fim classe

Agora lá na classe “main” principal do seu sistema você chama os métodos da classe “Control” acima, ficará da seguinte forma:

public static void main(String[] args) throws ParseException, UnsupportedLookAndFeelException {
        if (new Control().verificar()) {//Verifica se o sistema já está aberto
            try {
                UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");//Tema principal
            } catch (Exception e) {
                e.printStackTrace();
            }
            new CircleFrameLogin().setVisible(true);//Abre a tela de Login
        } else {//Se o sistema já estiver aberto
            System.exit(0);
            new Control().fecharApp();
        }
    }
2 curtidas

Obrigado por compartilhar @fabio.argenton!

Tem alguns tópicos aqui no GUJ discutindo como fazer isso, inclusive com a sua soluçao e os possíveis problemas com ela.
Esse é um deles com uma boa alternativa (server sockets):

1 curtida

Boa!

Outra forma é abrindo um server socket, ficar esperando por conexão nessa porta.
Quando abrir a segunda instância do sistema, se já houver uma em execução, não dará pra abrir o server socket, então é só abrir um socket normal e enviar uma mensagem para a outra instância receber o foco.