package com.limegroup.gnutella;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.util.HashSet;
import java.util.Set;
import junit.framework.Test;
import com.limegroup.gnutella.altlocs.AlternateLocation;
import com.limegroup.gnutella.altlocs.AlternateLocationCollection;
import com.limegroup.gnutella.messages.GGEP;
import com.limegroup.gnutella.util.PrivilegedAccessor;
import com.limegroup.gnutella.xml.LimeXMLDocument;
import com.limegroup.gnutella.xml.LimeXMLSchemaRepository;
/**
* This class tests the Response class.
*/
public final class ResponseTest extends com.limegroup.gnutella.util.BaseTestCase {
/**
* Constructs a new test instance for responses.
*/
public ResponseTest(String name) {
super(name);
}
public static Test suite() {
return buildTestSuite(ResponseTest.class);
}
/**
* Runs this test individually.
*/
public static void main(String[] args) {
junit.textui.TestRunner.run(suite());
}
/**
* Modified version of the unit test that was formerly embedded in
* the Response class.
*/
public void testLegacyResponseUnitTest() throws Exception {
Response r = new Response(3,4096,"A.mp3");
assertEquals("A.mp3", r.getName());
assertNull(r.getDocument());
//
//Response r2 = new Response("",999,4,"blah.txt");
//assertEquals("bad meta", null, r2.getMetaBytes());
//assertEquals("Meta size not right", 0, r2.getMetaBytesSize());
//Assert.that(r2.getMetaBytes()==null,"bad meta");
//Assert.that(r2.getMetaBytesSize() == 0,"Meta size not right");
//String md = "Hello";
//Response r3 = new Response(md,999,4,"king.txt");
//assertEquals("bad meta", null, r3.getMetaBytes());
//assertEquals("Meta size not right", 0, r3.getMetaBytesSize());
//Assert.that(r3.getMetaBytes()==null,"bad meta");
//Assert.that(r3.getMetaBytesSize() == 0,"Meta size not right");
//The three formats we support
/*
String[] meta = {"a kbps 44.1 kHz b","akbps 44.1 kHz b",
"b akbps 44.1kHz" };
for(int i=0;i<meta.length;i++){
Response r4 = new Response(meta[i],999+i,4,"abc.txt");
LimeXMLDocument d=null;
String xml = r4.getMetadata();
try{
d = new LimeXMLDocument(xml);
}catch (Exception e){
assertTrue("XML not created well from between nulls", false);
//Assert.that(false,"XML not created well from between nulls");
}
String br = d.getValue("audios__audio__bitrate__");
assertEquals("a", br);
//Assert.that(br.equals("a"));
String len = d.getValue("audios__audio__seconds__");
assertEquals("b", len);
//Assert.that(len.equals("b"));
}
*/
//Tests for checking new LimeXMLDocument code added.
String xml1 = "<?xml version=\"1.0\"?><audios xsi:noNamespaceSchemaLocation=\"http://www.limewire.com/schemas/audio.xsd\"><audio genre=\"Speech\" bitrate=\"192\"></audio></audios>";
String xml2 = "<?xml version=\"1.0\"?><audios xsi:noNamespaceSchemaLocation=\"http://www.limewire.com/schemas/audio.xsd\"><audio genre=\"Speech\" bitrate=\"150\"></audio></audios>";
//create documents.
LimeXMLDocument d1 = null;
LimeXMLDocument d2 = null;
d1 = new LimeXMLDocument(xml1);
d2 = new LimeXMLDocument(xml2);
Response ra = new Response(12,231,"def1.txt",d1);
Response rb = new Response(13,232,"def2.txt",d2);
assertEquals("problem with doc constructor", d1, ra.getDocument());
assertEquals("problem with doc constructor", d2, rb.getDocument());
}
/**
* Tests a simple response can be created from stream (no extensions)
*/
public void testSimpleCreateFromStream() throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ByteOrder.int2leb(257, baos);
ByteOrder.int2leb(1029, baos);
byte[] name = new byte[] { 's', 'a', 'm', 0 };
baos.write(name);
// write out closing null.
baos.write((byte)0);
// add on 16 bytes so it thinks a GUID is there.
baos.write( new byte[16] );
baos.flush();
byte[] output = baos.toByteArray();
ByteArrayInputStream in = new ByteArrayInputStream(output);
Response r = Response.createFromStream(in);
assertEquals("wrong index", 257, r.getIndex());
assertEquals("wrong size", 1029, r.getSize());
assertEquals("wrong name", "sam", r.getName());
for(int i = 0; i < 16; i++) // read the blank GUID stuff we added
assertEquals(0, in.read());
assertEquals("leftover input", -1, in.read());
}
/**
* Tests multiple responses can be stacked together (no extensions)
*/
public void testMultipleSimpleResponses() throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// RESPONSE 1.
ByteOrder.int2leb(257, baos);
ByteOrder.int2leb(1029, baos);
byte[] name = new byte[] { 's', 'a', 'm', 0 };
baos.write(name);
// write out closing null.
baos.write((byte)0);
// RESPONSE 2.
ByteOrder.int2leb(2181, baos);
ByteOrder.int2leb(1981, baos);
name = new byte[] { 's', '.', 'a', '.', 'b', 0 };
baos.write(name);
// write out closing null.
baos.write((byte)0);
// add on 16 bytes so it thinks a GUID is there.
baos.write( new byte[16] );
baos.flush();
byte[] output = baos.toByteArray();
ByteArrayInputStream in = new ByteArrayInputStream(output);
Response r = Response.createFromStream(in);
assertEquals("wrong index", 257, r.getIndex());
assertEquals("wrong size", 1029, r.getSize());
assertEquals("wrong name", "sam", r.getName());
r = Response.createFromStream(in);
assertEquals("wrong index", 2181, r.getIndex());
assertEquals("wrong size", 1981, r.getSize());
assertEquals("wrong name", "s.a.b", r.getName());
for(int i = 0; i < 16; i++) // read the blank GUID stuff we added
assertEquals(0, in.read());
assertEquals("leftover input", -1, in.read());
}
/**
* Tests a response can have some data between the nulls (garbage)
*/
public void testGarbageExtension() throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ByteOrder.int2leb(257, baos);
ByteOrder.int2leb(1029, baos);
byte[] name = new byte[] { 's', 'a', 'm', 0 };
baos.write(name);
baos.write("this is a garbage extension".getBytes());
// write out closing null.
baos.write((byte)0);
byte[] output = baos.toByteArray();
ByteArrayInputStream in = new ByteArrayInputStream(output);
Response r = Response.createFromStream(in);
assertEquals("wrong index", 257, r.getIndex());
assertEquals("wrong size", 1029, r.getSize());
assertEquals("wrong name", "sam", r.getName());
assertEquals("wrong extension",
"this is a garbage extension", new String(r.getExtBytes()));
assertEquals("leftover input", -1, in.read());
}
/**
* Tests multiple extensions (garbage) can be added with the delimiter.
*/
public void testMultipleGarbageExtensions() throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ByteOrder.int2leb(257, baos);
ByteOrder.int2leb(1029, baos);
byte[] name = new byte[] { 's', 'a', 'm', 0 };
baos.write(name);
baos.write("this is a garbage extension".getBytes());
baos.write((byte)0x1c);
baos.write("this is another garbage extension".getBytes());
// write out closing null.
baos.write((byte)0);
byte[] output = baos.toByteArray();
ByteArrayInputStream in = new ByteArrayInputStream(output);
Response r = Response.createFromStream(in);
assertEquals("wrong index", 257, r.getIndex());
assertEquals("wrong size", 1029, r.getSize());
assertEquals("wrong name", "sam", r.getName());
assertEquals("wrong extension",
"this is a garbage extension\u001cthis is another garbage extension",
new String(r.getExtBytes()));
assertEquals("leftover input", -1, in.read());
}
/**
* Tests that a URN can be read from a response.
*/
public void testHUGEUrn() throws Exception {
final String sha1 = "urn:sha1:PLSTHIPQGSSZTS5FJUPAKUZWUGYQYPFB";
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ByteOrder.int2leb(257, baos);
ByteOrder.int2leb(1029, baos);
byte[] name = new byte[] { 's', 'a', 'm', 0 };
baos.write(name);
// add the sha1
baos.write(sha1.getBytes());
// write out closing null.
baos.write((byte)0);
byte[] output = baos.toByteArray();
ByteArrayInputStream in = new ByteArrayInputStream(output);
Response r = Response.createFromStream(in);
assertEquals("wrong index", 257, r.getIndex());
assertEquals("wrong size", 1029, r.getSize());
assertEquals("wrong name", "sam", r.getName());
assertEquals("wrong extension", sha1, new String(r.getExtBytes()));
assertEquals("leftover input", -1, in.read());
Set urns = new HashSet();
URN urn = URN.createSHA1UrnFromUriRes("/uri-res/N2R?" + sha1);
urns.add(urn);
assertEquals("wrong urns", urns, r.getUrns());
}
/**
* Tests that HUGE can work even if seperated with chunk extensions.
*/
public void testHUGEUrnWithOtherExtensions() throws Exception {
final String sha1 = "urn:sha1:PLSTHIPQGSSZTS5FJUPAKUZWUGYQYPFB";
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ByteOrder.int2leb(257, baos);
ByteOrder.int2leb(1029, baos);
byte[] name = new byte[] { 's', 'a', 'm', 0 };
baos.write(name);
// add the sha1
baos.write("junkie junk".getBytes());
baos.write((byte)0x1c);
baos.write(sha1.getBytes());
baos.write((byte)0x1c);
baos.write("jankie jank".getBytes());
// write out closing null.
baos.write((byte)0);
byte[] output = baos.toByteArray();
ByteArrayInputStream in = new ByteArrayInputStream(output);
Response r = Response.createFromStream(in);
assertEquals("wrong index", 257, r.getIndex());
assertEquals("wrong size", 1029, r.getSize());
assertEquals("wrong name", "sam", r.getName());
assertEquals("wrong extension",
"junkie junk\u001c"+sha1+"\u001cjankie jank",
new String(r.getExtBytes()));
assertEquals("leftover input", -1, in.read());
Set urns = new HashSet();
URN urn = URN.createSHA1UrnFromUriRes("/uri-res/N2R?" + sha1);
urns.add(urn);
assertEquals("wrong urns", urns, r.getUrns());
}
/**
* Tests that we understand bearshare1-style metadata
*/
public void testBearShare1Extensions() throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ByteOrder.int2leb(257, baos);
ByteOrder.int2leb(1029, baos);
byte[] name = new byte[] { 's', 'a', 'm', 0 };
baos.write(name);
baos.write("192 kbps 160".getBytes());
// write out closing null.
baos.write((byte)0);
byte[] output = baos.toByteArray();
ByteArrayInputStream in = new ByteArrayInputStream(output);
Response r = Response.createFromStream(in);
assertEquals("wrong index", 257, r.getIndex());
assertEquals("wrong size", 1029, r.getSize());
assertEquals("wrong name", "sam", r.getName());
assertEquals("wrong extension",
"192 kbps 160",
new String(r.getExtBytes()));
assertEquals("leftover input", -1, in.read());
LimeXMLDocument doc = r.getDocument();
assertNotNull("should have document", doc);
assertEquals("wrong name",
"sam", doc.getValue("audios__audio__title__"));
assertEquals("wrong bitrate",
"192", doc.getValue("audios__audio__bitrate__"));
assertEquals("wrong length",
"160", doc.getValue("audios__audio__seconds__"));
}
/**
* Tests that we understand bearshare2-style metadata
*/
public void testBearShare2Extensions() throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ByteOrder.int2leb(257, baos);
ByteOrder.int2leb(1029, baos);
byte[] name = new byte[] { 's', 'a', 'm', 'm', 'y', 0 };
baos.write(name);
baos.write("256kbps something 3528".getBytes());
// write out closing null.
baos.write((byte)0);
byte[] output = baos.toByteArray();
ByteArrayInputStream in = new ByteArrayInputStream(output);
Response r = Response.createFromStream(in);
assertEquals("wrong index", 257, r.getIndex());
assertEquals("wrong size", 1029, r.getSize());
assertEquals("wrong name", "sammy", r.getName());
assertEquals("wrong extension",
"256kbps something 3528",
new String(r.getExtBytes()));
assertEquals("leftover input", -1, in.read());
LimeXMLDocument doc = r.getDocument();
assertNotNull("should have document", doc);
assertEquals("wrong name",
"sammy", doc.getValue("audios__audio__title__"));
assertEquals("wrong bitrate",
"256", doc.getValue("audios__audio__bitrate__"));
assertEquals("wrong length",
"3528", doc.getValue("audios__audio__seconds__"));
}
/**
* Tests that GGEP'd ALT extensions are read correctly.
*/
public void testGGEPAltExtension() throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ByteOrder.int2leb(257, baos);
ByteOrder.int2leb(1029, baos);
byte[] name = new byte[] { 's', 'a', 'm', 0 };
baos.write(name);
GGEP info = new GGEP();
// locations: 1.2.3.4:1, 4.3.2.1:2
byte[] alts = { 1, 2, 3, 4, 1, 0, 4, 3, 2, 1, 2, 0 };
info.put(GGEP.GGEP_HEADER_ALTS, alts);
info.write(baos);
// write out closing null.
baos.write((byte)0);
byte[] output = baos.toByteArray();
ByteArrayInputStream in = new ByteArrayInputStream(output);
Response r = Response.createFromStream(in);
assertEquals("wrong index", 257, r.getIndex());
assertEquals("wrong size", 1029, r.getSize());
assertEquals("wrong name", "sam", r.getName());
// too annoying to check extension was correct.
assertEquals("leftover input", -1, in.read());
assertEquals("wrong number of locations", 2, r.getLocations().size());
Set endpoints = new HashSet();
endpoints.add( new Endpoint("1.2.3.4", 1) );
endpoints.add( new Endpoint("4.3.2.1", 2) );
assertEquals("wrong alts", endpoints, r.getLocations());
assertEquals("should have no time", -1, r.getCreateTime());
}
/**
* Tests that the GGEP'd CT extension is read correctly.
*/
public void testGGEPCreateTimeExtension() throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ByteOrder.int2leb(257, baos);
ByteOrder.int2leb(1029, baos);
byte[] name = new byte[] { 's', 'a', 'm', 0 };
baos.write(name);
GGEP info = new GGEP();
long time = System.currentTimeMillis();
info.put(GGEP.GGEP_HEADER_CREATE_TIME, time / 1000);
info.write(baos);
// write out closing null.
baos.write((byte)0);
byte[] output = baos.toByteArray();
ByteArrayInputStream in = new ByteArrayInputStream(output);
Response r = Response.createFromStream(in);
assertEquals("wrong index", 257, r.getIndex());
assertEquals("wrong size", 1029, r.getSize());
assertEquals("wrong name", "sam", r.getName());
// too annoying to check extension was correct.
assertEquals("leftover input", -1, in.read());
time = time / 1000 * 1000; // we lose precision when sending.
assertEquals("wrong time", time, r.getCreateTime());
assertEquals("should have no locs", new HashSet(), r.getLocations());
}
/**
* Test GGEP with multiple extensions.
*/
public void testGGEPMultipleExtensions() throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ByteOrder.int2leb(257, baos);
ByteOrder.int2leb(1029, baos);
byte[] name = new byte[] { 's', 'a', 'm', 0 };
baos.write(name);
GGEP info = new GGEP();
long time = System.currentTimeMillis();
info.put(GGEP.GGEP_HEADER_CREATE_TIME, time / 1000);
// locations: 1.2.3.4:1, 4.3.2.1:2
byte[] alts = { 1, 2, 3, 4, 1, 0, 4, 3, 2, 1, 2, 0 };
info.put(GGEP.GGEP_HEADER_ALTS, alts);
info.write(baos);
// write out closing null.
baos.write((byte)0);
byte[] output = baos.toByteArray();
ByteArrayInputStream in = new ByteArrayInputStream(output);
Response r = Response.createFromStream(in);
assertEquals("wrong index", 257, r.getIndex());
assertEquals("wrong size", 1029, r.getSize());
assertEquals("wrong name", "sam", r.getName());
// too annoying to check extension was correct.
assertEquals("leftover input", -1, in.read());
time = time / 1000 * 1000; // we lose precision when sending.
assertEquals("wrong time", time, r.getCreateTime());
assertEquals("wrong number of locations", 2, r.getLocations().size());
Set endpoints = new HashSet();
endpoints.add( new Endpoint("1.2.3.4", 1) );
endpoints.add( new Endpoint("4.3.2.1", 2) );
assertEquals("wrong alts", endpoints, r.getLocations());
}
/**
* Tests that GGEP can be both before & after other extensions.
*/
public void testGGEPWithOtherExtensions() throws Exception {
final String sha1 = "urn:sha1:PLSTHIPQGSSZTS5FJUPAKUZWUGYQYPFB";
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ByteOrder.int2leb(257, baos);
ByteOrder.int2leb(1029, baos);
byte[] name = new byte[] { 's', 'a', 'm', 0 };
baos.write(name);
baos.write(sha1.getBytes());
baos.write((byte)0x1c);
GGEP info = new GGEP();
// locations: 1.2.3.4:1, 4.3.2.1:2
byte[] alts = { 1, 2, 3, 4, 1, 0, 4, 3, 2, 1, 2, 0 };
info.put(GGEP.GGEP_HEADER_ALTS, alts);
info.write(baos);
baos.write((byte)0x1c);
baos.write("192 kbps 160".getBytes());
// write out closing null.
baos.write((byte)0);
byte[] output = baos.toByteArray();
ByteArrayInputStream in = new ByteArrayInputStream(output);
Response r = Response.createFromStream(in);
assertEquals("wrong index", 257, r.getIndex());
assertEquals("wrong size", 1029, r.getSize());
assertEquals("wrong name", "sam", r.getName());
// too annoying to check extension was correct.
assertEquals("leftover input", -1, in.read());
assertEquals("wrong number of locations", 2, r.getLocations().size());
Set endpoints = new HashSet();
endpoints.add( new Endpoint("1.2.3.4", 1) );
endpoints.add( new Endpoint("4.3.2.1", 2) );
assertEquals("wrong alts", endpoints, r.getLocations());
Set urns = new HashSet();
URN urn = URN.createSHA1UrnFromUriRes("/uri-res/N2R?" + sha1);
urns.add(urn);
assertEquals("wrong urns", urns, r.getUrns());
LimeXMLDocument doc = r.getDocument();
assertNotNull("should have document", doc);
assertEquals("wrong name",
"sam", doc.getValue("audios__audio__title__"));
assertEquals("wrong bitrate",
"192", doc.getValue("audios__audio__bitrate__"));
assertEquals("wrong length",
"160", doc.getValue("audios__audio__seconds__"));
}
/**
* Tests the GGEPUtil.addGGEP method to correctly write
* the correct number of alts out, in the correct format.
*/
public void testOnly10AltsAreWritten() throws Exception {
final String sha1 = "urn:sha1:PLSTHIPQGSSZTS5FJUPAKUZWUGYQYPFB";
ByteArrayOutputStream baos = new ByteArrayOutputStream();
URN urn = URN.createSHA1UrnFromUriRes("/uri-res/N2R?" + sha1);
// First create a bunch of alts.
AlternateLocationCollection alc =
AlternateLocationCollection.create(urn);
for(int i = 0; i < 20; i++) {
AlternateLocation al = AlternateLocation.create(
"http://1.2.3." + i + ":1/uri-res/N2R?" + sha1);
alc.add(al);
}
// Then get them as endpoints (should remove the extra alts).
Set endpoints = getAsEndpoints(alc);
assertEquals("didn't filter out extras", 10, endpoints.size());
// Add them to the output stream as a GGEP block.
Response.GGEPContainer gc = new Response.GGEPContainer(endpoints, -1);
addGGEP(baos, gc);
// See if we can correctly read the GGEP block.
baos.flush();
byte[] output = baos.toByteArray();
GGEP alt = new GGEP(output, 0, null);
Set headers = alt.getHeaders();
assertEquals("wrong size", 1, headers.size());
assertEquals("wrong header", "ALT", headers.iterator().next());
byte[] data = alt.getBytes("ALT");
assertEquals("wrong data length", 60, data.length);
for(int i = 0; i < data.length; i+=6) {
assertEquals(1, data[i]);
assertEquals(2, data[i+1]);
assertEquals(3, data[i+2]);
// data[i+3] is the one that changed, and because
// iterators may return values in any order,
// it doesn't matter what it is, so long as everything
// else is correct.
assertEquals(1, data[i+4]);
assertEquals(0, data[i+5]);
}
}
/**
* Tests the GGEPUtil.getGGEP method.
*/
public void testGGEPUtilGetGGEP() throws Exception {
GGEP ggep = new GGEP();
Response.GGEPContainer container;
long ctime;
Set locs;
byte[] data;
data = new byte[20]; // not % 6.
ggep.put("ALT", data);
locs = getGGEP(ggep).locations;
assertNotNull("should never be null", locs);
assertEquals("shouldn't have locs", 0, locs.size());
data = new byte[18]; // multiple of 6, but all blank (invalid)
ggep.put("ALT", data);
locs = getGGEP(ggep).locations;
assertNotNull("should never be null", locs);
assertEquals("shouldn't have locs", 0, locs.size());
// multiple of 6, but same
byte[] d1 = {1, 2, 3, 4, 1, 0, 1, 2, 3, 4, 1, 0};
ggep.put("ALT", d1);
locs = getGGEP(ggep).locations;
assertNotNull("should never be null", locs);
assertEquals("wrong number of locs", 1, locs.size());
assertEquals("wrong endpoint",
new Endpoint("1.2.3.4:1"), locs.iterator().next());
// multiple of 6, diff
byte[] d2 = {1, 2, 3, 4, 1, 0, 1, 2, 3, 4, 2, 0};
ggep.put("ALT", d2);
locs = getGGEP(ggep).locations;
assertNotNull("should never be null", locs);
assertEquals("wrong number of locs", 2, locs.size());
Set eps = new HashSet();
eps.add( new Endpoint("1.2.3.4:1") );
eps.add( new Endpoint("1.2.3.4:2") );
assertEquals("wrong endpoints", eps, locs);
// ctime.
ggep = new GGEP();
ggep.put("CT", 5341L);
ctime = getGGEP(ggep).createTime;
assertEquals(5341000, ctime);
// alt & ctime.
ggep.put("CT", 1243L);
ggep.put("ALT", d2);
container = getGGEP(ggep);
assertNotNull(container);
assertNotNull(container.locations);
assertEquals(2, container.locations.size());
assertEquals(eps, container.locations);
assertEquals(1243000, container.createTime);
// invalid alt, valid ctime
ggep.put("ALT", new byte[0]);
ggep.put("CT", 3214);
container = getGGEP(ggep);
assertEquals(0, container.locations.size());
assertEquals(3214000, container.createTime);
// invalid ctime, valid alt
ggep.put("ALT", d2);
// use 9 bytes (1 byte over the max for a long)
ggep.put("CT", new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0 } );
container = getGGEP(ggep);
assertEquals(2, container.locations.size());
assertEquals(eps, container.locations);
assertEquals(-1, container.createTime);
}
private Set getAsEndpoints(AlternateLocationCollection col)
throws Exception {
return (Set)PrivilegedAccessor.invokeMethod(Response.class,
"getAsEndpoints", new Object[] { col } );
}
private void addGGEP(OutputStream os, Response.GGEPContainer gc) throws Exception {
Class c = PrivilegedAccessor.getClass(Response.class, "GGEPUtil");
PrivilegedAccessor.invokeMethod(c, "addGGEP",
new Object[] { os, gc },
new Class[] { OutputStream.class, Response.GGEPContainer.class } );
}
private Response.GGEPContainer getGGEP(GGEP info) throws Exception {
Class c = PrivilegedAccessor.getClass(Response.class, "GGEPUtil");
return (Response.GGEPContainer)PrivilegedAccessor.invokeMethod(
c, "getGGEP", new Object[] { info } );
}
}