JHTTPd 0.1 por Demian Lessa =========================== Projeto ======= 1. Threads - a idéia inicial era trabalhar com pools de threads para minimizar a sobrecarga de criar threads o tempo todo, sempre que surge uma nova solicitação HTTP; no entanto, após alguma leitura e também tendo em vista a aplicação acadêmica deste exercício, decidi por bem deixar de lado os pools de threads (vistos com certa preocupação por Bloch em Effective Java, item 5) e concentrar-me na arquitetura das classes e interfaces. Seguindo a construção da arquitetura, pensei em trabalhar com dois tipos básicos de threads: threads servidoras, que escutariam numa porta TCP e delegariam a execução do processamento de cada uma das solicitações a threads clientes. Infelizmente, depois de quebrar a cabeça com as hierarquias e chegar a uma solução ao menos razoável, verifiquei que, num mesmo processo, a JVM não me permitiria ter mais de um ServerSocket bloqueando simulteamente, mesmo que em threads distintos. Tentei utilizar o ServerSocket com timeout, mas também só me tomou tempo, sem resultados; tentei, finalmente, fazer das threads servidoras, threads daemon, também sem sucesso. Finalmente, tive que abandonar a opção de ter três serviços rodando simultaneamente no mesmo processo. Para ter isso funcionando, só mesmo um pouco mais de experiência… 2. Handlers - a idéia principal dos manipuladores era ter uma hierarquia de classes e interfaces que me desse flexibilidade para trabalhar com vários tipos de serviços (e demandas). Por isso, comecei com interfaces simples e, ao ver a real necessidade de uma implementação concreta, acabei com uma interface um tanto quanto grande demais… Felizmente, estava boa o suficiente para resolver os problemas propostos. Depois das interfaces, vinha a questão de como implementar manipuladores concretos, cobrindo apenas parte das especificações do projeto, e ainda assim ter a flexibilidade de estender o funcionamento do servidor para permitir a manipulação de páginas dinâmicas. Primeiramente, resolvi o problema mais simples, o das páginas estáticas. Com algum trabalho, acabei conseguindo oferecer suporte aos tipos mime básicos (texto e imagem) através das propriedade de cada web e, quando eram desconhecidos, eram simplesmente enviados ao cliente como um stream de octetos, exatamente como sugerido pela RFC. Aproveitei a chance para implementar também os arquivos padrão (também configurável), que são procurados quando o recurso solicitado é identificado como sendo uma pasta; quando um desses arquivos é encontrado, ele é retornado; senão, uma listagem do diretório (simiplificada) é apresentada. Finalmente, várias foram as oportunidades em que se fez necessário o tratamento de erros; portanto, foi necessário criar um esquema simples de delegação do tratamento de erros para um método, cujo papel principal era o de retornar ao usuário uma página HTML com alguma informação a respeito do erro e, a esse respeito, uma cópia (um dump) da solicitação HTTP conforme montada pelo manipulador. Feito isso, faltava apenas resolver a parte das páginas dinâmicas. Eu podia delegar isso para uma outra classe, mas pensei melhor e resolvi que essa classe podia pelo menos delegar a tarefa de processar uma solicitação já montada, caso houvesse interesse. Então, utilizando as interfaces previamente construídas, montei um esquema através do qual o processamento da página só ocorre se nenhuma outra classe externa faça esse processamento antes. Assim, é possível registrar um sem número de classes para processamento dinâmico das solicitações e, em cada uma dessas classes, apenas processar o que for de interesse, deixando sem processamento (para outras classes ou para o manipulador padrão) o que não for do seu interesse. Basicamente, então, a classe JHTTPDefaultHandler faz o seguinte: monta o request (JHTTPRequest); verifica se há classes registradas para processamento; se há: localiza e carrega cada classe, passando a solicitação e verificando se houve processamento; se não há, ou se nenhuma das classes carregadas processou: ocorre o processamento padrão, que é o processamento de páginas estáticas. Os métodos POST, GET e HEAD são suportados. Além disso, muito pouco do protocolo é suportado- apesar disso, bastante coisas pode ser feita com o servidor, caso haja mais tempo para expandir o projeto. Bibliografia: ============= 1. Bloch, Joshua. Effective Java. Sun. 2. Darwin, Ian F. Java Cookbook. O'Reilly. 3. Flanagen, David. Java Examples in a Nutshell. O'Reilly. 4. Flanagen, David. Java in a Nutshell. O'Reilly. 5. Eckel, Bruce. Thinking in Java. PH PTR. 6. Kurose, James F. e outros. Computer Networking. 7. sites na Internet, códigos fonte gratuitos. Hierarquia de Interfaces: ========================= HANDLERS (5) 1. JHTTPRequestHandler (suporta o processamento de solicitações HTTP) 2. JHTTPResponseHandler (suporta o processamento das respostas HTTP) 3. JHTTPDualHandler (combina as interfaces acima, 1 e 2) 4. JHTTPHandler (estende 3 e é utilizada para implementar o JHTTPDefaultHandler) 5. JHTTPCustomHandler (estende a interface 2, e é a interface que classes devem implementar se desejam estender o funcionamento do servidor através da utilização de páginas dinâmicas) ERROS (1) 1. JHTTPError (especifica a interface para tratamento de erros) OUTRAS (2) 1. JHTTPMethod (especifica as constantes de métodos utilizadas no JHTTPd) 2. JHTTPProperties (especifica as constantes de propriedades utilizadas no JHTTPd) TOTAL: 8 interfaces Hierarquia de Classes: ====================== HANDLERS (2) 1. JHTTPDefaultHandler (implementa o tratamento HTTP estático padrão e delega a manipuladores que implementam a interface JHTTPCustomHandler a tarefa de tratar páginas de conteúdo dinâmico) 1.1 JHTTPAdmHandler (estende a JHTTPDefaultHandler para promover a administração do servidor HTTP através do próprio HTTP, a partir de uma porta específica para a administração) ERROS (1) 1. JHTTPErrorHandler (implementa JHTTPHandler e é utilizada por JHTTPDefaultHandler) PROPERTIES (3) 1. JHTTPFileProperties (implementa a estrutura básica para carga e verificação das propriedades do servidor e de cada site web em especial) 1.1 JHTTPWebProperties (estende a JHTTPFileProperties especificando as propriedade de cada site web e oferecendo valores padrão para elas) 1.1.1 JHTTPServerProperties (estende a JHTTPWebProperties especificando as demais propriedades que se aplicam também ao servidor) THREADS (10) 1. JHTTPThread (abstrata, define a propriedade protegida server, que relaciona as threads com a classe do servidor) 2. JHTTPServerThread (abstrata, define o formato das threads servidoras, como escutar na porta designada e como disparar um processo de trabalho) 2.1. JHTTPWebServiceThread (processamento de solicitações HTTP) 2.1.1 JHTTPAdmServiceThread (processamento de solicitações HTTP de administração) 2.2. JHTTPLogServiceThread (processamento de solicitações de log: não implementada) 3. JHTTPClientThread (abstrata, define o formato das threads clientes, como devem processar suas tarefas) 3.1 JHTTPWebClientThread (abstrata, define como todas as threads de processamento HTTP devem se comportar, delegando seu processamento a uma classe que implemente a interface JHTTPDualHandler) 3.1.1 JHTTPWorkerThread (atende solicitações HTTP) 3.1.1.1 JHTTPAdmClientThread (atende solicitações HTTP de administração) 3.2 JHTTPLogClientThread (atende solicitações de log: não implementada) OUTRAS (4) 1. JHTTPHTMLBuilder (classe auxiliar na construção de HTML) 2. JHTTPServer (implementação de uma classe para representar o servidor propriamente dito; deveria ser mais que isso, sendo a classe responsável pelos três serviços planejados: web, log e administração) 3. JHTTPInvalidRequestException (exceção de tratamento de solicitação HTTP) 4. JHTTPErrorHandler (implementação da interface JHTTPError para tratamento de erros nas solicitações HTTP, vide JHTTPDefaultHandler) TOTAL: 20 classes e mais a classe ServerTest para rodar o servidor!