Fórum Interface e migração de legado #6906

18/06/2009

0

Olá Pessoal, Fiquei muito contente com a disponibilização deste canal da Devmedia que certamente vai ajudar muito àqueles que tem dúvidas sobre este tema. São ideias como estas que fazem a roda girar e o conhecimento contaminar a todos!! Muito bom mesmo Vamos lá. Estou iniciando o desenvolvimento de uma pequena aplicação de relatórios gerenciais e de auditoria para um determinado setor da área de serviços. Mesmo com o meu contato com alguns cursos em Java, semprei achei que ficou faltando um mapa mais geral para o entendimento da arquitetura de uma aplicação. A descrição do ambiente e as minhas dúvidas estão relacionadas ao diagrama abaixo:     O texto que explica o ambiente e as minhas dúvidas é este:   # Descrição Dúvida / Considerações 1 Trata-se de um sistema legado que possui hoje mais de 300 tabelas em Oracle e SQL Server. Não possuímos, em tese, permissão para criar nenhum objeto neste banco e assim as consultas são feitas diretamente nas tabelas. As consultas em geral utilizam no máximo 10 tabelas pois estão relacionadas a um determinado tema da aplicação. Para a migração futura da aplicação construiremos um novo modelo de dados a partir deste atual. Obviamente a utilização do banco de dados deve ser transparente para a aplicação 2 Camada de persistência Hoje esta camada não existe e gostaria de saber a necessidade da mesma em função das características do projeto descritas nos próximos tópicos 3 Biblioteca de SQL. São aproximadamente 30 SQLs que recuperam informações do banco legado. Estas consultas são de média complexidade e envolvem join com várias tabelas, group by, having e sub-selects. Os campos retornados entretanto são muito próximos. Hoje estas consultas já existem e estão armazenadas em arquivos texto. Estas consultas poderiam ou deveriam ser transformadas em xml ou Properties para serem incorporadas ao código da aplicação? Além disto, existe a necessidade é que o texto destas consultas não deve estar acessível aos usuários ou a outros desenvolvedores seja diretamente no código ou pela edição dos arquivos xml ou Properties. Outra consideração é que o número de consultas (e SQLs) pode aumentar mas a incorporação na aplicação deve ser facilitada 4 Aplicação Java. Hoje para esta aplicação cada SQL é executado dentro do código de um programa Java distinto, ou seja, tenho 30 programas Java. Atualmente um único operador chama cada programa para gerar um arquivo texto que é importado posteriormente para uma planilha. Como esta aplicação será acessada via Web e por mais de um operador futuramente não sei se o correto é continuar com a opção de um programa para cada SQL ou um único que faça a chamada para o SQL correspondente. Obviamente o retorno dos dados, apesar de muito similar, possui diferenças entre as consultas. Faz sentido falar em POJO para esta camada? 5 Servidor de aplicação Hoje esta camada não existe mas vai existir em função da utilização da Web como camada de apresentação. A dúvida é que ambiente e porque usar para esta camada? Tomcat puro, JBoss ou outro qualquer? 6 Web. Todas as consultas estarão disponíveis via browser em Intra e Internet Que tecnologia utilizar e porque para esta camada? HTML puro, JSP, JSF, Adobe Flex ou outras? 7 Relatórios A dúvida aqui é qual a ferramenta que melhor se integra à aplicação em termos de Relatórios? Jasper, Birt ou outra?   Pode parecer um pouco extenso mas certamente para o pessoal da Devmedia vai ser muito tranquilo. A partir destas respostas e considerações vou começar a construir a aplicação segundo a orientação de Vocês. Conto com a ajuda e agradeço desde já   Abraços Oswaldo Castro
Oswaldo Castro

Oswaldo Castro

Responder

Posts

19/06/2009

Henrique Weissmann

