Archief - RMI server: NoClassDefFoundError, server draait toch

Het archief is een bevroren moment uit een vorige versie van dit forum, met andere regels en andere bazen. Deze posts weerspiegelen op geen enkele manier onze huidige ideeën, waarden of wereldbeelden en zijn op sommige plaatsen gecensureerd wegens ontoelaatbaar. Veel zijn in een andere tijdsgeest gemaakt, al dan niet ironisch - zoals in het ironische subforum Off-Topic - en zouden op dit moment niet meer gepost (mogen) worden. Toch bieden we dit archief nog graag aan als informatiedatabank en naslagwerk. Lees er hier meer over of start een gesprek met anderen.

blackrabbit

Legacy Member
Om een te omzeilen heb ik mijn code aangepast zodat ze gebruik maakt van een shared repository (die dus op een 'remote' server draait. Die respository code is vrij simpel: bevat een queue voor de elementen die de clients dan met pop/push kunnen accessen (synced).

Anyway, het 'probleem' zit hem in het volgende: bij het opstarten van de repository krijg ik een NoClassDefFoundError exception van een klasse die zich in een aparte JAR bevindt. De server start echter wel op & aanvaard verbindingen (de repository lijkt dus te werken, ik kan elementen toevoegen en verwijderen).

Door die exception lijkt mijn repository trouwens niet te registreren in de RMIregistry :/ Momenteel draait alles nog op dezelfde machine, en start ik de repository met de volgende command:

Code:
java -classpath "D:\SHARED\MyLibs\*;." be.XXX.RepositoryServer

De exception:
Code:
Error occured in server thread; nested exception is:
java.lang.NoClassDefFoundError: be/XXX/Particle
...
(Particle is het supertype van de elementen die ik wil opslaan, en die is dus gedefinieerd in een JAR-file die in MyLibs zit.

Ik hoop dat ik hiermee genoeg info geef & dat het probleem duidelijk is (en dat iemand me hier wat mee kan helpen :-) )



PS: die paden zijn correct, ik gebruik diezelfde om mijn 'hoofdprogramma' (de client) op te starten.

Wolf2000me

Legacy Member
Het ziet er toch redelijk correct uit. Gebruik je effectief Java 6 ?

Indien ja, probeer toch dit maar eens:
java -classpath ".;d:\SHARED\MyLibs\*" be.XXX.RepositoryServer

Of
java -classpath D:\SHARED\MyLibs be.XXX.RepositoryServer


Verder ben je met die remote repository het wiel aan het heruitvinden. Indien dit niet de bedoeling is dan kan je best eens kijken naar Maven 2.

"be.XXX.*" Ben je pr0n aan het maken? :p :)

blackrabbit

Legacy Member
Wolf2000me zei:
Het ziet er toch redelijk correct uit. Gebruik je effectief Java 6 ?
Zit momenteel op een windows machine, zou normaal gezien JAVA6 moeten opstaan. Hoe check ik dit?


Wolf2000me zei:
Indien ja, probeer toch dit maar eens:
java -classpath ".;d:\SHARED\MyLibs\*" be.XXX.RepositoryServer
Zelfde error.

Wolf2000me zei:
java -classpath D:\SHARED\MyLibs be.XXX.RepositoryServer
Werkt niet, omdat RepositoryServer uiteraard niet in MyLibs zit.

Wolf2000me zei:
Verder ben je met die remote repository het wiel aan het heruitvinden. Indien dit niet de bedoeling is dan kan je best eens kijken naar Maven 2.

"be.XXX.*" Ben je pr0n aan het maken? :p :)
De reden waarom ik snel effe dit heb geschreven is omdat ik al een volledig werkend project hebn, maar wegens memory leaks in 'externe' software heb ik deze oplossing bedacht die gegevens-verlies moet voorkomen wanneer de machine waar de software op draait crashed... (*)
Die XXX is omdat die package naam miss wat lang is + privé info bevat ;)



(*) Meer info: TORCS server heeft memory leaks, heb een AI driver (client dus, die via netwerk op server kan verbinden). TORCS vult RAM geheugen na teveel iteraties, waardoor machine crashed. Client-code kan daar niet goed mee om met verlies van de huidige state (huidige geleerde toestand) als gevolg. Die repository was echt snel geschreven en leek mij meteen een goede oplossing om meerdere PCs aan hetzelfde probleem te laten werken.



Effe code van de server posten:
Code:
package be.XXX;

import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.UnknownHostException;
import java.rmi.AlreadyBoundException;
import java.rmi.Naming;
import java.rmi.RMISecurityManager;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.server.UnicastRemoteObject;
import java.util.LinkedList;
import java.util.Queue;


public class ParticleRepositoryServer extends UnicastRemoteObject implements ParticleRepositoryProtocol 
{
    private static final long serialVersionUID = 3200925754019051579L;
    private Queue<RuleParticle> particleQueue;
    private static String serviceName = "ParticleRepositoryServer"; 
    
    
    protected ParticleRepositoryServer() throws RemoteException 
    {
	super();
	this.particleQueue = new LinkedList<RuleParticle>();
    }

    


