Programação com Objectos/Projecto de Programação com Objectos/Enunciado do Projecto de 2022-2023 (rascunho): Difference between revisions

From Wiki**3

Root (talk | contribs)
Root (talk | contribs)
Line 62: Line 62:
== Propriedades das comunicações ==
== Propriedades das comunicações ==


Cada comunicação, além do identificador único, possui ainda informação sobre o terminal que a originou, o terminal de destino, a sua duração (no caso do texto, esta duração é o número de caracteres da mensagem; nos outros casos, é o número de segundos da comunicação) e o tipo de comunicação (voz, texto ou vídeo). A primeira comunicação tem como identificador “1”, devendo o identificador das comunicações subsequentes ser obtido por incremento unitário do identificador anterior.
Existem 3 tipos de comunicação entre terminais: texto (denominada '''TEXT'''), voz (denominada '''VOICE''') e vídeo (denominada '''VIDEO''').


Existem 3 tipos de comunicação entre terminais: texto (denominada '''TEXT'''), voz (denominada '''VOICE''') e vídeo (denominada '''VIDEO'''). O custo das comunicações não é uniforme (ver [[#Planos tarifários|Planos tarifários]]), dependendo do terminal e do cliente, entre outros factores. Também dependendo do cliente, é possível avisar quem o tentou contactar quando: (i) um terminal desligado é colocado em silêncio; (ii) um terminal desligado é ligado; ou (iii) um terminal em silêncio é ligado.
Cada comunicação, além do identificador único (no contexto de um dado cliente), possui ainda informação sobre o terminal que a originou, o terminal de destino, a sua duração (no caso do texto, esta duração é o número de caracteres da mensagem; nos outros casos, é o número de segundos da comunicação) e o tipo de comunicação (voz, texto ou vídeo). A primeira comunicação tem como identificador “1”, devendo o identificador das comunicações subsequentes ser obtido por incremento unitário do identificador anterior.
 
O custo das comunicações não é uniforme (ver [[#Planos tarifários|Planos tarifários]]), dependendo do cliente e do terminal, entre outros factores.


== Planos tarifários ==
== Planos tarifários ==

Revision as of 09:28, 29 July 2022

AVISOS - Avaliação em Época Normal

Esclarecimento de dúvidas:

  • Consultar sempre o corpo docente atempadamente: presencialmente ou através do endereço oficial da disciplina [1].
  • Não utilizar fontes de informação não oficialmente associadas ao corpo docente (podem colocar em causa a aprovação à disciplina).
  • Não são aceites justificações para violações destes conselhos: quaisquer consequências nefastas são da responsabilidade do aluno.

Requisitos para desenvolvimento, material de apoio e actualizações do enunciado (ver informação completa em Projecto de Programação com Objectos):

  • O material de apoio é de uso obrigatório e não pode ser alterado.
  • Verificar atempadamente (mínimo de 48 horas antes do final de cada prazo) os requisitos exigidos pelo processo de desenvolvimento.

Processo de avaliação (ver informação completa em Avaliação do Projecto):

  • Datas: 2022/10/04 12:00 (inicial); 2022/10/21 12:00 (intercalar); 2022/11/04 12:00 (final); 2022/11/04 (early bird) 2022/11/07 (normal) (teste prático).
  • Todas as entregas são cruciais para o bom desenvolvimento do projecto, sendo obrigatórias: a não realização de uma entrega implica a exclusão da avaliação do projecto e, por consequência, da avaliação da disciplina.
  • Verificar atempadamente (até 48 horas antes do final de cada prazo) os requisitos exigidos pelo processo de avaliação, incluindo a capacidade de acesso ao repositório.
  • Apenas se consideram para avaliação os projectos existentes no repositório oficial. Apenas se considera para avaliação o ramo 'master'.
  • Trabalhos não presentes no repositório no final do prazo têm classificação 0 (zero) (não são aceites outras formas de entrega). Não são admitidas justificações para atrasos em sincronizações do repositório. A indisponibilidade temporária do repositório ou de outros materiais, desde que inferior a 24 horas, não justifica atrasos na submissão de um trabalho.
  • A avaliação do projecto pressupõe o compromisso de honra de que o trabalho correspondente foi realizado pelos alunos correspondentes ao grupo de avaliação.
  • Fraudes na execução do projecto terão como resultado a exclusão dos alunos implicados do processo de avaliação.
Material de Uso Obrigatório
As bibliotecas po-uilib e o conteúdo inicial do CVS são de uso obrigatório:
  • po-uilib (classes de base) po-uilib-202209081626.tar.bz2 (não pode ser alterada) - javadoc
  • prr-core (classes do "core") (via CVS) (deve ser completada -- os nomes das classes fornecidas não podem ser alterados)
  • prr-app (classes de interacção) (via CVS) (deve ser completada -- os nomes das classes fornecidas não podem ser alterados)
A máquina virtual, fornecida para desenvolvimento do projecto, já contém todo o material de apoio.
Uso Obrigatório: Repositório CVS
Apenas se consideram para avaliação os projectos existentes no repositório CVS oficial.

Trabalhos não presentes no repositório no final do prazo têm classificação 0 (zero) (não são aceites outras formas de entrega). Não são admitidas justificações para atrasos em sincronizações do repositório. A indisponibilidade temporária do repositório, desde que inferior a 24 horas, não justifica atrasos na submissão de um trabalho.

EM PREPARAÇÃO

ÉPOCA NORMAL

O objectivo do projecto e desenvolver um gestor de uma rede de terminais de comunicação, denominado por prr. Genericamente, o programa permite a gestão e consulta de clientes, terminais e comunicações.

Especificamente, o sistema disponibiliza vários serviços, entre outros: (i) registar dados sobre os clientes; (ii) registar dados sobre os terminais; (iii) registar dados sobre comunicações efectuadas; (iv) fazer pesquisas sobre comunicações efectuadas; (v) contabilizar o saldo associado a terminais.

Clientes, terminais, comunicações, planos tarifários

Os clientes, terminais e comunicações possuem chaves únicas, cadeias de caracteres para os clientes e inteiros para os terminais e para as comunicações.

Propriedades e funcionalidade dos clientes

Cada cliente, para além da chave única, é identificado pelo nome (cadeia de caracteres) e número de identificação fiscal (inteiro). A cada cliente podem estar associados vários terminais.

Existem três tipos de clientes: Normal (situação inicial, após o registo), Gold e Platinum. O custo das comunicações está indexado ao tipo de cliente (ver planos tarifários). Um cliente transita de tipo nas seguintes condições:

Antes Depois Condições
Normal Gold o saldo (após realizar um pagamento) é superior a 500 cêntimos
Normal Platinum (não é possível)
Gold Normal o saldo (após realizar uma comunicação) é inferior a 0 cêntimos
Ouro Platinum realizar 5 comunicações de vídeo consecutivas (a contabilização da 5ª comunicação ainda considera que o cliente é do tipo Gold)
Platinum Gold realizar 2 comunicações de texto consecutivas (a contabilização da 2ª comunicação ainda considera que o cliente é do tipo Platinum)
Platinum Normal tentativa de realizar uma comunicação de vídeo para um terminal Basic

Um cliente tem dívidas se tiver, pelo menos, um terminal com saldo negativo, sendo a sua dívida total a soma de todos os saldos negativos.

Propriedades e funcionalidade dos terminais

Os terminais são identificados por um número (exactamente 6 dígitos) e estão associados a um cliente. Cada terminal pode estar ligado, em silêncio, ocupado ou desligado. Quando o terminal está desligado, não pode iniciar ou receber comunicações. Quando o terminal está em silêncio, pode iniciar qualquer tipo de comunicação que suporte, mas só pode receber comunicações de texto. Quando um terminal está ocupado, apenas pode receber mensagens de texto, não podendo iniciar outras comunicações. Não é possível desligar um terminal ocupado. Cada terminal está associado a um plabo tarifário e tem contabilidade própria, sendo sempre possível saber o saldo que lhe está associado.

Os terminais Basic só conseguem realizar comunicações texto e de voz, não podendo nem iniciar nem receber comunicações de vídeo. Os terminais Fancy podem realizar todos os tipos de comunicação.

Para promover as comunicações, quando uma comunicação não se efectua por o terminal de destino estar num estado incompatível, regista-se a tentativa de contacto, para que, assim que seja possível a realização do contacto pretendido, se enviarem notificações aos terminais de origem. O registo da tentativa de contactos só tem lugar quando o cliente do terminal de destino tem activa a recepção de contactos falhados no instante em que se tentou efectuar a comunicação (que não teve lugar por o terminal de destino o não permitir). VER MELHOR AS NOTIFICAÇÕES

Propriedades das comunicações

Existem 3 tipos de comunicação entre terminais: texto (denominada TEXT), voz (denominada VOICE) e vídeo (denominada VIDEO).

Cada comunicação, além do identificador único (no contexto de um dado cliente), possui ainda informação sobre o terminal que a originou, o terminal de destino, a sua duração (no caso do texto, esta duração é o número de caracteres da mensagem; nos outros casos, é o número de segundos da comunicação) e o tipo de comunicação (voz, texto ou vídeo). A primeira comunicação tem como identificador “1”, devendo o identificador das comunicações subsequentes ser obtido por incremento unitário do identificador anterior.

O custo das comunicações não é uniforme (ver Planos tarifários), dependendo do cliente e do terminal, entre outros factores.

Planos tarifários

Os custos de uma comunicação dependem do tipo de cliente que inicia a comunicação, do tipo da comunicação e do plano tarifário. Os planos tarifários têm um nome podem ser alterados depois da criação do cliente.

Quando é efectuada uma comunicação do tipo texto com N caracteres enviados é como indicado na tabela (plano tarifário base):

Normal Gold Platinum
N < 50 caracteres 10 cêntimos 10 cêntimos 0 cêntimos
50 caracteres <= N < 100 caracteres 16 cêntimos 10 cêntimos 4 cêntimos
N >= 100 caracteres 2 * N cêntimos 2 * N cêntimos 4 cêntimos

Quando é efectuada uma comunicação de voz ou de vídeo, o custo no plano tarifário base é proporcional ao tempo de conversação e quando se liga para um terminal registado como amigo é aplicado um desconto de 50%. O custo, em cêntimos por minuto, é o seguinte para terminais não registados como amigos:

Normal Gold Platinum
VOICE 20 cêntimos 10 cêntimos 10 cêntimos
VIDEO 30 cêntimos 20 cêntimos 10 cêntimos

Por questões fiscais, todos os cálculos envolvendo os custos das comunicações devem ser apresentados em cêntimos, não sendo possível fazer arredondamentos. Por exemplo, uma comunicação de voz que dure 6 minutos tem um custo de 120 cêntimos para um cliente Normal e 60 cêntimos para clientes Gold ou Platinum.

Funcionalidade da aplicação

A aplicação permite manter informação sobre as entidades do modelo. Possui ainda a capacidade de preservar o seu estado (não é possível manter várias versões do estado da aplicação em simultâneo).

Deve ser possível efectuar pesquisas sujeitas a vários critérios e sobre as diferentes entidades geridas pela aplicação.

A base de dados com os conceitos pré-definidos é carregada no início da aplicação.

Note-se que não é necessário/desejável implementar de raiz a aplicação: já existem classes que representam e definem a interface geral da funcionalidade do core da aplicação, tal como é visível pelos comandos da aplicação.
A interface geral do core já está parcialmente implementada na classe prr.Manager e outras fornecidas (cujos nomes devem ser mantidos), devendo ser adaptadas onde necessário. É ainda necessário criar e implementar as restantes classes que suportam a operação da aplicação.

Serialização

É possível guardar e recuperar o estado actual da aplicação, preservando toda a informação relevante, descrita acima.

Funcionalidade Associada a Entidades do Domínio

Funcionalidade associadas aos clientes

A seguinte funcionalidade sobre clientes deve ser suportada pela aplicação: (i) visualizar um cliente; (ii) registar um novo cliente; (iii) permitir o registo de contactos falhados; (iv) inibir o registo de contactos falhados; (v) calcular o saldo de um cliente.

Um cliente não pode ser removido, sendo sempre possível aceder a todo o seu historial.

Funcionalidade associadas aos terminais

A seguinte funcionalidade sobre terminais deve ser suportada pela aplicação: (i) visualizar um terminal; (ii) registar um novo terminal; (iii) ligar, desligar e colocar no silêncio um terminal; (iv) adicionar e remover telefones da lista dos telefones amigos de um terminal; (v) proceder a um pagamento; (vi) calcular o saldo de um terminal.

Um terminal não pode ser removido, sendo sempre possível aceder a todo o seu historial.

Funcionalidade associada a comunicações

A seguinte funcionalidade de pesquisa deve ser suportada: (i) comunicações efectuadas por um cliente; (ii) terminais que iniciaram comunicações para um determinado terminal; (iii) terminais que iniciaram uma comunicação para um determinado cliente; (iv) terminais com um determinado plano tarifário; (v) clientes com pagamentos em atraso.

Requisitos de Desenho

Devem ser possíveis extensões ou alterações de funcionalidade com impacto mínimo no código já produzido para a aplicação. O objectivo é aumentar a flexibilidade da aplicação relativamente ao suporte de novas funções. Assim, deve ser possível:

  • Definir novos tipos de clientes;
  • Definir novos tipos de comunicação;
  • Adicionar novos planos tarifários;
  • Adicionar novas formas de pesquisa;
  • Permitir a gestão de várias redes de terminais.

Deve ser possível a definição de diferentes entidades que estejam interessadas em ser notificadas com os dados referentes a cada comunicação realizada por um dado terminal sem que isso provoque alterações no código da aplicação. As entidades podem registar ou cancelar o seu interesse em qualquer momento e podem existir várias entidades interessadas distintas em simultâneo.

Embora na especificação actual não seja possível remover entidades, a inclusão desta funcionalidade deve ser prevista, por forma a minimizar o impacto da sua futura inclusão.

Interacção com o utilizador

Descreve-se nesta secção a funcionalidade máxima da interface com o utilizador. Em geral, os comandos pedem toda a informação antes de procederem à sua validação (excepto onde indicado). Todos os menus têm automaticamente a opção Sair (fecha o menu).

As operações de pedido e apresentação de informação ao utilizador devem realizar-se através dos objectos form e display, respectivamente, presentes em cada comando. As mensagens são produzidas pelos métodos das bibliotecas de suporte (po-uilib e prr-app). As mensagens não podem ser usadas no núcleo da aplicação (prr-core). Além disso, não podem ser definidas novas. Potenciais omissões devem ser esclarecidas antes de qualquer implementação.

A apresentação de valores monetários (preços, saldos, etc.) é sempre feita com arredondamento ao inteiro mais próximo (note-se que a representação interna não deve ser arredondada).

As excepções usadas na interacção (subclasses de pt.tecnico.uilib.menus.CommandException), excepto se indicado, são lançadas pelos comandos (subclasses de pt.tecnico.uilib.menus.Command) e tratadas pelos menus (instâncias de subclasses de pt.tecnico.uilib.menus.Menu). Outras excepções não devem substituir as fornecidas nos casos descritos.

A apresentação de listas de entidades do domínio (clientes, etc.) faz-se por ordem crescente da respectiva chave: dependendo dos casos, a ordem pode ser numérica ou lexicográfica (UTF-8), não havendo distinção entre maiúsculas e minúsculas.

Note-se que o programa principal e os comandos e menus, a seguir descritos, já estão parcialmente implementados nas packages prr.app, prr.app.main, prr.app.clients, prr.app.terminals, prr.app.communications, prr.app.lookups. Estas classes são de uso obrigatório e estão disponíveis no CVS (módulo prr-app).

Menu Principal

As acções deste menu permitem gerir a salvaguarda do estado da aplicação, abrir submenus e aceder a alguma informação global. A lista completa é a seguinte: Abrir, Guardar, Gestão de clientes, Gestão de terminais, Consultas, Consultas, Mostrar saldo global.

As etiquetas das opções deste menu estão definidas na classe prr.app.main.Label. Todos os métodos correspondentes às mensagens de diálogo para este menu estão definidos na classe prr.app.main.Message.

Estes comandos já estão implementados nas classes da package prr.app.main (disponível no CVS), respectivamente: DoOpenFile, DoSaveFile, DoOpenMenuClients, DoOpenMenuTerminals, DoOpenMenuLookups, DoShowGlobalBalance.

Salvaguarda do estado actual da aplicação

Inicialmente, a aplicação está vazia ou tem apenas informação sobre as entidades que foram carregados no arranque (via ficheiro textual).

O conteúdo da aplicação (toda a informação actualmente em memória) pode ser guardado para posterior recuperação (via serialização Java: java.io.Serializable). Na leitura e escrita do estado da aplicação, devem ser tratadas as excepções associadas. A funcionalidade é a seguinte:

  • Abrir -- Carrega os dados de uma sessão anterior a partir de um ficheiro previamente guardado (ficando este ficheiro associado à aplicação, para futuras operações de salvaguarda). Pede-se o nome do ficheiro a abrir (Prompt.openFile()). Caso ocorra um problema na abertura ou processamento do ficheiro, deve ser lançada a excepção FileOpenFailedException. A execução bem-sucedida desta opção substitui toda a informação da aplicação.
  • Guardar -- Guarda o estado actual da aplicação no ficheiro associado. Se não existir associação, pede-se o nome do ficheiro a utilizar, ficando a ele associado. Esta interacção realiza-se através do método Prompt.newSaveAs(). Não é executada nenhuma acção se não existirem alterações desde a última salvaguarda.

Note-se que a opção Abrir não permite a leitura de ficheiros de texto (estes apenas são utilizados na inicialização da aplicação).

A opção Sair nunca implica a salvaguarda do estado da aplicação, mesmo que existam alterações.

Gestão e consulta de dados da aplicação

  • Menu de Gestão de Clientes -- Abre o menu de gestão de clientes.
  • Menu de Gestão de Terminais -- Abre o menu de gestão de terminais.
  • Menu de Consultas -- Abre o menu de consultas (pesquisas).

Mostrar saldo global

Esta opção apresenta o valor correspondente ao saldo global (soma dos sados de todos os clientes registados na rede). Embora internamente os valores dos saldos estejam representados em vírgula flutuante, a apresentação é arredondada ao inteiro mais próximo.

A apresentação faz-se através da mensagem Message.currentBalance().

Menu de gestão de clientes

Este menu permite efectuar operações sobre a base de dados de clientes. A lista completa é a seguinte: Visualizar todos os clientes, Registar cliente, Activar recepção de contactos falhados, Desactivar recepção de contactos falhados, Mostrar saldo de cliente.

Todos os métodos correspondentes às mensagens de diálogo para este menu estão definidos na classe prr.app.products.Message.

Sempre que é pedido o identificador de um cliente (Prompt.clientKey()) e o identificador não existir (excepto no processo de registo), é lançada a excepção UnknownClientKeyException. Na ocorrência de excepções, as operações não têm efeito.

Estes comandos já estão implementados nas classes da package prr.app.clients (disponível no CVS), respectivamente: DoShowAllClients, DoRegisterClient, DoSetFailedContactsOn, DoSetFailedContactsOff, DoShowClientBalance.

Visualizar todos os clientes

O formato de apresentação de cada cliente é o seguinte, em que nTerminals é o número de terminais activos associados ao cliente e balance é o somatório do saldo de cada um desses terminais (valor arredondado ao inteiro mais próximo). Os valores para clientType são NORMAL, GOLD, ou PLATINUM. Os valores para answeringStatus são ON ou OFF. Se o cliente não tiver terminais, o saldo é 0 (zero).

CLIENTE|clientId|clientName|NIF|clientType|answeringStatus|nTerminals|balance

Registar cliente

O sistema pede o identificador que ficará associado ao cliente (identificador único}. De seguida, pede o nome do cliente (Prompt.clientName()) e o número de identificação fiscal (Prompt.fiscalId()). Após o registo, o cliente fica no estado Normal e o registo de contactos falhados fica activo.

Caso o identificador indicado já exista, deve ser lançada a excepção DuplicateClientKeyException, não se realizando o registo.

Activar recepção de contactos falhados

É pedido o identificador do cliente. Se o registo de contactos falhados já estava activo, o cliente não é alterado e é enviada a mensagem alreadyActive().

Desactivar recepção de contactos falhados

É pedido o identificador do cliente. Se o registo de contactos falhados já estava inactivo, o cliente não é alterado e é enviada a mensagem alreadyInactive().

Mostrar saldo de cliente

O sistema pede o identificador do cliente, apresentando o seu saldo. Tal como acima, o saldo do cliente é o somatório do saldo de cada um desses terminais (valor arredondado ao inteiro mais próximo).

Menu de Gestão de Terminais

Este menu permite efectuar operações sobre a base de dados de parceiros. A lista completa é a seguinte: Mostrar todos os terminais, Registar terminal, Menu de administração de terminal.

Todos os métodos correspondentes às mensagens de diálogo para este menu estão definidos na classe prr.app.terminals.Message.

Sempre que for pedido o identificador de um terminal (Prompt.terminalKey()) e o terminal não existir, é lançada a excepção UnknownTerminalKeyException (excepto no processo de registo). Sempre que é pedido o identificador de um cliente (Prompt.clientKey()) e o identificador não existir, é lançada a excepção UnknownClientKeyException. Na ocorrência de excepções (estas ou outras), as operações não têm efeito.

Estes comandos já estão implementados nas classes da package prr.app.partners (disponível no CVS), respectivamente: DoShowAllTerminals, DoRegisterTerminal, DoOpenMenuTerminalAdministration.

Mostrar todos os terminais

O formato de apresentação de cada terminal é o seguinte:

TERMINAL|terminalId|clientId|terminalType|terminalStatus|terminalBalance|friend1,...,friendN

Os valores para o campo terminalType são Basic ou Fancy. Os valores para o campo terminalStatus são ON, OFF, SILENCE. Os valores friend1, ..., friendN são os identificadores dos terminais amigos e são apresentados por ordem crescente desses identificadores.

Registar terminal

É pedido o número identificador do terminal com exactamente 6 dígitos (se o número introduzido não contiver exactamente 6 dígitos, o pedido é repetido). De seguida, o sistema pede o tipo de terminal (Prompt.terminalType()). A resposta deve ser Basic ou Fancy. Se a resposta não corresponder a nenhum dos dois valores, a pergunta é repetida até se obter uma resposta válida. Finalmente, é pedido o identificador do cliente que ficará associado ao terminal.

Caso o identificador indicado já exista, deve ser lançada a excepção DuplicateTerminalKeyException, não se realizando o registo.

Quando um terminal é registado, fica no estado ligado, com saldo zero e com uma lista de amigos vazia.

Menu de administração de terminal

É pedido o número identificador de um terminal, sendo aberto o correspondente menu de administração.

Menu de Consultas

Este menu apresenta as operações relacionadas com consultas. A lista completa é a seguinte: Mostrar todas as comunicações, Mostrar comunicações feitas por um cliente, Mostrar comunicações recebidas por um cliente, Mostrar clientes sem dívidas, Mostrar clientes com dívidas, Mostrar terminais sem actividade, Mostrar terminais com saldo positivo.

Sempre que é pedido o identificador do parceiro (Prompt.clientKey()), é lançada a excepção UnknownClinetKeyException, se o parceiro indicado não existir. Sempre que é pedido o identificador de produto (Prompt.terminalKey()), é lançada a excepção UnknownTerminalKeyException, se o produto indicado não existir.

A apresentação de resultados é como se indica nos casos já descritos de apresentação das várias entidades. Sempre que for feita uma consulta e nenhuma entidade satisfizer as condições associadas ao pedido, nada deve ser apresentado.

Estes comandos já estão parcialmente implementados nas classes da package prr.app.lookups (disponível no CVS), respectivamente: DoShowAllCommunications, DoShowCommunicationsInitiatedByClient, DoShowCommunicationsReceivedByClient, DoShowClientsWithoutDebt, DoShowClientsWithDebt, DoShowUnusedTerminals, DoShowTerminalsWithPositiveBalance.

Mostrar todas as comunicações

O formato de apresentação é o seguinte:

COMMUNICATION|idCommunication|idSender|idReceiver|type|cost|price|status

Os possíveis valores para o campo type são VOICE, TEXT ou VIDEO.

Os possíveis valores para o campo status são COMPLETE (a comunicação teve lugar); FORGOTTEN (a comunicação não teve lugar e a tentativa não ficou registada no chamador); REGISTERED (a comunicação não teve lugar, mas a tentativa ficou registada no chamador). Quando o tipo de mensagem é FORGOTTEN ou REGISTERED, tanto a duração (length) como o custo (cost) são 0 (zero).

Mostrar comunicações feitas por um cliente

É pedido o identificador do cliente, sendo apresentadas as por ele originadas.

Mostrar comunicações recebidas por um cliente

É pedido o identificador do cliente, sendo apresentadas as por ele recebidas.

Mostrar clientes sem dívidas

São apresentados os clientes sem dívidas.

Mostrar clientes com dívidas

São apresentados os clientes por ordem decrescente do valor das respectivas dívidas (valores superiores a zero). Se as dívidas tiverem o mesmo valor, apresentam-se os clientes por ordem crescente do seu identificador.

Mostrar terminais sem actividade

São apresentados os terminais que ainda não efectuaram nem receberam qualquer comunicação.

Mostrar terminais com saldo positivo

São apresentados os terminais que que têm saldo positivo, ou seja, superior a zero cêntimos.

Menu de administração de terminal

Este menu apresenta as operações relacionadas com admibistração de um terminal. A lista completa é a seguinte: Ligar terminal, Desligar terminal, Silenciar terminal, Adicionar amigo, Retirar amigo, Efectuar pagamento, Consultar saldo, Efectuar comunicação.

Todos os métodos correspondentes às mensagens de diálogo para este menu estão definidos na classe prr.app.admin.Message.

Sempre que é pedido o identificador do cliente (Prompt.clientKey()), é lançada a excepção UnknownClientKeyException, se o cliente indicado não existir. Sempre que é pedido o identificador do terminal (Prompt.terminalKey()), é lançada a excepção UnknownTerminalKeyException, se o terminal indicado não existir.

Estes comandos já estão implementados nas classes da package prr.app.admin (disponível no CVS), respectivamente: DoTurnTerminalOn, DoTurnTerminalOff, DoSilenceTerminal, DoAddFriend, DoRemoveFriend, DoPerformPayment, DoShowBalance, DoPerformCommunication.

Ligar terminal

Se o terminal indicado já estiver ligado, envia a mensagem alreadyOn(). Se for necessário enviar mensagens aos terminais que tentaram o contacto enquanto o terminal não permaneceu ligado, usa-se a mensagem isNowAvailable(), indicando-se o emissor. Estas mensagens devem ser ordenadas pelos números dos terminais que tentaram o contacto e só deve ser enviada uma mensagem a cada terminal que tentou o contacto, mesmo que tenha havido mais do que uma tentativa de contacto.

Desligar terminal

Se o terminal indicado já estiver desligado, envia a mensagem alreadyOff().

Silenciar terminal

Se o terminal já estiver em silêncio, envia a mensagem alreadySilent(). Se estava anteriormente desligado e se for necessário enviar mensagens aos terminais que tentaram o contacto por SMS enquanto o terminal permaneceu desligado, usa-se a mensagem isAvailableForSMS(), indicando-se o emissor. Estas mensagens devem ser ordenadas pelos números dos terminais que tentaram o contacto e só deve ser enviada uma mensagem a cada terminal que tentou o contacto, mesmo que tenha havido mais do que uma tentativa de contacto.

Adicionar amigo

É pedido o identificador do terminal a adicionar à lista de amigos. Se o terminal indicado já fizer parte da lista de amigos, a operação termina sem alterações.

Retirar amigo

É pedido o identificador do terminal a retirar da lista de amigos. Se o terminal indicado não fizer parte da lista de amigos, a operação termina sem alterações.

Efectuar pagamento

É pedido o valor (inteiro) a pagar através da mensagem Prompt.paymentValue(). O valor indicado é em cêntimos.

Consultar saldo

É apresentado o saldo, em cêntimos, associado ao terminal.

Iniciar comunicação

Se o terminal a partir do qual se pretende efectuar a comunicação estiver desligado, apresenta a mensagem terminalIsOff() e a operação termina.

É pedido o identificador do número do terminal a contactar. Se o número pretendido não existir, apresenta a mensagem noSuchTerminal() (neste caso, excepcionalmente, não é lançada nenhuma excepção). Se o número existir, é pedido o tipo de comunicação (Prompt.commType()) (a resposta deve ser uma cadeia de caracteres: VOICE, TEXT, VIDEO. Se a resposta não corresponder a nenhum dos três valores, a pergunta é repetida até se obter uma resposta válida.

Sempre que se tenta iniciar uma comunicação VIDEO a partir de um terminal Basic, deve ser lançada a excepção VideoFromBasicException. Se o terminal de origem for Fancy mas tentar realizar uma comunicação VIDEO para um terminal Basic, é lançada a excepção VideoToBasicException. Quando é lançada uma excepção, não se regista a tentativa de comunicação (o contador de chamadas não deve ser incrementado) e não são feitas mais perguntas.

Quando o terminal de destino está desligado, é apresentada a mensagem termoinalIsOff(). Quando o terminal de destino está em silêncio e a comunicação pretendida é VOICE ou VIDEO, é apresentada a mensagem terminalIsSilent().

No caso de comunicações de texto, a mensagem termina automaticamente.

Terminar comunicação

Se o terminal estiver em comunicação (ocupado), é terminada a comunicação e registada a sua duração da não estiver ocupado. Só o chamador é que pode terminar a comunicação.

Se e só se a comunicação for possível, é pedida a duração da chamada (VOICE e VIDEO) com Prompt.duration() (número inteiro) ou o número de caracteres (TEXT) com Prompt.chararacters(). É ainda apresentada a mensagem costOfMessage() com o custo da comunicação para o interlocutor (chamador ou chamado -- o custo para o chamado é zero).

Leitura de Dados a Partir de Ficheiros Textuais

Além das opções de manipulação de ficheiros descritas no menu principal, é possível iniciar a aplicação com um ficheiro de texto especificado pela propriedade Java import.

As várias entidades têm os formatos descritos abaixo. Assume-se que os títulos não podem conter o carácter | e que o preço é um número inteiro (sugere-se a utilização do método String.split para o processamento preliminar destas linhas). Não existem entradas mal-formadas.

Cada linha tem uma descrição distinta, mas que segue os seguintes formatos:

CLIENT|id|nome|xxx|nível
TERMINAL|idTerminal|idClient|type|state|balance
FRIENDS|idTerminal|idTerminal1,...,idTerminalN

As definições de clientes precedem sempre as dos terminais. As ligações entre amigos estão sempre após a definição das restantes entidades.

Um exemplo de conteúdo do ficheiro inicial é como se segue:

Exemplo de ficheiro de entrada textual
CLIENT|cli001|Manuel Pinheiro|103443|NORMAL
CLIENT|cli002|Pedro Pinheiro|103447|NORMAL
CLIENT|Cli201|Ludgero Oliveira|103440|NORMAL
CLIENT|cli Es|Maria Eucalipto|103441|GOLD
CLIENT|01|Oliveira Preto|103547|NORMAL
CLIENT|cli003|Pedro Oliveira|103449|PLATINUM
TERMINAL|969001|cli001|Basic|ON|-900
TERMINAL|969003|cli002|Basic|ON|0
TERMINAL|969002|cli002|Fancy|SILENCE|330
TERMINAL|969007|cli Es|Fancy|ON|700
TERMINAL|969008|cli003|Basic|OFF|2500
TERMINAL|969009|cli003|Basic|OFF|1200
TERMINAL|969010|cli003|Basic|ON|-2100
TERMINAL|969006|cli003|Fancy|ON|4800
TERMINAL|969005|cli003|Fancy|ON|3400
TERMINAL|969004|cli003|Basic|ON|1000
FRIENDS|969001|969008,969009,969004
FRIENDS|969004|969001
FRIENDS|969003|969008

A codificação dos ficheiros a ler é garantidamente UTF-8.

Note-se que o programa nunca produz ficheiros com este formato.

Execução dos Programas e Testes Automáticos

Usando os ficheiros test.import, test.in e test.out, é possível verificar automaticamente o resultado correcto do programa. Note-se que é necessária a definição apropriada da variável CLASSPATH (ou da opção equivalente -cp do comando java), para localizar as classes do programa, incluindo a que contém o método correspondente ao ponto de entrada da aplicação (prr.app.App.main). As propriedades são tratadas automaticamente pelo código de apoio.

       java -Dimport=test.import -Din=test.in -Dout=test.outhyp prr.app.App

Assumindo que aqueles ficheiros estão no directório onde é dado o comando de execução, o programa produz o ficheiro de saída test.outhyp. Em caso de sucesso, os ficheiros das saídas esperada (test.out) e obtida (test.outhyp) devem ser iguais. A comparação pode ser feita com o comando:

        diff -b test.out test.outhyp

Este comando não deve produzir qualquer resultado quando os ficheiros são iguais. Note-se, contudo, que este teste não garante o correcto funcionamento do código desenvolvido, apenas verificando alguns aspectos da sua funcionalidade.

Notas de Implementação

Tal como indicado acima, algumas classes fornecidas como material de apoio, são de uso obrigatório e não podem ser alteradas. Outras dessas classes são de uso obrigatório e têm de ser alteradas.

A serialização Java usa as classes da package java.io, em particular, a interface java.io.Serializable e as classes de leitura java.io.ObjectInputStream e escrita java.io.ObjectOutputStream (entre outras).