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

From Wiki**3

< Programação com Objectos‎ | Projecto de Programação com Objectos
(Mostrar terminais sem actividade)
 
(7 intermediate revisions by the same user not shown)
Line 1: Line 1:
{{PRJPOAvisosEN20222023}}
+
#REDIRECT [[Programação com Objectos/Projecto de Programação com Objectos/Enunciado do Projecto de 2022-2023]]
{{PRJPOMandatory20222023}}
 
{{TOCright}}
 
'''<font color="red">EM PREPARAÇÃO</font>'''
 
 
 
'''<font color="red">ÉPOCA NORMAL</font>'''
 
 
 
O objectivo do projecto e desenvolver uma aplicação de gestão de uma rede de terminais de comunicação, denominada por '''prr'''. Genericamente, o programa permite o registo, gestão e consulta de clientes, terminais e comunicações.
 
 
 
= Clientes, terminais, comunicações, planos tarifários =
 
 
 
Os clientes, terminais e comunicações possuem chaves únicas, cadeias de caracteres para os clientes e para os terminais e inteiros para as comunicações.
 
 
 
A noção de saldo é definida como a diferença entre os valores dos pagamentos efectuados e das dívidas por pagar. O saldo pode ser calculado globalmente (considerando todos os clientes), por cliente (considerando todos os terminais do cliente) ou por terminal (considerando todas as comunicações do terminal, pagas e por pagar).
 
 
 
== Propriedades e funcionalidade dos clientes ==
 
 
 
Cada cliente, para além da chave única, tem ainda o nome (cadeia de caracteres) e o número de identificação fiscal (inteiro). A cada cliente podem estar associados vários terminais.
 
 
 
O cliente mantém informação sobre os pagamentos efectuados (sobre comunicações passadas) e valores em dívida (comunicações cujo valor ainda não foi pago).
 
 
 