    @Override
    public synchronized RuleParticle pop() throws RemoteException 
    {
	System.out.println("Popped particle from the repository. Repository size is now "+(particleQueue.size()-1)+" particles.");
	return this.particleQueue.remove();
    }

    @Override
    public synchronized void push(RuleParticle particle) throws RemoteException 
    {
	this.particleQueue.add(particle);
	System.out.println("Pushed particle in the repository. Repository size is now "+particleQueue.size()+" particles.");
    }
    
    
    public static void main(String[] args) throws Exception 
    {
	/*if (System.getSecurityManager() == null)
	{
            System.setSecurityManager ( new RMISecurityManager() );
	}
*/
	if(args.length < 1)
	{
	    throw new Exception("Missing argument: start/stop");
	}
	if(args[0].equalsIgnoreCase("start"))
	{
	    ParticleRepositoryServer repositoryServer = new ParticleRepositoryServer();
	    repositoryServer.setup();
	}
	else if(args[0].equalsIgnoreCase("stop"))
	{
	    String[] list = LocateRegistry.getRegistry().list();
	    for(int index=0;index<list.length;index++)
	    {
		System.out.println(list[index]);
	    }
	    System.out.println();
	    LocateRegistry.getRegistry().unbind(serviceName);
	}
	else
	{
	    throw new Exception("Unknown command: "+ args[0]);
	}

    }

    private void setup() 
    {
	System.out.println("Setting up repository..");
	try 
	{
		//UnicastRemoteObject.exportObject(this, 0);
		InetAddress address = InetAddress.getLocalHost(); 
		//LocateRegistry.getRegistry().rebind(serviceName, this);
	    	Naming.bind(serviceName, this);
		System.out.println(" SUCCEEDED! Repository listening on IP "+address.toString());
	} 
	catch (UnknownHostException e)
	{
		System.out.println(" FAILED: unknown host.");
		e.printStackTrace();
	}
	catch(RemoteException e) 
	{
		System.out.println(" FAILED: Remote Exception");
		System.out.println(e.getMessage());
		e.printStackTrace();
	} 
	catch (MalformedURLException e) 
	{
	    // TODO Auto-generated catch block
	    e.printStackTrace();
	} 
	catch (AlreadyBoundException e)
	{
	    // TODO Auto-generated catch block
	    e.printStackTrace();
	}

    }

    
}

Wolf2000me

Legacy Member
blackrabbit zei:
Zit momenteel op een windows machine, zou normaal gezien JAVA6 moeten opstaan. Hoe check ik dit?

Code:
C:\Documents and Settings\Thomas>java -version
java version "1.6.0_23"
Java(TM) SE Runtime Environment (build 1.6.0_23-b05)
Java HotSpot(TM) Client VM (build 19.0-b09, mixed mode, sharing)

C:\Documents and Settings\Thomas>

blackrabbit zei:
Werkt niet, omdat RepositoryServer uiteraard niet in MyLibs zit.

Dan ga je toch duidelijker moeten zijn waar exact alles zich bevindt. Het is mij ook niet echt duidelijk wanneer en hoe je je jars van je remote naar je local repository brengt. In elk geval is het zo dat wanneer class A nodig is (new A() of static) en deze A heeft een referentie naar B de B ook op dat moment (pretty much) beschikbaar moet zijn. Indien dat niet het geval is zou dit uw NoClassDef kunnen veroorzaken.


blackrabbit zei:
De reden waarom ik snel effe dit heb geschreven is omdat ik al een volledig werkend project hebn, maar wegens memory leaks in 'externe' software heb ik deze oplossing bedacht die gegevens-verlies moet voorkomen wanneer de machine waar de software op draait crashed... (*)
Die XXX is omdat die package naam miss wat lang is + privé info bevat ;)

Eigenlijk een reden te meer om Maven 2 te gebruiken op je doel machines. Dit framework zorgt er oa. voor dat je je classes remote gaat halen. Maak je zelf geen remote repo aan dan heb je reeds een aantal online repositories default ter beschikking over het net.
Maven 2 gaat zelf je gedefinieerde "artifacts (jars etc)" op voorhand voor een build gaan checken in je local repository. Zijn ze er niet dan gaat het framework de gedefinieerde remote repositories één voor één gaan aanspreken. Is het er dan nog niet dan faalt je build. Maar ik merk precies op dat jij je jars wil laten refreshen at runtime?
Maar dan nog zie ik niet goed in hoe dit ervoor gaat zorgen dat je je state niet kwijt bent wanneer je server out of memory gaat.


blackrabbit zei:
(*) Meer info: TORCS server heeft memory leaks, heb een AI driver (client dus, die via netwerk op server kan verbinden). TORCS vult RAM geheugen na teveel iteraties, waardoor machine crashed. Client-code kan daar niet goed mee om met verlies van de huidige state (huidige geleerde toestand) als gevolg. Die repository was echt snel geschreven en leek mij meteen een goede oplossing om meerdere PCs aan hetzelfde probleem te laten werken.

Wat voor iteratie bedoel je? TORCS ken ik helemaal niet, na ff googlen val ik op een soort van Race simulator :p , maar er zijn niet veel servers die niet na x-aantal deploys out of memory gaan.

blackrabbit

