Atualizando o classpath em runtime

Alguem aê sabe se dá e como pra atualizar o classpath durante a execução de uma aplicação?
Pesquisei na web a respeito e o melhor q achei foi:
http://forum.java.sun.com/thread.jspa?threadID=608200&tstart=0
ou seja: imagino q terei q usar um custom class loader, correto??

Mas num ajuda muito, pq num faço idéia de como fazer isso…

Só pra tornar mais claro meu objetivo:
Tenho uma aplicação SWING, empacotada em um jar. só q essa aplicação depende de vários outros jar’s. Eu poderia sim criar um arquivo batch pra setar o classpath ou setar ele no ambiente msm… Mas ambas as alternativas tem seus inconvenientes para mim.
Exemplo: se algum dia mais tarde eu precisar adicionar mais arquivos ao classpath, precisarei modificar o ambiente ou o arquivo batch… Por amis estranho q pareça, pra mim seria mais fácil alterar o meu jar, de modo a encontrar os novos arquivos.
Isso se dá pq tenho meu jar em um servidor, no qual vários usuários acessam ele… se eu mudar o jar, todos os usuários serão atualizados automaticamente… se eu usasse arquivo batch, teria q atualizar um por um.

Bem… é isso… espero q alguém possa me ajudar…

[]'s

Artur Sampaio

Xi, acho que não é fácil (obviamente eu não tentei isso; no máximo tentei usar um custom class loader só para ver se eu conseguia carregar e descarregar uma biblioteca JNI dentro de um applet assinado, e não fui lá muito bem sucedido…)
É que o Tomcat e outros web ou EJB containers fazem algumas mágicas com class loaders, para poder atualizar as classes (carregar novas versões das aplicações) em tempo de execução.

Eu já fiz ambas as (duas) coisas… heheheehehe…

Anexei os BATs que adicionam todos os JARs de um diretório, sem necessidade de alterá-lo depois. (Meio que xupinhei do Tomcat).

Quanto a usar Classloader, que me parece ser mais adequado, olhe aqui:
http://www.guj.com.br/posts/list/19913.java

Este é o código que eu uso para iniciar uma aplicação que desenvolvi. Ele carrega todos os “jar” e “zip” que estejam no mesmo diretório.

A linha que está com o asterisco é a que você deve mudar para apontar para o seu método “main”.

[code]package launcher;

import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;

public class Launch implements Runnable {

private static String[] arguments;

public static void main(String args[]) {
    arguments = args;

    try {
        new Thread((Runnable)Class.forName("launcher.Launch").newInstance()).start();
    } catch (Exception ex) {
        ex.printStackTrace();
    }
}



public void run() {
    try {
        File temp = new File(".");
        File[] files = temp.listFiles();
        ArrayList aFiles = new ArrayList();
        for (int i = 0; i < files.length; i ++) {
            if (files[i].getName().endsWith(".jar") || files[i].getName().endsWith(".zip")) {
                System.out.println("adicionando " + files[i].getCanonicalFile());
                aFiles.add(new URL("jar", "", "file:" + files[i].getAbsolutePath() + "!/"));
            }
        }

        URL[] url = new URL[aFiles.size()];
        for (int i = 0; i < aFiles.size(); i ++) {
            url[i] = (URL)aFiles.get(i);
        }
        URLClassLoader l = new URLClassLoader(url);
        Thread.currentThread().setContextClassLoader(l);

        System.out.println("preparando carga do programa");
  •        Class loadedClass = l.loadClass("sua.classe.que.contem.o.main");
          System.out.println("buscando método main");
          Method method = loadedClass.getMethod("main", new Class[] { String[].class });
          System.out.println("invocando método main");
          method.invoke(method, new Object[] { Launch.arguments });
          System.out.println("método main invocado!!!");
      } catch (Exception ex) {
          ex.printStackTrace();
      }
    
    }
    }[/code]

Beleza, obrigado pela dica.

galera: tentei de todo jeito, mas num consegui MSM… num sei o q tô fazendo de errado…
só pra esclarecer: a princípio, meu objetivo pra fazer isso é pra usar o jasper, em uma aplicação q tô desenvolvendo.
minha aplicação tá em um jar.
o que kero: colocar todos os jar’s utilizados pelo jasper na msm pasta q meu jar…
mas kero executar minha aplicação sem usar os famosos .bat… acho isso tão ruim… deixa o projeto com uma cara tão anti-profissional…