Ola Oswaldo,
bem: vamos às suas dúvidas: Camada de persistência: no caso por você exposto, o Hibernate (ou qualquer outro ORM) cairá como uma luva.Pelo que você nos descreve, há uma série de arquivos .sql, cada um representando uma entidade do seu sistema, correto? Neste caso, você poderá criar uma entidade para cada arquivo SQL (dado que não conheço estes arquivos, estou chutando esta possibilidade. pode ser que em um arquivo .sql haja mais de uma entidade) e em seguida mapeá-los usando o Hibernate.Uma camada de persistência entra bem em sua aplicação por uma única razão: caso a estrutura de dados sofra alterações no futuro, você saberá exatamente aonde deverão ser feitas as alterações, ou seja, em um único lugar: na camada de persistência.
Com relação a transformar ou não os seus arquivos .sql em properties ou documentos no formato XML: há algumas opções para este caso.Caso opte por usar uma ferramenta de ORM, você poderá mantê-los apenas para fins de documentação, uma vez que o conteúdo destes arquivos acabará por ser incluido nos arquivos de mapeamento desta ferramenta.Outra opção consiste na utilização de um framework como o BoxSQL (https://boxsql.dev.java.net/) para lidar com estes arquivos .sql pra você. No caso, este framework irá ler o conteúdo destes comandos SQL e, basicamente, executar a mesma tarefa que o Hibernate (ou qualquer outro ORM) faria.Como esta aplicação será acessada via Web e por mais de um operador futuramente não sei se o correto é continuar com a opção de um programa para cada SQL ou um único que faça a chamada para o SQL correspondente. Obviamente o retorno dos dados, apesar de muito similar, possui diferenças entre as consultas.
Faz sentido falar em POJO para esta camada?
Faz muito sentido. Tanso se for utilizar um ORM (como Hibernate) quanto uma outra opção como o Box SQL que descrevi na pergunta anterior.No caso, pense nos POJOs como as entidades do seu sistema, que serão populados com base nas informações presentes no banco de dados. Lembre-se também que POJOs não são apenas classes que armazenam dados. Elas também contém métodos para gerenciar as informações armazenadas nas mesmas, ou seja, também possuem parte importante da lógica de negócios de sua aplicação.Sobre o servidor de aplicaçãoHà diversos servidores de aplicação presentes no mercado hoje. Os mais populares (gratuitos) consiste no JBoss, Glassfish e Tomcat.No caso, o Tomcat é apenas um servidor servlet, ou seja, ele apenas oferece suporte a aplicações web baseadas em servlets apenas, enquanto o JBoss e o Glassfish também oferecem suporte a EJBs, JNDIs e outros componentes da plataforma Java Enterprise Edition.Se sua aplicação for apenas web, ou seja, se não utilizar nenhum dos outros recursos avançados da plataforma Java Enterprise Edition, o Tomcat já está de bom tamanho (mesmo porque, no caso do JBoss, o Tomcat é que consiste no servidor de aplicações servlet).Que tecnologia utilizar e porque para esta camada? HTML puro, JSP, JSF, Adobe Flex ou outras?Boa pergunta. No caso, não há como responder de imediato a esta sua pergunta. No entanto, da pra pelo menos dar alguns palpites:* JSF é um framework que faz parte da especificação da plataforma Java Enterprise Edition. Como consequencia, voce terá mais de um fornecedor disponível, além de que, também possui a vantagem de estar trabalhando com um padrão estável de desenvolvimento.* JSP puro: fuja disto! A complexidade gerada pelo desenvolvimento de aplicações utilizando apenas JSP torna inviável qualquer projeto. Neste caso, o ideal é partir para qualquer outro framework web (QUALQUER OUTRO). No entanto, JSP irá fazer parte de basicamente todos os demais frameworks, porque é a base da camada de visualização web da plataforma JEE* Adobe Flex: lembre-se que se trata de uma tecnologia proprietária, e não de um padrão aberto. No entanto, o resultado visual com o Flex é fenomenal. Afinal de contas, é Flash o que será gerado, ao contrário de páginas HTML convencionais.* Caso queria uma abordagem ágil, pode também experimentar o Grails. http://grails.orgMas no final das contas, a escolha por qual framework utilizar é quase pessoal. Minha sugestão é: utilize a tecnologia com a qual você se sente mais familiarizado (mesmo que seja JSP puro)A dúvida aqui é qual a ferramenta que melhor se integra à aplicação em termos de Relatórios? Jasper, Birt ou outra?Todas as soluções são igualmente boas. Novamente aqui, utilize aquela com a qual você se sentir mais confortável para trabalhar.
Responder

Gostei + 0

20/06/2009

Oswaldo Castro

Obrigado pelo retorno Henrique. Vamos lá ao complemento de algumas informações:   Persistencia - Na verdade cada consulta não retorna exatamente uma entidade no conceito clássico de entidade. Cada uma destas consultas retorna um grupo de dados que apresenta as utilizações potencialmente fraudulentas de cartões de transporte (os cartões utilizados no Metrô, Trens e Ônibus da grande São Paulo). Por exemplo uma das consultas retorna as viagens realizadas pelos estudantes que utilizam o mesmo onibus em mais de 5 vezes em um periodo inferior a 4 horas. Outra consulta retorna os cartões VT (vale-transporte) que foram utilizados pelo menos 5 vezes com o mesmo cobrador em um dia de operação. Outro exemplo são consultas que retornam os cartões de doentes cronicos que realizam viagens fora das linhas estipuladas em cadastro. Desta forma cada consulta retorna informações de sobre viagens mas cada uma com um conceito diferente sobre as possibilidades de fraude. Cada uma destas consultas envolve o join de 5 a 8 tabelas diferentes. Pelo que Você falou cada um destes .sql pode ser mapeado por exemplo no Hibermate. Neste caso como ficaria uma consulta com varias tabelas com group by mapeada no Hibernate? Uma preocupação que comentei no texto anterior seria proteger estas consultas do acesso indevido. Pelo que entendi se estas consultas forem mapeadas no Hibernate elas estariam protegidas (acredito que o mesmo ocorra com o boxsql). Agora se as mesmas ficarem e arquivos xml ou Properties como isto poderia ser feito? (um pequeno exemplo de sql usando xml ou Properties já ajuda muito).   Apenas a titulo de ilustração coloco abaixo um dos sql utilizados para confirmar a possibilidade de mapeamento ORM  
select
 '01.04.'||lpad(to_char(cu.crd_snr), 10, '0') cartao_vt
 , cu.CU_CRDCHKDG digito
 ,'03.01.'||lpad(ddt.DLDT_CRDSNRCOB, 10, '0') as cartao_cobrador
 , usr.usr_name nome_cobrador
 , ddt.DLDT_PRSHRIDCOB cod_setrerj
 , pf.pf_desc cargo
 , tp.tp_nameoncard empresa
 , app.app_descshort aplicacao
 , cu.app_id cd_aplicacao
 , cu.iss_id emissor
 , dmt.veh_id onibus
 , ddt.DLDT_SHIFT turno
 , to_char(cu.cu_datetime, 'dd/mm/yyyy hh24:mi:ss') as embarque
 , to_char(ddt.DLDT_DTSTART, 'dd/mm/yyyy hh24:mi:ss') inicio_viagem
 , to_char(ddt.DLDT_DTSTOP, 'dd/mm/yyyy hh24:mi:ss') fim_viagem
 , trunc(1440*(cu.cu_datetime - ddt.DLDT_DTSTART), 1) tempo_inicio
 , trunc(1440*(ddt.DLDT_DTSTOP - cu.cu_datetime ), 1) tempo_fim
 , cu.CU_PARTFAREVALUE tarifa
 , nvl(cu.cu_tsn,0) as transacao
 , ldt.ld_desc linha
 , lmt.lm_desc nome_linha
 , ld.ldr_desc sentido
 , dlf.dlf_filename arquivo
 , ds.dvs_desc estado_operacao
 , ddt.DLDT_CRDSNRMOT as cartao_motorista
 , nvl(cu.cu_interrorcode,0) as erro
 , vm.msg_desc mensagem
 , nvl2(vm.msg_desc, vm.msg_desc, decode(cut_id, 1, '', 2, 'RECARGA')) msg1
 , cu.cu_id
 , cu.CU_PARTFARESEQNBR bolsa
from
 cardusage cu
 inner join devicelogdt ddt on ( ddt.pb_id = cu.pb_id and ddt.dlf_id = cu.dlf_id and ddt.dlmt_id = cu.dlmt_id and ddt.dldt_id = cu.dldt_id)
 left join tripmt tmt on ( cu.tmt_id=tmt.tmt_id and cu.dvs_id=tmt.dvs_id and cu.dvt_id=tmt.dvt_id and cu.ld_id=tmt.ld_id)
 inner join devicestates ds on (ds.dvt_id=ddt.dvt_id and ds.dvs_id=ddt.dvs_id)
 inner join devicelogmt dmt on ( ddt.pb_id=dmt.pb_id and ddt.dlf_id=dmt.dlf_id and ddt.dlmt_id=dmt.dlmt_id)
 inner join devicelogfiles dlf on (dlf.pb_id = dmt.pb_id and dlf.dlf_id = dmt.dlf_id)
 inner join cards c on c.crd_snr = ddt.DLDT_CRDSNRCOB and c.cd_id = 1 and c.iss_id = 3 and c.crd_status = 'A'
 inner join cardsxusers cxu on cxu.crd_snr = c.crd_snr and cxu.cd_id = c.cd_id and cxu.iss_id = c.iss_id and cxu.crdusr_status = 'A'
 inner join users usr on usr.usr_id = cxu.usr_id and usr.usr_status = 'A'
 inner join personnel prs on prs.usr_id = usr.usr_id and prs.prs_status = 'A'
 inner join personnelxprsfcts pfx on pfx.prs_id = prs.prs_id and pfx.PRSPF_STATUS = 'A'
 inner join personnelfunctions pf on pf.pf_id = pfx.pf_id
 left join linedirections ld on (ld.ldr_id = tmt.ldr_id)
 inner join linedetails ldt on (ldt.ld_id=tmt.ld_id)
 inner join linemt lmt on (ldt.lm_id = lmt.lm_id)
 inner join transportproviders tp on tp.tp_id = dmt.tp_id
 inner join applications app on app.app_id = cu.app_id and app.iss_id = 1 -- VT Fetranspor
 left join validatormessages vm on vm.msg_id = cu.cu_interrorcode
 ,
 (
 select
   cu1.crd_snr cartao_VT
   , to_char(cu1.cu_datetime, 'dd/mm/yyyy') data_operacao
   , dmt1.tp_id empresa_utilizada
 from
  cardusage cu1
  inner join  tripmt tmt on ( cu1.tmt_id=tmt.tmt_id and cu1.dvs_id=tmt.dvs_id and cu1.dvt_id=tmt.dvt_id and cu1.ld_id=tmt.ld_id)
  inner join devicelogdt ddt on ( ddt.tmt_id=tmt.tmt_id and ddt.dvs_id=tmt.dvs_id and ddt.dvt_id=tmt.dvt_id)
  inner join devicestates ds on (ds.dvt_id=ddt.dvt_id and ds.dvs_id=ddt.dvs_id)
  inner join devicelogmt dmt1 on ( ddt.pb_id=dmt1.pb_id and ddt.dlf_id=dmt1.dlf_id and ddt.dlmt_id=dmt1.dlmt_id)
 where
  cu1.app_id =400
  and cu1.iss_id = 1
--  and dmt.tp_id = 26
  and cu1.cu_datetime >= '03-Jan-2007'
  and nvl(cu1.cu_interrorcode, 0) = 0
  and cu1.CU_PARTFARESEQNBR = 1  -- elimina as duplicidades
 group by
  cu1.crd_snr
  , to_char(cu1.cu_datetime, 'dd/mm/yyyy')
  , dmt1.tp_id
 having
  count(*) >= 7 ) b
where
  cu.crd_snr = b.cartao_VT
 and to_char(cu.cu_datetime, 'dd/mm/yyyy') = b.data_operacao
 and dmt.tp_id = b.empresa_utilizada
 and cu.app_id = 400
 and cu.iss_id = 1
 and cu.cu_datetime >= '03-Jan-2007'
  and nvl(cu.cu_interrorcode, 0) <> 135   -- importante enquanto 135 não é tratado no TR
order by
 cu.crd_snr
 , cu.cu_datetime
Sobre o servidor de aplicações vamos ficar com o Tomcat  pois como Você falou não vamos utilizar nenhum recurso de JEE   Com relação a Web acho que o JSF é uma ótima opção mas se Você tiver alguma referencia sobre a integração de POJO com Adobe Flex vou dar uma olhada com muita atenção.   Finalmente pediria que Você me informasse se um dos cursos da Devmedia tem as caracteristicas próximas a esta aplicação que te descrevi ou ainda um site, livro ou outra referencia qualquer.   Obrigado mais uma vez Henrique e espero por estas informações.      
Responder

Gostei + 0

22/06/2009

Henrique Weissmann

Olá Oswaldo,

você ainda assim poderá mapear estas suas consultas sql como entidades no Hibernate. Para tal, basta que os atributos presentes em cada entidade correspondam aos campos retornados pela Tabela.

Lembre-se: para a classe de entidade, o que realmente importa são os campos da sua consulta SQL, não como eles são obtidos, ou seja, tanto faz se forem obtidos a partir de varios joins ou funções, views, etc. O que realmente importa são os campos. Sendo assim, bastaria ter uma classe de entidades com n atributos correspondendo aos n campos retornados pela sua consulta.

Agora, com relação ao modo como você mapearia no Hibernate estas suas consultas SQL. Vejo duas alternativas Oswaldo:

1) Criar views no seu banco de dados utilizando estas consultas.
    Neste caso, você mapearia as suas classes de entidade normalmente. Para o Hibernate não há muita diferença com relação ao fato de os dados estarem vindo de uma tabela ou de uma view no banco de dados.

