ClassLoader

:wink: , bem galera , de fato realmente ,inclusive aqui , tem varios artigos sobre isso , Mas quanto mais leio e pesquiso mais confuso eu fico . Estou desenvolvendo um projeto e ao longo do percurso varias duvidas surgiram no entanto nenhum se perpetuou tanto como essa e sinceramente nao vejo nenhuma outra saida a nao ser uma consulta direta ! è o seguinte

O programa está 99% pronto oque falta e esta dando problema é um esquema que estou tentando fixar para fazer atualizações do programa. Eu nao quero criar uma aplicao para javaws !

As classes foram dividas em dois packages , Sources.jar e Bin.jar , contando com uma classe externa á loader.class.

Deveria funcionar assim , o loader.class consulta a web e verifica que o hash do Bin.jar é diferente do hash da versao atual e entao faz download do novo package e deleta antigo e entao inicia a aplicacao , Isso nao é o problema fiz numa boa ,o problema é que nao consigo de forma alguma fazer esse loader funcionar . Pra nao ter que escrever muito abaixo to postando algo analogo[color=darkblue] [/color] ao que eu preciso.


arquivos:

C:\pro\packteste\Bin.jar
|__sub1.class
|
|_sub2.class

C:\pro\packteste\principal.class

import Vini.*;

public class principal{
public static void main(String[] args){
sub1 s1 = new sub1();
sub2 s2 = new sub2();
s1.run("Frase 1");
s2.run("Frase 2");
}
}
package Vini;

public class sub1{
public void run(String input){
System.out.println(input);
}
}
package Vini;

public class sub2{
public void run(String input){
System.out.println(input);
}
}

Ao compilar :
crio uma pasta com o nome Vini e jogo la dentro os arquivos sub1.java e sub2.java

e executo o seguinte comando no console:
C:\pro\packteste>javac principal.java

Ok ,compila numa boa em seguida executo:
C:\pro\packteste>java principal

O progrma funciona tambem , mas como eu disse la em cima nao da pra ser assim preciso de uma jar e a duvida aparece aqui:

Crio um arquivo Bin.jar ( pego a pasta Vini e compacto com o zip e renomeio para Bin.jar)
deleto a pasta Vini.

Ao compilar novamente:
C:\pro\packteste>javac -cp Bin.jar principal.java

Sim ,compila perfeitamente outra vez , mas eis que chego ao lugar que ja me fez perder noite de sono
:x :x :x

Agora quando tento executar:
C:\pro\packteste>java principal

[quote]Exception in thread “main” java.lang.NoClassDefFoundError: Vini/sub1
at principal.main(principal.java:5)
[/quote]

ou

C:\pro\packteste>java -cp Bin.jar principal


È isso ai , poxaa alguem podia me dar uma forca , nao tenho muita exeperiencia com packages , lendo pela net penso que eu deveria criar um classloader ,porem ja li tantoo a respeito e mesmo assim nao consegui fazer um. Se alguem puder postar um codigo de um classloader que funcione nesse exemplo analogo que eu citei ja é o suficiente , ou se nao propor algo melhor.

Vc precisa implementar seu proprio classloader ( o que parece que já fez) e associá-lo à thread principal.
Ou seja, a primeira instruçõa no main deverá ser o registro do seu class loader no class loader corrente

[quote=sergiotaborda]Vc precisa implementar seu proprio classloader ( o que parece que já fez) e associá-lo à thread principal.
Ou seja, a primeira instruçõa no main deverá ser o registro do seu class loader no class loader corrente[/quote]

kra , nem precisou , olha só como a solucao era simples:

:hauhau: :idea:

Como eu so burro !
aff como eu nao tinha pensado antes ,vo compra uma caixa de fogos de artificio ! Como algp tao simples me amarrou tanto , rssss , uma dessas aqui tinha que ta no java basico , kkkk

Sinceramente , eu to com dor de cabeça de tanto pensar.

Eis que resolvo deitar pra relaxar e me surge uma idéia :stuck_out_tongue:

Pensei na seguinte logica , quando tento executar
C:\pro\packteste>java -cp Bin.jar principal

eu defino como class-path apenas Bin.jar , ele só vai buscar lah dentro por classes
externas ,entao foi só adicionar a pasta local ao cp … HUAHUA ,putzz
que alivio
ficou assim :

C:\pro\packteste>java -cp Bin.jar;. principal

valeww gente

Olá

Parabéns por ter conseguido.

Porém…

Até agora não mostrou ter feito nada melhor do que o Java Web Start.

Mas em compensação, pode estar no caminho de resolver um problema muito grave do Java Web Start, mesmo quando a gente separa os jars e usa o jardiff.

