/*
* A CCNx command line utility.
*
* Copyright (C) 2008, 2009, 2012 Palo Alto Research Center, Inc.
*
* This work is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License version 2 as published by the
* Free Software Foundation.
* This work 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 General Public License
* for more details. You should have received a copy of the GNU General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
package org.ccnx.ccn.utils;
import java.io.IOException;
import java.util.ArrayList;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.logging.Level;
import org.ccnx.ccn.CCNHandle;
import org.ccnx.ccn.config.ConfigurationException;
import org.ccnx.ccn.impl.support.Log;
import org.ccnx.ccn.profiles.nameenum.BasicNameEnumeratorListener;
import org.ccnx.ccn.profiles.nameenum.CCNNameEnumerator;
import org.ccnx.ccn.protocol.ContentName;
import org.ccnx.ccn.protocol.MalformedContentNameStringException;
/**
* Java utility to explore content stored under a given prefix in a repository. Uses name
* enumeration to limit responses to repositories and other NE responders.
* The program defaults to a prefix of "/"
* but takes a prefix as the first command-line argument. The tool displays names under the prefix
* after collecting names for a given time period. The initial default setting is 2 seconds. To enumerate
* names for more than 2 seconds (for example, if you have a long round trip time to a repository, the time
* can be extended using the -timeout flag and the time to wait in milliseconds. Another option is to have
* a long running enumeration that outputs results as they are received at the client. This is triggered
* with the -c flag. The tool utilizes the basic name enumeration protocol and currently does not properly
* handle responses from multiple repositories. If this is run with multiple repositories responding, it
* will not crash, it just may not receive all of the information from each repository.
*
*/
public class ccnlsrepo implements BasicNameEnumeratorListener {
private String prefix = "";
private ContentName name = null;
private long timeout = 2000;
private SortedSet<ContentName> allNames;
/**
* Main function for the ccnlsrepo tool. Initializes the tool and triggers name enumeration.
*
* @param args Command line arguments: prefix to enumeration and timeout flag (and time in ms)
*
* @return void
*/
public static void main(String[] args) {
Log.setDefaultLevel(Level.WARNING);
ccnlsrepo lister = new ccnlsrepo();
lister.init(args);
lister.enumerateNames();
System.exit(0);
}
/**
* Initialization function for ccnlsrepo. This method parses the command line input
* and creates a ContentName for the supplied prefix (or creates a new ContentName for the default "/" prefix).
* The program prints the usage and exits if the input is not correct.
*
* @param args Command line arguments. Prefix to enumerate and timeout flags.
*
* @return void
*
* @throws org.ccnx.ccn.protocol.MalformedContentNameStringException Converting the input to a
* ContentName can throw a MalformedContentNameException.
*
* @see org.ccnx.ccn.protocol.ContentName
*/
private void init(String[] args) {
// first look for prefix and timeout in the args list
boolean tflag = false;
boolean cflag = false;
String extraUsage = "";
for (int i = 0; i < args.length; i++) {
if (i == 0 && args[0].startsWith("[")) {
extraUsage = args[0];
continue;
}
if (args[i].equals("-h")) {
usage(extraUsage);
System.exit(0);
}
if (!args[i].equals("-timeout") && !args[i].equals("-c") && !args[i].equals("-continuous")) {
prefix = args[i];
} else if (args[i].equals("-timeout")) {
if (cflag) {
System.err.println("please use either the -timeout or -c flags, not both");
usage(extraUsage);
System.exit(1);
}
tflag = true;
i++;
if (i >= args.length) {
usage(extraUsage);
System.exit(1);
} else {
try {
timeout = Long.parseLong(args[i]);
} catch (Exception e) {
System.err.println("Could not parse timeout. Please check and retry.");
usage(extraUsage);
System.exit(1);
}
}
} else if (args[i].equals("-c") || args[i].equals("-continuous")) {
cflag = true;
if (tflag) {
System.err.println("please use either the -timeout or -c flags, not both");
usage(extraUsage);
System.exit(1);
}
timeout = 0;
}
}
try {
if (prefix == null || prefix.equals(""))
name = ContentName.ROOT;
else
name = ContentName.fromURI(prefix);
Log.fine("monitoring prefix " + name.toString());
} catch (MalformedContentNameStringException e) {
System.err.println(e.toString());
System.err.println("could not create parse prefix, please be sure it is a valid name prefix");
System.exit(1);
}
if (timeout > 0)
Log.fine("monitoring prefix for " + timeout + "ms");
allNames = new TreeSet<ContentName>();
}
/**
* Method to initialize a CCNHandle and the CCNNameEnumerator for the ccnlsrepo tool.
* This method also determines when the program should print out results and exit.
*
* @return void
*
* @throws org.ccnx.ccn.config.ConfigurationException A configuration exception is
* thrown if the CCNHandle is not properly configured
* @throws java.io.IOException Am IOException is thrown if the CCNHandle is not properly initialized.
*
* @see org.ccnx.ccn.CCNHandle
* @see org.ccnx.ccn.profiles.nameenum.CCNNameEnumerator
*/
private void enumerateNames() {
try {
CCNHandle handle = CCNHandle.open();
CCNNameEnumerator ccnNE = new CCNNameEnumerator(handle, this);
ccnNE.registerPrefix(name);
if (timeout > 0) {
try {
Thread.sleep(timeout);
} catch (InterruptedException e) {
System.err.println("error while waiting for responses from CCNNameEnumerator");
}
Log.fine("finished waiting for responses, cleaning up state");
ccnNE.cancelPrefix(name);
printNames();
} else {
// we do not have to exit
while (true) {
}
}
} catch (ConfigurationException e) {
System.err.println("Configuration Error");
e.printStackTrace();
} catch (IOException e) {
System.err.println(e.toString());
e.printStackTrace();
}
}
/**
* Function to print out the options for ccnlsrepo
*
* @returns void
*/
public void usage(String extraUsage) {
System.out.println("usage: ccnlsrepo " + extraUsage + "<ccnprefix> [-timeout millis (default is 2000ms) | -c(ontinuous)]");
}
/**
* Callback method to handle names returned through enumeration. Adds all names not already in the
* stored list to be printed out before the program exits. In the case of a long-running iteration
* (called with -c), the names are printed out as they are returned in enumeration responses.
*
* @param prefix The registered prefix for the returned names.
* @param names Returned names matching the prefix.
*
* @return int Number of names in the collection. (currently unused in this implementation)
*
* @see org.ccnx.ccn.profiles.nameenum.BasicNameEnumeratorListener
*/
public int handleNameEnumerator(ContentName prefix, ArrayList<ContentName> names) {
synchronized (allNames) {
allNames.addAll(names);
}
if (timeout <= 0) {
System.out.println("-----");
printNames();
System.out.println("-----");
System.out.println();
}
return 0;
}
/**
* Method to print the names collection through enumeration. Iterates through the names and prints each content name.
* Uses the ContentName.toString method and removes the leading "/" - component separator.
*
* @return void
*/
private void printNames() {
synchronized (allNames) {
for (ContentName c : allNames)
System.out.println(c.toString().replaceFirst("/", ""));
}
}
}