Legacy Member
Code:
C:\Documents and Settings\Bart>java -version
java version "1.6.0_25"
Java(TM) SE Runtime Environment (build 1.6.0_25-b06)
Java HotSpot(TM) 64-Bit Server VM (build 20.0-b11, mixed mode)

C:\Documents and Settings\Bart>
Lijkt me alvast ok, neen?


TORCS is idd een racing simulator. Mijn AI moet 10000'en episodes (races, if you will) draaien om deftig te leren rijden. Dus de client (mijn code) stuurt na elke lap een reset commando naar de server, die de race dan herstart en zo de client de kans geeft om nieuwe dingen uit te proberen.

Mijn code bevat een variabel aantal 'configuraties' (die de client dus 1 voor 1 test en bijwerkt) en dus in een queue zitten. DIe queue heb ik nu extern gemaakt: clients kunnen gewoon uit die queue-server configuraties opvragen en na testen/bijwerken terugplaatsen. Valt een machine uit, dan is de externe repo (die op andere machine zou staan) nog safe. Bovendien kunnen op die manier meerdere simulaties tegelijk worden gedraaid op dezelfde configuratieset. Is ook handig, als je weet dat de zwaardere dingen een 10tal seconden per episode duren :-)

Anyway, project (= client, de driver) staat op deze machine gewoon in mijn Eclipse workspace. Ik heb 2 libraries X.ai.pso.jar en X.util.jar, waarin een aantal classes zitten die ik in mijn project gebruik.

Mijn client roep ik normaal zo op:
Code:
java -classpath "C:\Documents and Settings\Bart\workspace\TorcsClient\bin;C:\Documents and Settings\Bart\workspace\TorcsClient;D:\SHARED\MyLibs\*" champ2011client.Client be.XXX.torcs.PSODriver (+ parameters)
Die PSODriver is een parameters voor Client, en laat toe om bia commandline een driver te kiezen bij het opstarten. Merk op: "C:\Documents and Settings\Bart\workspace\TorcsClient\bin" = "."

Die code en command werkten zonder problemen. Vermits zowel RepositoryServer als PSODriver momenteel in dezelfde package/source/bin-folder zitten, lijkt mij dat beide wel aan die libraries moeten aangeraken.

blackrabbit

Legacy Member
Effe code wat aangepast:
Code:
public class ParticleRepositoryServer implements ParticleRepositoryServerProtocol 
{
private static final long serialVersionUID = 3265925654019051579L;

//...
public static void main(String[] args) throws Exception 
    {
	if(args.length < 1)
	{
	    throw new Exception("Missing argument: start/stop");
	}
	if(args[0].equalsIgnoreCase("start"))
	{
	    ParticleRepositoryServer repositoryServer = new ParticleRepositoryServer();
	    ParticleRepositoryServer stub = (ParticleRepositoryServer) UnicastRemoteObject.exportObject(repositoryServer, 0);
	    Registry registry = LocateRegistry.getRegistry();
            registry.rebind(serviceName, stub);

	}
	else if(args[0].equalsIgnoreCase("stop"))
	{
	    String[] list = LocateRegistry.getRegistry().list();
	    for(int index=0;index<list.length;index++)
	    {
		System.out.println(list[index]);
	    }
	    System.out.println();
	    LocateRegistry.getRegistry().unbind(serviceName);
	}
	else
	{
	    throw new Exception("Unknown command: "+ args[0]);
	}

    }
Ik krijg nu een andere Exception:
Code:
C:\Documents and Settings\Bart\workspace\TorcsClient\bin>java  -classpath "C:\Do
cuments and Settings\Bart\workspace\TorcsClient\bin;C:\Documents and Settings\Ba
rt\workspace\TorcsClient;D:\SHARED\MyLibs\*"  be.XXX.ParticleRepos
itoryServer start
Exception in thread "main" java.lang.ClassCastException: $Proxy0 cannot be cast
to be.XXX.torcs.ParticleRepositoryServer
        at be.XXX.ParticleRepositoryServer.main(ParticleRepository
Server.java:59)

In die lijn staat:
Code:
ParticleRepositoryServer stub = (ParticleRepositoryServer) UnicastRemoteObject.exportObject(repositoryServer, 0);
Edit: fixed: moet ParticleRepositoryServerProtocol zijn. Nu zit ik weer met de aloude exception.


De serviceName wordt ook nog steeds niet gebonden in de RMI registry



Code:
Exception in thread "main" java.rmi.ServerError: Error occurred in server thread
; nested exception is:
        java.lang.NoClassDefFoundError: be/XXX/pso/Particle
        at sun.rmi.server.UnicastServerRef.oldDispatch(UnicastServerRef.java:393
)
        at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:250)
        at sun.rmi.transport.Transport$1.run(Transport.java:159)
        at java.security.AccessController.doPrivileged(Native Method)
        at sun.rmi.transport.Transport.serviceCall(Transport.java:155)
        at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:5
35)
        at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTranspor
t.java:790)
        at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport
.java:649)
        at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExec
