Skip to main content

Unit Testing jxta applications? (only one peer in a JVM!?)

19 replies [Last post]
enygma2002
Offline
Joined: 2008-12-22
Points: 0

Hi!

I have a wrapper class that does the jxta work and I am trying to unit test it.

for it, I have these 2 methods for instance:
- configureNetwork() - instantiate a networkManager and do some settings.
- startNetworkAndConnect() - manager.startNetwork() and wait for a connect to a rdv.

I create 3 instances of this class representing 3 peers and another instance representing a RDV peer.

- I do configureNetwork() on all 4 instances, each one with a different jxtaHome.
- I do a startNetworkAndConnect() on the RDV peer and it starts up.

But when I want to startNetworkAndConnect() on one of the simpe edge peers, right after starting the RDV peer, I get:

testConnectToNetwork(jxta.test.NetworkTest) Time elapsed: 5.112 sec <<< ERROR!
net.jxta.exception.PeerGroupException: Only a single instance of the World Peer Group may be instantiated at a single time.
at net.jxta.peergroup.WorldPeerGroupFactory.newWorldPeerGroup(WorldPeerGroupFactory.java:282)
at net.jxta.peergroup.WorldPeerGroupFactory.(WorldPeerGroupFactory.java:178)
at net.jxta.peergroup.NetPeerGroupFactory.(NetPeerGroupFactory.java:205)
at net.jxta.platform.NetworkManager.startNetwork(NetworkManager.java:410)
at org.xwoot.jxta.JxtaPeer.startNetworkAndConnect(JxtaPeer.java:134)
at org.xwoot.jxta.test.NetworkTest.testConnectToNetwork(NetworkTest.java:59)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:59)
at org.junit.internal.runners.MethodRoadie.runTestMethod(MethodRoadie.java:98)
at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:79)
at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:87)
at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:77)
at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:42)
at org.junit.internal.runners.JUnit4ClassRunner.invokeTestMethod(JUnit4ClassRunner.java:88)
at org.junit.internal.runners.JUnit4ClassRunner.runMethods(JUnit4ClassRunner.java:51)
at org.junit.internal.runners.JUnit4ClassRunner$1.run(JUnit4ClassRunner.java:44)
at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:27)
at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:37)
at org.junit.internal.runners.JUnit4ClassRunner.run(JUnit4ClassRunner.java:42)
at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:62)
at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.executeTestSet(AbstractDirectoryTestSuite.java:140)
at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.execute(AbstractDirectoryTestSuite.java:127)
at org.apache.maven.surefire.Surefire.run(Surefire.java:177)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:338)
at org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:997)

Each instance has its own networkManager that has a home in a different directory. All of the 4 peers are started in the same JVM but why does JXTA use the same registry for the worldPeerGroup? It should use the existing worldPeer group or at least create a new one and associate it to the creating networkManager.

Can't I have more than one peer in tha same JVM? If not, how can I do unit tests then?

Am I doing something wrong? Please help.

Thank you.

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
bondolo
Offline
Joined: 2003-06-11
Points: 0

> Are you referring to this technique
> http://osdir.com/ml/java.jxta.user/2007-01/msg00179.ht
> ml ?

I'm confused. This post seems to be about running multiple network peer group instances which is supported. You do have to bypass the NeworkManager helper class. (another case where a convenience class that helps 95% of the time gets in the way for 5%).

Have you seen : https://jxta-jxse.dev.java.net/source/browse/jxta-jxse/trunk/tutorials/s... ? It's not relevant for the unit testing problem but seems to solve what the osdir question is asking.

enygma2002
Offline
Joined: 2008-12-22
Points: 0

I do not need to start multiple networks(net peer groups with different infrastructure IDs like in the multinetgroup tutorial) from one JVM. I need to have multiple connections to the same network in one JVM. (multiple peers in the same network interacting with each other).

I referred the osdir thread because of the classLoader suggested technique.

Sorry for the confusion. I will try your previous suggestion from the bechmarking project.

P.S.: You said something about a better example of the classLoader work-around in the practical jxta code samples. I can not find it. Can you please point it out? (maybe Jerome can?)

Thanks!

bondolo
Offline
Joined: 2003-06-11
Points: 0

There is a technique which allows more than one JXSE instance to run within a single JVM. The technique loads each JXTA peer into a separate class loader.

An example of this technique is included as part of the new 'Practical JXTA'. This example is derived from code which was originally developed for the JXTA benchmark project. The source for the original sample can be found at 'https://jxta-benchmarking.dev.java.net'.

