| Autor |
Mensagem |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 20/07/2010 13:13:02
|
diego_qmota
JavaEvangelist
![[Avatar]](/images/avatar/e355819c0931a90b594aeb8d6a73587f.jpg)
Membro desde: 28/09/2008 15:44:35
Mensagens: 346
Localização: Paulínia
Offline
|
Boa tarde pessoal,
A primeira seção explica a minha situação. A segunda corresponde a minha pergunta.
Situação atual
Estou desenvolvendo um sistema SWING onde, devido ao crescimento e aumento das necessidades, deixou de ser um programa básico de consulta e se tornará um sistema de gerenciamento com escopo muito maior e mais complexo.
O sistema é de duas camadas: a camada de apresentação e a de persistência. A camada de negócios está embutida na de persistência e algumas poucas vezes embutida na camada de apresentação (eu sei, fiz cagada mas porquê só comecei a conhecer essa arquitetura agora ).
Está conforme o esquema abaixo:
USUÁRIO <-> CAMADA DE APRESENTAÇÃO <-> (CAMADA DE PERSISTÊNCIA + LÓGICA DO NEGÓCIO)
Quando o usuário requisita uma operação, a interface (camada de apresentação) faz:
Cria uma Thread para executar a operação e os próximos passos ocorrem dentro dela;
Instancia um DAO que será responsável pela lógica de negócios e a camada de persistência;
O DAO recebe os valores da interface e executa a operação;
Crio uma thread que a cada meio segundo, consulta o andamento do status no DAO e atualiza a interface do usuário;
Através da camada da interface, após execução da lógica e persistência pelo DAO, informo se a operação ocorreu com sucesso. Recollho as exceções na camada da interface.
Alguns conceitos acima estão corretos, mas sinto uma dificuldade grande de trabalhar com essa arquitetura, devido a mistura: (CAMADA DE PERSISTÊNCIA + LÓGICA DO NEGÓCIO).
Por isso, comecei o processo de migração para 3 camadas... criei uma interface para representar os serviços, em nível superior, para ir controlando a migração.
Dúvidas
Tenho dúvidas sobre como devo gerenciar e controlar interrupções de operações de processos longos.
O que devo fazer quando o usuário requisita a interrupção de uma operação de uma classe de Serviço?
Qual é o melhor jeito de controlar a operação, seu retorno a interface do usuário e sua interrupção? Onde esse controle deve ser feito?
Que tipos de validações devo fazer e de que forma devo interromper o processo? No DAO, lançando uma exceção, por exemplo?
Que metodologias vocês usam para fazer esse controle de processos longos? Que envolvam operações complexas e muitos métodos executados?
This message was edited 1 time. Last update was at 23/07/2010 14:51:35
|
"Go ahead, make my day!" |
|
|
 |
|
|
![[Post New]](/templates/default/images/icon_minipost_new.gif) 20/07/2010 13:49:03
|
rogelgarcia
GUJ Master
![[Avatar]](/images/avatar/861e8bae74e22a572164fdb59b1caa8b.jpg)
Membro desde: 21/06/2007 23:27:21
Mensagens: 1850
Offline
|
Vou explicar de forma genérica aqui.. como eu faria... (se eu fosse fazer um programa com interface gráfica, utilizaria SWT/jFace que inclusive já possui uma arquitetura pra fazer isso do jeito que to explicando)
Coloco uma barra de progresso para o usuário com um botão cancelar...
Enquanto isso a thread de serviços está executando...
Tanto o botao cancelar quando o objeto de serviços terão referencia para o mesmo objeto...
Quando o usuário clicar em cancelar... esse cancelar atualiza um status no objeto compartilhado com a camada de negócios
Quando possível, a camada de negócios testa o objeto verificando se é para cancelar ou nao...
Tem que ficar esperto sobre os pontos onde pode ser feito o cancelamento para nao deixar o sistema com dados inválidos.. (use transaçoes para te ajudar)
This message was edited 1 time. Last update was at 20/07/2010 13:50:48
|
Rógel Garcia, criador do framework NEXT
http://www.nextframework.org
 |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 20/07/2010 14:21:53