utor.java:886)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor
.java:908)
        at java.lang.Thread.run(Thread.java:619)
        at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(Unknow
n Source)
        at sun.rmi.transport.StreamRemoteCall.executeCall(Unknown Source)
        at sun.rmi.server.UnicastRef.invoke(Unknown Source)
        at sun.rmi.registry.RegistryImpl_Stub.rebind(Unknown Source)
        at be.maesbart.ai.torcs.ParticleRepositoryServer.main(ParticleRepository
Server.java:64)
Caused by: java.lang.NoClassDefFoundError: be/maesbart/ai/pso/Particle
        at java.lang.ClassLoader.defineClass1(Native Method)
        at java.lang.ClassLoader.defineClass(ClassLoader.java:616)
        at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:12
4)
        at java.net.URLClassLoader.defineClass(URLClassLoader.java:260)
        at java.net.URLClassLoader.access$000(URLClassLoader.java:56)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:195)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:303)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
        at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:316)
        at java.lang.Class.getDeclaredMethods0(Native Method)
        at java.lang.Class.privateGetDeclaredMethods(Class.java:2427)
        at java.lang.Class.privateGetPublicMethods(Class.java:2547)
        at java.lang.Class.getMethods(Class.java:1410)
        at sun.misc.ProxyGenerator.generateClassFile(ProxyGenerator.java:409)
        at sun.misc.ProxyGenerator.generateProxyClass(ProxyGenerator.java:306)
        at java.lang.reflect.Proxy.getProxyClass(Proxy.java:501)
        at sun.rmi.server.LoaderHandler.loadProxyClass(LoaderHandler.java:680)
        at sun.rmi.server.LoaderHandler.loadProxyClass(LoaderHandler.java:669)
        at sun.rmi.server.LoaderHandler.loadProxyClass(LoaderHandler.java:592)
        at java.rmi.server.RMIClassLoader$2.loadProxyClass(RMIClassLoader.java:6
28)
        at java.rmi.server.RMIClassLoader.loadProxyClass(RMIClassLoader.java:294
)
        at sun.rmi.server.MarshalInputStream.resolveProxyClass(MarshalInputStrea
m.java:238)
        at java.io.ObjectInputStream.readProxyDesc(ObjectInputStream.java:1531)
        at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1493)
        at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1
732)
        at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
        at java.io.ObjectInputStream.readObject(ObjectInputStream.java:351)
        at sun.rmi.registry.RegistryImpl_Skel.dispatch(Unknown Source)
        at sun.rmi.server.UnicastServerRef.oldDispatch(UnicastServerRef.java:386
)
        at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:250)
        at sun.rmi.transport.Transport$1.run(Transport.java:159)
        at java.security.AccessController.doPrivileged(Native Method)
        at sun.rmi.transport.Transport.serviceCall(Transport.java:155)
        at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:5
35)
        at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTranspor
t.java:790)
        at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport
.java:649)
        at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExec
utor.java:886)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor
.java:908)
        at java.lang.Thread.run(Thread.java:619)
Caused by: java.lang.ClassNotFoundException: be.maesbart.ai.pso.Particle
        at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:303)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
        at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:316)
        ... 41 more

blackrabbit

Legacy Member
Ok, het heeft écht te maken met die .JAR bestanden.
Ik heb de .class files in die .jar files eens in mijn project toegevoegd, REpository start op zonder enig probleem...

Hoe los ik dit op? Ik verwijs wllicht op de verkeerde manier naar die jar-bestanden ofzo?

Wolf2000me

Legacy Member
blackrabbit zei:
Ok, het heeft écht te maken met die .JAR bestanden.
Ik heb de .class files in die .jar files eens in mijn project toegevoegd, REpository start op zonder enig probleem...

Hoe los ik dit op? Ik verwijs wllicht op de verkeerde manier naar die jar-bestanden ofzo?

Dat het te maken heeft met de jar bestanden is inderdaad wel duidelijk. Dit is dus ofwel een probleem met je classpath of met het beschikbaar zijn van de juiste class op het juiste moment, of een combinatie van beiden. As you well know natuurlijk.
Elk jar bestand dat op het root classpath staat z'n classes zijn beschikbaar voor je applicatie. Deze dus in je classpath injecteren zodat ze beschikbaar zijn at runtime is perfect in orde. Nu kan dit wel afhangen van je applicatieserver waar je repo in draait. Er zijn servers die jars "cachen", als ik mij niet vergis, want daar ben ik geen expert in. In dat geval moet je zorgen dat je jars tijdens het deployen EN starten van je applicatie op de server beschikbaar zijn.


Nu denk ik wel dat je het voor jezelf nogal moeilijk maakt. Je zoekt dus een soort van distributed model te gebruiken om je configuraties mee te geven en je repo server beslist dus aan welke client welke jar wordt meegegeven. Tot daar ben ik mee, maar waarom worden deze configuraties in aparte jars gestoken? En is een configuratie een 1 op 1 relatie met 1 jar?
Ik zou eigenlijk eerder opteren om een configuratie handler te maken die via je repo server configuraties aangeleverd krijgt en deze doorspeelt aan de TORCS server. Weliswaar zonder deze in een aparte jar te verpakken. Zoek een datatype, en xml is dan het eerste waar ik aan denk. Vergeet de RMI maw.

blackrabbit

