Processar arquivos no Java EE

Eu tenho um sistema que deve levar arquivos grandes contendo documentos e processá-los para dividir os documentos individuais e criar objects de documento a serem persistidos com JPA (ou pelo menos é assumido nesta questão).

Os arquivos estão no intervalo de 1 documento para 100 000 em cada arquivo. Os arquivos vêm em vários tipos

  • Comprimido
    • Fecho eclair
    • Tar + gzip
    • Gzip
  • Texto simples
  • XML
  • PDF

Agora, a maior preocupação é que a especificação proíbe o access a arquivos locais. Pelo menos do jeito que estou acostumado.

Eu poderia salvar os arquivos em uma tabela de database, mas isso é realmente uma boa maneira de fazer isso? Os arquivos podem ter até 2 GB e acessar os arquivos do database exigiria que você baixasse o arquivo inteiro, na memory ou no disco.

Meu primeiro pensamento foi separar esse processo do servidor de aplicativos e usar uma abordagem mais tradicional, mas estive pensando em como mantê-lo no servidor de aplicativos para fins futuros, como clustering etc.

Minhas perguntas são basicamente

  1. Existe uma maneira padrão ou uma maneira recomendada de lidar com isso no Java EE?
  2. Existe uma maneira específica de servidor de aplicativos em torno disso?
  3. Você pode justificar a quebra deste processo fora do servidor de aplicativos? E como você projetaria o canal de comunicação entre esses dois sistemas separados?

Eu esboço aqui mais algumas proposições e considero as seguintes preocupações:

  • escalabilidade (tamanho do arquivo, clustering, etc.)
  • arquitetura em lote (recuperação de tarefas, tratamento de erros, monitoramento, etc.)
  • conformidade com o J2EE

Com JCA

Os conectores JCA pertencem à pilha Java EE e permitem conectividade inboud / outboud de / para o mundo EJB. JDBC e JMS são geralmente implementados como conector JCA. Um conector JCA de input pode usar encadeamento (por meio da abstração de trabalhador) e transactions. Em seguida, ele pode encaminhar qualquer processamento para um bean controlado por mensagem (MDB).

  • escreva um conector JCA que busca um novo arquivo, processe-o e delegue processamento adicional ao bean acionado por mensagens de maneira síncrona.
  • o MDB pode, então, perseverar as informações no database com JPA
  • o conector JCA tem controle sobre a transação e várias chamadas do MDB podem estar na mesma transação
  • o sistema de arquivos não é transacional, portanto, você precisará descobrir como lidar com erros, como arquivos de input defeituosos.
  • você provavelmente pode usar streaming (InputStream) ao longo de toda a linha de

Com linhas simples

Podemos obter mais ou menos o mesmo que o modo JCA, usando encadeamentos que são iniciados a partir de um ouvinte de contexto de servlet da web (ou até mesmo de um EJB Timer).

  • O encadeamento pesquisa um novo arquivo, se for encontrado um arquivo, ele o processará e delegará processamento adicional ao SLSB regular de maneira síncrona.
  • Thread no contêiner da web tem access ao UserTransaction e pode controlar a transação
  • O EJB pode ser local para que o InputStream seja passado por referência
  • Implantação do módulo web + ejb pode ser feito com um ouvido

Com JMS

Para evitar a necessidade de ter vários encadeamentos de pesquisa simultâneos e o problema de aquisição / bloqueio de tarefas, o processamento real pode ser realizado de forma assíncrona usando o JMS. O JMS também pode ser interessante para dividir o processamento em tarefas menores.

  • Uma tarefa periódica pesquisa por novo arquivo. Se o arquivo for encontrado, uma mensagem JMS será enfileirada.
  • Quando a mensagem JMS é entregue, o arquivo é lido e processado e as informações são persistidas no database com o JPA
  • Se o processamento do JMS falhar, o aplicativo. servidor pode tentar novamente automaticamente ou colocar a mensagem na fila de mensagens inativas
  • monitoramento / manipulação de erros é mais complicado
  • você provavelmente pode usar o streaming

Com ESB

Muitos projetos surgiram no ano passado para lidar com a integração: JBI, ServiceMix, OpenESB, Mule, integração Spring, Java CAPS, BPEL. Algumas são tecnologias, outras são plataformas e há alguma sobreposição entre elas. Todos eles têm um conjunto de conectores para rotear, transformar e orquestrar o stream de mensagens. IMHO, a mensagem deve ser uma pequena informação, e pode ser difícil usar essas tecnologias para processar seu grande arquivo de dados. Os padrões de website da integração de aplicativos corporativos é um excelente site para mais informações.

IMO, a abordagem mais adequada à filosofia do Java EE é a JCA. Mas o esforço para investir é relativamente alto. No seu caso, o uso de thread simples que delega processamento adicional ao SLSB é talvez a solução mais fácil. A abordagem JMS (perto da proposição de P. Thivent) pode ser interessante se o pipeline de processamento ficar mais complicado. Usando um ESB parece um exagero para mim.