I recall that Jerome found a few issues with the implementation found at jxta-benchmarking and he can probably suggest what needs to be fixed/changed.

enygma2002
Offline
Joined: 2008-12-22
Points: 0

Hi Mike!

Are you referring to this technique http://osdir.com/ml/java.jxta.user/2007-01/msg00179.html ?

I have already tried it and it did not work for me (as you can see in this thread).

After checking out the project you mentioned, I see the https://jxta-benchmarking.dev.java.net/source/browse/jxta-benchmarking/t... tests use the techinique you mentioned. It's basically the same one I tried, but I probably did it wrong.

I will try it the way it is done here and I should be able to get the desired result.

For others following this thread, the main files to look at regarding this solution are:
https://jxta-benchmarking.dev.java.net/source/browse/jxta-benchmarking/t... for the custom ClassLoader that separates static instances. (you need a class loader for each peer you want to start)
https://jxta-benchmarking.dev.java.net/source/browse/jxta-benchmarking/t... (this is where it is used)
https://jxta-benchmarking.dev.java.net/source/browse/jxta-benchmarking/t... (this is a test -- the testClass that requires multiple instances)

As soon as I have time to go back and write tests for my application's jxta module, I`ll post here my results.

Others are welcomed to post their results as well.

Thanks for all the help, especially Mike (bondolo) for your precious information.

P.S.: It would be really nice if we could see this in new versions of jxta without all the classLoader hacking stuff. ( my whishlist :P )

bondolo
Offline
Joined: 2003-06-11
Points: 0

> P.S.: It would be really nice if we could see this in
> new versions of jxta without all the classLoader
> hacking stuff. ( my whishlist :P )

Agreed. For API simplification reasons JXSE was implemented with a singleton in PeerGroup an option to 'instantiate jxse but don't use the global groups registry' would help.

One major blocker to this is the static Timer objects contained in a few places. Before JXSE used NIO there was (and according to some people still is) an issue with the number of Threads JXSE uses. The static timers save a few threads. However, they should be converted to used a group local ScheduledExcutorService before we can remove the requirement of statics.

hamada
Offline
Joined: 2003-06-12
Points: 0

The current NetworkManager in the JXTA platform only supports a single instance in a VM. NetworkManager has evolved to support this feature (multiple instances in a single vm) under project http://shoal.dev.java.net

I don't have the cycles today to back port the changes, however I will provide guidance to any volunteers wishing to embark on the task.

Cheers

enygma2002
Offline
Joined: 2008-12-22
Points: 0

Thanks for the answer hamada!