Legacy Member
Ow, het was toch niet helemaal zo duidelijk precies :(

Misschien is 'repository' ook niet de beste naam. Uiteindelijk is het gewoon een veredelde queue die op een aparte machine komt te draaien. Ik gebruik trouwens geen applicatie server ofzo.

Die 'configuraties': data-structuur waar dit inzit is een 'Rule', die basically een set van name-value paren bevat. Die name-value paren worden door mijn AI-driver gebruikt als instellingen bij het rijden. Nu, als je wat met AI bekent bent, dan weet je dat bij AI vaak dmv herhaling een optimalisatie wordt bereikt. Dat is in dit geval ook zo (PSO): je maakt een grote set (random) configuraties (Rules) aan, dewelke om de beurt worden getest en bijgesteld.

Dus, mijn originele systeem bestond uit volgende onderdelen:
- de TORCS server, dewelke dus memory leaks heeft
- mijn AI client, dewelke een vrij stabiele memory-footprint heeft.

Echter, door het veelvuldig resetten van een race (om te kunnen herhalen dus), loopt het geheugen van de PC vol (en dat gaat vrij snel :s) door TORCS server. Nu valt mijn code niet zomaar te onderbreken & uitzetten/terug opstarten van server lukt ook niet (client code waar ik van overerf kan daar blijkbaar niet meer om).

Dus ik kwam dan met het idee van een aparte machine op te stellen, waar de set Rules in opgeslagen staat. Initiële idee was gewoon: laat Client die queue aanspreken & bij elke iteratie een nieuwe Rule opvragen/terugplaatsen. Als PC dan crasht/TORCS crasht (want ook dat gebeurt soms), is die queue gewoon nog steeds ok omdat die toch op een andere pc zou draaien. Server/Client gewoon terug opstarten, Client zou gewoon terug Rule vragen en verder beginnen werken.


De bovenstaande Rpository code is dan ook vrij op zichzelf staand: die spreekt ook geen methodes aan van de Rule-objecten die het krijgt ofzo. Die heeft enkel de definities nodig I guess, om geheugen te kunnen reserveren.

Maar dat lijkt maar niet te lukken, zolang de benodigde klasses in die JAR files zitten. En dat vind ik toch wel erg raar. Als ik mijn gewone Client draai (de versie zonder de externe repo), dan kan die zonder probleem aan de klasses in die JAR files & loopt alles zoals het hoort.

Wolf2000me

Legacy Member
Je kan eens testen door een dummy object aan te maken, dit als eerste in je queue te zetten en daar een instantie van aanmaken in je client. Zo'n dummy object zonder vars en zonder getters en setters, gewoon een public class Dummy {}. Als je daar dan een NoClassDef exception op krijgt dan weet je dat het ligt aan andere classes die niet op het juiste moment op je classpath geraakt zijn, maar wel gebruikt worden in je aangeleverde jars.

Maar toch nog zou ik niet aanraden van je approach met jars te behouden.

blackrabbit

Legacy Member
Wolf2000me zei:
Maar toch nog zou ik niet aanraden van je approach met jars te behouden.
???
Wat als dat System libraries zouden zijn? Zit al die standaard Java code niet in JAR files? (ArrayList, Math.*, ..)

Wolf2000me

Legacy Member
blackrabbit zei:
???
Wat als dat System libraries zouden zijn? Zit al die standaard Java code niet in JAR files? (ArrayList, Math.*, ..)

System libraries zitten inderdaad in de Java 6 stack.

Ik bedoel dat ik het voordeel niet zie van configuratie met jar files mee te nemen via een repo.

Je repo server, of eigenlijk client zeker? Want je zegt dat deze niet in een appserver draait. Deze mankeert dus volgens de stacktrace je benodigde jar(s). Het gaat in de stacktrace over Particle.

Ik neem aan dat RuleParticle gebruik maakt van Particle en dat ParticleRepositoryServerProtocol gebruik maakt van één of beiden? Waar zitten deze classes? Ik neem aan dat deze eerste 2 sowieso nodig zijn in zowel je client als in je reposerver, right?

blackrabbit

Legacy Member
Mmmmh, die ParticleRepositoryServerProtocol zit in dezelfde package als de rest van mijn client & werd tijdens het testen ook gewoon op dezelfde machine, in hetzelfde pad uitgevoerd. Vandaar dat het zo raar is dat mijn client code die JAR files wel kan gebruiken (Rule, Particle e.d. zitten in die JAR files), maar de RepositoryServer niet. Vandaar dat dat zo raar is: die Repo-server kan in princiepe aan dezelfde bestanden/klasses als mijn normale client code.

RuleParticle is idd een subklasse van Particle.

RuleParticle IS EEN Particle.
Een Rule IS EEN configuratie voor een client (voor een driver). Bevat dus settings die de driver gebruikt om het circuit rond te rijden.
Een RuleParticle HEEFT EEN Rule.
RepositoryServer HEEFT EEN SET RuleParticle

Die RepositoryServer heeft geen applicatieserver nodig he, die heeft een eigen main-method en registreert zich in de RMI registry, zodat de client(s) een reference naar die repository server kunnen aanvragen & zo kunnen communiceren.


In die JAR files zit dus oa:
- Rule
- Particle
- ...

RuleParticle echter, zit in dezelfde package als mijn client code en de repo-server code, en zit NIET in een JAR (ik roep de .class bestanden gewoon rechtstreeks op voor die klasses).


Ik ben trouwens effe een andere weg ingeslagen (omdat ik me dood ergerde aan dit probleem + ik ook wel enkele drawbacks zien aan deze 'architectuur').
Nieuwe idee: centrale master pusht opdrachten (= configuraties) naar clients die deze dan behandelen en resultaat-info terugsturen naar de server. Ik ga wss op dezelfde problemen stoten (kan nog niet testen, deze aanpak vergt meer verandering aan de originele code :( ) maar uiteindelijk gaat het wel een mooiere aanpak zijn dan bovenstaande. (vb: verantwoordelijkheid van initieel vullen van repository, bijhouden van de resultaten (die ALLE clients nodig hebben) etc etc).

Wolf2000me

Legacy Member
blackrabbit zei:
Mmmmh, die ParticleRepositoryServerProtocol zit in dezelfde package als de rest van mijn client & werd tijdens het testen ook gewoon op dezelfde machine, in hetzelfde pad uitgevoerd. Vandaar dat het zo raar is dat mijn client code die JAR files wel kan gebruiken (Rule, Particle e.d. zitten in die JAR files), maar de RepositoryServer niet. Vandaar dat dat zo raar is: die Repo-server kan in princiepe aan dezelfde bestanden/klasses als mijn normale client code.


RuleParticle is idd een subklasse van Particle.

RuleParticle IS EEN Particle.
Een Rule IS EEN configuratie voor een client (voor een driver). Bevat dus settings die de driver gebruikt om het circuit rond te rijden.
Een RuleParticle HEEFT EEN Rule.
RepositoryServer HEEFT EEN SET RuleParticle

Dus tijdens de runtime van RepositoryServer, wanneer je main method er een instantie van aanmaakt is je Particle class niet beschikbaar.
Welke IDE gebruik je? Best van op new RepositoryServer() een breakpoint te zetten om dan eens naar je structuur te kijken van je target. Veel ervaring met RMI registry heb ik nu niet.


blackrabbit zei:
In die JAR files zit dus oa:
- Rule
- Particle
- ...

RuleParticle echter, zit in dezelfde package als mijn client code en de repo-server code, en zit NIET in een JAR (ik roep de .class bestanden gewoon rechtstreeks op voor die klasses).

Een class file staat normaal gezien ergens anders dan een java file. Zoals je wel weet is de java file de source en de class de target. Wanneer je code uitvoert wordt altijd de class file gebruikt en omgezet naar bytecode, het is het classpath van die class files dat juist moet staan. Mijns inziens klopt dan het classpath niet met het pad van de jars wanneer je je repo server draait. Wanneer RuleParticle gebruikt wordt is echt wel best practice van in dezelfde jar of module ook je base classes te hebben. Uiteraard zijn hier tal van uitzonderingen op, maar dan enkel wanneer je project structuur met deftig dependency management werkt zoals met Maven.


blackrabbit zei:
Ik ben trouwens effe een andere weg ingeslagen (omdat ik me dood ergerde aan dit probleem + ik ook wel enkele drawbacks zien aan deze 'architectuur').
Nieuwe idee: centrale master pusht opdrachten (= configuraties) naar clients die deze dan behandelen en resultaat-info terugsturen naar de server. Ik ga wss op dezelfde problemen stoten (kan nog niet testen, deze aanpak vergt meer verandering aan de originele code :( ) maar uiteindelijk gaat het wel een mooiere aanpak zijn dan bovenstaande. (vb: verantwoordelijkheid van initieel vullen van repository, bijhouden van de resultaten (die ALLE clients nodig hebben) etc etc).

Terecht. Ik denk dat als je je dependencies in orde brengt, voor de gemakkelijkheid dus al je java in jar, dit een stuk gemakkelijker gaat werken. Hou er ook rekening mee dat jars op zichzelf geen dependent jars in zich meedragen tenzij je dit specifiek zelf regelt met je build tool. Hoe maak je je jars aan?

blackrabbit

Legacy Member
Wolf2000me zei:
Dus tijdens de runtime van RepositoryServer, wanneer je main method er een instantie van aanmaakt is je Particle class niet beschikbaar.
Welke IDE gebruik je? Best van op new RepositoryServer() een breakpoint te zetten om dan eens naar je structuur te kijken van je target. Veel ervaring met RMI registry heb ik nu niet.
Ik gebruik Eclipse, maar ik start mijn programma's altijd van de command line.
En idd, Particle is dan niet beschikbaar maar:
- mijn client-klasse (die dus ook een main heeft) staat in dezelfde directory als particle repo, en verwijst naar dezelfde JAR bestanden (met succes).

Wolf2000me zei:
Een class file staat normaal gezien ergens anders dan een java file. Zoals je wel weet is de java file de source en de class de target. Wanneer je code uitvoert wordt altijd de class file gebruikt en omgezet naar bytecode, het is het classpath van die class files dat juist moet staan. Mijns inziens klopt dan het classpath niet met het pad van de jars wanneer je je repo server draait.
Ofcourse, mijn .class files zitten in */bin, source files in */src. Ik laat Eclipse alles compileren en voer dan via command line mijn programma uit (zie ook eerste post). En dat pad, tja, ik zie niet wat daar verkeerd aan kan zijn. Zoals ik al zei: andere .class file die in dezelfde dir zit als repo-klasse en dezelfde JAR bestanden aanspreekt, draait wél zonder problemen.

Wolf2000me zei:
Wanneer RuleParticle gebruikt wordt is echt wel best practice van in dezelfde jar of module ook je base classes te hebben. Uiteraard zijn hier tal van uitzonderingen op, maar dan enkel wanneer je project structuur met deftig dependency management werkt zoals met Maven.
Daar ben ik het niet mee eens. Het kan toch geen probleem zijn om subklasses te schrijven voor klasses die in een JAR file zitten? Mijn *pso.jar file bevat algemene code voor het PSO-algoritme. Mijn client applicatie overschrijft die met client-specifieke code (Rule, RuleParticle). Das toch net het punt van libraries (wat die beide JAR files in princiepe zijn).

Wolf2000me zei:
Terecht. Ik denk dat als je je dependencies in orde brengt, voor de gemakkelijkheid dus al je java in jar, dit een stuk gemakkelijker gaat werken. Hou er ook rekening mee dat jars op zichzelf geen dependent jars in zich meedragen tenzij je dit specifiek zelf regelt met je build tool. Hoe maak je je jars aan?
JAR files maak ik gewoon aan met Eclipse: Export -> JAR.
Over welke dependencies heb je het nu? Qua structuur zit die code goed in elkaar hoor. En zoals ik al zei: mijn originele client werkte op net dezelfde manier.

Maar goed, ik had ondertussen zoveel in die code liggen knoeien dat het van geen kanten meer werkte & ik alles dus heb weggesmeten en ben begonnen aan die nieuwe aanpak. Van zodra dat wat werkt laat ik wel iets weten ;-)

In ieder geval bedankt!

Wolf2000me

Legacy Member
blackrabbit zei:
Ik gebruik Eclipse, maar ik start mijn programma's altijd van de command line.
En idd, Particle is dan niet beschikbaar maar:
- mijn client-klasse (die dus ook een main heeft) staat in dezelfde directory als particle repo, en verwijst naar dezelfde JAR bestanden (met succes).

Ofcourse, mijn .class files zitten in */bin, source files in */src. Ik laat Eclipse alles compileren en voer dan via command line mijn programma uit (zie ook eerste post). En dat pad, tja, ik zie niet wat daar verkeerd aan kan zijn. Zoals ik al zei: andere .class file die in dezelfde dir zit als repo-klasse en dezelfde JAR bestanden aanspreekt, draait wél zonder problemen.

Mja, inderdaad dat zag er allemaal in orde uit. Je kan Eclipse natuurlijk ook je main classes laten uitvoeren in debug mode zodat je met breakpoints werken.
Ik weet nu niet hoe het zit met Eclipse, da's al te lang geleden, maar met IntelliJ kan je in debug mode een soort van "prediction" zien. Dit laat dan ook mogelijke toekomstige runtime exceptions zien zoals NullPointerExceptions en dus ook NoClassDef.


blackrabbit zei:
Daar ben ik het niet mee eens. Het kan toch geen probleem zijn om subklasses te schrijven voor klasses die in een JAR file zitten? Mijn *pso.jar file bevat algemene code voor het PSO-algoritme. Mijn client applicatie overschrijft die met client-specifieke code (Rule, RuleParticle). Das toch net het punt van libraries (wat die beide JAR files in princiepe zijn).

For arguments sake dan maar :)

Ja absoluut maar het moet een nut hebben. Er is iets zoals bv. API zoals xml-api en een implementatie zoals Xerces.

Maven Repository: org.bluestemsoftware.open.maven.tparty &#187; xerces-impl &#187; 2.9.0

Maar het moet een nut hebben. Als je niet van plan bent van bv. meer dan 1 implementatie te hebben van je base classes dan denk ik dat als je problemen hebt met het classpath het beter is van deze bij elkaar te houden. Als alles werkt is het uiteindelijk een koud kunstje van dit te scheiden.



blackrabbit zei:
JAR files maak ik gewoon aan met Eclipse: Export -> JAR.
Over welke dependencies heb je het nu? Qua structuur zit die code goed in elkaar hoor. En zoals ik al zei: mijn originele client werkte op net dezelfde manier.

Maar goed, ik had ondertussen zoveel in die code liggen knoeien dat het van geen kanten meer werkte & ik alles dus heb weggesmeten en ben begonnen aan die nieuwe aanpak. Van zodra dat wat werkt laat ik wel iets weten ;-)

