ISSN 2316-2872 T.I.S. São Carlos, v. 1, n. 1, p. 35-53, jul. 2012 ©Tecnologias, Infraestrutura e Software Web Service no ambiente escolar: um estudo de caso Alberto René Zanetti, Valter Vieira de Camargo Abstract: This paper proposes the development of a Web Service destined to the school environment whose main function is to provide information about students’ grades (transcripts) to other schools in an integrated way. So every institution can access the Web Service and request transcripts of any student registered through an access key. Also it is provided the possibility of registered institutions update their students’ information by sending them directly to the Web Service. A case study is presented to illustrate the ideas proposed in this paper. Keywords: web service, framework, web application Resumo: Neste artigo propõe-se o desenvolvimento de um Web Service destinado ao ambiente escolar cuja principal função é fornecer informações sobre as notas dos alunos (histórico escolar) para outros estabelecimentos de ensino de uma forma integrada. Assim toda instituição pode acessar o Web Service e solicitar o histórico escolar de qualquer aluno cadastrado por meio de uma chave de acesso. Também foi previsto a possibilidade das instituições cadastradas atualizarem as informações de seus alunos enviando-as diretamente para o Web Service. Um estudo de caso é apresentado para ilustrar as idéias propostas neste artigo. Palavras-chave: web service, framework, aplicação web I. INTRODUÇÃO No ambiente escolar o histórico dos alunos é de extrema importância, mas infelizmente a sua disponibilização está, na maior parte das vezes, restrita à instituição de origem do aluno, dade de se ter acesso a um histórico on-line agilizaria o trabalho das instituições. Pensando nisso, teve-se a ideia de desenvolver um Web Service para suprir essa necessidade. O Web Service em questão possui uma base de dados que mantêm instituições, alunos, disciplinas e suas respectivas notas. Quando uma instituição precisar do histórico escolar de um aluno que não faça parte de seu corpo discente, a mesma envia uma solicitação para o Web Service fornecendo a chave de acesso para aquele aluno. O Web Service prontamente fornece os dados necessários para a montagem do histórico escolar desejado. Esses dados estão no formato XML. Para manter a base de dados do Web Service, este pode receber solicitações de inclusão/alteração de dados provenientes das instituições cadastradas. No decorrer deste artigo será apresentada a estrutura em que os dados deverão ser enviados e sugerido que isso seja feito automaticamente quando ocorrer alguma alteração nas notas no sistema da instituição. Todo o processo de desenvolvimento é abordado passo-a-passo, bem como um exemplo de utilização é apresentado para que o Web Service possa ser incorporado em outras aplicações. O restante do artigo está organizado da seguinte maneira. Na seção II são apresentados conceitos básicos utilizados no restante do artigo. Na seção III é apresentado um estudo de caso e II. CONCEITOS BÁSICOS Nesta seção são descritos os conceitos utilizados no desenvolvimento do web service descrito neste artigo. A. XML XML (eXtensible Markup Language) é uma linguagem simples capaz de descrever diversos tipos de dados, baseada em arquivo texto e composta por tags (palavras demarcadas por ta um exemplo de um documento XML. demos enfatizar sua representação estruturada e hierárquica, separação clara do conteúdo da formatação, simplicidade e fácil entendimento, possibilidade de criação de tags próprias e ênfase na estrutura e não na aparência. Departamento de Computação – Universidade Federal de São Carlos (UFSCar) Caixa Postal 676 – 13.565-905 – São Carlos – SP – Brasil Autor para correspondência: [email protected], [email protected] B. HTTP atributos: mustUnderstand, actor, e encodingStyle. O atributo mustUndestand valor “1” obriga o receptor a processar essa entrada do Header e actor sagem. O elemento Body possui a chamada dos métodos da aplicação e seus respectivos parâmetros de requisição e resposta. O elemento Fault é opcional, e é utilizado para indicar mensagens de erro. Ele pode ser utilizado apenas uma vez no Envelope. Possui os seguintes sub-elementos: faultcode, faultstring, faultactor e detail HTTP (HyperText Transfer Protocol) é um padrão de comunicação “requisição-resposta” amplamente utilizado pela Internet. O cliente envia uma requisição ao servidor que envia uma mensagem de resposta ao cliente. C. Web Services Web Services são aplicações criadas para receber e dar portanto não são acessadas diretamente pelos usuários, sendo desenvolvidas para serem acessadas por outras aplicações. Web Services trabalham basicamente com XML para os dados e HTTP para a comunicação. A independência de linguagem e plataforma dos Web Services tornou-os excepcionalmente úteis na integração de sistemas. O único requisito para um sistema se comunicar a um Web Service é interpretar uma mensagem XML. do erro. III ESTUDO DE CASO Nesta seção é apresentado todos os passos do desenvolvimento do Web Service em questão. D. SOAP A. Documento de requisitos SOAP (Simple Object Access Protocol) é o protocolo utilizado para comunicação com os Web Services. É basicamente um documento XML composto por um elemento Envelope, um Header, um Body e um Fault (Header e Fault são opcionais). No Quadro 2 temos um modelo da estrutura de um documento SOAP com seus principais elementos: XML é um O elemento Envelope encodingStyle, SOAP, o atributo xmlns as regras de serialização do elemento (este atributo pode ser utilizado em todos os elementos). O elemento Header é opcional, mas se utilizado deve ser o primeiro elemento dentro do Envelope. Ele serve para man- No Quadro 3 é apresentado o documento de requisitos, onde sárias para o seu desenvolvimento. B. Casos de uso guras as funcionalidades propostas para o Sistema. atorAluno se relaciona com o caso de uso SolicitarHistorico, que por sua vez inclui os casos de uso ValidarChave e GerarHistórico. No caso do atorInstituicao, este se relaciona com o caso de uso CadastrarNota Figura 1. Diagrama de Casos de Uso T.I.S. 2012; 1 (1): 35-53 36 Web Service no ambiente escolar: um estudo de caso que inclui, se necessário, os casos de uso ValidarChave, CadastrarInstituicao, CadastrarAluno e CadastrarDisciplina. Os estereótipos <<include>> e <<extend>> representam, respectivamente, uma ação obrigatória e uma ação opcional. Complementando o diagrama de casos de uso, no Quadro 4 atribuição de permissões de Select, Insert, Update e Delete em todas as tabelas necessárias. Foram criadas quatro tabelas assim como o diagrama de classes indicou, mas com alguns detalhes: em todas as tabelas foi adicionado um campo id chave primária e auto-incremento; na tabela disciplina foi adicionado o campo id_instituicao chave estrangeira para a tabela instituicao; na tabela nota foi adicionado o campo id_aluno chave estrangeira para a tabela aluno e id_disciplina chave estrangeira para a tabela disciplina; UNIQUE nos campos cpf e cnpj das tabelas aluno e instituição para garantir a unicidade dos registros. No Quadro 5 é apresentado o script completo utilizado nesta aplicação. No NetBeans, para criar a conexão do banco de dados com o projeto, foram realizados os passos abaixo: a) Aba Serviços, botão direito em Banco de dados, Nova conexão; b) Modo de entrada de dados: Entrada direta de URL, Nome do driver: PostgreSQL, Nome do usuário: postgres, Senha: (senha do usuário postgres), marque Lembrar senha, URL JDBC: jdbc:postgresql://localhost:5432/ WSHistorico, Ok; c) Selecione um esquema: public, Ok. passo a passo as ações realizadas em cada caso de uso. Essas Alternativo. onde as condições (se-então) são sempre verdadeiras e os dados GerarHistorico temos os passos 2. Enquanto houver notas e 2.1 Carregar nota. Nesses passos é previsto que existam notas para serem carregadas. Des2a. Não existem notas, 2a.1 Gerar mensagem de erro e 2a.2 Abandonar caso de uso butos, métodos e relações entre elas. C. Implementação O sistema foi implementado utilizando Java EE 5 no NetBeans IDE 6.8 em uma máquina com Ubuntu 9.04, banco de dados PostgreSQL 8.3.11 e servidor Apache Tomcat 6.0.20. Projeto no NetBeans O projeto foi criado como uma Aplicação Web e chamado de WSHistorico, segundo os seguintes passos: a) Menu Arquivo, Novo projeto, Categorias: Java Web, Projetos: Aplicação Web, Próximo; b) Nome do projeto: WSHistorico, Próximo; Banco de Dados No PostgreSQL foi criado o banco de dados WSHistorico, foi mantido o usuário postgres - Figura 2. Diagrama de Classes 37 T.I.S. 2012; 1 (1): 35-53 c) Servidor: Apache Tomcat 6.0.20 EE 5, Finalizar. DAO Java EE: Java Outro padrão utilizado é o DAO (Data Access Object), ele propõe a criação de uma camada de persistência, para isolar a aplicação da comunicação com o banco de dados. Seguindo esse padrão foram criados as classes DAO referentes a cada uma das entidades, como abaixo: a) Aba Projetos, botão direito em WSHistorico, Novo, Classe java (ou Outro, Categorias: Java, Tipos de arquivos: Classe java); b) Nome da classe: InstituicaoDAO, Pacote: persistencia, Finalizar; c) Esses procedimentos foram repetidos para as classes DisciplinaDAO, AlunoDAO e NotaDAO. Unidade de persistência Para que o banco de dados relacional “converse” com os objetos java, foi criado uma Unidade de persistência: a) Aba Projetos, botão direito em WSHistorico, Novo, Unidade de persistência (ou Outro, Categorias: Persistence, Tipos de arquivos: Unidade de persistência), Próximo; b) Nome da unidade de persistência: WSHistoricoPU, Biblioteca de persistência: TopLink, Conexão de banco de dados: jdbc:postgresql: //localhost:5432/WSHistorico, Estratégia de geração de tabela: Nenhum, Finalizar. O corpo da classe InstituicaoDAO, AlunoDAO e NotaDAO são apresentados pelos Quadros 8 a 10, respectivamente. Entidades Façade As entidades foram criadas automaticamente pelo NetBeans a partir do banco de dados, como segue: a) Aba Projetos, botão direito em WSHistorico, Novo, Classes de entidade do banco de dados (ou Outro, Categorias: Persistence, Tipos de arquivos: Classes de entidade do banco de dados), Próximo; b) Conexão de banco de dados: jdbc:postgresql://localhost:5432/ WSHistorico, Adicionar todos, Próximo; c) Pacote: negocio.entidade, Finalizar. O padrão de projeto Façade cria a camada de negócio, a qual desacoplamento requerido pelo MVC. As classes Façades foram criadas seguindo os passos abaixo: a) Aba Projetos, botão direito em WSHistorico, Novo, Classe java (ou Outro, Categorias: Java, Tipos de arquivos: Classe java); c) Nome da classe: InstituicaoFacade, Pacote: negocio.facade, Finalizar; d) Esses procedimentos foram repetidos para as classes DisciplinaFacade, AlunoFacade e NotaFacade. Alguns atributos das entidades foram refatorados para facilitar o seu entendimento: em Aluno, notaCollection foi refatorado para notas; em Disciplina, idInstituicao para instituicao e notaCollection para notas; em Instituicao, disciplinaCollection para disciplinas; e em Nota, idAluno para aluno e idDisciplina para disciplina. Refatorar é simples, clique com o botão direito no atributo desejado, escolha Refatorar, Renomear, digite o novo nome e o clique no botão Refatorar. Não podemos esquecer que ao refatorar os atributos, o NetBeans não refatora automaticamente os métodos O corpo das classes InstituicaoFacade, DisciplinaFacade, AlunoFacade e NotaFacade é apresentado no quadro 11: Os Quadros 12,13 e 14 apresentam os corpos das classes DisciplinaFacade, AlunoFacade e NotaFacade, respectivamente. Classe Chave Foi criada a classe de persistência Chave, responsável pela geração da chave de acesso, utilizada no cadastro de alunos e ma de classes por se tratar de uma classe de persistência e não de negócio como as demais. a) Aba Projetos, botão direito em WSHistorico, Novo, Classe java (ou Outro, Categorias: Java, Tipos de arquivos: Classe java); b) Nome da classe: Chave, Pacote: persistencia, Finalizar; O NetBeans não mapeia corretamente os auto-incrementos, por isso as anotações apresentadadas no Quadro 6 foram inseridas nas entidades, entre os atributo @Column(name = «id»); e private Integer id; MVC O corpo da classe Chave é apresentado no Quadro 15. padronização ao software. MVC (Model-View-Controller) propõe dividir a aplicação em 3 camadas distintas e independentes: Model representa as classes, objetos e a lógica de acesso ao banco de dados; View representa a interface que exibe os dados dos objetos; e Controller recebe as requisições dos usuários e as converte em ações para o Model View mais apropriada para cada resposta. Utilizando o MVC, as classes foram divididas da seguinte forma: as entidades e os DAOs representam a camada Model enquanto os Façades e a classe Historico.java representam a camada Controller. A camada View não é utilizada visto que os Web Services não possuem interface com o usuário. T.I.S. 2012; 1 (1): 35-53 Web Service mentação do Web Service. Foi criado um Web Service, chamado Historico, seguindo os passos abaixo: a) Aba Projetos, botão direito em WSHistorico, Novo, Serviço Web (ou Outro, Categorias: Web Services, Tipos de arquivos: Serviço Web); b) Nome do serviço web: Historico, Pacote: webservices, Finalizar. 38 Web Service no ambiente escolar: um estudo de caso O Web Service possui dos métodos: solicitarHistorico e cadastrarNota. O método solicitarHistorico recebe CPF e chave de um aluno e retorna a lista de disciplinas cursadas em uma string XML apresentada no Quadro 16 ou uma mensagem de erro apresentada no Quadro 17, sendo que o código do método solicitarHistorico é apresentado no Quadro 18. O método cadastrarNota recebe CNPJ da instituição, nome da instituição, chave da instituição, disciplina, CPF do aluno, nome do aluno, chave do aluno, nota, data da nota e status e retorna os dados cadastrados em uma string XML apresentada no Quadro 19 ou uma mensagem de erro semelhante ao método anterior. sário passar o CNPJ e o nome, a chave de acesso será gerada e devolvida no retorno. E para uma instituição existente, apenas o CNPJ e a chave de acesso, o nome não será atualizado. O mesmo se aplica para o aluno. O código do método cadastrarNota é apresentado no Quadro 20: Agora que o Web Service está pronto, apresenta-se um exemplo simples de utilização: a) Aba Projetos, botão direito no seu projeto, Novo, Cliente para serviço Web (ou Outro, Categorias: Web Services, Tipos de arquivos: Cliente para serviço Web), Próximo; b) WSDL URL: http://localhost:8080/WSHistorico/ HistoricoService?wsdl, Pacote: infraestrutura, Finalizar; IV. CONCLUSÃO Levando-se em conta o que foi apresentado neste artigo, observa-se que o Web Service cumpre os objetivos pretendidos: fornecer um histórico escolar on-line mediante dados previamente cadastrados. Sobre os Web Services, conclui-se que a sua implementação é uma tarefa consideravelmente simples e muito útil para os desenvolvedores. Os Web Services podem desempenhar com elegância desde tarefas simples, como a geração de um histórico escolar, até as mais complexas, como a integração de sistemas de grande porte. Deve-se ressaltar que o Web Service cado pois não ha necessidade de complexidade computacional para expor a ideia apresentada, e que para a completa utilização deste Web Service, algumas funcionalidade devem ser implementadas, tais como: recuperação da chave-de-acesso e alteração/exclusão dos registros. REFERÊNCIAS FOSCHINI, Ivan J. Frameworks para Desenvolvimento Web. São Carlos: UFSCar/DC, 2010. Apostila. JOSUTTIS, Nicolai M. SOA na Prática. Rio de Janeiro: Alta Books, 2008. Web Services. São Carlos: UFSCar/DC, 2010. Apostila. Exemplo de utilização O trecho de código no Quadro 21 instancia o Web Service, passa as informações necessárias para o cadastro e recebe como resultado uma string XML com os dados fornecidos ou o erro ocorrido. Além disso instancia duas variáveis para receber a chave de acesso da instituição e do aluno (caso a instituição e/ ou o aluno não existam na base do Web Service). w3schools.com/soap/>. Acesso em: 04 ago. 2010. W3SCHOOLS. Web Services www.w3schools.com/webservices/>. Acesso em: 01 jun. 2010. w3schools.com/xml/>. Acesso em: 08 jul. 2010. 39 T.I.S. 2012; 1 (1): 35-53 Quadro 1. Exemplo de arquivo XML <note> <to>Tove</to> <from>Jani</from> <heading>Reminder</heading> <body>Don’t forget me this weekend!</body> </note> Quadro 2. Estrutura do documento SOAP <?xml version=”1.0”?> <soap:Envelope xmlns:soap=”http://www.w3.org/2001/12/soap-envelope” soap:encodingStyle=”http://www.w3.org/2001/12/soap-encoding”> <soap:Header> . . . </soap:Header> <soap:Body> . . . <soap:Fault> . . . </soap:Fault> </soap:Body> </soap:Envelope> Quadro 3. Descrição dos Casos de Uso O sistema possui dois atores: aluno e instituição. Qualquer um deles pode solicitar um histórico escolar fornecendo o CPF e a chave de acesso de um aluno. O histórico é composto pelo nome do aluno, nome da instituição, disciplinas, notas, datas e status das notas. A instituição pode cadastrar as notas de seus alunos, fornecendo CNPJ, nome e chave de acesso da instituição, CPF, nome e chave de acesso do aluno, disciplina, nota, data e status. Caso a instituição não exista, esta será cadastrada e uma chave de acesso será gerada e devolvida. Caso o aluno não exista, este será cadastrado e uma chave de acesso será gerada e devolvida. Caso a disciplina não exista, está será data) não exista, está será cadastrada, e caso exista, está terá sua nota e status atualizados. T.I.S. 2012; 1 (1): 35-53 40 Web Service no ambiente escolar: um estudo de caso SolicitarHistórico Fluxo Normal: 1. Usuário informa cpf e chave de acesso. 2. Chamar ValidarChave. 3. Chave válida. 4. Chamar GerarHistórico. 5. Encerrar caso de uso. ValidarChave Fluxo normal: 1. Recebe cpf/cnpj e chave de acesso. 2. Chave válida. 3. Encerrar caso de uso. Fluxo alternativo: 2a. Chave inválida. 2a.1 Gerar mensagem de erro. 2a.2 Abandonar caso de uso . GerarHistórico Fluxo normal: 1. Recebe cpf. 2. Enquanto houver notas 2.1 Carregar nota. 3. Montar histórico escolar. 4. Encerrar caso de uso. Fluxo alternativo: 2a. Não existem notas. 2a.1 Gerar mensagem de erro. 2a.2 Abandonar caso de uso. CadastrarInstituição Fluxo normal: 1. Recebe cnpj e nome da instituição. 2. Chamar GerarChave. 3. Cadastrar instituição. 4. Retornar chave. 5. Encerrar caso de uso. GerarChave Fluxo normal: 1. Recebe cpf/cnpj. 2. Gerar chave. 3. Retornar chave. 4. Encerrar caso de uso. CadastrarNota Fluxo normal: 1. A instituição fornece dados. 2. Instituição cadastrada. 3. Chamar ValidarChave. 4. Aluno cadastrado. 5. Chamar ValidarChave. 6. Disciplina cadastrada. 7. Nota não existe. 8. Cadastrar nota. 9. Encerrar caso de uso. Fluxos alternativos: 2a. Instituição não cadastrada. 2a.1 Chamar CadastrarInstituição. 2a.2 Retornar ao passo 4. 4a. Aluno não cadastrado. 4a.1 Chamar CadastrarAluno. 4a.2 Retornar ao passo 6. 6a. Disciplina não cadastrada. 6a.1 Chamar CadastrarDisciplina. 6a.2 Retornar ao passo 7. 7a. Nota existe. 7a.1 Alterar nota. 7a.2 Retornar ao passo 9. CadastrarAluno Fluxo normal: 1. Recebe cpf e nome do aluno. 2. Chamar GerarChave. 3. Cadastrar aluno. 4. Retornar chave. 5. Encerrar caso de uso. CadastrarDisciplina Fluxo normal: 1. Recebe instituição e nome disciplina. 2. Cadastrar disciplina. 3. Encerrar caso de uso. 41 T.I.S. 2012; 1 (1): 35-53 Quadro 5. Script de criação do banco de dados CREATE TABLE aluno ( id serial PRIMARY KEY, cpf character varying(11) NOT NULL UNIQUE, nome character varying(100) NOT NULL, chave character varying(9) NOT NULL ) CREATE TABLE instituicao ( id serial PRIMARY KEY, cnpj character varying(14) NOT NULL UNIQUE, nome character varying(100) NOT NULL, chave character varying(9) NOT NULL ) CREATE TABLE disciplina ( id serial PRIMARY KEY, id_instituicao integer NOT NULL, nome character varying(100) NOT NULL, FOREIGN KEY (id_instituicao) REFERENCES instituicao (id) ) CREATE TABLE nota ( id serial PRIMARY KEY, id_aluno integer NOT NULL, id_disciplina integer NOT NULL, nota double precision NOT NULL, data date NOT NULL, status character varying(11) NOT NULL, FOREIGN KEY (id_aluno) REFERENCES aluno (id), FOREIGN KEY (id_disciplina) REFERENCES disciplina (id) ) Quadro 6. Anotações para os auto-incrementos nas entidades Aluno.java @SequenceGenerator(name=”aluno_id_seq”, sequenceName=”aluno_id_seq”, allocationSize=1) @GeneratedValue(strategy=GenerationType.SEQUENCE, generator=”aluno_id_seq”) Instituicao.java @SequenceGenerator(name=”instituicao_id_seq”, sequenceName=”instituicao_id_seq”,allocationSize=1) @GeneratedValue(strategy=GenerationType.SEQUENCE, generator=”instituicao_id_seq”) Disciplina.java @SequenceGenerator(name=”disciplina_id_seq”, sequenceName=”disciplina_id_seq”, allocationSize=1) @GeneratedValue(strategy=GenerationType.SEQUENCE, generator=”disciplina_id_seq”) Nota.java @SequenceGenerator(name=”nota_id_seq”, sequenceName=”nota_id_seq”, allocationSize=1) @GeneratedValue(strategy=GenerationType.SEQUENCE, generator=”nota_id_seq”) T.I.S. 2012; 1 (1): 35-53 42 Web Service no ambiente escolar: um estudo de caso Quadro 7. Métodos do classe InstituicaoDAO private static EntityManagerFactory emf; private static EntityManager em; private static void conectar() { emf = Persistence.createEntityManagerFactory(“WSHistorico2PU”); em = emf.createEntityManager(); } private static void desconectar() { em.close(); emf.close(); } public static void inserir(Instituicao instituicao) { conectar(); try { em.getTransaction().begin(); em.persist(instituicao); em.getTransaction().commit(); desconectar(); } } public static Instituicao recuperarPorCnpj(String cnpj) { conectar(); try { Instituicao instituicao = (Instituicao) em.createNamedQuery(“Instituicao. setParameter(“cnpj”, cnpj).getSingleResult(); return instituicao; } catch (Exception e) { return null; desconectar(); } } public static boolean validarChave(Instituicao instituicao, String chave) { try { return chave.equals(instituicao.getChave()); } catch (Exception e) { return false; } } 43 T.I.S. 2012; 1 (1): 35-53 Quadro 8. Métodos da classe DisciplinaDAO private static EntityManagerFactory emf; private static EntityManager em; private static void conectar() { emf = Persistence.createEntityManagerFactory(“WSHistorico2PU”); em = emf.createEntityManager(); } private static void desconectar() { em.close(); emf.close(); } public static void inserir(Disciplina disciplina) { conectar(); try { em.getTransaction().begin(); em.persist(disciplina); em.getTransaction().commit(); desconectar(); } } public static Disciplina recuperarPorInstituicaoENome(Instituicao instituicao, String nome) { conectar(); try { Disciplina disciplina = (Disciplina) em.createQuery(“SELECT d FROM Disciplina AS d WHERE (d.instituicao.cnpj = ‘” + instituicao.getCnpj() + “’) AND (d.nome = ‘” + nome + “’)”).getSingleResult(); return disciplina; } catch (Exception e) { return null; desconectar(); } } T.I.S. 2012; 1 (1): 35-53 44 Web Service no ambiente escolar: um estudo de caso Quadro 9. Métodos da classe AlunoDAO private static EntityManagerFactory emf; private static EntityManager em; private static void conectar() { emf = Persistence.createEntityManagerFactory(“WSHistorico2PU”); em = emf.createEntityManager(); } private static void desconectar() { em.close(); emf.close(); } public static void inserir(Aluno aluno) { conectar(); try { em.getTransaction().begin(); em.persist(aluno); em.getTransaction().commit(); desconectar(); } } public static Aluno recuperarPorCpf(String cpf) { conectar(); try { setParameter(“cpf”, cpf) .getSingleResult(); return aluno; } catch (Exception e) { return null; desconectar(); } } public static boolean validarChave(Aluno aluno, String chave) { try { return chave.equals(aluno.getChave()); } catch (Exception e) { return false; } } 45 T.I.S. 2012; 1 (1): 35-53 Quadro 10. Métodos da classe NotaDAO private static EntityManagerFactory emf; private static EntityManager em; private static void conectar() { emf = Persistence.createEntityManagerFactory(“WSHistorico2PU”); em = emf.createEntityManager(); } private static void desconectar() { em.close(); emf.close(); } public static void inserir(Nota nota) { conectar(); try { em.getTransaction().begin(); em.persist(nota); em.getTransaction().commit(); desconectar(); } } public static void alterar(Nota nota) { conectar(); try { em.getTransaction().begin(); em.merge(nota); em.getTransaction().commit(); desconectar(); } } public static Nota recuperarPorDisciplinaAlunoEData(Disciplina disciplina, Aluno aluno, Date data) { SimpleDateFormat dataMascara = new SimpleDateFormat(“yyyy-MM-dd”); conectar(); try { Nota nota = (Nota) em.createQuery(“SELECT n FROM Nota AS n WHERE (n.disciplina.nome = ‘” + disciplina.getNome() + “’) AND (n.aluno.cpf = ‘” + aluno.getCpf() + “’) AND (n.data = ‘” + dataMascara.format(data) + “’)”).getSingleResult(); return nota; } catch (Exception e) { return null; desconectar(); } } public static List<Nota> recuperarTodosPorAluno(Aluno aluno) { conectar(); try { List<Nota> notas = em.createQuery(“SELECT n FROM Nota AS n WHERE (n.aluno. cpf = ‘” + aluno.getCpf() + “’) ORDER BY n.data ASC”).getResultList(); return notas; } catch (Exception e) { return null; desconectar(); } } T.I.S. 2012; 1 (1): 35-53 46 Web Service no ambiente escolar: um estudo de caso Quadro 11. Métodos da classe InstituicaoFacade public static void inserir(Instituicao instituicao) { InstituicaoDAO.inserir(instituicao); } public static Instituicao recuperarInstituicaoPorCnpj(String cnpj) { return InstituicaoDAO.recuperarPorCnpj(cnpj); } public static boolean validarChaveInstituicao(Instituicao instituicao, String chave) { return InstituicaoDAO.validarChave(instituicao, chave); } Quadro 12. Métodos da classe DisciplinaFacade public static void inserir(Disciplina disciplina) { DisciplinaDAO.inserir(disciplina); } public static Disciplina recuperarDisciplinaPorInstituicaoENome(Instituicao instituicao, String nome) { return DisciplinaDAO.recuperarPorInstituicaoENome(instituicao, nome); } Quadro 13. Métodos da classe AlunoFacade public static void inserir(Aluno aluno) { AlunoDAO.inserir(aluno); } public static Aluno recuperarAlunoPorCpf(String cpf) { return AlunoDAO.recuperarPorCpf(cpf); } public static boolean validarChaveAluno(Aluno aluno, String chave) { return AlunoDAO.validarChave(aluno, chave); } Quadro 14. Métodos da classe NotaFacade public static void inserir(Nota nota) { NotaDAO.inserir(nota); } public static void alterar(Nota nota) { NotaDAO.alterar(nota); } public static Nota recuperarNotaPorDisciplinaAlunoEData(Disciplina disciplina, Aluno aluno, Date data) { return NotaDAO.recuperarPorDisciplinaAlunoEData(disciplina, aluno, data); } public static List<Nota> recuperarTodosNotaPorAluno(Aluno aluno) { return NotaDAO.recuperarTodosPorAluno(aluno); } 47 T.I.S. 2012; 1 (1): 35-53 Quadro 15. Métodos da classe Chave static Random random = new Random(); public static String gerar() { String chave = “”; for (int i = 0; i < 8; i++) chave += Integer.toHexString(random.nextInt(16)); return chave.substring(0, 4) + “-” + chave.substring(4); } solicitarHistorico <aluno> <nome>...</nome> <instituicao> <nome>...</nome> <disciplina> <nota> <nota>...</nota> <data>...</data> <status>...</status> </nota> </disciplina> </instituicao> </aluno> Quadro 17. Erro do método solicitarHistorico <erro>...</erro> T.I.S. 2012; 1 (1): 35-53 48 Web Service no ambiente escolar: um estudo de caso Quadro 18. Método solicitarHistorico @WebMethod(operationName = “solicitarHistorico”) public String solicitarHistorico(@WebParam(name = “cpf”) String cpf, @WebParam(name = “chave”) String chave) { SimpleDateFormat dataMascara = new SimpleDateFormat(“dd-MM-yyyy”); try { String lista = “”; // validações de entrada if(cpf == null) { throw new Exception(“CPF não fornecido!”); } if(chave == null) { throw new Exception(“Chave de acesso não fornecida!”); } Aluno aluno = AlunoFacade.recuperarAlunoPorCpf(cpf); if(aluno != null) { if(AlunoFacade.validarChaveAluno(aluno, chave)) { // recuperar as notas List<Nota> notas = NotaFacade.recuperarTodosNotaPorAluno(aluno); lista += “<aluno>” + “<nome>” + aluno.getNome() + “</nome>”; Instituicao instituicaoTMP = null; for (Nota nota : notas) { if(!nota.getDisciplina().getInstituicao().equals(instituicaoTMP)) { if(instituicaoTMP != null) { lista += “</instituicao>”; } instituicaoTMP = nota.getDisciplina().getInstituicao(); lista += “<instituicao>” + “<nome>” + instituicaoTMP.getNome() + “</nome>”; } lista += “<disciplina>” + “<nome>” + nota.getDisciplina().getNome() + “</nome>” + “<nota>” + “<nota>” + nota.getNota() + “</nota>” + “<status>” + nota.getStatus() + “</status>” + “<data>” + dataMascara.format(nota.getData()) + “</data>” + “</nota>” + “</disciplina>”; } if(instituicaoTMP != null) { lista += “</instituicao>”; } lista += “</aluno>”; } else { throw new Exception(“Chave inválida!”); } } else { throw new Exception(“Aluno inválido!”); } return lista; } catch (Exception e) { return “<erro>” + e.getMessage() + “</erro>”; } } 49 T.I.S. 2012; 1 (1): 35-53 cadastrarNota <instituicao> <cnpj>...</cnpj> <nome>...</nome> <chave>...</chave> </instituicao> <disciplina> <nome>...</nome> </disciplina> <aluno> <cpf>...</cpf> <nome>...</nome> <chave>...</chave> </aluno> <nota> <nota>...</nota> <data>...</data> <status>...</status> </nota> Quadro 20. Método cadastrarNota @WebMethod(operationName = “cadastrarNota”) public String cadastrarNota(@WebParam(name = “insCnpj”) String insCnpj, @WebParam(name = “insNome”) String insNome, @WebParam(name = “insChave”) String insChave, @WebParam(name = “disNome”) String disNome, @WebParam(name = “aluCpf”) String aluCpf, @WebParam(name = “aluNome”) String aluNome, @WebParam(name = “aluChave”) String aluChave, @WebParam(name = “ntNota”) String ntNota, @WebParam(name = “ntData”) String ntData, @WebParam(name = “ntStatus”) String ntStatus) { SimpleDateFormat dataMascara = new SimpleDateFormat(“dd-MM-yyyy”); dataMascara.setLenient(false); try { if(insCnpj == null) { throw new Exception(“CPNJ da instituição não fornecido!”); } // recuperar a instituição (se existir) Instituicao instituicao = InstituicaoFacade.recuperarInstituicaoPorCnpj(insCnpj); if(instituicao == null) { // instituição não existe if(insNome == null) { throw new Exception(“Nome da instituição não fornecido!”); } if(insNome.length() > 100) { throw new Exception(“Nome da instituição maior que 100 caracteres!”); } } else { if(!InstituicaoFacade.validarChaveInstituicao(instituicao, insChave)) { throw new Exception(“Chave de acesso da instituição inválida!”); } } if(disNome == null) { throw new Exception(“Nome da disciplina não fornecido!”); } // recuperar a disciplina (se existir) T.I.S. 2012; 1 (1): 35-53 50 Web Service no ambiente escolar: um estudo de caso Disciplina disciplina = DisciplinaFacade. recuperarDisciplinaPorInstituicaoENome(instituicao, disNome); if(disciplina == null) { // disciplina não existe if(disNome.length() > 100) { throw new Exception(“Nome da instituição maior que 100 caracteres!”); } } if(aluCpf == null) { throw new Exception(“CPF do aluno não fornecido!”); } // recuperar o aluno (se existir) Aluno aluno = AlunoFacade.recuperarAlunoPorCpf(aluCpf); if(aluno == null) { // aluno não existe if(aluNome == null) { throw new Exception(“Nome do aluno não fornecido!”); } if(aluNome.length() > 100) { throw new Exception(“Nome do aluno maior que 100 caracteres!”); } } else { if(!AlunoFacade.validarChaveAluno(aluno, aluChave)) { throw new Exception(“Chave de acesso do aluno inválida!”); } } if(ntNota == null) { throw new Exception(“Nota não fornecida!”); } try { Double.parseDouble(ntNota); } catch (Exception e) { throw new Exception(“Nota inválida!”); } if((Double.parseDouble(ntNota) < 0) || (Double.parseDouble(ntNota) > 10)) { throw new Exception(“Nota fora da faixa permitida (0..10)!”); } if(ntData == null) { throw new Exception(“Data da nota não fornecida!”); } try { dataMascara.parse(ntData); } catch (Exception e) { throw new Exception(“Data da nota inválida (dd-mm-aaaa)!”); } if(ntStatus == null) { throw new Exception(“Status da nota não fornecido!”); } if(ntStatus.length() > 100) { } if(instituicao == null) { // instituição não existe - inserir a instituição instituicao = new Instituicao(); instituicao.setCnpj(insCnpj); instituicao.setNome(insNome); insChave = Chave.gerar(); instituicao.setChave(insChave); InstituicaoFacade.inserir(instituicao); 51 T.I.S. 2012; 1 (1): 35-53 } if(disciplina == null) { // disciplina não existe - inserir a disciplina disciplina = new Disciplina(); disciplina.setInstituicao(instituicao); disciplina.setNome(disNome); DisciplinaFacade.inserir(disciplina); } if(aluno == null) { // aluno não existe - inserir o aluno aluno = new Aluno(); aluno.setCpf(aluCpf); aluno.setNome(aluNome); aluChave = Chave.gerar(); aluno.setChave(aluChave); AlunoFacade.inserir(aluno); } // recuperar a nota (se existir) Nota nota = NotaFacade.recuperarNotaPorDisciplinaAlunoEData(disciplina, aluno,dataMascara.parse(ntData)); if(nota == null) { // nota não existe - inserir nota nota = new Nota(); nota.setDisciplina(disciplina); nota.setAluno(aluno); nota.setNota(Double.parseDouble(ntNota)); nota.setData(dataMascara.parse(ntData)); nota.setStatus(ntStatus); NotaFacade.inserir(nota); } else { // nota existe - atualizar nota.setNota(Double.parseDouble(ntNota)); nota.setStatus(ntStatus); NotaFacade.alterar(nota); } return “<instituicao>” + “<cnpj>” + instituicao.getCnpj() + “</cnpj>” + “<nome>” + instituicao.getNome() + “</nome>” + “<chave>” + instituicao.getChave() + “</chave>” + “</instituicao>” + “<disciplina>” + “<nome>” + disciplina.getNome() + “</nome>” + “</disciplina>” + “<aluno>” + “<cpf>” + aluno.getCpf() + “</cpf>” + “<nome>” + aluno.getNome() + “</nome>” + “<chave>” + aluno.getChave() + “</chave>” + “</aluno>” + “<nota>” + “<nota>” + nota.getNota() + “</nota>” + “<data>” + dataMascara.format(nota.getData()) + “</data>” + “<status>” + nota.getStatus() + “</status>” + “</nota>”; } catch (Exception e) { return “<erro>” + e.getMessage() + “</erro>”; } } T.I.S. 2012; 1 (1): 35-53 52 Web Service no ambiente escolar: um estudo de caso Quadro 21. Teste do cadastrarNota webservices.HistoricoService servico = new webservices.HistoricoService(); webservices.Historico porta = servico.getHistoricoPort(); String resultado = porta.cadastrarNota(“55732312000181”, “Escola de teste”, null, “Disciplina de teste”, “73548738966”, “Aluno de teste”, null, “9.0”, “27-09-2010”, “Aprovado”); String instituicaoChave = null; String alunoChave = null; if(resultado.indexOf(“<erro>”) < 0) { String instituicao = resultado.substring(resultado. indexOf(“<instituicao>”), resultado.indexOf(“</instituicao>”)); if(instituicao.indexOf(“<chave>”) >= 0) instituicaoChave = instituicao.substring(instituicao.indexOf(“<chave>”) + 7, instituicao.indexOf(“</chave>”)); String aluno = resultado.substring(resultado.indexOf(“<aluno>”), resultado.indexOf(“</aluno>”)); if(aluno.indexOf(“<chave>”) >= 0) alunoChave = aluno.substring(aluno.indexOf(“<chave>”) + 7, aluno. indexOf(“</chave>”)); // gravar as chaves no banco da aplicação } else { // tratar o erro aqui } 53 T.I.S. 2012; 1 (1): 35-53