/*
* Copyright (c) 2002-2007 Sun Microsystems, Inc. All rights reserved.
*
* The Sun Project JXTA(TM) Software License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The end-user documentation included with the redistribution, if any, must
* include the following acknowledgment: "This product includes software
* developed by Sun Microsystems, Inc. for JXTA(TM) technology."
* Alternately, this acknowledgment may appear in the software itself, if
* and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must
* not be used to endorse or promote products derived from this software
* without prior written permission. For written permission, please contact
* Project JXTA at http://www.jxta.org.
*
* 5. Products derived from this software may not be called "JXTA", nor may
* "JXTA" appear in their name, without prior written permission of Sun.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN
* MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JXTA is a registered trademark of Sun Microsystems, Inc. in the United
* States and other countries.
*
* Please see the license information page at :
* <http://www.jxta.org/project/www/license.html> for instructions on use of
* the license in source files.
*
* ====================================================================
*
* This software consists of voluntary contributions made by many individuals
* on behalf of Project JXTA. For more information on Project JXTA, please see
* http://www.jxta.org.
*
* This license is based on the BSD license adopted by the Apache Foundation.
*/
package net.jxta.impl.loader;
import java.io.File;
import java.net.URI;
import net.jxta.content.ContentProviderEvent;
import net.jxta.impl.peergroup.*;
import java.net.URL;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import junit.framework.JUnit4TestAdapter;
import net.jxta.content.Content;
import net.jxta.content.ContentID;
import net.jxta.content.ContentProvider;
import net.jxta.content.ContentProviderListener;
import net.jxta.content.ContentService;
import net.jxta.content.ContentShare;
import net.jxta.discovery.DiscoveryService;
import net.jxta.document.AdvertisementFactory;
import net.jxta.document.Document;
import net.jxta.document.Element;
import net.jxta.id.IDFactory;
import net.jxta.peergroup.PeerGroup;
import net.jxta.peergroup.PeerGroupID;
import net.jxta.platform.JxtaLoader;
import net.jxta.platform.Module;
import net.jxta.platform.ModuleClassID;
import net.jxta.platform.ModuleSpecID;
import net.jxta.platform.NetworkManager;
import net.jxta.protocol.ModuleImplAdvertisement;
import net.jxta.protocol.PeerGroupAdvertisement;
import net.jxta.test.util.TempDir;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;
public class RefJxtaLoaderTest {
static final Logger LOG =
Logger.getLogger(RefJxtaLoaderTest.class.getName());
/**
* Default compatibility equater instance.
*/
private static final CompatibilityEquater COMP_EQ =
new CompatibilityEquater() {
public boolean compatible(Element test) {
return CompatibilityUtils.isCompatible(test);
}
};
static TempDir home;
static NetworkManager netMan;
static PeerGroup pg;
static ContentService service;
static Content parentContent;
static Content bothContent;
static URL testJar;
ContentService testService;
RefJxtaLoader loader;
PeerGroup testGroup;
public static junit.framework.Test suite() {
return new JUnit4TestAdapter(RefJxtaLoaderTest.class);
}
@BeforeClass
public static void setupClass() throws Exception {
LOG.info("============ Begin setupClass");
home = new TempDir();
netMan = new NetworkManager(NetworkManager.ConfigMode.ADHOC, "test");
netMan.setInstanceHome(home.toURI());
pg = netMan.startNetwork();
netMan.waitForRendezvousConnection(1000);
testJar = RefJxtaLoaderTest.class.getResource("/TestJar.jar");
assertNotNull("TestJar could not be located", testJar);
service = pg.getContentService();
assertNotNull("ContentService not present in peer group");
Document jarDoc = new URIDocument(testJar.toURI());
ContentID contentID = IDFactory.newContentID(pg.getPeerGroupID(), true);
bothContent = new Content(contentID, null, jarDoc);
List<ContentShare> shares = service.shareContent(bothContent);
assertNotNull(shares);
assertTrue(shares.size() > 0);
contentID = IDFactory.newContentID(pg.getPeerGroupID(), true);
parentContent = new Content(contentID, null, jarDoc);
shares = service.shareContent(parentContent);
assertNotNull(shares);
assertTrue(shares.size() > 0);
LOG.finest("NPG PGA: " + pg.getPeerGroupAdvertisement());
LOG.info("============ End setupClass");
}
@AfterClass
public static void tearDownClass() throws InterruptedException {
LOG.info("============ Begin tearDownClass");
service.unshareContent(bothContent.getContentID());
home.delete();
netMan.stopNetwork();
LOG.info("============ End tearDownClass");
System.err.flush();
System.out.flush();
Thread.sleep(500);
}
@Before
public void setup() throws Exception {
LOG.info("============ Begin setup");
PeerGroupAdvertisement pga;
/*
* Setup a test-specific peer group.
*/
PeerGroupID pgid = IDFactory.newPeerGroupID();
ModuleImplAdvertisement pgMIA =
pg.getAllPurposePeerGroupImplAdvertisement();
testGroup = pg.newGroup(pgid, pgMIA, "Test group", "Test group");
testService = testGroup.getContentService();
if (LOG.isLoggable(Level.FINE)) {
for (ContentProvider provider : testService.getContentProviders()) {
provider.addContentProviderListener(
new ContentProviderListener() {
public void contentShared(ContentProviderEvent event) {
LOG.fine(event.toString());
}
public void contentUnshared(ContentProviderEvent event) {
LOG.fine(event.toString());
}
public boolean contentSharesFound(
ContentProviderEvent event) {
LOG.fine(event.toString());
return true;
}
});
}
}
assertNotNull(testService);
List<ContentShare> shares = testService.shareContent(bothContent);
assertNotNull(shares);
assertTrue(shares.size() > 0);
/*
* Create a test loader referencing our test-specific group.
*/
loader = new RefJxtaLoader(new URL[0], null, COMP_EQ, testGroup);
LOG.info("============ End setup");
}
@After
public void tearDown() throws Exception {
LOG.info("============ Begin tearDown");
testService.unshareContent(bothContent.getContentID());
testGroup.unref();
Thread.sleep(300);
LOG.info("============ End tearDown");
}
/**
* Verify that we cannot load the POJO class as a Module when the package
* URI references a jar URL.
*/
@Test
public void loadPOJO() {
LOG.info("loadPOJO");
try {
ModuleClassID baseClass = IDFactory.newModuleClassID();
ModuleImplAdvertisement mia = (ModuleImplAdvertisement)
AdvertisementFactory.newAdvertisement(
ModuleImplAdvertisement.getAdvertisementType());
mia.setModuleSpecID(IDFactory.newModuleSpecID(baseClass));
mia.setCode("TestPOJO");
mia.setUri(testJar.toString());
mia.setCompat(
pg.getAllPurposePeerGroupImplAdvertisement().getCompat());
mia.setDescription("Non-Module in a Jar");
Class clazz = loader.defineClass(mia);
fail("Was able to load a POJO as a Module");
} catch (ClassFormatError err) {
// Good. Fall through.
} catch (Exception exc) {
LOG.log(Level.SEVERE, "Caught exception", exc);
fail("Caught exception");
}
}
/**
* Verify that we can load Modules when the package URI references a
* Jar URL.
*/
@Test
public void loadModule() {
LOG.info("loadModule");
try {
ModuleClassID baseClass = IDFactory.newModuleClassID();
ModuleImplAdvertisement mia = (ModuleImplAdvertisement)
AdvertisementFactory.newAdvertisement(
ModuleImplAdvertisement.getAdvertisementType());
mia.setModuleSpecID(IDFactory.newModuleSpecID(baseClass));
mia.setCode("TestModule");
mia.setUri(testJar.toString());
mia.setCompat(
pg.getAllPurposePeerGroupImplAdvertisement().getCompat());
mia.setDescription("Module in a Jar");
Class clazz = loader.defineClass(mia);
assertTrue(Module.class.isAssignableFrom(clazz));
} catch (Error err) {
fail("Was not able to load a Module");
} catch (Exception exc) {
LOG.log(Level.SEVERE, "Caught exception", exc);
fail("Caught exception");
}
}
/**
* Verify that once a package is referenced that the other classes in the
* package can be resolved without additional packages being referenced.
*/
@Test
public void packageLoadIsSticky() {
LOG.info("packageLoadIsSticky");
// First, make sure we cant load TestPOJO
try {
Class clazz = loader.loadClass("TestPOJO");
fail("Shouldn't be able to load TestPOJO at this point");
} catch (Exception ex) {
// Good.
}
// Now load in the Module requiring the additional package
Class moduleClazz = null;
try {
ModuleClassID baseClass = IDFactory.newModuleClassID();
ModuleImplAdvertisement mia = (ModuleImplAdvertisement)
AdvertisementFactory.newAdvertisement(
ModuleImplAdvertisement.getAdvertisementType());
mia.setModuleSpecID(IDFactory.newModuleSpecID(baseClass));
mia.setCode("TestModule");
mia.setUri(testJar.toString());
mia.setCompat(
pg.getAllPurposePeerGroupImplAdvertisement().getCompat());
mia.setDescription("Module in a Jar");
moduleClazz = loader.defineClass(mia);
} catch (Error err) {
fail("Was not able to load a Module");
} catch (Exception exc) {
LOG.log(Level.SEVERE, "Caught exception", exc);
fail("Caught exception");
}
// Now we should be able to load TestPOJO
try {
Class pojo = loader.loadClass("TestPOJO");
assertSame(moduleClazz.getClassLoader(), pojo.getClassLoader());
} catch (Exception ex) {
fail("Should have been able to load TestPOJO at this point");
}
}
/**
* Verify that we can load the Module class via MIA referencing a
* package URI that is in the form of a ContentID.
*/
@Test
public void loadModuleContent() {
LOG.info("loadModuleContent");
try {
ModuleClassID baseClass = IDFactory.newModuleClassID();
ModuleImplAdvertisement mia = (ModuleImplAdvertisement)
AdvertisementFactory.newAdvertisement(
ModuleImplAdvertisement.getAdvertisementType());
mia.setModuleSpecID(IDFactory.newModuleSpecID(baseClass));
mia.setCode("TestModule");
mia.setUri(bothContent.getContentID().toString());
mia.setCompat(
pg.getAllPurposePeerGroupImplAdvertisement().getCompat());
mia.setDescription("Module in a Jar");
Class clazz = loader.defineClass(mia);
assertTrue(Module.class.isAssignableFrom(clazz));
// Check that it is stored in the correct location
URI storeHomeURI = testGroup.getStoreHome();
File storeHome = new File(storeHomeURI);
assertTrue(storeHome.exists());
File grpHome = new File(storeHome,
testGroup.getPeerGroupID().getUniqueValue().toString());
assertTrue(grpHome.isDirectory());
ModuleSpecID groupMSID =
testGroup.getPeerGroupAdvertisement().getModuleSpecID();
File modHome = new File(grpHome,
groupMSID.getUniqueValue().toString());
assertTrue(modHome.isDirectory());
File svcHome =
new File(modHome, RefJxtaLoader.class.getSimpleName());
assertTrue(svcHome.isDirectory());
File contentFile = new File(svcHome,
bothContent.getContentID().getUniqueValue().toString());
assertTrue(contentFile.exists());
} catch (ClassFormatError err) {
LOG.log(Level.SEVERE, "Caught error", err);
fail("Module load failed");
} catch (Exception exc) {
LOG.log(Level.SEVERE, "Caught exception", exc);
fail("Caught exception");
}
}
/**
* Test the loading of a module which references a package URI that is
* in the form of a ContentID and cannot be retreived.
*/
@Test(timeout=120000)
public void loadModuleContentNotFound() throws Exception {
LOG.info("loadModuleNotFound");
ModuleClassID baseClass = IDFactory.newModuleClassID();
ContentID contentID = IDFactory.newContentID(
testGroup.getPeerGroupID(), true);
ModuleImplAdvertisement mia = (ModuleImplAdvertisement)
AdvertisementFactory.newAdvertisement(
ModuleImplAdvertisement.getAdvertisementType());
mia.setModuleSpecID(IDFactory.newModuleSpecID(baseClass));
mia.setCode("Non-existant Module");
mia.setUri(contentID.toString());
mia.setCompat(pg.getAllPurposePeerGroupImplAdvertisement().getCompat());
mia.setDescription("Module which can't be found");
try {
loader.defineClass(mia);
fail("Was able to load module which did not exist");
} catch (ClassFormatError err) {
// Good. Fall through.
}
}
/**
* Test that classes loaded in sibling groups when the class definition
* is not provided by the parent group will resolve to difference class
* instances, indicating different class loaders were used to load
* them.
*/
@Test
public void siblingGroupsDifferentClasses() throws Exception {
LOG.info("siblingGroupsDifferentClasses");
// Create the sibling peer groups
DiscoveryService disco = pg.getDiscoveryService();
PeerGroupAdvertisement sib1adv = createGroupAdv(disco, "sibling1");
PeerGroup sibling1 = pg.newGroup(sib1adv);
PeerGroupAdvertisement sib2adv = createGroupAdv(disco, "sibling2");
PeerGroup sibling2 = pg.newGroup(sib2adv);
// Load the Module into sibling1
Class<?> clazz1 = null;
try {
ModuleClassID baseClass = IDFactory.newModuleClassID();
ModuleImplAdvertisement mia = (ModuleImplAdvertisement)
AdvertisementFactory.newAdvertisement(
ModuleImplAdvertisement.getAdvertisementType());
mia.setModuleSpecID(IDFactory.newModuleSpecID(baseClass));
mia.setCode("TestModule");
mia.setUri(testJar.toString());
mia.setCompat(
sibling1.getAllPurposePeerGroupImplAdvertisement().getCompat());
mia.setDescription("Module in a Jar");
JxtaLoader groupLoader = sibling1.getLoader();
clazz1 = groupLoader.defineClass(mia);
} catch (Error err) {
fail("Was not able to load a Module into sibling1");
} catch (Exception exc) {
LOG.log(Level.SEVERE, "Caught exception", exc);
fail("Caught exception");
}
// Load the Module into sibling2
Class<?> clazz2 = null;
try {
ModuleClassID baseClass = IDFactory.newModuleClassID();
ModuleImplAdvertisement mia = (ModuleImplAdvertisement)
AdvertisementFactory.newAdvertisement(
ModuleImplAdvertisement.getAdvertisementType());
mia.setModuleSpecID(IDFactory.newModuleSpecID(baseClass));
mia.setCode("TestModule");
mia.setUri(testJar.toString());
mia.setCompat(
sibling2.getAllPurposePeerGroupImplAdvertisement().getCompat());
mia.setDescription("Module in a Jar");
JxtaLoader groupLoader = sibling2.getLoader();
clazz2 = groupLoader.defineClass(mia);
} catch (Error err) {
fail("Was not able to load a Module into sibling2");
} catch (Exception exc) {
LOG.log(Level.SEVERE, "Caught exception", exc);
fail("Caught exception");
}
// Ensure they are not the same class
assertFalse(clazz1.isAssignableFrom(clazz2));
assertFalse(clazz2.isAssignableFrom(clazz1));
}
/**
* Test that classes loaded in a parent group will be used in child
* groups such that the Classes.
*/
@Test
public void parentGroupSameClasses() throws Exception {
LOG.info("parentGroupSameClasses");
// Create the hierarchy
DiscoveryService disco = pg.getDiscoveryService();
PeerGroupAdvertisement childAdv = createGroupAdv(disco, "child");
PeerGroup child = pg.newGroup(childAdv);
// Load the Module into parent
Class<?> clazz1 = null;
try {
ModuleClassID baseClass = IDFactory.newModuleClassID();
ModuleImplAdvertisement mia = (ModuleImplAdvertisement)
AdvertisementFactory.newAdvertisement(
ModuleImplAdvertisement.getAdvertisementType());
mia.setModuleSpecID(IDFactory.newModuleSpecID(baseClass));
mia.setCode("TestModule");
mia.setUri(testJar.toString());
mia.setCompat(
pg.getAllPurposePeerGroupImplAdvertisement().getCompat());
mia.setDescription("Module in a Jar");
JxtaLoader groupLoader = pg.getLoader();
clazz1 = groupLoader.defineClass(mia);
} catch (Error err) {
fail("Was not able to load a Module into parent");
} catch (Exception exc) {
LOG.log(Level.SEVERE, "Caught exception", exc);
fail("Caught exception");
}
// Load the Module into child
Class<?> clazz2 = null;
try {
ModuleClassID baseClass = IDFactory.newModuleClassID();
ModuleImplAdvertisement mia = (ModuleImplAdvertisement)
AdvertisementFactory.newAdvertisement(
ModuleImplAdvertisement.getAdvertisementType());
mia.setModuleSpecID(IDFactory.newModuleSpecID(baseClass));
mia.setCode("TestModule");
mia.setUri(testJar.toString());
mia.setCompat(
child.getAllPurposePeerGroupImplAdvertisement().getCompat());
mia.setDescription("Module in a Jar");
JxtaLoader groupLoader = child.getLoader();
clazz2 = groupLoader.defineClass(mia);
} catch (Error err) {
fail("Was not able to load a Module into child");
} catch (Exception exc) {
LOG.log(Level.SEVERE, "Caught exception", exc);
fail("Caught exception");
}
// Ensure they are the same class
assertTrue(clazz1.isAssignableFrom(clazz2));
assertTrue(clazz2.isAssignableFrom(clazz1));
}
///////////////////////////////////////////////////////////////////////////
// Private methods:
/**
* Creates a peer group advertisement set for testing.
*
* @param disco discovery service to publish into
* @param name peer group name
* @return peer group advertisement
* @throws java.lang.Exception on error
*/
private PeerGroupAdvertisement createGroupAdv(
DiscoveryService disco, String name)
throws Exception {
ModuleClassID mcid = IDFactory.newModuleClassID();
ModuleImplAdvertisement mia =
pg.getAllPurposePeerGroupImplAdvertisement();
ModuleSpecID msid = IDFactory.newModuleSpecID(mcid);
mia.setDescription(name + " impl");
mia.setModuleSpecID(msid);
disco.publish(mia);
LOG.finest(name + " MIA:\n" + mia);
PeerGroupID pgid = IDFactory.newPeerGroupID();
PeerGroupAdvertisement pga = (PeerGroupAdvertisement)
AdvertisementFactory.newAdvertisement(
PeerGroupAdvertisement.getAdvertisementType());
pga.setName(name);
pga.setModuleSpecID(msid);
pga.setPeerGroupID(pgid);
disco.publish(pga);
LOG.finest(name + " PGA:\n" + pga);
return pga;
}
}