Laboratório

Objetivos

O objetivo deste laboratório é melhorar suas habilidades de depuração e de teste. O laboratório requer que você construa classes para um aplicativo existente e trate adequadamente situações de erro e exceção.

Descrição do NodeNet

O NodeNet é um simulador de roteamento em redes. Nele você pode desenhar uma rede composta de vários nós que geram, roteiam e consomem nós. Na prática, os nós poderiam ser, por exemplo, computadores conectados pela internet, enviando e recebendo dados. Para ver o simulador executando, digite: java -jar nodenet.jar. Na barra à esquerda aparecerão três tipos de nós: "Generator", "Intermediate" e "Terminator". À direita está o espaço onde uma rede pode ser criada e simulada. Para criar uma rede clique sobre um tipo de nó e, em seguida, clique na área de simulação para criar nós do tipo escolhido. Para formar uma rede, os nós devem ser interconectados por "canais". Para criar um canal faça um duplo clique sobre o nó de origem e, em seguida, um clique simples no nó de destino. A aplicação tem três menus: "File", "Simulation" e "Selection". Os comandos disponíveis são bastante intuitivos para serem entendidos com o uso.

Entenda a aplicação

Antes de começar a programar, faça algumas simulações com os nós existentes. Observe o comportamento e entenda o funcionamento dos nós. Crie algumas topologias de rede e grave-as (como templates) em um diretório compartilhado por todos da turma, de forma que se crie um repositório de topologias que poderão ser usadas para testar o comportamento das classes que vocês irão descrever. Dê nomes significativos às topologias. Mude o nó intermediário default da aplicação, digitando:

java -cp nodenet.jar nodenet.Main nodenet.DefaultNodeBehavior

Compare o comportamento desse nó com o intermediate. Observe que quando você lê uma topologia, são usados os nós que tiverem sido lidos pela aplicação. Eles são usados na ordem em que estiverem na coluna à esquerda (para mudar clique com o botão direito do mous). Descreva as diferenças entre as duas classes de nós intermediários.

Veja que cada nó e cada canal pode ser configurado (selecione o objeto e escolha o comando "Configure" no menu Selection). Veja o efeito disso sobre a simulação. Perceba que durante a simulação você pode desabilitar e habilitar novamente os nós e os canais. Remoções e adições de nós e canais, contudo, não devem ser feitas durante as simulações.

Os números nos nós Generator e Terminator durante uma simulação indicam o número de pacotes gerados e consumidos, respectivamente. Além disso, o número de "bolinhas" em cada canal indica o número de pacotes que trafegam por ali naquele instante. Quando o canal fica cheio ele muda de cor para vermelho. Tente fazer simulações em que os canais fiquem cheios. O que ocorre com os pacotes nessa situação?

Programe novos nós!

Seu objetivo é escrever o código necessário para descrever o comportamento de um nó intermediário (um nó corretamente implementado não deverá perder ou criar pacotes). Para isso você deve criar uma classe que implemente a interface "NodeBehavior". Embora os nós implementem Runnable, suas classes não precisam ser. Na prática, os nós têm sua própria Thread, mas eles repassam a responsabilidade para determinar o comportamento para um objeto do tipo NodeBehavior. O nó também faz todo o tratamento gráfico necessário, logo sua classe só deve tratar especificamente com a questão lógica do comportamento do nó. Quando você tiver feito a classe, leia-a do NodeNet para usá-la em simulações e experimentá-la.

O método run() do nó é essencialmente o seguinte:

public void run( ) {
    while( true ) {
        this.nodeBehavior.transmitPacket( this.inputChannels, this.outputChannels );
    }
}

Veja que transmitPacket() recebe dois argumentos: inputChannels e outputChannels. O primeiro é do tipo InputChannelVector e o segundo do tipo OutputChannelVector. Cada um deles corresponde a um vetor de objetos do tipo InputChannel e OutputChannel, respectivamente. O comportamento de um nó a cada ciclo (o que você deve escrever) consiste em ler um objeto de um dos canais de entrada e escrevê-lo em um dos canais de saída. Embora pareça simples, lembre que há múltiplos canais de entrada e de saída e que eles podem estar habilitados ou desabilitados e que eles podem estar vazios (os de entrada) ou cheios (os de saída). Todas essas condições devem ser adequadamente tratadas.

Há diversas estratégias que você pode adotar para decidir quais canais usar a cada ciclo. Pense em pelo menos duas e implemente-as. Leia atentamente a documentação das classes envolvidas. Experimente sua classe com diversas simulações. Use as topologias disponibilizadas pelos outros usuários. Isso irá submeter sua classe a situações que você não previu, de forma semelhante como código real é submetido a condições inesperadas quando colocado em produção. Para facilitar a execução de suas classes use a seguinte linha para executar o NodeNet, incluindo o diretório em que sua classe está como parte do classpath:

java -cp /caminho/do/nodenet.jar:/caminho/de/sua/classe/ nodenet.Main