/** * Copyright 2007-2008 University Of Southern California * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package edu.isi.pegasus.planner.client; import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.LineNumberReader; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.MissingResourceException; import java.util.Properties; import java.util.Set; import java.util.StringTokenizer; import org.apache.log4j.ConsoleAppender; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.apache.log4j.PatternLayout; import org.apache.log4j.Priority; import org.griphyn.vdl.toolkit.Toolkit; import edu.isi.pegasus.common.logging.LogManager; import edu.isi.pegasus.common.logging.LogManagerFactory; import edu.isi.pegasus.common.util.CommonProperties; import edu.isi.pegasus.common.util.Version; import edu.isi.pegasus.planner.catalog.ReplicaCatalog; import edu.isi.pegasus.planner.catalog.replica.ReplicaCatalogEntry; import edu.isi.pegasus.planner.catalog.replica.ReplicaCatalogException; import edu.isi.pegasus.planner.catalog.replica.ReplicaFactory; import edu.isi.pegasus.planner.common.PegasusProperties; import gnu.getopt.Getopt; import gnu.getopt.LongOpt; /** * This class interfaces the with the replica catalog API to delve into the * underlying true catalog without knowing (once instantiated) which one it is. * * @author Jens-S. Vöckler * @author Yong Zhao * @version $Revision$ * * @see edu.isi.pegasus.planner.catalog.replica.ReplicaCatalog * @see edu.isi.pegasus.planner.catalog.replica.ReplicaCatalogEntry * @see edu.isi.pegasus.planner.catalog.replica.impl.JDBCRC */ public class RCClient extends Toolkit { /** * The message for LFN's not found. */ private static final String LFN_DOES_NOT_EXIST_MSG = "LFN doesn't exist:"; /** * The default chunk factor that is used for biting off chunks of large * files. */ private static final int DEFAULT_CHUNK_FACTOR = 1000; /** * Maintains the interface to the replica catalog implementation. */ private ReplicaCatalog m_rc; /** * Maintains instance-local settings on user preferences. */ private Map m_prefs; /** * Keeps track of log4j's root logger as singleton. */ private static Logger m_root; /** * Logger for RLS implementation for the time being. */ private LogManager m_rls_logger; /** * The number of lines that are to be parsed for chunking up large input * files. */ private int m_chunk_factor; /** * The total number of lines on which the client has worked on till yet. */ private int m_total_lines_worked; /** * The total number of lines on which the client has successfully worked on * till yet. */ private int m_total_lines_succ_worked; /** * Indication of batch mode. */ private boolean m_batch; /** * The object holding all the properties pertaining to Pegasus. */ protected PegasusProperties m_pegasus_props; /** * Reference to the property file passed using the --conf option */ private String m_conf_property_file = null; /** * Initializes the root logger when this class is loaded. */ static { if ((m_root = Logger.getRootLogger()) != null) { m_root.removeAllAppenders(); // clean house m_root.addAppender(new ConsoleAppender(new PatternLayout( "%d{yyyy-MM-dd HH:mm:ss.SSS} %-5p [%c{1}] %m%n"))); m_root.setLevel(Level.INFO); m_root.debug("starting"); } } /** * Sets a logging level. * * @param level * is the new level to achieve. */ public void setLevel(int level) { doSet(Level.toLevel(level)); } /** * Logs messages from main() method. * * @param level * is the log4j level to generate the log message for * @param msg * is the message itself. * * @see org.apache.log4j.Category#log(Priority, Object ) */ public static void log(Level level, String msg) { m_root.log(level, msg); } /** * Our own logger. */ private Logger m_log; private void doSet(Level level) { m_root.setLevel(level); m_log.setLevel(level); m_rls_logger.setLevel(level); } /** * Adds a preference to the instance preferences settings. * * @param key * is a key into the preference map. * @param value * is the new value to add. * @return the previous value, or null if no such value exists. */ public Object enter(String key, String value) { String newkey = key.toLowerCase(); Object result = m_prefs.put(newkey, value); return result; } /** * ctor: Constructs a new instance of the commandline interface to replica * catalogs. * * @param appName * is the name of to print in usage records. */ public RCClient(String appName) { super(appName); } /** * Initialize the RCClient object * @param opts the command line argument passed by the user * @param confChar the short option corresponding the conf property. */ private void initialize(String [] opts , char confChar){ m_rc = null; m_prefs = new HashMap(); m_batch = false; m_total_lines_worked = 0; m_total_lines_succ_worked = 0; // private logger m_log = Logger.getLogger(RCClient.class); String propertyFile =lookupConfProperty(opts, confChar); m_pegasus_props = PegasusProperties.getInstance(propertyFile); m_conf_property_file = propertyFile; m_rls_logger = LogManagerFactory.loadSingletonInstance(m_pegasus_props); m_rls_logger.setLevel(Level.WARN); m_rls_logger.logEventStart("pegasus-rc-client", "planner.version", Version.instance().toString()); m_log.debug("starting instance"); determineChunkFactor(); } /** * Prints the usage string on stdout. */ public void showUsage() { String linefeed = System.getProperty("line.separator", "\r\n"); System.out .println("$Id$" + linefeed + "Pegasus version " + Version.instance().toString() + linefeed); System.out .println("Usage: " + this.m_application + " [-p k=v] [ [-f fn] | [-i|-d fn] | [cmd [args]] ]" + linefeed + " -h|--help print this help text" + linefeed + " -V|--version print some version identification string and exit" + linefeed + " -f|--file fn uses non-interactive mode, reading from file fn." + linefeed + " The special filename hyphen reads from pipes" + linefeed + " -c|--conf fn path to the property file" + linefeed + " -v|--verbose increases the verbosity level" + linefeed + " -p|--pref k=v enters the specified mapping into preferences (multi-use)." + linefeed + " remember quoting, e.g. -p 'format=%l %p %a'" + linefeed + " -i|--insert fn the path to the file containing the mappings to be inserted." + linefeed + " Each line in the file denotes one mapping of format <LFN> <PFN> [k=v [..]]" + linefeed + " -d|--delete fn the path to the file containing the mappings to be deleted." + linefeed + " Each line in the file denotes one mapping of format <LFN> <PFN> [k=v [..]]." + linefeed + " -l|--lookup fn the path to the file containing the LFN's to be looked up." + linefeed + " Each line in the file denotes one LFN" + linefeed + " For now attributes are not matched to determine the entries to delete." + linefeed + " cmd [args] exactly one of the commands below with arguments."); showHelp(); System.out .println("FIXME list:" + linefeed + " o permit input to span multiple lines (format free input)" + linefeed + " o permit whitespaces within PFNs (but not in SITE nor LFN)" + linefeed + " o permit commands to deal with values that contain whitespaces (quoting)" + linefeed + " o add some missing out-of-bounds checks to the format string" + linefeed); } /** * Creates a set of GNU long options. * * @return an initialized array with the options */ protected LongOpt[] generateValidOptions() { LongOpt[] lo = new LongOpt[9]; lo[0] = new LongOpt("help", LongOpt.NO_ARGUMENT, null, 'h'); lo[1] = new LongOpt("version", LongOpt.NO_ARGUMENT, null, 'V'); lo[2] = new LongOpt("file", LongOpt.REQUIRED_ARGUMENT, null, 'f'); lo[3] = new LongOpt("pref", LongOpt.REQUIRED_ARGUMENT, null, 'p'); lo[4] = new LongOpt("insert", LongOpt.REQUIRED_ARGUMENT, null, 'i'); lo[5] = new LongOpt("delete", LongOpt.REQUIRED_ARGUMENT, null, 'd'); lo[6] = new LongOpt("lookup", LongOpt.REQUIRED_ARGUMENT, null, 'l'); lo[7] = new LongOpt("verbose", LongOpt.NO_ARGUMENT, null, 'v'); lo[8] = new LongOpt( "conf", LongOpt.REQUIRED_ARGUMENT, null, 'c' ); return lo; } /** * Connects the interface with the replica catalog implementation. The * choice of backend is configured through properties. * * @exception ClassNotFoundException * if the schema for the database cannot be loaded. You might * want to check your CLASSPATH, too. * @exception NoSuchMethodException * if the schema's constructor interface does not comply with * the database driver API. * @exception InstantiationException * if the schema class is an abstract class instead of a * concrete implementation. * @exception IllegalAccessException * if the constructor for the schema class it not publicly * accessible to this package. * @exception InvocationTargetException * if the constructor of the schema throws an exception while * being dynamically loaded. * @exception IOException * @exception MissingResourceException * */ void connect(PegasusProperties properties, String file ) throws ClassNotFoundException, IOException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException, MissingResourceException { m_rc = ReplicaFactory.loadInstance(properties, file); // auto-disconnect, should we forget it, or die in an orderly fashion Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { try { // log for the batch mode if (m_batch) { // log on stderr to prevent clobbing System.err.println("#Successfully worked on : " + m_total_lines_succ_worked + " lines."); System.err.println("#Worked on total number of : " + m_total_lines_worked + " lines."); } // disconnect from the replica catalog close(); } catch (Exception e) { e.printStackTrace(); } } }); } /** * Frees resources taken by the instance of the replica catalog. This method * is safe to be called on failed or already closed catalogs. */ void close() { if (m_rc != null) { m_rc.close(); m_rc = null; } } /** * Escapes quotes and backslashes by backslashing them. Identity s == * unescape(escape(s)) is preserved. * * @param s * is the string to escape * @return a string with escaped special characters. * @see #unescape(String ) */ private String escape(String s) { StringBuffer result = new StringBuffer(s.length()); for (int i = 0; i < s.length(); ++i) { char ch = s.charAt(i); if (ch == '"' || ch == '\\') result.append('\\'); result.append(ch); } return result.toString(); } /** * Unescapes previously backslashed characters. Identity s == * unescape(escape(s)) is preserved. * * @param s * is the string to escape * @return a string with unescaped special characters. * @see #escape(String ) */ private String unescape(String s) { StringBuffer result = new StringBuffer(s.length()); int state = 0; for (int i = 0; i < s.length(); ++i) { char ch = s.charAt(i); if (state == 0) { if (ch == '\\') state = 1; else result.append(ch); } else { result.append(ch); state = 0; } } return result.toString(); } /** * Removes a pair of outer quotes, which are optional. * * @param s * is a string which may start and end in quotes * @return a string without the optional quotes, or the string itself. */ private String noquote(String s) { int len = s.length(); // remove outer quotes, if they exist return ((s.charAt(0) == '"' && s.charAt(len - 1) == '"') ? s.substring( 1, len - 1) : s); } /** * Writes out a message about LFN not existing. * * @param lfn * the lfn. */ private void lfnDoesNotExist(String lfn) { System.err.println(LFN_DOES_NOT_EXIST_MSG + " " + lfn); } /** * Preliminary implementation of output method. * * @param lfn * is the logical filename to show * @param rce * is the replica catalog entry to show. It contains at minimum * the physical filename, and may contain any number of key-value * pairs. */ private void show(String lfn, ReplicaCatalogEntry rce) { System.out.print(lfn + " " + rce.getPFN()); for (Iterator i = rce.getAttributeIterator(); i.hasNext();) { String key = (String) i.next(); Object val = rce.getAttribute(key); if (val == null) continue; System.out.print(" " + key + "=\"" + escape(val.toString()) + "\""); } System.out.println(); } /** * Prints internal command help. */ public void showHelp() { String linefeed = System.getProperty("line.separator", "\r\n"); System.out.println(linefeed + "Commands and their respective arguments, line-by-line:" + linefeed + " help" + linefeed + " quit" + linefeed + " exit" + linefeed + " clear" + linefeed + " insert LFN PFN [k=v [..]]" + linefeed + " delete LFN PFN [k=v [..]]" + linefeed + " remove LFN [LFN [..]]" + linefeed + " lookup LFN [LFN [..]]" + linefeed + " list [lfn <pattern>] [pfn <pattern>] [<name> <pattern>]" + linefeed + " set [var [value]]" + linefeed); } /** * Works on the command contained within chunk of lines. * * @param lines * is a list of lines with each line being a list of words that * is split appropriately * @param command * the command to be invoked. * * @return number of entries affected, or -1 to stop processing. */ public int work(List lines, String command) { // sanity checks if (command == null) throw new RuntimeException( "The command to be applied to the file contents not specified"); if (lines == null || lines.isEmpty()) return 0; String c_argnum = "Illegal number of arguments, ignoring!"; int result = 0; // a map indexed by lfn Map entries = new HashMap(); if (command.equals("insert") || command.equals("delete")) { for (Iterator it = lines.iterator(); it.hasNext();) { List words = (List) it.next(); if (words.size() < 2) { m_log.warn(c_argnum); } else { Iterator i = words.listIterator(); String lfn = (String) i.next(); ReplicaCatalogEntry rce = new ReplicaCatalogEntry( (String) i.next()); while (i.hasNext()) { String attr = (String) i.next(); int pos = attr.indexOf('='); if (pos == -1) { m_log.error("attribute \"" + attr + "\" without assignment, " + "assuming resource handle"); rce.setResourceHandle(attr); } else { rce.setAttribute(attr.substring(0, pos), unescape(noquote(attr.substring(pos + 1)))); } } rce.checkAndUpdateForPoolAttribute(); // check to see if the lfn is already there // not doing a contains check as most of // the times lfn is expected to be unique // add all the old pfn's to the existing collection Collection c = new ArrayList(1); c.add(rce); Object old = entries.put(lfn, c); if (old != null) c.addAll((Collection) old); } }// end of iteration over the lines if (command.equals("insert")) { result = m_rc.insert(entries); m_log.info("inserted " + result + " entries"); } else { result = m_rc.delete(entries, true); m_log.info("deleted " + result + " entries"); } } else if (command.equals("lookup")) { Set<String> lfns = new HashSet(); // each line has a single LFN for (Iterator it = lines.iterator(); it.hasNext();) { List<String> words = (List) it.next(); if (words.size() != 1) { m_log.warn(c_argnum); } String lfn = words.get(0); lfns.add(lfn); } Map<String, Collection<ReplicaCatalogEntry>> results = m_rc .lookup(lfns); result = results.size(); // display results for LFN for (Iterator<Map.Entry<String, Collection<ReplicaCatalogEntry>>> it = results .entrySet().iterator(); it.hasNext();) { Map.Entry<String, Collection<ReplicaCatalogEntry>> entry = it .next(); String lfn = entry.getKey(); Collection rces = entry.getValue(); for (Iterator j = rces.iterator(); j.hasNext();) { show(lfn, (ReplicaCatalogEntry) j.next()); } } // try and figure out LFN's for which mappings were not found // and display them lfns.removeAll(results.keySet()); for (String lfn : lfns) { lfnDoesNotExist(lfn); } } return result; } /** * Works on the command contained within one line. * * @param words * is a list of the arguments, split appropriately * @return number of entries affected, or -1 to stop processing. */ public int work(List words) { String c_argnum = "Illegal number of arguments, ignoring!"; int result = 0; // sanity check if (words == null || words.size() == 0) return result; // separate command from arguments String cmd = ((String) words.remove(0)).toLowerCase(); if (cmd.equals("help")) { showHelp(); } else if (cmd.equals("lookup")) { for (Iterator i = words.iterator(); i.hasNext();) { String lfn = (String) i.next(); Collection c = m_rc.lookup(lfn); m_log.info("found " + c.size() + " matches"); for (Iterator j = c.iterator(); j.hasNext();) { show(lfn, (ReplicaCatalogEntry) j.next()); result++; } } } else if (cmd.equals("list")) { Map m = new HashMap(); for (Iterator i = words.iterator(); i.hasNext();) { String key = ((String) i.next()).toLowerCase(); if (i.hasNext()) { String val = (String) i.next(); m.put(key, val); } else { m.put(key, null); } } Map lfns = m_rc.lookup(m); if (lfns.size() > 0) { for (Iterator i = lfns.keySet().iterator(); i.hasNext();) { String lfn = (String) i.next(); for (Iterator j = ((List) lfns.get(lfn)).iterator(); j .hasNext();) { show(lfn, (ReplicaCatalogEntry) j.next()); result++; } } m_log.info("found " + result + " matches"); } else { m_log.info("no matches found"); } } else if (cmd.equals("insert") || cmd.equals("delete")) { if (words.size() < 2) { m_log.warn(c_argnum); } else { Iterator i = words.listIterator(); String lfn = (String) i.next(); ReplicaCatalogEntry rce = new ReplicaCatalogEntry( (String) i.next()); while (i.hasNext()) { String attr = (String) i.next(); int pos = attr.indexOf('='); if (pos == -1) { m_log.error("attribute \"" + attr + "\" without assignment, " + "assuming resource handle"); rce.setResourceHandle(attr); } else { rce.setAttribute(attr.substring(0, pos), unescape(noquote(attr.substring(pos + 1)))); } } //PM-813 backward support for pool attribute rce.checkAndUpdateForPoolAttribute(); if (cmd.equals("insert")) { result = m_rc.insert(lfn, rce); m_log.info("inserted " + result + " entries"); } else { result = rce.getAttributeCount() == 0 ? m_rc.delete(lfn, rce.getPFN()) : m_rc.delete(lfn, rce); m_log.info("deleted " + result + " entries"); } } } else if (cmd.equals("remove")) { // do it the slow way, better debugging for (Iterator i = words.iterator(); i.hasNext();) { String lfn = (String) i.next(); int count = m_rc.remove(lfn); result += count; if (count > 0) { m_log.info("removed LFN " + lfn); } else { m_log.info("ignoring unknown LFN " + lfn); } } } else if (cmd.equals("clear")) { result = m_rc.clear(); m_log.info("removed " + result + " entries"); } else if (cmd.equals("quit") || cmd.equals("exit")) { result = -1; m_log.info("Good-bye"); } else if (cmd.equals("set")) { String key, value; switch (words.size()) { case 0: // show all for (Iterator i = m_prefs.keySet().iterator(); i.hasNext();) { key = (String) i.next(); value = (String) m_prefs.get(key); System.out.println("set " + key + " " + value); result++; } break; case 1: // show one key = ((String) words.get(0)).toLowerCase(); if (m_prefs.containsKey(key)) { value = (String) m_prefs.get(key); System.out.println("set " + key + " " + value); result++; } else { m_log.warn("no such preference"); } break; case 2: // set one enter((String) words.get(0), (String) words.get(1)); result++; break; default: // other m_log.warn(c_argnum); break; } } else { // unknown command m_log.warn("Unknown command: " + cmd + ", ignoring!"); } return result; } /** * Consumes commands that control the replica management. * * @param filename * is the file to read from. If null, use stdin. * @exception IOException */ public void parse(String filename) throws IOException { boolean prompt = (filename == null); LineNumberReader lnr = null; if (filename != null) { // connect to file, use non-interactive mode if (filename.equals("-")) // reading from a pipe, don't prompt lnr = new LineNumberReader(new InputStreamReader(System.in)); else // reading from a file, don't prompt lnr = new LineNumberReader(new FileReader(filename)); } else { // connect to stdin lnr = new LineNumberReader(new InputStreamReader(System.in)); } int pos, result = 0; String line; StringTokenizer st; List words = new ArrayList(); if (prompt) System.out.print("rc> "); while ((line = lnr.readLine()) != null) { // do away with superflous whitespaces and comments if ((pos = line.indexOf('#')) != -1) line = line.substring(0, pos); line = line.trim(); // skip empty lines if (line.length() == 0) continue; // repeat what we are working on now m_log.debug("LINE " + lnr.getLineNumber() + ": " + line); words.clear(); st = new StringTokenizer(line); while (st.hasMoreTokens()) words.add(st.nextToken()); try { if (work(words) == -1) break; } catch (ReplicaCatalogException rce) { do { RCClient.log(Level.ERROR, rce.getMessage()); rce = (ReplicaCatalogException) rce.getNextException(); } while (rce != null); result = 1; } catch (RuntimeException rte) { do { RCClient.log(Level.ERROR, rte.getClass() + " " + rte.getMessage()); rte = (RuntimeException) rte.getCause(); } while (rte != null); result = 1; } if (prompt) System.out.print("rc> "); } // done if (prompt && line == null) System.out.println(); lnr.close(); // telmi, if something went wrong if (result == 1) throw new RuntimeException("Errors while processing input file"); } /** * Consumes commands that control the replica management. * * @param filename * is the file to read from. * @param command * is the command that needs to be applied to the file contents * * @exception IOException */ public void parse(String filename, String command) throws IOException { LineNumberReader lnr = null; int chunk = m_chunk_factor; int lines_succ_worked = 0; if (command == null) { // throw an exception throw new RuntimeException( "The command to be applied to the file contents not specified"); } if (filename != null) { // connect to file, use non-interactive mode // reading from a file lnr = new LineNumberReader(new FileReader(filename)); } else { // throw an exception throw new RuntimeException( "File containing the mappings not specified"); } int pos, result = 0; String line = null; StringTokenizer st; List words; // set the batch mode to true m_batch = true; // contains the number of valid lines read so far in the current block int counter = 0; List mappings = new ArrayList(chunk); while (true) { while (counter < chunk && (line = lnr.readLine()) != null) { // do away with superflous whitespaces and comments if ((pos = line.indexOf('#')) != -1) line = line.substring(0, pos); line = line.trim(); // skip empty lines if (line.length() == 0) continue; // repeat what we are working on now m_total_lines_worked = lnr.getLineNumber(); m_log.debug("LINE " + m_total_lines_worked + ": " + line); words = new ArrayList(chunk); st = new StringTokenizer(line); while (st.hasMoreTokens()) words.add(st.nextToken()); // add to the mappings counter++; mappings.add(words); } // hand off the mappings for work try { lines_succ_worked = work(mappings, command); m_total_lines_succ_worked += lines_succ_worked; } catch (ReplicaCatalogException rce) { do { RCClient.log(Level.ERROR, rce.getMessage()); rce = (ReplicaCatalogException) rce.getNextException(); } while (rce != null); result = 1; } catch (RuntimeException rte) { RCClient.log(Level.ERROR, rte.getMessage()); result = 1; } finally { // log the number of lines successfully worked m_log.info("Successfully worked on " + m_total_lines_succ_worked + " lines."); mappings.clear(); } m_log.info("Worked till line " + m_total_lines_worked); // System.out.println(); // get out of the loop if end if (line == null) break; else counter = 0; } // done lnr.close(); // telmi, if something went wrong if (result == 1) throw new RuntimeException("Errors while processing input file"); } /** * Looks up for the conf property in the command line arguments passed to the RCClient * @param opts command line arguments * @param confChar short char corresponding to the conf property * @return path to the property file */ private String lookupConfProperty(String[] opts , char confChar){ LongOpt[] longOptions = new LongOpt[1 ]; longOptions[ 0 ] = new LongOpt( "conf", LongOpt.REQUIRED_ARGUMENT, null,confChar ); // Create a clone before passing it to the GetOpts // Getopts changes the ordering of the array. String[] optsClone = new String[opts.length]; for(int i =0; i< opts.length;i++){ optsClone[i] = opts[i]; } Getopt g = new Getopt("RCClient", optsClone, confChar+":", longOptions, false); g.setOpterr(false); String propertyFilePath = null; int option = 0; while ( ( option = g.getopt() ) != -1 ) { if(option == confChar){ propertyFilePath = g.getOptarg(); break; } } return propertyFilePath; } /** * Manipulate entries in a given replica catalog implementation. * * @param args * are the commandline arguments. */ public static void main(String[] args) { int result = 0; int level = Level.ERROR_INT; RCClient me = null; try { // create an instance of self me = new RCClient("pegasus-rc-client"); me.initialize(args ,'c'); if (args.length == 0) { me.m_log.error("Please provide the required options."); me.showUsage(); System.exit(1); } // get the command line options Getopt opts = new Getopt(me.m_application, args, "f:hp:vVi:d:l:c:", me.generateValidOptions()); opts.setOpterr(false); String arg; String filename = null; int pos, option = -1; boolean interactive = false; String command = null; while ((option = opts.getopt()) != -1) { switch (option) { case 'V': System.out .println("$Id$"); System.out.println("Pegasus version " + Version.instance().toString()); return; case 'v': level -= 10000; break; case 'f': arg = opts.getOptarg(); interactive = true; if (arg != null) filename = arg; break; case 'p': arg = opts.getOptarg(); if (arg != null && (pos = arg.indexOf('=')) != -1) me.enter(arg.substring(0, pos), arg.substring(pos + 1)); break; case 'i': arg = opts.getOptarg(); command = "insert"; if (arg != null) filename = arg; break; case 'd': arg = opts.getOptarg(); command = "delete"; if (arg != null) filename = arg; break; case 'l': arg = opts.getOptarg(); command = "lookup"; if (arg != null) filename = arg; break; case 'c': // conf // do nothing break; case 'h': default: me.showUsage(); return; } } // Set verbosity level me.setLevel(level); // now work with me me.connect(me.m_pegasus_props, me.m_conf_property_file ); RCClient.log(Level.DEBUG, "connected to backend"); // are there any remaining CLI arguments? if (opts.getOptind() < args.length) { // there are CLI arguments if (filename != null) { // you must not use -f and CLI extra args throw new RuntimeException( "The -f|-i|-d|-l option and CLI arguments " + "are mutually exclusive"); } else { // just work on one (virtual, already shell-spit) line List words = new ArrayList(); for (int i = opts.getOptind(); i < args.length; ++i) words.add(args[i]); me.work(words); RCClient.log(Level.DEBUG, "done with CLI commands"); } } else { // no CLI args, use single command or interactive mode if (interactive && command != null) { throw new RuntimeException( "The -f and -i|-d|-l options are mutually exclusive"); } // in interactive mode parse each line if (interactive) me.parse(filename); // in the command mode parse chunks of lines together else if (command != null) me.parse(filename, command); RCClient.log(Level.DEBUG, "done parsing commands"); } } catch (ReplicaCatalogException rce) { do { RCClient.log(Level.FATAL, rce.getMessage()); rce = (ReplicaCatalogException) rce.getNextException(); } while (rce != null); result = 1; } catch (RuntimeException rte) { Exception org = rte; do { RCClient.log(Level.FATAL, rte.getClass() + " " + rte.getMessage()); rte = (RuntimeException) rte.getCause(); } while (rte != null); //print stack trace if debug or higher //or logmanger is not set at all if( me == null || me.m_log == null || me.m_log.getLevel().toInt() <= Level.DEBUG_INT ){ org.printStackTrace(); } result = 1; } catch (Exception e) { RCClient.log(Level.FATAL, e.getMessage()); e.printStackTrace(); result = 2; } finally { me.close(); RCClient.log(Level.DEBUG, "disconnected from backend"); } // log event completion in rls logger me.m_rls_logger.logEventCompletion(); // get out if (result != 0) { RCClient.log(Level.ERROR, "non-zero exit-code " + result); System.exit(result); } } /** * Sets the chunk factor for chunking up large input files. * */ private void determineChunkFactor() { int size = RCClient.DEFAULT_CHUNK_FACTOR; try { Properties properties = CommonProperties.instance().matchingSubset( ReplicaCatalog.c_prefix, false); String s = properties.getProperty(ReplicaCatalog.BATCH_KEY); size = Integer.parseInt(s); } catch (Exception e) { } m_chunk_factor = size; } }