In ieder geval bedankt!

Professionele build tools laten toe van dependencies te definieren op je project. Zoals bv een dependency te definiëren van de API op de implementatie. Ik wist niet hoe je je jars maakte, maar in elk geval komen zo'n dependencies nooit mee met een geëxporteerde jar. Dit is uiteraard anders met een war of ear. Maar dat is niet van toepassing.

In Eclipse kan je bv. ook je classpath beheren in de GUI, je hebt daardoor misschien wel een beter overzicht.

blackrabbit

Legacy Member
Wolf2000me zei:
Mja, inderdaad dat zag er allemaal in orde uit. Je kan Eclipse natuurlijk ook je main classes laten uitvoeren in debug mode zodat je met breakpoints werken.
Ik weet nu niet hoe het zit met Eclipse, da's al te lang geleden, maar met IntelliJ kan je in debug mode een soort van "prediction" zien. Dit laat dan ook mogelijke toekomstige runtime exceptions zien zoals NullPointerExceptions en dus ook NoClassDef.
True. De reden waarom ik command line gebruik is dan ook omdat ik het classpath gepruts in Eclipse niet in orde kreeg :D Ik denk dat ik dat ook maar ga doen wanneer deze nieuwe 'branch' afgewerkt is.


Wolf2000me zei:
For arguments sake dan maar :)