2) Criar seu mapeamento usando SQL customizado.
    Para maiores detalhes, veja este link na documentação oficial do Hibernate: http://docs.jboss.org/hibernate/stable/core/reference/en/html_single/#querysql-load

Com relação à segurança: a solução mais simples e eficiente para evitar o risco de alguém alterar a sua base de dados legada consiste em, no próprio SGBD criar um usuário específico para a sua aplicação que só possua permissão para executar instruções SELECT na sua base de dados.
Responder

Gostei + 0

22/06/2009

Oswaldo Castro

Perfeito Henrique, Como Você mesmo diz o segredo são os campos que retornam do select. Vou criar uma entidade para cada tipo de fraude ou ainda uma interface de onde todas derivam, creio que esta seja uma boa opção correto? Com relação ao mapeamento vou recorrer mesmo ao SQL customizado via Hibernate pois não pretendo criar esta view no legado. Temos isto espalhdo em diversos Clientes no Brasil e na AL e daria uma certa dor de cabeça. Pelo que entendi também quando utilizo o Hibernate ganho uma proteção natural no código SQL que ele terá embutido (sei que não é dos maiores o que te passei de exemplo mas deu trabalho). Isto ficará interno ao Hibernate e inacessível de forma trivial dos demais não é isto? Acho que estamos para finalizar este chamado pois as informações que Você me passou além de valiosas já são suficientes (exceto por estas lançadas acima) De qualquer modo quero te agradecer bastante por ora e já antecipando que entre hoje e amanhã abrirei outo chamado (ainda relativo a Arquitetura mas mais voltado a código com leitura e gravação de arquivos binários) Fico no aguardo para finalizar ok?
Responder