|
psevestre
JavaEvangelist
Membro desde: 13/05/2005 12:53:19
Mensagens: 432
Localização: São Paulo
Offline
|
Algumas alternativas para acessar a camada de negócios
1. Usar alguma variante de WebServices
Os stubs gerados normalmente possuem um método para setar o timeout da operação
2. Usar RMI
Vc. precisaria utilizar uma SocketFactory customizada onde os timeouts serias setados
3. Usar JMS
Cada transação envolveria um envio e um recebimento de mensagem. O timeout pode ser setado para limitar o tempo de espera e vc. ainda tem a possibilidade de usar um mecanismo de poll.
Em qualquer caso, adote como padrão executar qualquer chamada que envolva acesso a um recurso remoto na forma de uma tarefa a ser executada em background. Uma olhada na classe java.util.ThreadPoolExecutor vale a pena se vc. puder usar Java 1.5+
|
http://justaphilpicks.blogspot.com/ |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 21/07/2010 08:57:42
|
diego_qmota
JavaEvangelist
![[Avatar]](/images/avatar/e355819c0931a90b594aeb8d6a73587f.jpg)
Membro desde: 28/09/2008 15:44:35
Mensagens: 346
Localização: Paulínia
Offline
|
rogelgarcia wrote:Vou explicar de forma genérica aqui.. como eu faria... (se eu fosse fazer um programa com interface gráfica, utilizaria SWT/jFace que inclusive já possui uma arquitetura pra fazer isso do jeito que to explicando)
Coloco uma barra de progresso para o usuário com um botão cancelar...
Enquanto isso a thread de serviços está executando...
Tanto o botao cancelar quando o objeto de serviços terão referencia para o mesmo objeto...
Quando o usuário clicar em cancelar... esse cancelar atualiza um status no objeto compartilhado com a camada de negócios
Quando possível, a camada de negócios testa o objeto verificando se é para cancelar ou nao...
Tem que ficar esperto sobre os pontos onde pode ser feito o cancelamento para nao deixar o sistema com dados inválidos.. (use transaçoes para te ajudar)
Eu acredito que possa usar, um objeto Observer, com a referência passada para a área de negócios, para notificar a interrupção do processo. Mas vou ter que estudar o funcionamento dessa classe antes.
Hoje, como citei, crio uma thread que inicia a execução da camada de negócios e outra para ficar checando de meio em meio segundo se foi solicitada a interrupção.
Eu não gostaria de tornar a classe de Serviços filha da classe Thread, porquê o mesmo terá muitos métodos e para executá-los terei que ficar setando um atributo enum antes de chamar o método run() (para que ele saiba qual método deve executar ao rodar a thread). Mas não será possível se não for assim, né?
Talvez se eu disparasse uma InterruptedException do método da classe de serviços, mesmo ela não sendo uma thread. Aí voltava para a camada da interface e ela informava o usuário da interrupção da operação. Seria elegante, dessa forma?
This message was edited 5 times. Last update was at 21/07/2010 09:58:40
|
"Go ahead, make my day!" |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 21/07/2010 09:57:52
|
diego_qmota
JavaEvangelist
![[Avatar]](/images/avatar/e355819c0931a90b594aeb8d6a73587f.jpg)
Membro desde: 28/09/2008 15:44:35
Mensagens: 346
Localização: Paulínia
Offline
|
psevestre wrote:Algumas alternativas para acessar a camada de negócios
1. Usar alguma variante de WebServices
Os stubs gerados normalmente possuem um método para setar o timeout da operação
2. Usar RMI
Vc. precisaria utilizar uma SocketFactory customizada onde os timeouts serias setados
3. Usar JMS
Cada transação envolveria um envio e um recebimento de mensagem. O timeout pode ser setado para limitar o tempo de espera e vc. ainda tem a possibilidade de usar um mecanismo de poll.
Em qualquer caso, adote como padrão executar qualquer chamada que envolva acesso a um recurso remoto na forma de uma tarefa a ser executada em background. Uma olhada na classe java.util.ThreadPoolExecutor vale a pena se vc. puder usar Java 1.5+
Para alguns processos poderia usar uma das opções que você passou, psevestre. Mas o aplicativo é Desktop e a execução de uma transação (ou operação) completa são feitas em uma estação.
As opções que você apresentou são mais válidas para aplicativos web e sistemas distribuídos. Mas obrigado pelas dicas!
|
"Go ahead, make my day!" |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 21/07/2010 11:47:40
|
rogelgarcia
GUJ Master
![[Avatar]](/images/avatar/861e8bae74e22a572164fdb59b1caa8b.jpg)
Membro desde: 21/06/2007 23:27:21
Mensagens: 1850
Offline
|
Bem.. eu nao acho que a sua classe de serviços precise extender nada...
É só ela ter referencia para esse observer que vc falou.. e nem precisa de uma thread ficar checando de 5 em 5 segundos.. pq "matar" o serviço pode deixar o sistema em estado inválido o que nao é bom...
No seu método de serviço faz mais ou menos assim:
|
Rógel Garcia, criador do framework NEXT
http://www.nextframework.org
 |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 21/07/2010 14:52:09