Ja absoluut maar het moet een nut hebben. Er is iets zoals bv. API zoals xml-api en een implementatie zoals Xerces.

Maven Repository: org.bluestemsoftware.open.maven.tparty » xerces-impl » 2.9.0

Maar het moet een nut hebben. Als je niet van plan bent van bv. meer dan 1 implementatie te hebben van je base classes dan denk ik dat als je problemen hebt met het classpath het beter is van deze bij elkaar te houden. Als alles werkt is het uiteindelijk een koud kunstje van dit te scheiden.
Dat is dan ook net de reden waarom die code in 2 JAR bestanden zit: die staat op zichzelf. De ene is een package met 'general' utility klasses. De andere bevat klasses om aan PSO-optimalisatie te kunnen doen. In princiepe zou ik uit die package rechstreeks de Rule en Particle klasses kunnen gebruiken. Maar omdat het net wat performanter/generieker is om er van over te erven, heb ik het zo gedaan (anders moet er een O(n) conversie gebeuren, ziede). Dus: die JAR zijn er met goede reden ;-)


Wolf2000me zei:
Professionele build tools laten toe van dependencies te definieren op je project. Zoals bv een dependency te definiëren van de API op de implementatie. Ik wist niet hoe je je jars maakte, maar in elk geval komen zo'n dependencies nooit mee met een geëxporteerde jar. Dit is uiteraard anders met een war of ear. Maar dat is niet van toepassing.