Gostei + 0

22/06/2009

Henrique Weissmann

Olá Oswaldo,

bem: vamos por partes:

"Como Você mesmo diz o segredo são os campos que retornam do select. Vou criar uma entidade para cada tipo de fraude ou ainda uma interface de onde todas derivam, creio que esta seja uma boa opção correto?"

Neste caso, realmenete não sei qual a melhor alternativa para o seu caso, pois não cheguei a acessar o seu código. Sendo assim, o máximo que posso fazer consiste em dar alguns chutes ok?

1. Classes abstratas: caso existam atributos em comum entre os seus diferentes tipos de fraude, você pode incluí-los em uma classe abstrata, o que diminuirá o seu tempo de implementação das mesmas. (mas este caso somente se este tipo de informação compartilhada existir).

2. Criação de uma interface comum a todas: hmm... se houver um comportamento compartilhado entre as mesmas, variando apenas o comportamento a ser tomado, pode ser uma boa opção.

(há um forte debate a respeito de qual seria a melhor solução: classes abstratas ou interfaces.
  no entanto, o que observo é que trata-se de uma solução íntimamente ligada ao domínio de sua aplicação, razão pela qual realmente não sei como responder a esta pergunta sem maiores detalhamentos).

"Pelo que entendi também quando utilizo o Hibernate ganho uma proteção natural no código SQL que ele terá embutido (sei que não é dos maiores o que te passei de exemplo mas deu trabalho). Isto ficará interno ao Hibernate e inacessível de forma trivial dos demais não é isto?"