O Java Web Start simplesmente envia uma atualização do jar sempre que há uma versão mais nova no servidor. Mas isto de maneira inteiramente burra pois não permite selecionar os clientes que receberão atualizações e cria a possibilidade do servidor ser derrubado com todos os clientes querendo atualizar ao mesmo tempo. Isto acontecia no Banco Postal quando todas as milhares de agências iniciavam os serviços e havia uma atualização nova no servidor.

O que você precisa fazer é um esquema de só liberar as atualizações ao mesmo temo para um determinado grupo de clientes. Não é difícil criar uma solução assim quando se tem no servidor uma tabela com os clientes autorizados a usar o sistema (isto havia no Banco Postal).

[]s
Luca

:? voce tem toda a razão !

mas pensei em algo , veja se considera viavel !

junto do hash do arquivo novo , fixar também a data !

e no periodo de uma semana fazer rodizio durante 10 horas do dia com as 10 possiveis terminacoes dos IPs.
E mesmo que o usuario esteja fora da hora que pode fazer update emite alerta falando sobre a atualizacao e
o horario que ele pode carregala.

Se um rodizio do ultimo numero do IP ainda causar problemas ,pode-se ainda pegar os 2 ultimos numeros e no periodo de 1 semana distribuir os dias e ou horas .

ou um misto dos 2 .

Olá

Na verdade quando eu passei por estes problemas, surgiram outras idéias mas achei esta sua muito boa. Dependendo do tamanho do seu problema pode resolver perfeitamente.

Mesmo um pequeno supermercado pode parar se todos os terminais de caixa atualizarem o sistema ao mesmo tempo. O Dr Mauro Marinilli já alertava para esta falha do Java Web Start em seu livro Java Deployment with JNLP and webstart de setembro de 2001 (justo quando foi lançado o JWS). Até hoje ninguém da Sun tentou resolver o problema de modo efetivo e sobra para a gente fazer estes esquemas de carregamento de classes na raça com ClassLoaders customizados.

[]s
Luca

:?:

Porque eu gostaria que os clientes derrubassem o servidor ?

Se as classes do cliente e do servidor não são da mesma versão isso gerará uma exception na serialização o que deve ser interpretado como uma mudança de versão pela aplicação cliente, o que significa que o usuário deve sair e retornar à aplicação. Sendo que as aplicações cliente não rodam 24/7 se a atualização do servidor for fora de expediente não acontece nenhum problema: a versão do cliente será sempre a mais atual.
Eu uso o JWS e não entendi o problema que vc explicou. Poderia esclarecer ?

Olá

Imagina que na 6a feira a noite ou no fim de semana você coloca uma nova versão no servidor.

Na segunda pela manhã, no inicio do horário comercial em que todos abrem suas aplicações, o JWS percebe que há uma nova versão no servidor e então começa um download. Todos os downloads começam mais ou menos na mesma hora.

O servidor tenta atender a todos os downloads simultâneos mas é claro que não dá conta. Todos os downloads ficam lentos porque a largura de banda e a capacidade do servidor não foram dimensionados para atender os raros casos de downloads de instalação.

Aí, o funcionário que tenta usar a aplicação percene que está demorando para abrir e pensa que o download travou. O que faz? Reinicializa a máquina (isto acontecia com o dezenas ou centenas de agências do Banco Postal. O cluster penava apesar da gigantesca largura de banda do servidor)

Resultado: os downloads precisam ser reiniciados e o servidor na maldita 2a feira fica uma tartaruga e o cliente lembra logo do SLA, etc. e tal.

Este gravíssimo problema ficou claro desde o lançamento do JWS em setembro de 2001. A correção passa pelo caminho que o nosso amigo está adotando de fazer um ClassLoader customizado e não usar o JWS. Veja o livro que indiquei no post anterior com outras idéias e discussão ampla do assunto.

Se o JWS for usado por alguma aplicação que não precise ser aberta simultaneamente, então este problema talvez nem seja percebido.

[]s
Luca

[quote=Luca]Olá

Imagina que na 6a feira a noite ou no fim de semana você coloca uma nova versão no servidor.
(…)
[/quote]

Entendi, é um problema de carga do servidor. Mas, sendo assim, não é mais facil alterar o servlet que fornece os dados ? Essa lógica de controle de horário e IP etc, poderia ser feita no servidor, negando o update. Isso obriga o JWS a começar depois. Ok, a solução não é muito limpa, mas é melhor que reinventar a roda. Não?

