AVISOS - Avaliação em Época Normal |
---|
Esclarecimento de dúvidas:
|
Requisitos para desenvolvimento, material de apoio e actualizações do enunciado (ver informação completa em Projecto de Programação com Objectos):
|
Processo de avaliação (ver informação completa em Avaliação do Projecto):
|
Material de Uso Obrigatório |
---|
As bibliotecas po-uuilib e o conteúdo inicial do CVS são de uso obrigatório: |
|
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. |
O objectivo do projecto é criar uma aplicação que gere parte da actividade dos cursos de uma universidade. Em particular, a aplicação faz a gestão de inquéritos aos projectos realizados pelos alunos nas várias disciplinas do curso.
Neste texto, o tipo negrito indica um literal (i.e., é exactamente como apresentado); o símbolo indica um espaço; e o tipo itálico indica uma parte variável (i.e., uma descrição).
Existem vários conceitos importantes neste contexto: universidade, curso, aluno, professor, funcionário, projecto, inquérito,
Os conceitos listados não são os únicos possíveis no modelo e as suas relações (assim como relações com outros conceitos não mencionados) podem depender das escolhas do projecto.
Uma universidade tem um nome e pode ter vários cursos universitários, tendo ainda funcionários, docentes e alunos. Os alunos estão exclusivamente associados a cada curso. Os funcionários e os docentes podem estar associadoss a vários cursos.
Cada curso tem um nome (único no contexto da universidade) e é constituído por várias disciplinas. Cada curso tem ainda um conjunto de alunos que podem inscreverem-se nas várias disciplinas do curso. Cada aluno pode inscrever-se, no máximo, em 6 disciplinas.
Cada disciplina tem um nome e apenas pertence a um curso. O nome é o identificador único dentro do curso da disciplina. Cada disciplina é leccionada por um ou mais docentes e tem 0 ou mais alunos inscritos. Os alunos inscritos numa disciplina têm que pertencer ao curso da disciplina. Existe uma capacidade máxima relativamente aos alunos que se podem inscrever na disciplina.
O sistema a desenvolver tem que lidar com diferentes tipos de utilizadores: alunos, docentes e funcionários. Alunos, docentes e funcionários têm um nome, número de telefone e são são identificados por um identificador único no sistema. Este identificador é um número inteiro com 6 dígitos. Este identificador é atribuído automaticamente pelo sistema e começa em 100000. Um aluno pode ainda ser delegado de curso do curso em que o aluno está inscrito. O número máximo de delegados de um curso é 7. Em qualquer instante um aluno pode tornar-se delegado ou deixar de ser delegado.
Os docentes podem criar projectos associados às disciplinas que leccionam. Quando o projecto é criado fica automaticamente aberto. Cada projecto tem um nome e descrição. O nome deve ser único no contexto da disciplina. Os alunos da mesma disciplina que o projecto podem submeter a sua versão do projecto desde que o projecto ainda não esteja fechado. Os alunos podem realizar várias submissões no mesmo projecto mas apenas é guardada a última submissão. Por razões de simplificação a submissão é representada por uma cadeia de caracteres introduzida pelo aluno. A ordem de submissão deve ser preservada pelo sistema.
Cada inquérito tem um identificador único no contexto da disciplina (número inteiro único e sequencial, atribuído automaticamente na altura da criação) e está associado a um projecto dessa disciplina. Só é possível associar um inquérito a um projecto se este não estiver finalizado. Um inquétito pode estar em várias situações: criado, aberto, fechado e finalizado. O comportamento do inquérito dependa da situação em que ele esteja. A mudança de situação é explícita, excepto quando o projecto associado termina: neste caso, o inquérito do projecto passa automaticamente da situação criado para aberto.
Só os alunos que entregaram o projecto é que podem responder ao inquérito. Cada aluno só pode responder uma única vez. As respostas devem ser anónimas, ou seja, o sistema não deve guardar informação que permita saber qual a resposta de um dado aluno a um inquérito.
A gestão interna de um inquérito é da responsabilidade do delegado do curso, a única entidade que pode alterara situação de um inquérito (ver erxcepção acima).
É possível realizar várias operações sobre um inquérito: cancelar, abrir, fechar, finalizar, submeter resposta e obter resultados. Cancelar um inquérito criado ou aberto (e sem respostas) corresponde a remover o inquérito. Se o inquérito estiver aberto mas já tiver pelo menos uma resposta, então não pode ser removido e deve dar erro. Cancelar um inquérito fechado corresponde a abri-lo outra vez. Finalmente, cancelar um inquérito finalizado é impossível pelo que deverá dar erro.
Um delegado pode só pode abrir um inquérito que esteja criado. Em qualquer outra situação deve dar um erro a não ser que o inquérito esteja aberto. Neste caso, a operação não faz anda. Um delegado pode fechar um inquérito que esteja aberto. Se estiver fechado, a operação não faz nada. Em qualquer outra situação deve dar um erro. Finalmente, um delegado pode finalizar um inquérito que esteja fechado . Se o inquérito já estiver finalizado, a operação não faz nada. Nas restantes situações dará um erro.
Os alunos podem submeter uma resposta a um inquérito aberto. Em qualquer outra situação, esta operação deverá dar um erro. Alunos, docentes e delegados podem obter o resultado de um inquérito que esteja finalizado. Adicionalmente, um delegado pode obter os resultados de um inquérito que esteja aberto ou fechado. Esta operação deverá dar um erro em qualquer outra situação.
Note-se que tanto um delegado, como um aluno ou um docente podem realizar as operaçãoes indicas anteriormente desde que pertençam ao mesmo curso do inquérito. Adicionalmente, o aluno tem ainda que te entregue o projecto associado ao inquérito.
Pretende-se ainda concretizar um mecanismo de mensagens que permita avisar determinados utilizadores quando determinada informção relacionda com uma disciplina é alterada:
Nota: dado que um aluno pode também ser delegado, o mecanismo de envio de mensagens deve tratar este como se fosse uma única entidade. Assim, um aluno de uma disciplina que seja também delegado deve receber apenas uma mensagem e não duas cada vez que o sistema tem que enviar uma mensagem que diga respeito ao início de um projecto na disciplina em causa.
A apresentação das mensagens enviadas paea um dado utilizador deve ser feita quando o utilizador faz login no sistema. Após o login ter sido realizado com sucesso devem ser apresentados todas as mensagens que tenham sido enviadas para o utilizador em causa desde a última vez que se registou no sistema. Após esta visualização considera-se que o utilizador fica sem mensagens. As mensagens devem ser apresentadas pela mesma ordem em que enviadas pelo sistema.
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:
Quer-se uma solução que permita a diferentes entidades poderem receber uma mensagem quando os resultados de um inquétrico ficam disponíveis ou quando um novo aluno responde ao inquérito. No primeiro caso a mensagem deve indicar que o inquérito tem os resultados disponíveis en quanto que o segundo deve indicar que existe uma nova resposta registada no inquérico e o número total de respostas até ao momento.
A aplicação permite manter informação sobre as entidades do modelo, permitindo, em paricular, gerir projectos e inquéritos. 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).
A base de dados com os conceitos pré-definidos é carregada no início da aplicação. Não é possível adicionar ou remover pessoas durante a execução da aplicação.
É possível fazer várias consultas sobre serviços (ver também abaixo). É possível ver todos os serviços, inspeccionar um serviço particular e inspeccionar serviços com base na especificação de estações. Podem ser definidas, no futuro, outras formas de pesquisa e de apresentação de serviços.
A aplicação permite realizar várias operações sobre passageiros. É possível obter a lista completa de passageiros conhecidos, assim como informação detalhada sobre passageiros individuais. É ainda possível registar novos passageiros e alterar o nome dos passageiros.
A aplicação permite realizar várias operações sobre passageiros. É possível obter a lista completa de passageiros conhecidos, assim como informação detalhada sobre passageiros individuais. É ainda possível registar novos passageiros e alterar o nome dos passageiros.
A aplicação permite obter informações sobre todos os itinerários já comprados ou, em pormenor, sobre os itinerários de passageiros específicos. Permite ainda criar novos itinerários.
Os passageiros são creditados com o valor monetário de cada itinerário comprado e com o tempo decorrido nesses itinerários (medido entre os pontos extremos).
É possível reiniciar (ou seja, mantendo a informação sobre serviços, eliminar a informação sobre passageiros e itinerários), guardar e recuperar o estado actual da aplicação, preservando todos a informação sobre serviços, passageiros e itinerários.
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 proceder à 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-uuilib e sth-app). As mensagens não podem ser usadas no núcleo da aplicação (sth-core). Além disso, não podem ser definidas novas. Potenciais omissões devem ser esclarecidas antes de qualquer implementação.
As excepções usadas na interacção, excepto se indicado, são subclasses de pt.tecnico.po.ui.DialogException, são lançadas pelos comandos e tratadas por pt.tecnico.po.ui.Menu. Outras excepções não devem substituir as fornecidas nos casos descritos.
As acções do menu permitem gerir a salvaguarda do estado da aplicação e abrir submenus. A lista completa é a seguinte: Reiniciar, Abrir, Guardar e Portal Pessoal, Portal do Docente, Portal do Estudante e Portal do Delegado. Inicialmente, a aplicação apenas tem informação sobre os serviços que foram carregados no arranque.
As etiquetas das opções deste menu estão definidas na classe sth.app.main.Label. Todos os métodos correspondentes às mensagens de diálogo para este menu estão definidos na classe sth.app.main.Message.
O conteúdo da aplicação (inclui todos os serviços, passageiros e itinerários 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:
As opções Reiniciar e Abrir substituem a informação na aplicação nas condições indicadas acima.
A opção Sair nunca guarda o estado da aplicação, mesmo que existam alterações.
Este menu permite efectuar consultas sobre a base de dados de pessoal. A lista completa é a seguinte: Mostrar pessoa, Alterar número de telefone, Procurar pessoa.
As etiquetas das opções deste menu estão definidas na classe sth.app.person.Label. Todos os métodos correspondentes às mensagens de diálogo para este menu estão definidos na classe sth.app.person.Message.
Sempre que for pedido o identificador de um serviço (requestServiceId()) e o serviço não existir, é lançada a excepção sth.app.NoSuchServiceException. Sempre que for pedido o nome de uma estção (requestStationName()) e a estação não existir, é lançada a excepção sth.app.NoSuchStationException.
Apresenta informações sobre todos os serviços conhecidos. A lista é ordenada pelo identificador do serviço e o formato é o descrito em Mostrar serviço com um dado número.
Apresenta informações sobre um serviço. Depois de pedir o identificador do serviço (requestServiceId()), apresenta a informação sobre o serviço, tal como indicado no formato seguinte, para um serviço com N paragens (HH;MM representa o tempo em horas e minutos). O preço deve ser apresentado com duas casas decimais.
Serviço #número-do-serviço @ preço HH:MM nome-de-estação-1 ... HH:MM nome-de-estação-N
Apresenta os números e estações de origem dos serviços com término na estação indicada como resposta a requestStationName(), ordenado por hora de chegada do serviço.
O formato de apresentação é o descrito em Mostrar serviço com um dado número.
Este menu permite efectuar operações sobre um passageiro. A lista completa é a seguinte: Mostrar passageiros, Mostrar passageiro, Registar passageiro, Alterar nome de passageiro.
As etiquetas das opções deste menu estão definidas na classe mmt.app.passenger.Label. Todos os métodos correspondentes às mensagens de diálogo para este menu estão definidos na classe mmt.app.passenger.Message.
Sempre que for pedido o identificador de um passageiro (requestPassengerId()) e o passageiro não existir, é lançada a excepção mmt.app.NoSuchPassengerException.
Apresenta informações sobre todos os passageiros conhecidos. A lista é ordenada pelo identificador e o formato é o descrito em Mostrar passageiro.
Apresenta informações sobre um passageiro. Depois de pedir o identificador do passageiro (requestPassengerId()), apresenta o nome, a categoria do passageiro (NORMAL, FREQUENTE, ESPECIAL), o número de itinerários adquiridos, o tempo acumulado (formato HH:MM) correspondente aos itinerários adquiridos e o valor pago por esses itinerários (o valor pago deve ser apresentado com duas casas decimais).
Formato:
id | nome | categoria | número-de-itinerários | valor-pago | tempo-acumulado
Exemplo:
1234|John Doe|NORMAL|123|9876.54|123:45
Permite registar um passageiro no sistema. É pedido o nome do passageiro (requestPassengerName()). O novo passageiro é categorizado como NORMAL.
Permite alterar o nome do passageiro. Para tal, pede-se o identificador do passageiro cujo nome deve ser alterado (requestPassengerId()) e o novo nome (requestPassengerName()).
Este menu permite efectuar operações sobre itinerários. A lista completa é a seguinte: Mostrar todos os itinerários, Mostrar itinerários associados a um passageiro, Registar itinerário para um passageiro.
As etiquetas das opções deste menu estão definidas na classe mmt.app.itinerary.Label. Todos os métodos correspondentes às mensagens de diálogo para este menu estão definidos na classe mmt.app.itinerary.Message.
Apresenta todos os itinerários registados para todos os passageiros. O formato de apresentação é como para os serviços, mas apenas se apresenta o segmento percorrido e o respectivo custo. A informação é apresentada para cada passageiro, sendo os passageiros apresentados por ordem crescente do seu número de identificação.
O formato de apresentação é como definido para a apresentação dos itinerários de um passageiro, mas apresenta-se a informação relativamente a todos os passageiros.
Note-se que a apresentação de itinerários apenas tem significado quando existem itinerários para mostrar, i.e., não se devem apresentar passageiros que não têm itinerários.
Apresenta os itinerários do passageiro cujo identificador é pedido através de requestPassengerId(). A lista é ordenada pela data dos itinerários.
Se o passageiro não tiver itinerários, deve ser apresentada a mensagem noItineraries().
O formato de apresentação é análogo ao dos serviços, iniciado com uma linha com o identificador do passageiro, à qual se segue a lista de itinerários, cada um precedido da linha com o número de ordem do itinerário (no contexto de cada passageiro) e da data correspondente:
== Passageiro identificador-do-passageiro: nome-do-passageiro == Itinerário número-de-ordem-do-itinerário para data @ preço-total-do-itinerário
O preço associado a cada serviço no itinerário é o da fracção do tempo do serviço nesse itinerário, com duas casas decimais. O preço do itinerário é a soma (sem arredondamentos) dos preços dos segmentos que o formam, apresentado com duas casas decimais.
Este menu permite efectuar operações sobre itinerários. A lista completa é a seguinte: Mostrar todos os itinerários, Mostrar itinerários associados a um passageiro, Registar itinerário para um passageiro.
As etiquetas das opções deste menu estão definidas na classe mmt.app.itinerary.Label. Todos os métodos correspondentes às mensagens de diálogo para este menu estão definidos na classe mmt.app.itinerary.Message.
Apresenta todos os itinerários registados para todos os passageiros. O formato de apresentação é como para os serviços, mas apenas se apresenta o segmento percorrido e o respectivo custo. A informação é apresentada para cada passageiro, sendo os passageiros apresentados por ordem crescente do seu número de identificação.
O formato de apresentação é como definido para a apresentação dos itinerários de um passageiro, mas apresenta-se a informação relativamente a todos os passageiros.
Note-se que a apresentação de itinerários apenas tem significado quando existem itinerários para mostrar, i.e., não se devem apresentar passageiros que não têm itinerários.
Apresenta os itinerários do passageiro cujo identificador é pedido através de requestPassengerId(). A lista é ordenada pela data dos itinerários.
Se o passageiro não tiver itinerários, deve ser apresentada a mensagem noItineraries().
O formato de apresentação é análogo ao dos serviços, iniciado com uma linha com o identificador do passageiro, à qual se segue a lista de itinerários, cada um precedido da linha com o número de ordem do itinerário (no contexto de cada passageiro) e da data correspondente:
== Passageiro identificador-do-passageiro: nome-do-passageiro == Itinerário número-de-ordem-do-itinerário para data @ preço-total-do-itinerário
O preço associado a cada serviço no itinerário é o da fracção do tempo do serviço nesse itinerário, com duas casas decimais. O preço do itinerário é a soma (sem arredondamentos) dos preços dos segmentos que o formam, apresentado com duas casas decimais.
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.
Cada utilizador tem uma descrição distinta mas que segue o seguinte formato.
TIPO | identificador | telefone | nome
Dependendo do tipo de pessoa, TIPO pode tomar os valores FUNCIONÁRIO, DOCENTE, ALUNO e DELEGADO (para alunos que são delegados).
A seguir à linha da descrição, podem seguir-se outras que acrescentam informação adicional para o utilizador em causa. A informação adicional para os alunos (delegados ou não) e para os docentes é uma lista de disciplinas (uma por linha): para os alunos, são as disciplinas que frequentam; para os docentes, são as disciplinas que leccionam. Para os funcionários, não há informação adicional a processar.
<text> EXEMPLO.... </text>
A codificação dos ficheiros a ler é garantidamente UTF-8.
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 (mmt.app.App.main). As propriedades são tratadas automaticamente pelo código de apoio.
java -Dimport=test.import -Din=test.in -Dout=test.outhyp mmt.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.
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).
A representação e manipulação de datas e tempos deve ser realizada através das classes da package java.time, em particular, através das classes java.time.LocalDate e java.time.LocalTime. Diferenças entre tempos são representadas pela classe java.time.Duration.