However, this is quite a nasty thing to stumble upon :( No Unit testing makes jxta application development very fragile (sensitive to changes) :| and this was not mentioned anywhere in any available documentation.

It this feature going to be supported in future versions of jxta? If so, which one?

hamada
Offline
Joined: 2003-06-12
Points: 0

This feature is supported by JXTA already, but not the utility NetworkManager. The basic steps are to create a WorldPeerGroup which is shared by all instances of the NetPeerGroups. As for when, I don't have the spare cycles to port the utility, but as I stated, I would more than happy to work with someone willing to contribute the back port.

enygma2002
Offline
Joined: 2008-12-22
Points: 0

Thanks for the suggestion.

As for the modification of the current NetworkManager, would't this be just a matter of reusing the WorldPeerGroup if it already exists and if not, creating one? The current implementation looks at the registry and if a WorldPeerGroup is already registered, it just throws an exception. I don`t understand why it does that but there could be other implications that I have not noticed.

It should not be too hard to do and, in my opinion, this should get a higher priority in the jxta development because testing is a key element in any project, as I am sure you already know.

If time allows, I`ll try your suggestion.

Best wishes!

adamman71
Offline
Joined: 2007-01-31
Points: 0

There is one solution using different classloaders, but it is a pain...

Running multiple peer in the same JVM requires rewritting core parts of the code. There is a good chance that OSGi might really help with that, but that is for the future...

J.

artemgr
Offline
Joined: 2004-06-18
Points: 0

I was able to run two peers in the same JVM by using a reflection hack:
Using Java Reflection, I replaced
net.jxta.peergroup.PeerGroup$GlobalRegistry.registry
with a customized HashMap instance which makes all keys ThreadLocal.

The second peer discovered the redezvous started on the first peer
and was able to send a message to the first peer.

JXTA used: jxta-jxse-2.6-20090213.011822-22.jar

I can publish the Scala code of the hack if anybody is insterested.

enygma2002
Offline
Joined: 2008-12-22
Points: 0

This: http://osdir.com/ml/java.jxta.user/2007-01/msg00179.html did not work for me.

I did this:

ClassLoader parent = this.getClass().getClassLoader();
ClassLoader cl1 = new URLClassLoader(new URL[]{}, parent);
ClassLoader cl2 = new URLClassLoader(new URL[]{}, parent);

Peer peer1 = (Peer) cl1.loadClass("org.myPackage.JxtaPeer").newInstance();
Peer peer2 = (Peer) cl2.loadClass("org.myPackage.JxtaPeer").newInstance();

String peer1Name = "peer1";
String peer2Name = "peer2";

peer1.configureNetwork(new File(WORKING_DIR, peer1Name), ConfigMode.EDGE);
peer2.configureNetwork(new File(WORKING_DIR, peer2Name), ConfigMode.EDGE);

peer1.startNetworkAndConnect(null);
Assert.assertTrue(peer1.isConnectedToNetwork());

peer2.startNetworkAndConnect(null); <----------------------net.jxta.exception.PeerGroupException: Only a single instance of the World Peer Group may be instantiated at a single time.
Assert.assertTrue(peer2.isConnectedToNetwork());

peer1.stopNetwork();
Assert.assertFalse(peer1.isConnectedToNetwork());

peer2.stopNetwork();
Assert.assertFalse(peer2.isConnectedToNetwork());

deniswsrosa
Offline
Joined: 2006-05-05
Points: 0

Hi enygma2002 !!!

I guess that you can do it if you choose a diferent WORKING_DIR for the peer2 and run him on other thread, Because i run here any peers in the same machine just change the location of him in my directories.

Try this and tell me.

Best Wishes!

enygma2002
Offline
Joined: 2008-12-22
Points: 0

Hi deniswsrosa!

Thanks for your reply but I am afraid I already tried that before posting on the forum.

In my original post:
>Each instance has its own networkManager that has a home in a different directory. All of the 4 peers are started in the same JVM but why does JXTA use the same registry for the worldPeerGroup? It should use the existing worldPeer group or at least create a new one and associate it to the creating networkManager.

In my latest post:
>peer1.configureNetwork(new File(WORKING_DIR, peer1Name), ConfigMode.EDGE);
>peer2.configureNetwork(new File(WORKING_DIR, peer2Name), ConfigMode.EDGE);
- peer1 is in directory WORKING_DIR/peer1Name
- peer2 is in directory WORKING_DIR/peer2Name

It is just not enough. Jxta seems to have a static registry of worldPeerGroup instances that can have maximum one such entry.

If you do manager.startNetwork() more than once, Jxta just sees that one such group has already been registered and refuses to go on instead of just reusing the worldPeerGroup instance.

I fail to see the logic in this and would really appreciate some help.

This: http://osdir.com/ml/java.jxta.user/2007-01/msg00179.html suggested that using different class loaders will cause the static instances "split" and each class loader would manage an instance of the static fields.

I tried it and it did not work.

Please help.

deniswsrosa
Offline
Joined: 2006-05-05
Points: 0

Hi enygma2002 !

You are right, i did many attempts here, and when the peer2 runs the code throw a exception... Well, i will find more...

Best Wishes!

enygma2002
Offline
Joined: 2008-12-22
Points: 0

I don't remember reading this in the documentation. :|

enygma2002
Offline
Joined: 2008-12-22
Points: 0

It would seem that doing repeatedly pairs of:

manager.startNetwork();
manager.stopNetwork();

Totally confuses Jxta. The result most often is the dreaded "Only a single instance of the World Peer Group may be instantiated at a single time." PeerGroupException, but sometimes startNetwork() does not put JXTA in the right state and waitForRendezvousConnection(), while checking the flags started & !stopped, immediately returns and breaks application logic.

Can the JXTA platform be TOTALY and COMPLETELY shut-down programatically and then restarted whenever needed? Does the singleton design prevent this? Any solutions?

How are JXTA tests written then?

Thank you.

Please help out

deniswsrosa
Offline
Joined: 2006-05-05
Points: 0

hmm... i have exactly the same problem

enygma2002
Offline
Joined: 2008-12-22
Points: 0

If this http://www.prestonlee.com/archives/101 is true then it is a huge pain not being able to unit test the application :(

I really hope things have changed since the time the article was posted.

If things have not changed and JXTA is still singleton based then testing can only be done on the public network or else you have to manually set up a similar environment. Anyway, much harder than automatic testing. :|

Anyone know anything else?