Aqui depende do que você está chamando de "inacessível aos demais". Veja bem: a sua consulta SQL será inserida em um arquivo no formato XML que deverá ser distribuido com a sua aplicação. Neste caso, alguém poderia acessar o conteúdo dos seus arquivos e ver o conteúdo das consultas.

Uma solução para o problema poderia ser encriptar os arquivos de mapeamento do Hibernate e, em tempo de execução, desencripta-los e carregá-los para a memória. Não é uma solução 100% segura, mas é melhor do que nada.

Outra solução poderia ser acessar estes arquivos remotamente, isto é, poderia existir um servidor que os fornecesse aos clientes quando iniciados (neste caso, encriptados ou não). É uma solução um pouco melhor que a primeira, porém ainda não é 100% segura. Aliás, 100% de segurança é algo inexistente em basicamente qualquer situação.


Responder

Gostei + 0

22/06/2009

Oswaldo Castro

Ok Henrique, vamos lá Com relação a Classes abastratas x Interfaces vou com a primeira opção. Aproximadamente de 60 a 70% dos dados retornados são comuns. Praticamente não haveria comportamento nestas classes o que descarta em tese a criação de interfaces como Você mesmo diz. Trata-se sempre de um select que apresenta dados na Web (um sistema de consultas mesmo) Já com relação ao Hibernate Você está certo quando diz que não existe opção 100% segura. Vou optar pela criptografia dos arquivos localmente. A chave para descriptigrafar teria que estar dentro da aplicação, certo? Valeu por enquanto!!!
Responder