Existe uma maneira padrão ou uma maneira recomendada de lidar com isso no Java EE?

Eu usaria uma camada de integração real (como no EAI) para essa finalidade, executando como um processo externo. As ferramentas de integração (ETL, EAI, ESB) são projetadas especificamente para lidar com … integração e muitas delas fornecem tudo o que é necessário pronto para uso (versão simplificada: transporte, conectores, transformação, roteamento, segurança).

Basicamente, ao lidar com arquivos, um conector de arquivo é usado para monitorar um diretório de arquivos recebidos, que são então analisados ​​/ divididos em mensagens (aplicando opcionalmente algumas transformações) e enviados para um terminal para processamento de negócios.

Dê uma olhada no Mule ESB, por exemplo (tem um conector de arquivo, suporta muitos transportes, pode ser executado como um processo independente). Ou talvez o Spring Integration (acoplado ao Spring Batch?) Que também possui o File e o JMS Adapters. Mas eu não tenho muita experiência com isso, então não posso dizer nada sobre isso. Ou, se você é rico, você poderia olhar para Tibco EMS , WebMethods, etc. Ou construir sua própria solução usando alguma biblioteca de análise (por exemplo, jFFP ou Flatworm ).

Existe uma maneira específica de servidor de aplicativos em torno disso?

Eu não estou ciente de nada assim.

Você pode justificar a quebra deste processo fora do servidor de aplicativos? E como você projetaria o canal de comunicação entre esses dois sistemas separados?

Como eu disse, eu usaria um processo externo para o material de processamento de arquivos (melhor adequado) e enviaria o conteúdo do arquivo como mensagens através do JMS para o servidor de aplicativos para o processamento de negócios (e assim se beneficiaria de resources Java EE como load balanceamento e gerenciamento de transactions).

acessar os arquivos do database exigiria que você baixasse o arquivo inteiro, na memory ou no disco.

Isso não é inteiramente verdade. Você não é obrigado a colocar a coisa toda em um byte[] indermetia byte[] ou algo assim. Você pode continuar usando streams. Obter um InputStream dele usando ResultSet#getBinaryStream() e imediatamente manipulá-lo da maneira usual, por exemplo, escrevendo para HttpServletResponse#getOutputStream() . O custo é apenas o tamanho do buffer que você mesmo pode definir.

Existe uma maneira padrão ou uma maneira recomendada de lidar com isso no Java EE?

O database ou um caminho de sistema de arquivos de disco fixo com access r / w para o servidor de aplicativos. Por exemplo, /var/webapp/files no disco raiz.

Eu acho que a maneira mais saudável de fazer isso é sem um servidor de aplicativos Java.

Os servidores de aplicativos gostam de gerenciar resources (CPU, memory, threads) do seu próprio jeito. A execução de processamento em lote intensivo de E / S de longa execução tende a distorcer esse tipo de gerenciamento de resources.

Eu sugiro usar um processo externo para dividir os arquivos, com uma limpeza periódica para manter o uso do disco sob controle, e usando o AS para access de leitura via sistema de arquivos, como o BalusC sugeriu.

Eu suponho que os problemas de access simultâneo seriam tratados pela camada JPA – que eu reconhecidamente não sei muito sobre, mas acho que vem também no sabor do J2SE.

A especificação proíbe acessar arquivos usando java.io. Existem outras formas legais de acessar arquivos, por exemplo, por meio de um driver DataSource / JDBC ou por meio de um conector de resources.

Veja pp545 de “JSR 220: Enterprise JavaBeansTM, Contratos e Requisitos Principais do EJB Versão 3.0”


… usando o JDBC para access a arquivos. Você poderia por favor explicar um pouco mais em detalhes?

Um arquivo é um armazenamento de dados da mesma maneira que um database. É um armazenamento de dados muito bom para dados de caracteres acessados ​​serialmente, não estruturados, e não tão grande quando você deseja segurança de transactions, access multiusuário, access random gravável ou dados binários estruturados. Em um sistema corporativo, você tende a ter pelo menos um desses últimos requisitos quase o tempo todo.

Embora não seja estritamente verdadeiro dizer “Em um sistema corporativo não há arquivos” (porque existem arquivos de log e quase todos os bancos de dados usam arquivos em um nível baixo) é uma boa regra prática de design, por causa de todos os problemas que os arquivos de dados causam em um sistema corporativo de alto desempenho, multiusuário, seguro para transactions, de leitura e gravação.

Infelizmente, o mundo dos negócios está cheio de dados de negócios armazenados em arquivos. Você tem que lidar com eles. Alguns arquivos (por exemplo, planilhas do Excel) têm bastante em comum com um database simples que podem valer a pena acessar por meio de um driver JDBC. Nunca ouvi falar de alguém acessando arquivos de texto sem formatação através de um driver JDBC, mas você poderia – ou poderia usar um adaptador de resources mais genérico (de acordo com a especificação EJB3, o JDBC é uma API do gerenciador de resources).