diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..001c208 --- /dev/null +++ b/TODO.md @@ -0,0 +1,175 @@ +### Compreender os Conceitos Fundamentais + +Primeiro, as tecnologias e paradigmas chave necessários para este projeto devem ser totalmente compreendidos. + +- **Processos vs. Threads:** O projeto especifica o uso de ambos. + + - **Processos (para Cruzamentos)** são programas independentes, cada um com o seu próprio espaço de memória. Em Java, cada cruzamento será provavelmente executado como uma aplicação Java separada (uma instância distinta da JVM). + + - **Threads (para Semáforos)** existem _dentro_ de um processo e partilham memória. Isto é adequado para os semáforos, pois eles precisam de ser coordenados e partilhar dados (como filas de veículos) dentro do mesmo cruzamento. + +- **Comunicação Entre Processos (IPC - Inter-Process Communication):** Como os cruzamentos são processos separados, é necessário um método para que eles comuniquem. **Sockets** são o método especificado. Quando um veículo sai de um cruzamento (ex: `Cr1`) e vai para outro (ex: `Cr2`), o processo `Cr1` precisa de enviar uma mensagem contendo os dados do veículo para o processo `Cr2` através de uma conexão por socket. + +- **Simulação de Eventos Discretos (DES - Discrete-Event Simulation):** Este é o paradigma de simulação que deve ser utilizado. Em vez de o tempo fluir continuamente, o relógio da simulação salta de um evento para o seguinte. + + - Um **evento** é um objeto que representa algo que acontece num ponto específico no tempo (ex: "Veículo A chega ao Cr2 no tempo 15.7s"). + + - Uma **lista de eventos** central, frequentemente uma fila de prioridades, será necessária para armazenar eventos futuros, ordenados pelo seu timestamp. O ciclo principal da simulação retira o próximo evento da lista, processa-o e adiciona quaisquer novos eventos que resultem dele. + +- **Processo de Poisson:** Para o modelo "mais realista" de chegadas de veículos, é especificado um processo de Poisson. A principal conclusão é que o tempo _entre_ chegadas consecutivas de veículos segue uma **distribuição exponencial**. Em Java, este intervalo pode ser gerado usando `Math.log(1 - Math.random()) / -lambda`, onde `lambda` (λi​) é a taxa de chegada especificada. + + +--- + +### Uma Sugestão de Arquitetura de Alto Nível + +Abaixo, é apresentada uma possível estrutura para a aplicação distribuída. Pode ser vista como um conjunto de programas independentes que comunicam através de uma rede. + +1. **Processo Coordenador/Gerador (1 Processo):** + + - **Propósito:** Iniciar a simulação, gerar veículos e gerir o relógio global da simulação ou os critérios de paragem. + + - **Responsabilidades:** + + - Lê a configuração da simulação (ex: carga de tráfego λi​, tempos dos semáforos). + + - Gera veículos de acordo com o modelo selecionado (intervalo fixo ou processo de Poisson). + + - Atribui a cada novo veículo um percurso com base na distribuição uniforme especificada. + + - Injeta o veículo no sistema enviando uma mensagem para o primeiro processo de cruzamento no seu percurso (ex: de um ponto de entrada E1 para Cr1). + +2. **Processos de Cruzamento (5 Processos):** + + - **Propósito:** Simular cada cruzamento (`Cr1` a `Cr5`) como um processo distinto. + + - **Responsabilidades:** + + - Escuta por veículos a chegar de outros processos. + + - Gere as filas de veículos para os seus semáforos. + + - Executa múltiplas **threads de Semáforo** internamente. + + - Coordena estas threads para garantir que apenas uma direção de tráfego está aberta a cada momento. + + - Quando um veículo atravessa, é encaminhado para o processo seguinte no seu percurso. + + - Envia periodicamente as suas estatísticas (ex: comprimentos atuais das filas) para o Servidor do Dashboard. + +3. **Processo de Nó de Saída (1 Processo):** + + - **Propósito:** Representar o ponto de saída `S` e atuar como um coletor de dados para estatísticas globais. + + - **Responsabilidades:** + + - Recebe veículos que completaram o seu percurso. + + - Calcula métricas globais como o tempo total de viagem (tempo de permanência) para cada veículo. + + - Agrega e calcula as estatísticas finais (ex: tempo de viagem mínimo, máximo e médio por tipo de veículo). + + - Envia estas estatísticas globais para o Servidor do Dashboard. + +4. **Processo do Servidor do Dashboard (1 Processo):** + + - **Propósito:** Agregar e exibir todos os dados da simulação em tempo real. + + - **Responsabilidades:** + + - Abre um socket de servidor e escuta por dados a chegar de todos os processos de Cruzamento e de Saída. + + - Armazena e atualiza as estatísticas à medida que chegam. + + - Apresenta os dados numa interface de utilizador, que deve exibir métricas e ser atualizada durante a simulação. + + +--- + +### Plano + +Nem tudo deve ser construído de uma só vez. Os seguintes passos incrementais são recomendados. + +#### **Passo 1: Modelação e Classes Principais (Não-distribuído)** + +Antes de escrever qualquer lógica complexa, as estruturas de dados devem ser definidas. Devem ser criados Plain Old Java Objects (POJOs) para: + +- `Veiculo`: Com atributos como um identificador único, tipo, tempo de entrada e o percurso realizado. Deve ser tornado `Serializable` para que possa ser enviado através de sockets. + +- `Evento`: Com atributos como um timestamp e o tipo de evento (ex: `VEHICLE_ARRIVAL`), bem como dados associados. + +- `Semaforo`: Para conter o seu estado (`VERDE`/`VERMELHO`) e a fila de veículos. + +- `Cruzamento`: Para conter os seus semáforos e a lógica operacional. + + +#### **Passo 2: Construir um Protótipo de Processo Único** + +Este é um passo crucial. Sockets e processos devem ser deixados de lado por agora para construir toda a simulação numa única aplicação Java. + +- Deve ser criado um ciclo de simulação central baseado numa fila de prioridades para objetos `Evento`. + +- Todos os objetos `Cruzamento` e `Semaforo` devem ser instanciados. + +- A lógica principal deve ser tornada funcional: veículos a moverem-se entre filas, semáforos a mudar de estado e estatísticas básicas a serem recolhidas. + +- **Objetivo:** Uma simulação totalmente funcional e não-distribuída. Isto torna a depuração significativamente mais fácil. + + +#### **Passo 3: Distribuir os Cruzamentos** + +O protótipo pode agora ser convertido num sistema distribuído. + +- A classe `Cruzamento` deve ser tornada executável como uma aplicação Java autónoma (com um método `main`). Serão lançadas cinco instâncias, uma para cada cruzamento. + +- Devem ser configurados sockets TCP para comunicação. Cada processo de cruzamento precisa de saber o endereço/porta dos vizinhos para os quais pode enviar veículos. + +- Um **protocolo de comunicação** claro deve ser definido. Por exemplo, quando `Cr1` envia um veículo para `Cr2`, o objeto `Veiculo` é serializado e escrito no socket conectado a `Cr2`. O processo `Cr2` terá uma thread dedicada para escutar estas conexões de entrada. + + +#### **Passo 4: Implementar as Threads dos Semáforos** + +Dentro de cada processo `Cruzamento`, os semáforos devem ser implementados como threads. + +- O principal desafio aqui é a **sincronização**. As threads dos semáforos num único cruzamento partilham as filas de veículos. + +- As ferramentas de concorrência do Java (como `synchronized`, `ReentrantLock`, `Semaphore`) devem ser usadas para garantir que apenas um semáforo pode estar verde para um percurso conflituante e que o acesso às filas partilhadas é seguro (thread-safe). + + +#### **Passo 5: Implementar o Dashboard** + +- O processo `DashboardServer` deve ser criado. Ele irá escutar numa porta específica por estatísticas a chegar. + +- Nos processos `Cruzamento` e `Saida`, deve ser adicionado um mecanismo para enviar periodicamente um resumo das suas estatísticas atuais para o Servidor do Dashboard. + +- A UI deve ser construída para exibir estes dados em tempo real. + + +#### **Passo 6: Testes e Análise** + +Assim que o sistema completo estiver a funcionar, as experiências exigidas pela descrição do projeto podem ser realizadas. + +- A simulação deve ser executada com diferentes taxas de chegada de veículos para simular cargas baixas, médias e altas. + +- Diferentes políticas de temporização dos semáforos devem ser testadas para medir o seu impacto no congestionamento. + +- Diferentes algoritmos de seleção de percurso e o seu impacto no desempenho do sistema devem ser avaliados. + +- Para cada cenário, a simulação deve ser executada várias vezes para recolher estatísticas fiáveis (médias, desvios padrão, intervalos de confiança), conforme solicitado. + + +#### **Passo 7: Escrever o Relatório** + +À medida que cada passo é concluído, deve ser documentado. Isto tornará a escrita do relatório final muito mais fácil. Todos os pontos mencionados nas secções "Entrega" e "Critérios de Avaliação" devem ser abordados. + +--- + +### OBS: + +- **Começar de Forma Simples:** O protótipo de processo único (Passo 2) evitará grandes dificuldades mais tarde. + +- **Protocolo de Comunicação:** O protocolo de mensagens deve ser definido o mais cedo possível. A informação exata que um processo envia para outro deve ser clara//simples//consistente. + +- **Debugging:** Debugging de sistemas distribuídos podem ser difíceis. Uma framework de logging (como Log4j 2 ou SLF4J) pode ser usada para registar eventos//alterações de estado nos diferentes processos. + +- **Configuração:** Valores como endereços IP, números de porta ou parâmetros da simulação não devem ser "hardcoded". Um ficheiro de configuração (ex: um ficheiro `.properties` ou `.json`) torna a aplicação mais fácil de executar e testar. \ No newline at end of file diff --git a/main/src/main/java/sd/CruzamentoServer.java b/main/src/main/java/sd/CruzamentoServer.java deleted file mode 100644 index 1d84a00..0000000 --- a/main/src/main/java/sd/CruzamentoServer.java +++ /dev/null @@ -1,34 +0,0 @@ -package sd; - -import java.io.IOException; -import java.net.ServerSocket; -import java.net.Socket; - -public class CruzamentoServer { - public static void main(String[] args) { - // ... Inicializa Semáforos (Threads) ... - // ... Inicializa as Estruturas de Dados ... - - try (ServerSocket serverSocket = new ServerSocket(portaDoCruzamento)) { - while (true) { - Socket clienteSocket = serverSocket.accept(); - // Cria uma Thread de atendimento para lidar com o Veículo/Cliente - new Thread(new AtendenteVeiculo(clienteSocket)).start(); - } - } catch (IOException e) { /* ... */ } - } - - // Método chamado pelo AtendenteVeiculo para gerenciar o tráfego - public synchronized boolean tentarPassar(Veiculo veiculo, String direcao) { - // 1. Veículo entra na fila da direção - // 2. Verifica o estado do semáforo da direção: - Semaforo semaforo = getSemaforo(direcao); - semaforo.esperarPeloVerde(); // O Veículo fica bloqueado se for vermelho - - // 3. Após o verde: - // - Remove da fila - // - Permite a passagem (envia resposta de volta ao Veículo cliente) - // 4. Envia estatística de passagem ao Simulador Principal (Cliente TCP) - return true; - } -} diff --git a/main/src/main/java/sd/Entry.java b/main/src/main/java/sd/Entry.java new file mode 100644 index 0000000..b1d76a6 --- /dev/null +++ b/main/src/main/java/sd/Entry.java @@ -0,0 +1,7 @@ +package sd; + +public class Entry { + public static void main(String[] args) { + System.out.println("Hello, World!"); + } +} diff --git a/main/src/main/java/sd/Main.java b/main/src/main/java/sd/Main.java deleted file mode 100644 index 137fc4e..0000000 --- a/main/src/main/java/sd/Main.java +++ /dev/null @@ -1,7 +0,0 @@ -package sd; - -public class Main { - public static void main(String[] args) { - System.out.println("Hello world!"); - } -} \ No newline at end of file diff --git a/main/src/main/java/sd/Semaforo.java b/main/src/main/java/sd/Semaforo.java deleted file mode 100644 index 8f1d8ad..0000000 --- a/main/src/main/java/sd/Semaforo.java +++ /dev/null @@ -1,47 +0,0 @@ -package sd; - -import java.util.concurrent.locks.Condition; -import java.util.concurrent.locks.Lock; - -public class Semaforo extends Thread { - // ... atributos ... - private final Lock semaforoLock; // Para sincronizar acesso ao estado - private final Condition verdeCondition; // Para Veículos esperarem pelo verde - - public Semaforo(...) { - this.semaforoLock = new ReentrantLock(); - this.verdeCondition = semaforoLock.newCondition(); - } - - @Override - public void run() { - while (true) { - // Ciclo de tempo (ajustável para controle) - estado = Estado.VERMELHO; - // Notificar o Cruzamento sobre o estado - try { - Thread.sleep(tempoVermelho); - estado = Estado.VERDE; - // Ao ficar VERDE, notifica as threads Veículo que estão esperando - semaforoLock.lock(); - try { - verdeCondition.signalAll(); - } finally { - semaforoLock.unlock(); - } - Thread.sleep(tempoVerde); - } catch (InterruptedException e) { /* ... */ } - } - } - // Método para a thread Veículo esperar - public void esperarPeloVerde() throws InterruptedException { - semaforoLock.lock(); - try { - if (estado == Estado.VERMELHO) { - verdeCondition.await(); - } - } finally { - semaforoLock.unlock(); - } - } -} \ No newline at end of file diff --git a/main/src/main/java/sd/Veiculo.java b/main/src/main/java/sd/Veiculo.java deleted file mode 100644 index 2a55ec9..0000000 --- a/main/src/main/java/sd/Veiculo.java +++ /dev/null @@ -1,35 +0,0 @@ -package sd; - -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.net.Socket; - -public class Veiculo implements Runnable { - // ... - private String proximoCruzamentoIP; - private int proximoCruzamentoPorta; - - public void run() { - // Simular o movimento na rua (Thread.sleep(t)) - - // 1. Tenta se conectar ao próximo Cruzamento - try (Socket socket = new Socket(proximoCruzamentoIP, proximoCruzamentoPorta); - ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream()); - ObjectInputStream in = new ObjectInputStream(socket.getInputStream())) { - - // Envia o objeto Veículo com a solicitação de passagem - out.writeObject(this); - - // 2. BLOQUEIA a Thread, esperando a resposta do Servidor/Cruzamento - String permissao = (String) in.readObject(); - - if ("OK_PASSAR".equals(permissao)) { - // Simular tempo de travessia do cruzamento (pequeno Thread.sleep()) - // Atualiza a rota (próximo nó) - } - - } catch (IOException | ClassNotFoundException e) { /* ... */ } - // ... continua o loop da rota até a Saída (S) ... - } -} diff --git a/main/target/classes/sd/CruzamentoServer.class b/main/target/classes/sd/CruzamentoServer.class deleted file mode 100644 index f1925fd..0000000 Binary files a/main/target/classes/sd/CruzamentoServer.class and /dev/null differ diff --git a/main/target/classes/sd/Entry.class b/main/target/classes/sd/Entry.class new file mode 100644 index 0000000..72c0d91 Binary files /dev/null and b/main/target/classes/sd/Entry.class differ diff --git a/main/target/classes/sd/Main.class b/main/target/classes/sd/Main.class deleted file mode 100644 index fca87dc..0000000 Binary files a/main/target/classes/sd/Main.class and /dev/null differ diff --git a/main/target/classes/sd/Semaforo.class b/main/target/classes/sd/Semaforo.class deleted file mode 100644 index e275fc3..0000000 Binary files a/main/target/classes/sd/Semaforo.class and /dev/null differ diff --git a/main/target/classes/sd/Veiculo.class b/main/target/classes/sd/Veiculo.class deleted file mode 100644 index 3414695..0000000 Binary files a/main/target/classes/sd/Veiculo.class and /dev/null differ