Existem três tipos de clientes: '''Normal''' (situação inicial, após o registo -- no entanto, ver a situação da leitura de dados textuais), '''Gold''' e '''Platinum'''. O tipo de cliente influencia o custo das comunicações que efectua (ver [[#Planos tarifários|planos tarifários]]). O tipo do cliente evolui nas seguintes condições:
 
 
 
{|
 
| '''Antes'''
 
| '''Depois'''
 
| '''Condição'''
 
|-
 
| Normal
 
| Gold
 
| O saldo do cliente (após realizar um pagamento) é superior a 500 créditos.
 
|-
 
| Normal
 
| Platinum
 
| (não é possível)
 
|-
 
| Gold
 
| Normal
 
| O saldo do cliente (após realizar uma comunicação) é negativo.
 
|-
 
| Gold
 
| Platinum
 
| O cliente realizou 5 comunicações de vídeo consecutivas e não tem saldo negativo. A contabilização da 5ª comunicação ainda considera que o cliente é do tipo Gold.
 
|-
 
| Platinum
 
| Gold
 
| O cliente realizou 2 comunicações de texto consecutivas e não tem saldo negativo. A contabilização da 2ª comunicação ainda considera que o cliente é do tipo Platinum.
 
|-
 
| Platinum
 
| Normal
 
| O saldo do cliente (após realizar uma comunicação) é negativo.
 
|}
 
 
 
== Propriedades e funcionalidade dos terminais ==
 
 
 
Cada terminal é identificado por uma cadeia de caracteres numérica (exactamente 6 dígitos) e está associado a um único cliente.
 
 
 
Os terminais podem realizar três tipos de comunicação: texto, voz e vídeo. As comunicações realizadas pelo terminal são contabilizadas de acordo com o tarifário associado ao cliente. O terminal tem contabilidade própria, sendo sempre possível saber os valores dos pagamentos efectuados e dos valores devidos.
 
 
 
Existem, pelo menos, dois tipos de terminal: básicos e sofisticados. Os terminais básicos só conseguem realizar comunicações de texto e de voz, não podendo nem iniciar nem receber comunicações de vídeo. Os terminais sofisticados podem realizar todos os tipos de comunicação.
 
 
 
Um terminal recém-criado fica no estado de espera (''idle''); tem os valores de pagamentos e dívidas ambos a zero; e tem uma lista de amigos vazia. Existem outros estados, definidos a seguir.
 
 
 
=== Estados dos terminais ===
 
Cada terminal pode estar em espera, em silêncio, ocupado ou desligado.
 
* Espera -- situação normal sem actividade (''idle'');
 
* Silêncio -- tal como em Espera, pode iniciar-se qualquer tipo de comunicação suportada pelo terminal, mas só podem ser recebidas comunicações de texto;
 
* Ocupado -- não podendo iniciar-se comunicações, mas podem ser recebidas mensagens de texto;
 
* Desligado -- não podem ser iniciadas ou recebidas comunicações.
 
 
 
=== Transições entre estados de terminais ===
 
Um terminal pode chegar aos vários estados nas seguintes condições (outras transições não são possíveis):
 
* Espera -- de desligado (ao ligar em espera); de silêncio (ir para espera); de ocupado (final de comunicação);
 
* Silêncio -- de desligado (ao ligar em silêncio); de espera (colocar em silêncio); de ocupado (final de comunicação);
 
* Ocupado -- de espera ou de silêncio (início de comunicação);
 
* Desligado -- de espera ou de silêncio (ao desligar).
 
 
 
=== Notificações ===
 
 
 
Apenas são passíveis de notificação os clientes que tentaram comunicação com um terminal e a comunicação não foi possível nessa altura. Quando uma comunicação não se efectua, 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 origem tem activa a recepção de contactos falhados no instante em que se tentou efectuar a comunicação.
 
 
 
São geradas notificações e é possível avisar um cliente nas seguintes circunstâncias:
 
# Um terminal desligado é colocado em silêncio (''off-to-silent''): notifica-se disponibilidade para receber comunicações de texto.
 
# Um terminal desligado ou em silêncio é colocado em espera (''off-to-idle'' ou ''silent-to-idle''): notifica-se disponibilidade para receber comunicações (qualquer suportada).
 
# Um terminal deixa de estar ocupado (''busy-to-idle''): notifica-se disponibilidade para receber comunicações (qualquer suportada).
 
 
 
== Propriedades e funcionalidade das comunicações ==
 
 
 
Cada comunicação tem um identificador único (número inteiro, no contexto de todos os clientes). A primeira tem como identificador “1”, sendo os identificadores subsequentes obtidos por incremento unitário do mais recente identificador utilizado. A comunicação contém ainda informação sobre os terminais de origem e de destino e o estado da comunicação: em curso ou terminada.
 
 
 
As comunicações de texto têm ainda a mensagem enviada. As comunicações interactivas (vídeo e voz) possuem informação sobre a duração da comunicação. O custo de uma comunicação depende do comprimento da mensagem de texto ou da duração das comunicações interactivas. O custo depende ainda do [[#Planos tarifários|plano tarifário]] associado a cada cliente (calculado no final da comunicação). Todos os cálculos envolvendo os custos das comunicações devem ser realizados sem arredondamentos.
 
 
 
== Planos tarifários ==
 
 
 
Cada plano tarifário define os custos para cada tipo de comunicação, baseado no nível do cliente, no tipo de comunicação, entre outras características. Os planos tarifários têm um nome único no contexto da rede de terminais a que estão associados. A rede de terminais pode oferecer vários planos tarifários mas em cada momento um cliente apenas tem um plano tarifário. A rede de terminais oferece pelo menos o plano tarifário designado como '''base'''. Este plano tarifário é o plano atribuído inicialmente a todos os clientes. O custos das comunicações é medido em créditos.
 
 
 
O custo (medido em créditos) de uma comunicação de texto com '''N''' caracteres no plano tarifário base está representado na tabela seguinte:
 
 
 
{|
 
! style="width: 40%;" |
 
! style="width: 20%;" | '''Normal'''
 
! style="width: 20%;" | '''Gold'''
 
! style="width: 20%;" | '''Platinum'''
 
|-
 
| '''N''' < 50 caracteres
 
| 10
 
| 10
 
| 0
 
|-
 
| 50 caracteres <= '''N''' < 100 caracteres
 
| 16
 
| 10
 
| 4
 
|-
 
| '''N''' >= 100 caracteres
 
| 2 x '''N'''
 
| 2 x '''N'''
 
| 4
 
|}
 
 
 
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 comunica com um terminal amigo, é aplicado um desconto de 50%. O custo, em créditos por minuto, é o seguinte para terminais não amigos:
 
 
 
{|
 
! style="width: 40%;" |
 
! style="width: 20%;" | '''Normal'''
 
! style="width: 20%;" | '''Gold'''
 
! style="width: 20%;" | '''Platinum'''
 
|-
 
| Comunicação de voz
 
| 20
 
| 10
 
| 10
 
|-
 
| Comunicação de vídeo
 
| 30
 
| 20
 
| 10
 
|}
 
 
 
O custo de uma comunicação deve ser calculado quando a comunicação termina e guardado, por forma a garantir que o custo não é afectado por mudanças futuras dos planos tarifários.
 
 
 
== Entrega de notificações ==
 
 
 
Os clientes podem activar a recepção de notificações sobre eventos associados a terminais em algumas circunstâncias. Em qualquer momento, um cliente pode activar ou desactivar essas notificações. A entrega de notificações deve ser flexível e deve prever vários meios de entrega, e.g., correio postal, SMS, email, entre outras. O meio de entrega por omissão corresponde a registar a notificação na aplicação.
 
 
 
As notificações contêm informação acerca da sua natureza e do terminal a que dizem respeito. Um dado evento apenas produz uma notificação por cliente.
 
 
 
= 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.
 
 
 
Uma base de dados textual com conceitos pré-definidos pode ser [[#Leitura de Dados a Partir de Ficheiros Textuais|carregada no início da aplicação]].
 
 
 
{{Suggestion|Note-se que não é necessário nem 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.}}
 
{{CVSCode|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 clientes; (ii) registar novos clientes; (iii) registar contactos falhados; (iv) controlar o registo de contactos falhados; (v) apresentar valores de pagamentos e dívidas de clientes.
 
 
 
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 e desligar um terminal; (iv) colocar terminal em silêncio; (v) adicionar e remover terminais da lista de amigos de um terminal; (vi) proceder a um pagamento; (vii) apresentar valores de pagamentos e dívidas de terminais.
 
 
 
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 está associada às comunicações: (i) registar comunicações efectuadas por um terminal; (ii) activar/desactivar notificações associadas a terminais; (iii) consultar comunicações. A seguinte funcionalidade de consulta 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 dívidas.
 
 
 
As comunicações, uma vez registadas, não podem ser alteradas ou removidas.
 
-->
 
 
 
= 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; definir novos planos tarifários; definir 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 distintas interessadas em simultâneo.
 
-->
 
Embora na especificação actual não seja possível remover algumas 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 [[Programação com Objectos/Projecto de Programação com Objectos/Material de Apoio ao Desenvolvimento|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 é sempre feita com arredondamento ao inteiro mais próximo, mas a representação interna não deve ser arredondada.
 
 
 
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.
 
 
 
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.
 
 
 
{{CVSCode|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.clients''', '''prr.app.lookups''', '''prr.app.main''', '''prr.app.terminal''', '''prr.app.terminals'''. Estas classes são de uso obrigatório e estão disponíveis no [[Programação com Objectos/Projecto de Programação com Objectos/Repositório CVS|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: [[#Salvaguarda do estado actual da aplicação|Abrir]], [[#Salvaguarda do estado actual da aplicação|Guardar]], [[#Gestão e consulta de dados da aplicação|Gestão de clientes]], [[#Gestão e consulta de dados da aplicação|Gestão de terminais]], [[#Gestão e consulta de dados da aplicação|Consultas]], [[#Mostrar informação global sobre pagamentos e dívidas|Mostrar informação global sobre pagamentos e dívidas]].
 
 
 
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'''.
 
 
 
{{CVSCode|Estes comandos já estão implementados nas classes da ''package'' '''prr.app.main''' (disponível no CVS), respectivamente: '''DoOpenFile''', '''DoSaveFile''', '''DoShowGlobalPaymentsAndDebts'''.}}
 
 
 
=== Salvaguarda do estado actual da aplicação ===
 
 
 
Inicialmente, a aplicação está vazia ou tem apenas informação sobre as entidades que foram carregadas via [[#Leitura de Dados a Partir de Ficheiros Textuais|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 (para operações de salvaguarda subsequemtes). 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 podem ser utilizados no início 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 informação global sobre pagamentos e dívidas ===
 
 
 
Esta opção apresenta os valores globais correspondentes a pagamentos e dívidas (soma dos valores parciais para todos os clientes registados), através da mensagem '''Message.globalPaymentsAndDebts()'''.
 
 
 
== 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 cliente|Visualizar cliente]], [[#Visualizar todos os clientes|Visualizar todos os clientes]], [[#Registar cliente|Registar cliente]], [[#Activar recepção de contactos falhados|Activar recepção de contactos falhados]], [[#Desactivar recepção de contactos falhados|Desactivar recepção de contactos falhados]], [[#Mostrar informação sobre pagamentos e dívidas de cliente|Mostrar informação sobre pagamentos e dívidas de cliente]].
 
 
 
<!--As etiquetas das opções deste menu estão definidas na classe '''prr.app.clients.Label'''. -->Todos os métodos correspondentes às mensagens de diálogo para este menu estão definidos na classe '''prr.app.clients.Message'''.
 
 
 
Sempre que é pedido o identificador de um cliente ('''Prompt.key()''') e o identificador não existir (excepto no processo de registo), é lançada a excepção '''UnknownClientKeyException'''. Na ocorrência de excepções<!-- (estas ou outras)-->, as operações não têm efeito.
 
 
 
{{CVSCode|Estes comandos já estão implementados nas classes da ''package'' '''prr.app.clients''' (disponível no CVS), respectivamente: '''DoShowClient''', '''DoShowAllClients''', '''DoRegisterClient''', '''DoEnableClientNotifications''', '''DoDisableClientNotifications''', '''DoShowClientPaymentsAndDebts'''.}}
 
 
 
=== Visualizar cliente ===
 
É pedido o identificador do cliente e apresentada a sua informação. O formato de apresentação de cada cliente é como se indica de seguida. Os valores para ''type'' são '''NORMAL''', '''GOLD''', ou '''PLATINUM'''. Os valores para ''notifications'' são '''YES''' ou '''NO''' (notificações activas/inactivas). O campo ''terminals'' representa o número de terminais associados ao cliente, ''payments'' é o valor dos pagamentos do cliente e ''debts'' é o valor das dívidas do cliente. Se o cliente não tiver terminais, os valores de ''terminals'', ''payments'' e ''debts'' são 0 (zero).
 
 
 
CLIENT|''key''|''name''|''taxId''|''type''|''notifications''|''terminals''|''payments''|''debts''
 
 
 
Após esta linha, são apresentadas as notificações do cliente (modo de entrega por omissão), pela ordem em que foram enviadas pela aplicação.
 
 
 
''tipo-de-notificação''|''idTerminal''
 
 
 
O tipo de notificação é um de '''O2S''' (off-to-silent), '''O2I''' (off-to-idle) ou '''S2I''' (silent-to-idle), tal como descritos acima. Após esta visualização, considera-se que o cliente fica sem notificações registadas.
 
 
 
=== Visualizar todos os clientes ===
 
 
 
O formato de apresentação é como para clientes individuais (opção anterior), mas não se apresentam as notificações dos clientes (nem se limpam as listas correspondentes).
 
 
 
=== Registar cliente ===
 
 
 
O sistema pede o identificador que ficará associado ao cliente (identificador único}. De seguida, pede o nome do cliente ('''Prompt.name()''') e o número de identificação fiscal ('''Prompt.taxId()'''). 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 é apresentada a mensagem '''clientNotificationsAlreadyEnabled()'''.
 
 
 
=== 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 é apresentada a mensagem '''clientNotificationsAlreadyDisabled()'''.
 
 
 
=== Mostrar informação sobre pagamentos e dívidas de cliente ===
 
 
 
O sistema pede o identificador do cliente, apresentando os valores dos seus pagamentos e dívidas ('''Message.clientPaymentsAndDebts()''').
 
 
 
== Menu de Gestão de Terminais ==
 
 
 
Este menu permite efectuar operações sobre a base de dados de terminais. A lista completa é a seguinte: [[#Mostrar todos os terminais|Mostrar todos os terminais]], [[#Registar terminal|Registar terminal]], [[#Menu da consola de um terminal|Menu da consola de um 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).<!-- No processo de registo, caso o identificador indicado já exista, deve ser lançada a excepção '''DuplicateTerminalKeyException'''.--> 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.
 
 
 
{{CVSCode|Estes comandos já estão implementados nas classes da ''package'' '''prr.app.terminals''' (disponível no CVS), respectivamente: '''DoShowAllTerminals''', '''DoRegisterTerminal''', '''DoOpenMenuTerminalConsole'''.}}
 
 
 
=== Mostrar todos os terminais ===
 
 
 
O formato de apresentação de cada terminal é um dos seguintes:
 
 
 
''terminalType''|''terminalId''|''clientId''|''terminalStatus''|''balance-paid''|''balance-debts''|''friend1'',...,''friend''
 
''terminalType''|''terminalId''|''clientId''|''terminalStatus''|''balance-paid''|''balance-debts''
 
 
 
Os valores para o campo ''terminalType'' são '''BASIC''' (terminais básicos) ou '''FANCY''' (terminais sofisticados). Os valores para o campo ''terminalStatus'' são '''IDLE''', '''OFF''', '''SILENCE''', '''BUSY'''. Os valores ''friend1'', ..., ''friendN'' são os identificadores dos terminais amigos e são apresentados por ordem crescente desses identificadores. O segundo formato é para o caso de um terminal que não tem amigos. Note-se que os valores dos pagamentos efectuados e os dos valores em dívida são apresentados separadamente.
 
 
 
=== Registar terminal ===
 
 
 
É pedido o número identificador do terminal. De seguida, o sistema pede o tipo de terminal ('''Prompt.terminalType()'''). A resposta deve ser '''BASIC''' (terminal básico) ou '''FANCY''' (terminal sofisticado). 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 do terminal seja inválido, lança-se a excepção '''InvalidTerminalKeyException''', não se realizando o registo. Caso o identificador indicado já exista, deve ser lançada a excepção '''DuplicateTerminalKeyException''', não se realizando o registo.
 
 
 
=== Menu da consola de um terminal ===
 
 
 
É pedido o número identificador de um terminal, sendo aberto o correspondente menu da sua consola.
 
 
 
== Menu de Consultas ==
 
 
 
Este menu apresenta as operações relacionadas com consultas. A lista completa é a seguinte: [[#Mostrar todas as comunicações|Mostrar todas as comunicações]], [[#Mostrar comunicações feitas por um cliente|Mostrar comunicações feitas por um cliente]], [[#Mostrar comunicações recebidas por um cliente|Mostrar comunicações recebidas por um cliente]], [[#Mostrar clientes sem dívidas|Mostrar clientes sem dívidas]], [[#Mostrar clientes com dívidas|Mostrar clientes com dívidas]], [[#Mostrar terminais sem actividade|Mostrar terminais sem actividade]], [[#Mostrar terminais com saldo positivo|Mostrar terminais com saldo positivo]].
 
 
 
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 de terminal ('''Prompt.terminalKey()'''), é lançada a excepção '''UnknownTerminalKeyException''' se o terminal 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.
 
 
 
{{CVSCode|Estes comandos já estão parcialmente implementados nas classes da ''package'' '''prr.app.lookups''' (disponível no CVS), respectivamente: '''DoShowAllCommunications''', '''DoShowCommunicationsFromClient''', '''DoShowCommunicationsToClient''', '''DoShowClientsWithoutDebts''', '''DoShowClientsWithDebts''', '''DoShowUnusedTerminals''', '''DoShowTerminalsWithPositiveBalance'''.}}
 
 
 
=== Mostrar todas as comunicações ===
 
 
 
O formato de apresentação é o seguinte:
 
 
 
''type''|''idCommunication''|''idSender''|''idReceiver''|''units''|''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 '''ONGOING''' (comunicação em curso) ou '''FINISHED''' (comunicação terminada)<!--, '''MISSED''', '''LOGGED'''-->. O valor de ''units'' corresponde às unidades de contabilização (caracteres ou minutos). Caso a comunicação esteja em curso, os valores de '''units''' e de '''price''' são ambos zero.
 
 
 
=== Mostrar comunicações feitas por um cliente ===
 
 
 
É pedido o identificador do cliente, sendo apresentadas as comunicações iniciadas pelos seus terminais. O formato de apresentação é o descrito acima.
 
 
 
=== Mostrar comunicações recebidas por um cliente ===
 
 
 
É pedido o identificador do cliente, sendo apresentadas as comunicações recebidas pelos seus terminais. O formato de apresentação é o descrito acima.
 
 
 
=== Mostrar clientes sem dívidas ===
 
 
 
São apresentados os clientes sem dívidas. Utiliza-se o formato de apresentação de um cliente descrito anteriormente.
 
 
 
=== 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. Utiliza-se o formato de apresentação de um cliente descrito anteriormente.
 
 
 
=== Mostrar terminais sem actividade ===
 
 
 
São apresentados os terminais que ainda não efectuaram nem receberam qualquer comunicação. O formato de apresentação é o descrito acima.
 
 
 
=== Mostrar terminais com saldo positivo ===
 
 
 
São apresentados os terminais que que têm um valor de pagamentos estritamente superior ao valor das dívidas.
 
 
 
== Menu da consola de um terminal ==
 
Este menu apresenta as operações relacionadas com a consola de um terminal, i.e., o seu uso e administração. A lista completa é a seguinte: [[#Ligar terminal|Ligar terminal]],  [[#Desligar terminal|Desligar terminal]], [[#Silenciar terminal|Silenciar terminal]], [[#Adicionar amigo|Adicionar amigo]], [[#Retirar amigo|Retirar amigo]], [[#Efectuar pagamento|Efectuar pagamento]], [[#Mostrar informação sobre pagamentos e dívidas|Mostrar informação sobre pagamentos e dívidas]], [[#Enviar comunicação de texto|Enviar comunicação de texto]], [[#Iniciar comunicação interactiva|Iniciar comunicação interactiva]], [[#Terminar comunicação interactiva|Terminar comunicação interactiva]], [[#Mostrar comunicações em curso|Mostrar comunicações em curso]].
 
 
 
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.
 
<!--
 
Se o parceiro indicado estiver inibido de efectuar transacções, deve ser lançada a excepção '''UnauthorizedPartnerException''' e o comando não tem efeito. --><!--Se o identificador de um produto não corresponder ao fornecedor indicado, deve ser lançada a excepção '''WrongSupplierException''' e o comando não tem efeito.-->
 
 
 
{{CVSCode|Estes comandos já estão implementados nas classes da ''package'' '''prr.app.admin''' (disponível no CVS), respectivamente: '''DoTurnOnTerminal''', '''DoOffTurnTerminal''', '''DoSilenceTerminal''', '''DoAddFriend''', '''DoRemoveFriend''', '''DoPerformPayment''', '''DoShowTerminalPaymentsAndDebts''', '''DoSendTextCommunication''', '''DoStartInteractiveCommunication''', '''DoEndInteractiveCommunication''', '''DoShowOngoingCommunications'''.}}
 
 
 
=== Colocar terminal em espera ===
 
Se o terminal indicado já estiver em espera, é apresentada a mensagem '''alreadyIdle()''' e o comando não realiza outras acções. <!--
 
 
 
Caso contrário, são apresentadas as notificações emitidas para os terminais que tentaram o contacto enquanto este terminal não esteve ligado ('''isAvailable()'''). Só deve ser apresentada uma mensagem por cada terminal que tentou o contacto, mesmo que tenha havido mais do que uma tentativa de contacto. As notificações devem ser ordenadas pelos números dos terminais que tentaram o contacto.
 
-->
 
 
 
=== Desligar terminal ===
 
Se o terminal indicado já estiver desligado, é apresentada a mensagem '''alreadyOff()''' e o comando não realiza outras acções.
 
 
 
=== Silenciar terminal ===
 
Se o terminal indicado já estiver em silêncio, é apresentada a mensagem '''alreadySilent()''' e o comando não realiza outras acções.<!--
 
 
 
Caso contrário, são apresentadas as notificações emitidas para os terminais que tentaram o contacto enquanto o terminal esteve desligado ('''isAvaliableForTextCommunications()'''). Só deve ser apresentada uma mensagem por cada terminal que tentou o contacto, mesmo que tenha havido mais do que uma tentativa de contacto. As notificações devem ser ordenadas pelos números dos terminais que tentaram o 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 identificador da comunicação a pagar ('''Prompt.commKey()'''). A comunicação tem de pertencer ao terminal actual. Caso contrário, é apresentada a mensagem '''foreignCommunication()'''.
 
 
 
=== Mostrar informação sobre pagamentos e dívidas ===
 
São apresentados os valores dos pagamentos e das dívidas do terminal ('''terminalPaymentsAndDebts()''').
 
 
 
=== Enviar comunicação de texto ===
 
Esta operação está disponível para um terminal que não esteja desligado ou em comunicação. Permite enviar uma comunicação de texto para outro terminal.
 
 
 
É pedido o número do terminal de destino e o corpo da mensagem ('''Prompt.textMessage()''').
 
 
 
=== Iniciar comunicação interactiva ===
 
Esta operação está disponível para um terminal que não esteja desligado ou em comunicação. Permite estabelecer uma comunicação interactiva com outro terminal.
 
 
 
É pedido o número do terminal de destino e o tipo de comunicação ('''Prompt.commType()'''). A resposta deve ser uma das seguintes opções (cadeia de caracteres): '''VIDEO''', '''VOICE'''. Se a resposta não corresponder a nenhum destes valores, a pergunta é repetida até se obter uma resposta válida.
 
 
 
Quando o terminal de destino está desligado, é apresentada a mensagem '''destinationIsOff()'''. Quando o terminal de destino está ocupado, é apresentada a mensagem '''destinationIsBusy()'''. Quando o terminal de destino está em silêncio, é apresentada a mensagem '''destinationIsSilent()'''.
 
 
 
Se se tenta iniciar uma comunicação de video a partir de um terminal básico, deve ser apresentada a mensagem '''unsupportedAtOrigin()'''. Se se tenta iniciar uma comunicação de vídeo para um terminal básico, deve ser apresentada a mensagem '''unsupportedAtDestination()'''. Em qualquer destes casos, a operação termina sem qualquer acção.
 
 
 
=== Terminar comunicação interactiva ===
 
 
 
Esta operação está disponível para um terminal que iniciou uma comunicação interactiva enquanto a comunicação está em curso. O terminal de destino não pode interromper a comunicação, pelo que o comando não está disponível. O comando permite terminar a comunicação e registar a sua duração.
 
 
 
É pedida a duração da comunicação ('''Prompt.duration()''', em segundos). Após o término da comunicação, é apresentado o seu custo, através da mensagem '''communicationCost()'''.
 
 
 
=== Mostrar comunicação em curso ===
 
 
 
É apresentada a comunicação em curso (de acordo com o formato indicado acima).
 
 
 
Se não houver nenhuma comunicação em curso, é apresentada a mensagem '''noOngoingCommunication()'''.
 
 
 
= Leitura de Dados a Partir de Ficheiros Textuais =
 
 
Além das opções de manipulação de ficheiros descritas no [[#Salvaguarda do Documento Actual|menu principal]], é possível iniciar a aplicação com um ficheiro de texto especificado pela propriedade Java '''[[#Execução dos Programas e Testes Automáticos|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''|''taxId''|''client-level''
 
''terminal-type''|''idTerminal''|''idClient''|''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. Para os terminais, ''terminal-type'' é '''BASIC''' ou '''FANCY'''.
 
 
 
Um exemplo de conteúdo do ficheiro inicial é como se segue:
 
 
 
{{CollapsedCode|Exemplo de ficheiro de entrada textual|
 
<source lang="text">
 
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
 
BASIC|969001|cli001|ON|-900
 
BASIC|969003|cli002|ON|0
 
FANCY|969002|cli002|SILENCE|330
 
FANCY|969007|cli Es|ON|700
 
BASIC|969008|cli003|OFF|2500
 
BASIC|969009|cli003|OFF|1200
 
BASIC|969010|cli003|ON|-2100
 
FANCY|969006|cli003|ON|4800
 
FANCY|969005|cli003|ON|3400
 
BASIC|969004|cli003|ON|1000
 
FRIENDS|969001|969008,969009,969004
 
FRIENDS|969004|969001
 
FRIENDS|969003|969008
 
</source>
 
}}
 
A codificação dos ficheiros a ler é garantidamente [[wp:UTF-8|UTF-8]].
 
 
 
{{Suggestion|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 [[Programação com Objectos/Projecto de Programação com Objectos/Material de Apoio ao Desenvolvimento|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'' '''[https://docs.oracle.com/javase/8/docs/api/java/io/package-summary.html java.io]''', em particular, a interface '''[https://docs.oracle.com/javase/8/docs/api/java/io/Serializable.html java.io.Serializable]''' e as classes de leitura '''[https://docs.oracle.com/javase/8/docs/api/java/io/ObjectInputStream.html java.io.ObjectInputStream]''' e escrita '''[https://docs.oracle.com/javase/8/docs/api/java/io/ObjectOutputStream.html java.io.ObjectOutputStream]''' (entre outras).
 
<!--
 
A representação e manipulação de datas e tempos deve ser realizada através das classes da ''package'' '''[https://docs.oracle.com/javase/8/docs/api/java/time/package-summary.html java.time]''', em particular, através das classes '''[https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html java.time.LocalDate]''' e '''[https://docs.oracle.com/javase/8/docs/api/java/time/LocalTime.html java.time.LocalTime]'''. Diferenças entre tempos são representadas pela classe '''[https://docs.oracle.com/javase/8/docs/api/java/time/Duration.html java.time.Duration]'''.
 
-->
 
<!--
 
[[category:Ensino]]
 
[[category:PO]]
 
[[category:Projecto de PO]]
 
[[en:Object-Oriented Programming]]
 
-->
 

Latest revision as of 17:49, 14 September 2022