/*
* Part of the CCNx Java Library.
*
* Copyright (C) 2012, 2013 Palo Alto Research Center, Inc.
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License version 2.1
* as published by the Free Software Foundation.
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. You should have received
* a copy of the GNU Lesser General Public License along with this library;
* if not, write to the Free Software Foundation, Inc., 51 Franklin Street,
* Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.ccnx.ccn.test.profiles.sync;
import java.io.IOException;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Vector;
import junit.framework.Assert;
import org.ccnx.ccn.CCNContentHandler;
import org.ccnx.ccn.CCNSync;
import org.ccnx.ccn.CCNSyncHandler;
import org.ccnx.ccn.config.SystemConfiguration;
import org.ccnx.ccn.impl.support.Log;
import org.ccnx.ccn.impl.sync.NodeBuilder;
import org.ccnx.ccn.io.content.ConfigSlice;
import org.ccnx.ccn.io.content.SyncNodeComposite;
import org.ccnx.ccn.io.content.SyncNodeComposite.SyncNodeElement;
import org.ccnx.ccn.profiles.SegmentationProfile;
import org.ccnx.ccn.profiles.metadata.MetadataProfile;
import org.ccnx.ccn.profiles.sync.Sync;
import org.ccnx.ccn.protocol.Component;
import org.ccnx.ccn.protocol.ContentName;
import org.ccnx.ccn.protocol.ContentObject;
import org.ccnx.ccn.protocol.Interest;
import org.ccnx.ccn.test.CCNTestBase;
import org.ccnx.ccn.test.CCNTestHelper;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Test;
public class SyncTestRepo extends CCNTestBase implements CCNSyncHandler, CCNContentHandler {
public static CCNTestHelper testHelper = new CCNTestHelper(SyncTestRepo.class);
ContentName prefix;
ContentName topo;
Vector<ContentName> callbackNames = new Vector<ContentName>();
Vector<ContentName> callbackNames2 = new Vector<ContentName>();
Vector<ContentName> callbackNames3 = new Vector<ContentName>();
String errorMessage = null;
static Vector<ConfigSlice> slices = new Vector<ConfigSlice>();
@Before
public void setUpNameSpace() {
prefix = testHelper.getTestNamespace("ccnSyncTest");
topo = testHelper.getTestNamespace("topoPrefix");
Log.fine(Log.FAC_TEST, "setting up namespace for sync test data: {0} syncControlTraffic: {1}", prefix, topo);
}
@AfterClass
public static void cleanup() {
//need to delete the slices to clean up after the test.
for(ConfigSlice s: slices)
try {
s.deleteSlice(getHandle);
} catch (IOException e) {
Log.warning(Log.FAC_TEST, "failed to get handle to clean up sync slices:{0}", e.getMessage());
}
}
@Test
public void testSyncStartWithHandle() throws Exception {
Log.info(Log.FAC_TEST, "Starting testSyncStartWithHandle");
ContentName prefix1;
callbackNames.clear();
prefix1 = prefix.append("slice1");
CCNSync sync1 = new CCNSync();
ConfigSlice slice1 = sync1.startSync(getHandle, topo, prefix1, this);
slices.add(slice1);
sync1.stopSync(this, slice1);
Log.info(Log.FAC_TEST, "Completed testSyncStartWithHandle");
}
@Test
public void testSyncStartWithoutHandle() throws Exception {
Log.info(Log.FAC_TEST, "Starting testSyncStartWithoutHandle");
ContentName prefix1;
callbackNames.clear();
prefix1 = prefix.append("slice2");
CCNSync sync1 = new CCNSync();
ConfigSlice slice2 = sync1.startSync(getHandle, topo, prefix1, this);
slices.add(slice2);
sync1.shutdown(slice2);
Log.info(Log.FAC_TEST,"Finished running testSyncStartWithoutHandle");
}
@Test
public void testSyncClose() throws Exception {
Log.info(Log.FAC_TEST, "Starting testSyncClose");
ContentName prefix1;
callbackNames.clear();
prefix1 = prefix.append("slice3");
CCNSync sync1 = new CCNSync();
ConfigSlice slice3 = sync1.startSync(getHandle, topo, prefix1, this);
slices.add(slice3);
//the slice should be written.. now save content and get a callback.
Log.fine(Log.FAC_TEST, "writing out file: {0}", prefix1);
// Write a 100 block file to test a true sync tree
int segments = SyncTestCommon.writeFile(prefix1, false, SystemConfiguration.BLOCK_SIZE * 100, putHandle);
int segmentCheck = checkCallbacks(callbackNames, prefix1, segments, 0);
if (segmentCheck!=0)
Assert.fail("Did not receive all of the callbacks");
else
Log.fine(Log.FAC_TEST, "I got all the callbacks for part 1 of testSyncClose!");
//now close the callback interface
sync1.stopSync(this, slice3);
//then close and make sure we don't get a callback
prefix1 = prefix1.append("round2");
Log.fine(Log.FAC_TEST, "writing out file: {0}", prefix1);
segments = SyncTestCommon.writeFile(prefix1, true, 0, putHandle); //this should be a new version
segmentCheck = checkCallbacks(callbackNames, prefix1, segments, 0);
if (segmentCheck != segments) {
//we must have gotten callbacks... bad.
Assert.fail("received callbacks after interface was closed. ERROR");
}
sync1.shutdown(slice3);
Log.fine(Log.FAC_TEST, "I didn't get callbacks after I stopped sync for myself!");
Log.info(Log.FAC_TEST,"Finished running testSyncStop");
}
@Test
public void testCallbackRegistration() throws Exception {
Log.info(Log.FAC_TEST, "Starting testCallbackRegistration");
ContentName prefix1;
ContentName prefix2;
callbackNames.clear();
prefix1 = prefix.append("slice4");
CCNSync sync1 = new CCNSync();
ConfigSlice slice4 = sync1.startSync(getHandle, topo, prefix1, this);
slices.add(slice4);
prefix2 = prefix.append("slice5");
ConfigSlice slice5 = sync1.startSync(getHandle, topo, prefix2, this);
//the slice should be written.. now save content and get a callback.
Log.fine(Log.FAC_TEST, "writing out file: {0}", prefix1);
int segments = SyncTestCommon.writeFile(prefix1, true, 0, putHandle);
int segments2 = SyncTestCommon.writeFile(prefix2, true, 0, putHandle);
int segmentCheck = checkCallbacks(callbackNames, prefix1, segments, 0);
if (segmentCheck!=0)
Assert.fail("Did not receive all of the callbacks");
segmentCheck = checkCallbacks(callbackNames, prefix2, segments2, 0);
if (segmentCheck!=0)
Assert.fail("Did not receive all of the callbacks");
//now close the callback interface
sync1.shutdown(slice4);
sync1.shutdown(slice5);
Log.info(Log.FAC_TEST,"Finished running testSyncStop");
}
@Test
public void testSyncRestart() throws Exception {
Log.info(Log.FAC_TEST, "Starting testSyncRestart");
ContentName prefix1;
callbackNames.clear();
prefix1 = prefix.append("slice6");
CCNSync sync1 = new CCNSync();
ConfigSlice slice6 = sync1.startSync(getHandle, topo, prefix1, this);
slices.add(slice6);
//the slice should be written.. now save content and get a callback.
Log.fine(Log.FAC_TEST, "writing out file: {0}", prefix1);
int segments = SyncTestCommon.writeFile(prefix1, true, 0, putHandle);
int segmentCheck = checkCallbacks(callbackNames, prefix1, segments, 0);
if (segmentCheck!=0)
Assert.fail("Did not receive all of the callbacks");
else
Log.fine(Log.FAC_TEST, "I got all the callbacks for part 1 of testSyncRestart!");
//now close the callback interface
sync1.shutdown(slice6);
callbackNames.clear();
//then close and make sure we don't get a callback
ContentName prefix1a = prefix1.append("round2");
Log.fine(Log.FAC_TEST, "writing out file: {0}", prefix1a);
segments = SyncTestCommon.writeFile(prefix1a, true, 0, putHandle); //this should be a new version
segmentCheck = checkCallbacks(callbackNames, prefix1a, segments, 0);
if (segmentCheck != segments) {
//we must have gotten callbacks... bad.
Assert.fail("received callbacks after interface was closed. ERROR");
}
Log.fine(Log.FAC_TEST, "I didn't get callbacks after I stopped sync for myself!");
//now restart sync and make sure i get everything
ContentName prefix1b = prefix1.append("round3");
//ConfigSlice slice3 = sync1.startSync(topo, prefix1, null, this);
ConfigSlice slice6b = sync1.startSync(getHandle, topo, prefix1, this);
Log.fine(Log.FAC_TEST, "check if slice 6 == slice 6b, they should be equal!");
if (slice6.equals(slice6b)) {
Log.fine(Log.FAC_TEST, "the slices are equal!");
} else {
Log.warning("the slices are not equal!!!!");
//what makes them different?
Log.fine(Log.FAC_TEST, "slice6: {0}", slice6);
Log.fine(Log.FAC_TEST, "slice6b: {0}", slice6b);
Assert.fail("the slices were not equal, they should have been.");
}
//the slice should be written.. now save content and get a callback.
Log.fine(Log.FAC_TEST, "writing out file: {0}", prefix1b);
segments = SyncTestCommon.writeFile(prefix1b, true, 0, putHandle);
segmentCheck = checkCallbacks(callbackNames, prefix1b, segments, 0);
if (segmentCheck!=0)
Assert.fail("Did not receive all of the callbacks");
else
Log.fine(Log.FAC_TEST, "I got all the callbacks for part 2 of testSyncRestart!");
//now close the callback interface
sync1.shutdown(slice6b);
Log.info(Log.FAC_TEST,"Finished running testSyncRestart");
}
@Test
public void testSyncRoot() throws Exception {
Log.info(Log.FAC_TEST,"Starting testSyncRoot");
callbackNames.clear();
ContentName prefix1;
CCNSync sync1 = new CCNSync();
prefix1 = prefix.append("slice7");
ConfigSlice slice7 = sync1.startSync(getHandle, topo, prefix1, this);
slices.add(slice7);
ContentName prefix1a = prefix1.append("round1");
Log.fine(Log.FAC_TEST, "writing out file: {0}", prefix1a);
int segments = SyncTestCommon.writeFile(prefix1a, true, 0, putHandle);
int segmentCheck = checkCallbacks(callbackNames, prefix1a, segments, 0);
if (segmentCheck!=0)
Assert.fail("Did not receive all of the callbacks");
sync1.stopSync(this, slice7);
synchronized (callbackNames) {
callbackNames.clear();
}
/*
* Test for start with empty root. This should start at the time we start sync, but not give
* us anything before that.
*/
Log.info(Log.FAC_TEST, "Starting sync for empty root");
ContentName rootAdvise = new ContentName(slice7.topo, Sync.SYNC_ROOT_ADVISE_MARKER, slice7.getHash());
Interest interest = new Interest(rootAdvise);
interest.scope(1);
getHandle.registerInterest(interest, this);
slice7 = sync1.startSync(getHandle, topo, prefix1, null, new byte[]{}, null, this);
synchronized (this) {
wait(SystemConfiguration.EXTRA_LONG_TIMEOUT);
}
ContentName prefix1b = prefix1.append("round2");
int segments2 = SyncTestCommon.writeFile(prefix1b, true, 0, putHandle);
segmentCheck = checkCallbacks(callbackNames, prefix1b, segments2, 0);
if (segmentCheck!=0)
Assert.fail("Did not receive all of the callbacks");
synchronized (callbackNames) {
for (ContentName n: callbackNames) {
Assert.assertTrue("Saw unexpected data in zero length root test: " + n, prefix1b.isPrefixOf(n));
}
}
sync1.stopSync(this, slice7);
SyncNodeComposite snc = SyncTestCommon.getRootAdviseNode(slice7, getHandle);
Assert.assertTrue(null != snc);
ContentName name = snc.getMaxName().getName().parent();
boolean needRound2 = name.whereLast("round2") == -1;
Log.info(Log.FAC_TEST, "Starting sync for predefined root: {0}", Component.printURI(snc.getHash()));
synchronized (callbackNames) {
callbackNames.clear();
}
slice7 = sync1.startSync(getHandle, topo, prefix1, null, snc.getHash(), null, this);
ContentName prefix1c = prefix1.append("round3");
int segments3 = SyncTestCommon.writeFile(prefix1c, true, 0, putHandle);
segmentCheck = checkCallbacks(callbackNames, prefix1c, segments3, 0);
if (segmentCheck!=0)
Assert.fail("Did not receive all of the callbacks");
if (needRound2) {
segmentCheck = checkCallbacks(callbackNames, prefix1b, segments2, 0);
if (segmentCheck!=0)
Assert.fail("Did not receive all of the callbacks for round2");
}
sync1.shutdown(slice7);
for (ContentName n: callbackNames) {
Assert.assertFalse("Saw unexpected data in arbitrary root test: " + n, prefix1a.isPrefixOf(n)
|| (needRound2 ? false : prefix1b.isPrefixOf(n)));
}
Log.info(Log.FAC_TEST, "Testing predefined root after total shutdown: {0}", Component.printURI(snc.getHash()));
synchronized (callbackNames) {
callbackNames.clear();
}
slice7 = sync1.startSync(getHandle, topo, prefix1, null, snc.getHash(), null, this);
ContentName prefix1d = prefix1.append("round4");
int segments4 = SyncTestCommon.writeFile(prefix1d, true, 0, putHandle);
segmentCheck = checkCallbacks(callbackNames, prefix1c, segments3, 0);
if (segmentCheck!=0)
Assert.fail("Did not receive all of the callbacks");
segmentCheck = checkCallbacks(callbackNames, prefix1d, segments4, 0);
if (segmentCheck!=0)
Assert.fail("Did not receive all of the callbacks");
if (needRound2) {
segmentCheck = checkCallbacks(callbackNames, prefix1b, segments2, 0);
if (segmentCheck!=0)
Assert.fail("Did not receive all of the callbacks for round2");
}
sync1.shutdown(slice7);
for (ContentName n: callbackNames) {
Assert.assertFalse("Saw unexpected data in arbitrary root test: " + n, prefix1a.isPrefixOf(n)
|| (needRound2 ? false : prefix1b.isPrefixOf(n)));
}
Log.info(Log.FAC_TEST, "Testing zero length hash after total shutdown: {0}", Component.printURI(snc.getHash()));
synchronized (callbackNames) {
callbackNames.clear();
}
/*
* Why go through all this rigamarole? Well besides the fact that it tests some weirdo functionality :-),
* we hope to test that we see only the data we write down below in this test. But if sync is slow, there's
* at least some chance it hasn't caught up yet and we'll still see some old data from earlier tests so
* we don't want to fail the test in that case
*/
Thread.sleep(100);
boolean couldSeeRound4 = true;
boolean couldSeeRound3 = true;
boolean couldSeeRound2 = true;
boolean doUnexpectedDataTest = true;
snc = SyncTestCommon.getRootAdviseNode(slice7, getHandle);
Assert.assertNotNull("No answer from root advise request", snc);
SyncNodeElement sne = NodeBuilder.getFirstOrLast(snc, sync1.getNodeCache(slice7), false);
if (null != sne) {
ContentName lastName = sne.getName();
if (lastName.contains("round4".getBytes()) && lastName.contains(".header".getBytes())) {
couldSeeRound4 = false;
couldSeeRound3 = false;
couldSeeRound2 = false;
} else {
if (lastName.contains("round3".getBytes()) && lastName.contains(".header".getBytes())) {
couldSeeRound3 = false;
couldSeeRound2 = false;
} else {
if (lastName.contains("round2".getBytes()) && lastName.contains(".header".getBytes())) {
couldSeeRound2 = false;
} else doUnexpectedDataTest = false;
}
}
}
if (couldSeeRound4) {
Log.info(Log.FAC_TEST, "Too bad - We're running the poorer version of this test");
} else {
Log.info(Log.FAC_TEST, "We're running the better version of this test");
}
slice7 = sync1.startSync(getHandle, topo, prefix1, null, new byte[]{}, null, this);
snc = SyncTestCommon.getRootAdviseNode(slice7, getHandle); // Make sure root advise went through
Assert.assertNotNull("No answer from root advise request", snc);
ContentName prefix1e = prefix1.append("round5");
int segments5 = SyncTestCommon.writeFile(prefix1e, true, 0, putHandle);
segmentCheck = checkCallbacks(callbackNames, prefix1e, segments5, 0);
if (segmentCheck!=0)
Assert.fail("Did not receive all of the callbacks");
sync1.shutdown(slice7);
if (doUnexpectedDataTest) {
for (ContentName n: callbackNames) {
Assert.assertTrue("Saw unexpected data in cold start zero length hash test: " + n, prefix1e.isPrefixOf(n)
|| (couldSeeRound4 ? prefix1d.isPrefixOf(n) : false)
|| (couldSeeRound3 ? prefix1c.isPrefixOf(n) : false)
|| (couldSeeRound2 ? prefix1b.isPrefixOf(n) : false));
}
}
Log.info(Log.FAC_TEST,"Finished running testSyncRoot");
}
@Test
public void testSyncStartName() throws Exception {
Log.info(Log.FAC_TEST,"Starting testSyncStartName");
callbackNames.clear();
ContentName prefix1;
prefix1 = prefix.append("slice8");
CCNSync sync1 = new CCNSync();
Log.fine(Log.FAC_TEST, "writing out file: {0}", prefix1);
// Write a 100 block file to test a true sync tree
int segments = SyncTestCommon.writeFile(prefix1, false, SystemConfiguration.BLOCK_SIZE * 100, putHandle);
ContentObject checkObj = getHandle.get(prefix1, SystemConfiguration.MEDIUM_TIMEOUT);
Assert.assertNotNull("Didn't get back what we wrote to the repo", checkObj);
ContentName name = checkObj.name();
name = name.cut(name.count() - 1);
ContentName startName = SegmentationProfile.segmentName(name, 20);
// We should start looking starting with segment 20
ConfigSlice slice8 = sync1.startSync(getHandle, topo, prefix1, null, null, startName, this);
slices.add(slice8);
int segmentCheck = checkCallbacks(callbackNames, prefix1, segments - 20, 20);
if (segmentCheck!=0)
Assert.fail("Did not receive all of the callbacks");
else
Log.fine(Log.FAC_TEST, "I got all the callbacks for part 1 of testSyncRestart!");
sync1.shutdown(slice8);
Log.info(Log.FAC_TEST,"Finished running testSyncStartName");
}
@Test
public void testMultiSync() throws Exception {
Log.info(Log.FAC_TEST,"Starting testMultiSync");
callbackNames.clear();
callbackNames2.clear();
callbackNames3.clear();
ContentName prefix1;
prefix1 = prefix.append("slice9");
CCNSync sync1 = new CCNSync();
Log.fine(Log.FAC_TEST, "writing out file: {0}", prefix1);
int segments = SyncTestCommon.writeFile(prefix1, false, SystemConfiguration.BLOCK_SIZE * 40, putHandle);
ContentObject checkObj = getHandle.get(prefix1, SystemConfiguration.MEDIUM_TIMEOUT);
Assert.assertNotNull("Didn't get back what we wrote to the repo", checkObj);
ConfigSlice slice8 = sync1.startSync(getHandle, topo, prefix1, null, null, null, this);
CCNSyncHandler sh2 = new SyncHandler2();
CCNSyncHandler sh3 = new SyncHandler3();
slices.add(slice8);
sync1.startSync(getHandle, topo, prefix1, null, null, null, sh2);
sync1.startSync(getHandle, topo, prefix1, null, null, null, sh3);
int segmentCheck = checkCallbacks(callbackNames, prefix1, segments, 0);
int segmentCheck2 = checkCallbacks(callbackNames2, prefix1, segments, 0);
int segmentCheck3 = checkCallbacks(callbackNames3, prefix1, segments, 0);
if (segmentCheck!=0 || segmentCheck2 != 0 || segmentCheck3 != 0)
Assert.fail("Did not receive all of the callbacks");
else
Log.fine(Log.FAC_TEST, "I got all the callbacks for part 1 of testMultiSync!");
sync1.stopSync(this, slice8);
synchronized (callbackNames2) {
callbackNames2.clear();
}
synchronized (callbackNames3) {
callbackNames3.clear();
}
Log.fine(Log.FAC_TEST, "test another file: {0} after stopping a sync", prefix1);
ContentName prefix1b = prefix1.append("round2");
segments = SyncTestCommon.writeFile(prefix1b, false, SystemConfiguration.BLOCK_SIZE * 40, putHandle);
segmentCheck2 = checkCallbacks(callbackNames2, prefix1b, segments, 0);
segmentCheck3 = checkCallbacks(callbackNames3, prefix1b, segments, 0);
if (segmentCheck2 != 0 || segmentCheck3 != 0)
Assert.fail("Did not receive all of the callbacks");
else
Log.fine(Log.FAC_TEST, "I got all the callbacks for part 2 of testMultiSync!");
sync1.shutdown(slice8);
Log.info(Log.FAC_TEST,"Finished running testMultiSync");
}
public void handleContentName(ConfigSlice syncSlice, ContentName syncedContent) {
doHandleContentName(1, syncSlice, syncedContent, callbackNames);
}
public void doHandleContentName(int callerId, ConfigSlice syncSlice, ContentName syncedContent, Vector<ContentName> callbackNames) {
if ( MetadataProfile.isHeader(syncedContent)) {
Log.info(Log.FAC_TEST, "Number {0}: Callback for name: {1} - number is header", callerId, syncedContent);
} else {
Log.info(Log.FAC_TEST, "Number {0}: Callback for name: {1} - number is {2}", callerId, syncedContent, SegmentationProfile.getSegmentNumber(syncedContent));
}
synchronized (callbackNames) {
for (ContentName name : callbackNames) {
if (name.equals(syncedContent)) {
errorMessage = "Saw duplicate name for callerID: " + callerId + ": " + syncedContent;
}
}
callbackNames.add(syncedContent);
}
}
private int checkCallbacks(Vector<ContentName> callbacks, ContentName prefix, int segments, int firstSegment) {
Log.fine(Log.FAC_TEST, "checking for callbacks: {0} segments: {1}", prefix, segments);
boolean[] received = (boolean[]) Array.newInstance(boolean.class, segments);
Arrays.fill(received, false);
boolean[]finished = (boolean[]) Array.newInstance(boolean.class, segments);
Arrays.fill(finished, true);
int loopsToTry = (segments * 2) + 20;
boolean done = false;
while (segments != 0 && loopsToTry > 0 && !done) {
if (null != errorMessage)
Assert.fail(errorMessage);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
Log.warning(Log.FAC_TEST, "interrupted while waiting for names on callback");
}
synchronized (callbacks) {
for (ContentName n: callbacks) {
if (prefix.isPrefixOf(n)) {
//this is one of our names
if ( MetadataProfile.isHeader(n)) {
//this is the header!
received[segments-1] = true;
Log.fine(Log.FAC_TEST, "got the header");
} else {
//this is not the header... get the segment number
Assert.assertTrue("Saw segment " + SegmentationProfile.getSegmentNumber(n) + " which should not have been seen",
SegmentationProfile.getSegmentNumber(n) >= firstSegment);
received[(int) SegmentationProfile.getSegmentNumber(n) - firstSegment] = true;
Log.fine(Log.FAC_TEST, "got segment {0}", SegmentationProfile.getSegmentNumber(n));
}
Log.fine(Log.FAC_TEST, "received: {0} finished: {1}", Arrays.toString(received), Arrays.toString(finished));
if (Arrays.equals(received, finished)) {
//all done!
segments = 0;
Log.fine(Log.FAC_TEST, "got all the segments!");
done = true;
break;
}
}
}
}
loopsToTry = loopsToTry - 1;
Log.fine(Log.FAC_TEST, "trying to loop again looking for segments");
}
int outstanding = 0;
String unreceived = "";
for (int i = 0; i < received.length; i++) {
if (received[i] != finished[i]) {
outstanding++;
unreceived += (i == segments - (firstSegment + 1) ? "header " : i + firstSegment + ", ");
}
}
Log.fine(Log.FAC_TEST, "done looping, returning.");
if (! unreceived.equals("")) {
Log.info(Log.FAC_TEST, "{0} outstanding segments = {1}", outstanding, unreceived);
}
return segments;
}
public Interest handleContent(ContentObject data, Interest interest) {
synchronized(this) {
notify();
}
return null;
}
public class SyncHandler2 implements CCNSyncHandler {
public void handleContentName(ConfigSlice syncSlice, ContentName syncedContent) {
Log.fine(Log.FAC_TEST, "Saw a name for callbackNames2");
doHandleContentName(2, syncSlice, syncedContent, callbackNames2);
}
}
public class SyncHandler3 implements CCNSyncHandler {
public void handleContentName(ConfigSlice syncSlice, ContentName syncedContent) {
Log.fine(Log.FAC_TEST, "Saw a name for callbackNames3");
doHandleContentName(3, syncSlice, syncedContent, callbackNames3);
}
}
}