Gostei + 0

22/06/2009

Henrique Weissmann

Neste caso, sim. A chave deveria estar dentro da aplicação.
Responder

Gostei + 0

22/06/2009

Oswaldo Castro

Bom Henrique,   Vou construir uma das consultas com o Hibernate e te mando mando o código apenas para a sua avaliação. Se estiver ok dou continuidade segundo as suas orientações Pode ser assim?
Responder

Gostei + 0

22/06/2009

Henrique Weissmann

Claro, estou a sua disposição.
Responder

Gostei + 0

22/06/2009

Oswaldo Castro

Olá Henrique,   Comecei a codificar uma das consultas utilizando o Hibernate e me deparei com a utilização do famoso DAO em um dos tutoriais. Vale a pena a utilização deste pattern ou ele sofreu atualizações que modificam as suas caracteristicas e utilização?
Responder

Gostei + 0

23/06/2009

Henrique Weissmann

No caso do Hibernate, acredito que não seja necessário criar um DAO para cada classe de entidade.  Você pode criar um DAO genérico e, conforme novas necessidades de busca vão surgindo, você pode criar classes derivadas do mesmo para cada caso.
Responder

Gostei + 0

29/06/2009

Devmedia

Oswaldo,
a resposta do consultor foi suficiente? Podemos encerrar o chamado?
Responder

Gostei + 0

30/06/2009

Oswaldo Castro

Claro Pessoal, desculpem por não ter retornado.
Desde já agradeço às informações que o Henrique me passou de forma clara e objetiva.
Responder

Gostei + 0

Utilizamos cookies para fornecer uma melhor experiência para nossos usuários, consulte nossa política de privacidade.

Aceitar