Depois de responder me ocurreu que o problema poderia ser resolvido com um instalador customizado
(passado na tag ) e/ou usando o DownloadService (mais ou menos seguindo a linha em http://forum.java.sun.com/thread.jspa?threadID=5173345&tstart=255 ) .Não ?

Olá

O JWS não tem este ajuste fino. Para reescalonar os downloads de acordo com o MacAddress (IP nem sempre serve) é preciso uma solução de instalador customizado.

É disso que estamos tratando desde o início da thread.

Um dos passos mais difíceis em termos de programação é justamente entender como o Java carrega as classes. É possível criar uma solução de instalador customizado que carregue novas classes sem precisar reinicializar o cliente. O modo de trabalho do Erlang é profícuo em idéias neste sentido.

[]s
Luca

Olá

Legal ter trazido este link para a discussão.

Sem nada a ver com o nosso tópico mas com tudo a ver com atualização de software, trago um link de hoje:
Microsoft Updates Both XP and Vista Without User Permission or Notification em http://www.schneier.com/blog/archives/2007/09/microsoft_updat.html

[]s
Luca

[quote=Luca]Olá

O JWS não tem este ajuste fino. Para reescalonar os downloads de acordo com o MacAddress (IP nem sempre serve) é preciso uma solução de instalador customizado.
[/quote]

O JWS padrão da sun não tem, mas o Servlet que ela usa pode ser extendido.
Não ha necessidade de diferenciar os IP nem os Mac. Se a máquina X tenta atualizar-se e eu nego essa atualização ela vai tentar de novo mais tarde. Ela vai ocncerteza fazer isso porque sem o update o JWS não funciona. Se eu permito apenas um numero limitado de updates por vez , não interessa as máquinas que os estão fazendo.
Outra forma de negar o update é por um servlet no endereço dos recursos que controla os respetivos downloads.
Todos os clientes têm que fazer o update dos mesmos arquivos e o fazem na mesma ordem (por cusa do arquivo jnlp), não interessa quem faz primeiro , nem que os arquivos estejam indo para o mesmo cliente.

Eu sei. Eu estou só tentando entender se essa é realmente a solução mais correta.

Olá

Como o servlet entende que é para fazer o download de uns e não de outros? O .jnlp é um recurso estático cujo download não é comamdado pelo servlet.

Se você conseguiu fazer funcionar assim, ppr favor descreva com mais detalhes.

[]s
Luca

[quote=Luca]Olá

Como o servlet entende que é para fazer o download de uns e não de outros? O .jnlp é um recurso estático cujo download não é comamdado pelo servlet.

[/quote]

Sim o jnlp é um arquivo cujo download não depende do servlet, mas…

  1. os arquivos que o JWS baixa , cujo endereço está escrito no jnlp , podem passar por um servlet.
  2. o ppr jnlp pode ser gerado dinamicamente.

Se o problema é carga, usem-se mais máquinas. faça-se um cluster. Afinal não é assim que faria se o problema fosse carga do webserver ? Então, mas é exatamente isso o problema que vc descreveu. Um problema de carga do dowload a partir do webserver.
Vc pode impedir sim o dowload do lado do servidor (basta retornar um erro 500). A lógica para isso pode ser variada. Podem limitar por numero (100 downloads simultaneos - não importa o arquivo nem o IP do cliente) ou qq outra logica.
Ou vc pode simplesmente gerar jnlp com url diferenciada. Desta forma os cliente se atualizaram usando diferentes servidores. Afinal é só para isso que interessa usar o jws : deployment remoto.

O que o v_vinicius_v exemplificou é uma boa se o seu programa é standalone, ou se vc pode instalar pessoalmente em cada máquina. É bom para jogos , ou qq programa que precise se auto-atualizar mas não é a mesma coisa que deployment remoto.
Luca, vc está sugerindo que o classloader que o v_vinicius_v fez é um substituto do jws, mas não é. O jws é mais do que um classloader remoto. Não estou desmerecendo a solução do v_vinicius_v, apenas estou dizendo que o problema de carga que vc referiu pode ser solucionado com jws padrão sem ter que fabricar um classloader especial.

Olá

Sérgio, pelo seu texto desconfio que você ainda não testou ou ainda não passou pelo problema. Sugiro que faça um teste. Duvido que não chegue a mesma conclusão do que eu, o Vinicius e o Dr Marinilli sobre as limitações do JWS. Só não retorne erro 500 que pode parar seu cliente.

Só mais uma coisinha. Quando testar monitore a rede. Verificará que a largura de banda é o problema. Pode colocar quantas máquinas quiser no seu cluster. Quando passei por estes problemas, o cluster era formado por 2 AIX de última geração com 16 processadores e 12 Gb de memória usando alta disponibilidade. As máquinas sempre estiveram longe de esgotar sua capacidade.

[]s
Luca

Entendi.