|
diego_qmota
JavaEvangelist
![[Avatar]](/images/avatar/e355819c0931a90b594aeb8d6a73587f.jpg)
Membro desde: 28/09/2008 15:44:35
Mensagens: 346
Localização: Paulínia
Offline
|
rogelgarcia wrote:Bem.. eu nao acho que a sua classe de serviços precise extender nada...
É só ela ter referencia para esse observer que vc falou.. e nem precisa de uma thread ficar checando de 5 em 5 segundos.. pq "matar" o serviço pode deixar o sistema em estado inválido o que nao é bom...
No seu método de serviço faz mais ou menos assim:
Essa é uma opção. Mas pensei bem e preferi disparar uma InterruptedException, sem estender a classe Thread na camada de serviço.
Acho que essa abordagem me ajuda a parar toda a pilha de execução (sem ter que ficar validando o retorno dos métodos na camada de interface gráfica (com return)) ou parar a thread da interface gráfica (colocando em estado incosistente).
Vou lançar uma exceção de interrupção para a interface gráfica, se identificar pelo objeto compartilhado ou observer, que o usuário pediu a interrupção.
Muito obrigado pelos dicas!
This message was edited 1 time. Last update was at 21/07/2010 14:56:42
|
"Go ahead, make my day!" |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 21/07/2010 17:32:12
|
rogelgarcia
GUJ Master
![[Avatar]](/images/avatar/861e8bae74e22a572164fdb59b1caa8b.jpg)
Membro desde: 21/06/2007 23:27:21
Mensagens: 1850
Offline
|
Concordo... acho que a exceção vai ficar melhor que o return mesmo...
|
Rógel Garcia, criador do framework NEXT
http://www.nextframework.org
 |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 21/07/2010 22:24:29
|
psevestre
JavaEvangelist
Membro desde: 13/05/2005 12:53:19
Mensagens: 432
Localização: São Paulo
Offline
|
diego_qmota wrote:
Para alguns processos poderia usar uma das opções que você passou, psevestre. Mas o aplicativo é Desktop e a execução de uma transação (ou operação) completa são feitas em uma estação.
As opções que você apresentou são mais válidas para aplicativos web e sistemas distribuídos. Mas obrigado pelas dicas!
Havia entendido um ambiente Swing chamando serviços remotos. De fato, em um cenário auto-contido, estas opções não fazem muito sentido. O uso do ThreadPoolExecutor para submeter os jobs ainda faz sentido.
|
http://justaphilpicks.blogspot.com/ |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 22/07/2010 10:17:14
|
diego_qmota
JavaEvangelist
![[Avatar]](/images/avatar/e355819c0931a90b594aeb8d6a73587f.jpg)
Membro desde: 28/09/2008 15:44:35
Mensagens: 346
Localização: Paulínia
Offline
|
Para o envio das atualizações da classe Service para a atualização de status na interface gráfica, estou implantando o modelo anexo, sujeito a alterações.
Espero que dê certo...
|
| Nome do arquivo |
imagem.JPG |
Download
|
| Descrição |
|
| Tamanho |
19 Kbytes
|
| Baixado: |
36 vez(es) |
|
"Go ahead, make my day!" |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 22/07/2010 10:29:22
|
diego_qmota
JavaEvangelist
![[Avatar]](/images/avatar/e355819c0931a90b594aeb8d6a73587f.jpg)
Membro desde: 28/09/2008 15:44:35
Mensagens: 346
Localização: Paulínia
Offline
|
psevestre wrote:
diego_qmota wrote:
Para alguns processos poderia usar uma das opções que você passou, psevestre. Mas o aplicativo é Desktop e a execução de uma transação (ou operação) completa são feitas em uma estação.
As opções que você apresentou são mais válidas para aplicativos web e sistemas distribuídos. Mas obrigado pelas dicas!
Havia entendido um ambiente Swing chamando serviços remotos. De fato, em um cenário auto-contido, estas opções não fazem muito sentido. O uso do ThreadPoolExecutor para submeter os jobs ainda faz sentido.
Sim, é claro. Eu implantei um pool de threads que implementa ExecutorService há duas semanas atrás, para execução de processos muito longos que precisei dividir o processamento entre várias threads assíncronas:
Estou utilizando esse recurso onde um processo rodando sozinho leva muito tempo.
Os processos que rodam dentro de um tempo satisfatório (a maioria), estou rodando em uma thread só. No caso do processo que citei, não é necessário entrar nesse âmbito (é longo mas não a ponto de ser um problema de desempenho - leva de 2 a 4 min. e para o objetivo do processo e o usuário que utiliza, é aceitável). Mesmo assim, para um processo nesse intervalo, têm que haver notificação de status na interface gráfica, já é um tempo que exige exibição de status...
Para processos que levam de 10 min. para cima, eu estou usando Pools.
This message was edited 2 times. Last update was at 22/07/2010 10:34:06
|
"Go ahead, make my day!" |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 23/07/2010 14:51:16
|
diego_qmota
JavaEvangelist
![[Avatar]](/images/avatar/e355819c0931a90b594aeb8d6a73587f.jpg)
Membro desde: 28/09/2008 15:44:35
Mensagens: 346
Localização: Paulínia
Offline
|
A solução do Observer que apresentei também deu certo.
Segue exemplo em dois níveis: A classe de serviços notificando a interface gráfica do progresso da operação.
Quando necessário, posso também fazer a inclusão da DAO (que em métodos muito longos, notificaria o progresso do processo a classe de Serviços que, por sua vez, notificaria a classe de interface gráfica).
This message was edited 1 time. Last update was at 23/07/2010 14:52:00
|
"Go ahead, make my day!" |
|
|
 |
|
|