RMI com ClassNotFoundException em Agentes Móveis

E aí galera, tudo bem com vocês?

Gostaria de solicitar uma ajuda para a galera que manja de java, já que sou um completo noob kkkkkk.

Estou desenvolvendo um trabalho de agentes móveis para a faculdade que consiste em um servidor RMI que recebe qualquer objeto que implemente a interface IAgenteMovel que contém o método public void ExecutarAgente();

O meu problema é que quando tento executar este método no servidor, geralmente ele me retorna um erro, visto que ele não possui o .java e nem o .class para esta classe, disparando assim um ClassNotFoundException.

Meu professor me orientou a enviar o .class do micro que está chamando o método e depois chamar o método novamente. Isto funciona porém existe um problema que não consegui tratar.

Quanto a classe enviada usa outra classe também, ele ainda irá dar um erro de ClassNotFoundException, portanto eu teria que analisar a classe a ser enviada e recuperar todas as classes que ele tem de dependência, e isso eu naõ consegui fazer.

Utilizando a API de reflection eu consigo pegar quase todas as classes que preciso, porém, existe um caso em que não consigo trata-lo, que seria quando um método usa uma classe, ou seja, ela não vem por parâmetro. Ex.:


public class Classe1 extends ClasseExtendida {
	public Classe1(){
		Classe2 c2 = new Classe2();
	}
}

class ClasseExtendida {
	
}

class Classe2 {
	
}

Neste caso, eu precisaria recuperar o nome das 2 classes que eu uso na Classe1, 1 por extends (ClasseExtendida) e outra que é usada no Método (Classe2)

Quem puder fico agradecido =]

Você quer que um algoritimo local seja reproduzido remotamente?

Do jeito que você explicou, me leva a entender isso e que ainda você quer fazer isso sem prévia garantia de que todas as classes estarão no servidor.

No geral, não entendi o que é isso.

wiliamps

Sim, é isso mesmo!

Os algorítmos estão prontos, funcionam, mas preciso saber como descobrir todas as dependências da classe antes de enviar, caso contrário ainda continuará dando erro de ClassNotFoundException

Vou deixar o código do client e do server pra tu entender!

Cliente

import java.io.Serializable;
import java.rmi.Naming;
import java.rmi.RMISecurityManager;
import java.util.HashMap;

public class AgenciaLancadora implements Serializable {

	ObjetoRemotoI obj = null;

	public AgenciaLancadora() {
		try {
			this.obj = (ObjetoRemotoI) Naming.lookup("SrvAgenteMovel");
		} catch (Exception excp) {
			System.out.println("Erro ao tentar executar RMI.\nErro: " + excp);
			excp.printStackTrace();
		}
	}

	public void executarAgente() {
		IAgenteMovel agente = new AgenteMovel();
		try {
			try {
				//Tento executar o agente!
				this.obj.ExecutaAgente(agente);
			} catch (ClassNotFoundException cnfe) {
				
				//Aqui eu teria que ler todos os .class que são dependencia da minha classe
				HashMap<String, String> classes = new HashMap<>();
				classes.put("Classe1", "código_do_.class");
				
				this.obj.SalvarClasses(classes);
				this.obj.ExecutaAgente(agente);
			}
		} catch (Exception excp) {
			System.out.println("Exceção ao rodar agente!\nErro: " + excp);
			excp.printStackTrace();
		}
	}

	public static void main(String args[]) {
		System.setProperty("java.security.policy",
				"file:/" + util.Util.getAppPath() + "/policy/client.policy");
		if (System.getSecurityManager() == null) {
			System.setSecurityManager(new RMISecurityManager());
		}

		AgenciaLancadora agenciaLancadora = new AgenciaLancadora();
		agenciaLancadora.executarAgente();
	}

	/*
	 * public void lancarAgente(Class<?> agente){ try {
	 * 
	 * } catch (Exception e) { // TODO: handle exception } }//
	 */
}

Servidor

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.HashMap;

public class AgenciaSrvIMP extends UnicastRemoteObject implements ObjetoRemotoI {
	@Override
	public void SalvarClasses(HashMap<String, String> classesSerializadas)
			throws RemoteException {
		// Pego o classPath atual
		String classPath = System.getProperty("java.class.path");

		// Corrige o caminho do classPath
		classPath += !classPath.endsWith("\\") ? "\\" : "";
		File f = null;
		FileWriter fw = null;

		// iterar as chaves
		for (String className : classesSerializadas.keySet()) {
			// System.out.println("Classe: " + chave + "!\nConteúdo: " +
			// classesSerializadas.get(chave) + "!");
			try {
				fw = new FileWriter(new File(classPath + className + ".class"));
				fw.write(classesSerializadas.get(className));
				fw.flush();
			} catch (IOException ioe) {
				System.out.println("Erro ao gravar classe " + className
						+ " no classPath!");
			}

		}
	}

	/**
	 * Construtor padrão
	 * 
	 * @throws RemoteException
	 * @author William
	 */
	public AgenciaSrvIMP() throws RemoteException {
		System.out.println("Foi construído um AgenciaSrvIMP");
	}

	public void ExecutaAgente(IAgenteMovel agente) throws RemoteException, ClassNotFoundException {
		System.out.println("Foi executado um agente!");
		agente.executarAgente();
	}

}

Por reflexão, você só poderá mesmo analisar a estrutura das classes e não as implementações. De qualquer forma, a reflexão não basta nem para estrutura se você encontrar uma classe herdeira de uma superclasse proprietária.

Forma simples para resolver:

Se sua aplicação remota for estática, basta reunir as dependências numa pasta “lib” e copiar o conteúdo em algum classpath da aplicação servidora, de preferência uma pasta “lib” também.

Veja, esta situação é a mais comum para evitar automação de uma tarefa simples. O custo benefício não compensa automação.

Forma complexa para resolver:

No entanto, se você não se enquadra nesta situação convencional, pode contar com a ajuda do JOOPS para descobrir em forma de texto quais são as dependências do tipo CLASS, JAR e CLASSPATH inteiro vinculado a sua aplicação remota. O link do projeto JOOPS é http://code.google.com/p/joops/.

wiliamps

Opa, vou dar uma olhada nesse Joops, valeu.

Eu tinha tentando usar o dependency-finder, mas não consegui kkkkkk, sou iniciante na linguagem e estou tendo problemas em entender como tudo funciona ainda rs.

Olhando pelo inpect do debug, se eu uso o classLoader, existe um atributo privado chamado classes que é um vector com as dependências, mas não consegui acessar esse dado por nada que seja mais sagrado nesse mundo rsrsrs.

Vou testar e dou um reply =]

Obrigado pela atenção e pela boa vontade!

Mesmo que você consiga acessar este vetor de dependências, você pode ter mais problemas se este vetor somente trouxer classes ligadas diretas ao seu código. Pois em Java você pode ter classes de herança o que pode normalmente complexo se existir uma classe com uma longa herança.

Também você deve avaliar onde estão as classes da dependências, o que pode ser um transtorno fazer isso por heroísmo porque podem estar em JAR ou CLASSPATH.

O JOOPS faz isso para você.

wiliamps