In Eclipse kan je bv. ook je classpath beheren in de GUI, je hebt daardoor misschien wel een beter overzicht.
Mja ok, miss moet ik me daar eens in verdiepen... IK ben het gewoon om 'from the ground up' te werken. Voel me daar ook comfortabeler bij, eerlijk gezegd.

En classpaths in Eclipse kreeg ik vorige keer niet in orde :D Maar dat zal wel aan mij gelegen hebben ;-)

Wolf2000me

Legacy Member
blackrabbit zei:
True. De reden waarom ik command line gebruik is dan ook omdat ik het classpath gepruts in Eclipse niet in orde kreeg :D Ik denk dat ik dat ook maar ga doen wanneer deze nieuwe 'branch' afgewerkt is.


Mja ok, miss moet ik me daar eens in verdiepen... IK ben het gewoon om 'from the ground up' te werken. Voel me daar ook comfortabeler bij, eerlijk gezegd.

En classpaths in Eclipse kreeg ik vorige keer niet in orde Maar dat zal wel aan mij gelegen hebben ;-)

Ik zou aanraden van te beginnen werken met IntelliJ. Daar is een community edition van die gratis is. Ik vind het classpath gepruts in IntelliJ een stuk beter geregeld.
En als je dan toch bezig bent kan ik je ten sterkste aanraden van Maven 2 in je setup te steken. Het modulair systeem met dependency management dat native werkt in IntelliJ maar ook onafhankelijk is heel goed om jars etc mee te builden.

Beetje documentatie:

Creating and importing Maven projects - IntelliJ-Wiki

In jouw geval zou je dan je project hebben met 3 modules. Je repo server, je client, en je utility classes. Elke module kan je apart builden tot een jar met één simpel command.

Ik werk al meer dan 3 jaar met IntelliJ en Maven2. Binnenkort moet ik met een andere build tool werken, wat wel ok is, maar ook met Eclipse. Vooral dit laatste wordt stevig afkicken van IntelliJ.
Maar da's natuurlijk mijn persoonlijke preference ;)

hf & gl ;)

blackrabbit

Legacy Member
FYI: het lag aan de codebase die niet was gespecifieerd :(

Code:
-Djava.rmi.server.codebase=...

Er achter gekomen toen bleek dat oude RMI-code (waarvan ik wist dat ze had gewerkt) het ook niet meer deed, met dezelfde foutmeldingen...
Het archief is een bevroren moment uit een vorige versie van dit forum, met andere regels en andere bazen. Deze posts weerspiegelen op geen enkele manier onze huidige ideeën, waarden of wereldbeelden en zijn op sommige plaatsen gecensureerd wegens ontoelaatbaar. Veel zijn in een andere tijdsgeest gemaakt, al dan niet ironisch - zoals in het ironische subforum Off-Topic - en zouden op dit moment niet meer gepost (mogen) worden. Toch bieden we dit archief nog graag aan als informatiedatabank en naslagwerk. Lees er hier meer over of start een gesprek met anderen.
Terug
Bovenaan