tentei as soluções enviadas aki e num deu certo… até q resolvi usar msm os .bat, msm q temporariamente até achar outra solução… o problema é q nem com .bat consegui ! ! ! ! !
num sei onde estou errando. Qdo testo minha aplicação no netbeans, com os jar’s do jasper e as dependências adicionadas ao classpath do projeto, funciona blz… qdo crio meu jar, num funciona mais…
Por favor, alguém pode me dar alguma solução, exemplo, ou luz???
Num sei mais o q tentar…

vlw
[]'s

Artur Sampaio

Então configura o classpath no MANIFEST.MF do seu JAR.

tá… só q como nunca fiz isso, preciso de mais uma ajudinha:
1 - onde configuro isso usando o netbeans?
2 - posso colocar path’s relativos? ou tem q ser absolutos? pra mim, sem dúvida, seria ideal q fossem relativos (tipo: .\blablabla1.jar;.\blablabla2.jar;etc)

vlw

[]'s

Artur Sampaio

MANIFEST.MF

[code]Class-Path: ./ ./lib/jar-legal.jar ./lib/jar-tri-legal.jar

[/code]

  • Manter duas linhas em branco depois do “Class-Path”. (Não me pergunte o porquê).

Esse arquivo deve ir dento do diretório META-INF, dentro do seu JAR.

Neste caso os seus JARs devem estar dentro do diretório “lib”, junto ao seu JAR.

./ -- seu jar -- lib |-- jar1 |-- jar2

E como dica, seria interessante que você tentasse desenvolver alguma coisa SEM usar o Netbeans!

Usar uma IDE para facilitar o trabalho é legal…mas sem saber trabalhar sem ela, acabam acontecendo coisas como essas!! Quanto tempo você perdeu nesse problema??? E quanto já não teria aprendido se usasse um editor de textos e o javac pela linha de comando? :wink:

fenrir, acho que não é o caso.
Abraços

O que eu entendi daqui:

…é que está tentando montar o JAR de dentro do Netbeans!
Por isso que comentei que é melhor primeiro aprender do jeito “difícil”, ou seja, linha de comando, para depois partir para alguma IDE.

Se eu entendi errado, sorry…20 chibatadas pra mim!! :oops:

cara… perfeito… todos os problemas resolvidos…

vlw.

[]'s

Artur Sampaio

ah, sim… só pra ajudar kem tiver o msm problema:
Pra fazer isso no netbeans, basta abrir a pasta do projeto e lá já existe um arquivo manifest. Basta editá-lo

[quote=fenrir]Este é o código que eu uso para iniciar uma aplicação que desenvolvi. Ele carrega todos os "jar" e "zip" que estejam no mesmo diretório.

A linha que está com o asterisco é a que você deve mudar para apontar para o seu método "main".

[code]package launcher;

import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;

public class Launch implements Runnable {

private static String[] arguments;

public static void main(String args[]) {
    arguments = args;

    try {
        new Thread((Runnable)Class.forName(&quot;launcher.Launch&quot;).newInstance()).start();
    } catch (Exception ex) {
        ex.printStackTrace();
    }
}



public void run() {
    try {
        File temp = new File(&quot;.&quot;);
        File[] files = temp.listFiles();
        ArrayList aFiles = new ArrayList();
        for (int i = 0; i &lt files.length; i ++) {
            if (files[i].getName().endsWith(&quot;.jar&quot;) || files[i].getName().endsWith(&quot;.zip&quot;)) {
                System.out.println(&quot;adicionando &quot; + files[i].getCanonicalFile());
                aFiles.add(new URL(&quot;jar&quot;, &quot;&quot;, &quot;file:&quot; + files[i].getAbsolutePath() + &quot;!/&quot;));
            }
        }

        URL[] url = new URL[aFiles.size()];
        for (int i = 0; i &lt aFiles.size(); i ++) {
            url[i] = (URL)aFiles.get(i);
        }
        URLClassLoader l = new URLClassLoader(url);
        Thread.currentThread().setContextClassLoader(l);

        System.out.println(&quot;preparando carga do programa&quot;);
  •        Class loadedClass = l.loadClass(&quot;sua.classe.que.contem.o.main&quot;);
          System.out.println(&quot;buscando método main&quot;);
          Method method = loadedClass.getMethod(&quot;main&quot;, new Class[] { String[].class });
          System.out.println(&quot;invocando método main&quot;);
          method.invoke(method, new Object[] { Launch.arguments });
          System.out.println(&quot;método main invocado!!!&quot;);
      } catch (Exception ex) {
          ex.printStackTrace();
      }
    
    }
    }[/code][/quote]

mas esses jars carregados não ficam disponiveis para toda a aplicação como quando colocamos isso no manifest do jar…é possivel isso?