sexta-feira, 2 de julho de 2010

Google App Engine + Adobe Flex - Parte 3

Olá pessoal, vou continuar com a epopéia GAE + FLEX focando um pouco do Spring.

No trabalho aprendi a usar o Spring para basicamente 4 coisas:
  1. Injeção de Dependências
  2. Segurança
  3. Transações
  4. Comunicação com Flex via BlazeDS
Como já citei em posts anteriores, eu simplesmente baixei o plugin do GAE e fui tentar colocar tudo isso para funcionar com o que eu já sabia até então. Depois de trocar o BlazeDS pelo GraniteDS (Post 2) e seguir o tutorial desse último framework, consegui fazer a comunicação remota com o Flex de forma muito parecida de como fazia com o Blaze, mudando apenas a anotação para exportar os serviços de acesso remoto.
Foi então que surgiu a primeira dor de cabeça: a maioria dos meus serviços eram anotados com @Transaction, já que eu queria que o Spring se encarregasse das transações para mim. Contudo, recebi algumas exceções em alguns desses métodos anotados. Pesquisei um pouco e achei a explicação na própria documentação do GAE sobre transações. 
As transações do serviço Google são limitadas a entidades pertencentes a um mesmo grupo. Para exemplificar, eu estava tentando salvar todos Estados Brasileiros em um serviço, mas ele não deixava porque cada estado pertencia a um grupo diferente. Isso me levou a não mais utilizar o controle de transação do Spring, então retirei todas dependências desse controle de transação, bem como da parte de controle de ORM do Spring. Passei então a utilizar o Próprio PersistenceManager do JDO para realizar as operações de persistência.
Feito isso, o servidor passou a funcionar, executando minhas chamadas remotas com sucesso, inclusive utilizando a segurança de ROLES básica fornecida pelo Spring Security, segurança essa suportada pelo Granite. Passei a ler a documentação do Spring Security sobre segurança para aprender a fazer casos mais granulares de segurança, como por exemplo, deixar um administrador de uma loja alterar somente os recursos de sua loja e não de outras. Não sei se por preguiça minha ler ou se porque realmente a documentação do Spring Security é extensa, eu definitivamente não consegui encontrar uma resposta simples para esse problema. Se fosse só para utilizar o Spring Security para autenticação básica de Roles, a verdade é que seria melhor eu fazer tudo na mão. Então também removi a parte de segurança do Framework da minha aplicação.
Com as eliminação dos dois módulos do Spring, eu efetivamente usaria o framework apenas para injeção de dependências e pretendia inclusive gerar Wrapers das interfaces do GAE que são acessadas por métodos estáticos, como por exemplo o UserService e o PersistenceManagerFactory, de forma a facilitar a confecção de meus testes unitários. Na hora de executar alguns testes com chamadas remotas no servidor, percebi pelos logs que a contagem de CPU estava muito alta, isso porque por várias vezes ele subia o contexto do Spring.
Constatado o problema, mais uma vez fui pesquisar para encontrar uma resposta. Em alguns fóruns encontrei o X da questão. Quando sua aplicação não recebe requisições por certo tempo, o GAE simplesmente "desativa" sua aplicação, inicializando a mesma só quando uma nova requisição ocorre. Isso até pode fazer sentido em termos de uso de recursos, mas uma vez que a inicialização do contexto do Spring é custosa em termos de CPU, eu acabaria excedendo minha cota desse recurso em pouco tempo.
Uma solução alternativa que encontrei na internet foi utilizar "tarefas agendadas" para chamar um serviço que não fazia nada, só para "enganar" o GAE e fazê-lo não desativar minha App por inatividade. Pessoalmente achei isso uma grande gambiarra e tomei uma decisão radical: eliminei todo o Spring do meu projeto. Sei que os amantes do framework ao lerem isso vão achar loucura, mas isso teve um ponto extremamente positivo: acabei criando uma arquitetura própria que não só resolveu o problema de performance na inicialização, como também permitiu com que a configuração do GraniteDS fosse extremamente pequena no Java e a configuração no Flex fosse nula. Sim, isso mesmo, configuração nula no Flex! Bom, nula é muito forte, mas definitivamente bem transparente ao programador...rsPretendo organizar essa parte de comunicação do código em um projeto open source separado para quem sabe tornar a vida dos programadores em Flex mais simples. Nessa semana irei dar um curso de flex para uns amigos do trabalho e pretendo documentar as idéias básica do protótipo aqui nesse blog. Então aguardem as cenas dos próximos capítulos...

2 comentários:

Marcelo Magalhães disse...

Caro Renzo, estou criando uma APP com GAE/J e FLEX usando GraniteDS como comunicação. Inicialmente fiz tudo na mão e depois pensei em adicionar o Spring (security + DI) para resolver a parte de expor os serviços Java ao Flex. Ai li seu post e percebi que o ganho não valeria devido ao fato do ColdStart do GAE. Como você "radicalmente" eliminou o Spring do seu framework, como resolveu a questão da exposição dos serviços ao Flex. Hoje o que tenho é a configuração de cada classe de serviço Java no services-config.xml. Mas penso que em um projeto grande (diversos serviços) ficar adicionando manualmente cada serviço ao XML é custoso e pode gerar erros. Como você está fazendo isso? recaptcha_challenge_field=03AHJ_Vuum0iiVzb3UsohMrgbCCvQUSivneMDs2FM1C5cerhSeIvvFB6qRBweeT3V610Ib6maK_q16ztNxWDG-f2PNULylK2BNqLubCMgA18N6rfSeF3kF6EiA9Pd__j1Pvs3uijg2yQ4NLfIVM-QEv44kV2iCjAZAYQ

Renzo disse...

Olá Marcelo,

Na época eu escrevi um framework open source próprio: http://code.google.com/p/jfera/
http://jfera.nuccitec.com.br/content/index.php

Depois disso, fiz umas experiencias e acabei trabalhando com Python no backend, por achar mais adequado ao GAE, e em vez de trabalhar com o AMF, hoje trabalho com chamadas http comuns, enviando JSON para os cliente, que podem ser em Flex ou não. A vantagem é que justamente eu posso expor os serviços web em um formato que pode ser utilizado por qualquer cliente.

Na época o que usava o Flex ele não tinha biblioteca para fazer o parsing de JSON, então eu utilizava o https://github.com/mikechambers/as3corelib. Acho que agora tem biblioteca de parsing nativa.

Enfim, espero ter contribuido.

Abs