001: /*
002: * This file or a portion of this file is licensed under the terms of
003: * the Globus Toolkit Public License, found in file GTPL, or at
004: * http://www.globus.org/toolkit/download/license.html. This notice must
005: * appear in redistributions of this file, with or without modification.
006: *
007: * Redistributions of this Software, with or without modification, must
008: * reproduce the GTPL in: (1) the Software, or (2) the Documentation or
009: * some other similar material which is provided with the Software (if
010: * any).
011: *
012: * Copyright 1999-2004 University of Chicago and The University of
013: * Southern California. All rights reserved.
014: */
015: package org.griphyn.common.catalog.toolkit;
016:
017: import java.io.*;
018: import java.lang.reflect.*;
019: import java.sql.*;
020: import java.util.*;
021:
022: import gnu.getopt.*;
023: import org.apache.log4j.Logger;
024: import org.apache.log4j.Level;
025: import org.apache.log4j.ConsoleAppender;
026: import org.apache.log4j.PatternLayout;
027:
028: import org.griphyn.common.util.*;
029: import org.griphyn.common.catalog.*;
030: import org.griphyn.common.catalog.replica.ReplicaFactory;
031: import org.griphyn.common.catalog.replica.ReplicaCatalogException;
032:
033: import org.griphyn.cPlanner.common.LogManager;
034:
035: import org.griphyn.vdl.toolkit.Toolkit; // for now
036:
037: /**
038: * This class interfaces the with the replica catalog API to delve into
039: * the underlying true catalog without knowing (once instantiated) which
040: * one it is.
041: *
042: * @author Jens-S. Vöckler
043: * @author Yong Zhao
044: * @version $Revision: 175 $
045: *
046: * @see org.griphyn.common.catalog.ReplicaCatalog
047: * @see org.griphyn.common.catalog.ReplicaCatalogEntry
048: * @see org.griphyn.common.catalog.replica.JDBCRC
049: */
050: public class RCClient extends Toolkit {
051:
052: /**
053: * The default chunk factor that is used for biting off chunks of large files.
054: */
055: private static final int DEFAULT_CHUNK_FACTOR = 1000;
056:
057: /**
058: * Maintains the interface to the replica catalog implementation.
059: */
060: private ReplicaCatalog m_rc;
061:
062: /**
063: * Maintains instance-local settings on user preferences.
064: */
065: private Map m_prefs;
066:
067: /**
068: * Keeps track of log4j's root logger as singleton.
069: */
070: private static Logger m_root;
071:
072: /**
073: * Logger for RLS implementation for the time being.
074: */
075: private LogManager m_rls_logger;
076:
077: /**
078: * The number of lines that are to be parsed for chunking up large input
079: * files.
080: */
081: private int m_chunk_factor;
082:
083: /**
084: * The total number of lines on which the client has worked on till yet.
085: */
086: private int m_total_lines_worked;
087:
088: /**
089: * The total number of lines on which the client has successfully worked on
090: * till yet.
091: */
092: private int m_total_lines_succ_worked;
093:
094: /**
095: * Indication of batch mode.
096: */
097: private boolean m_batch;
098:
099: /**
100: * Initializes the root logger when this class is loaded.
101: */
102: static {
103: if ((m_root = Logger.getRootLogger()) != null) {
104: m_root.removeAllAppenders(); // clean house
105: m_root.addAppender(new ConsoleAppender(new PatternLayout(
106: "%d{yyyy-MM-dd HH:mm:ss.SSS} %-5p [%c{1}] %m%n")));
107: m_root.setLevel(Level.INFO);
108: m_root.debug("starting");
109: }
110: }
111:
112: /**
113: * Logs messages from main() method.
114: *
115: * @param level is the log4j level to generate the log message for
116: * @param msg is the message itself.
117: *
118: * @see org.apache.log4j.Category#log( Priority, Object )
119: */
120: public static void log(Level level, String msg) {
121: m_root.log(level, msg);
122: }
123:
124: /**
125: * Our own logger.
126: */
127: private Logger m_log;
128:
129: private void doSet(Level level) {
130: m_root.setLevel(level);
131: m_log.setLevel(level);
132: m_rls_logger.setLevel(level);
133: }
134:
135: /**
136: * Sets a logging level.
137: *
138: * @param level is the new level to achieve.
139: */
140: public void setLevel(Level level) {
141: if (!m_prefs.containsKey("level"))
142: doSet(level);
143: }
144:
145: /**
146: * Adds a preference to the instance preferences settings.
147: *
148: * @param key is a key into the preference map.
149: * @param value is the new value to add.
150: * @return the previous value, or null if no such value exists.
151: */
152: public Object enter(String key, String value) {
153: String newkey = key.toLowerCase();
154: Object result = m_prefs.put(newkey, value);
155:
156: // and do the action, too.
157: if (newkey.equals("level")) {
158: String v = value.toLowerCase();
159: if (v.startsWith("debug"))
160: doSet(Level.DEBUG);
161: else if (v.equals("info"))
162: doSet(Level.INFO);
163: else if (v.startsWith("warn"))
164: doSet(Level.WARN);
165: else if (v.equals("error"))
166: doSet(Level.ERROR);
167: else if (v.equals("fatal"))
168: doSet(Level.FATAL);
169: else
170: ;
171: }
172:
173: return result;
174: }
175:
176: /**
177: * ctor: Constructs a new instance of the commandline interface to
178: * replica catalogs.
179: *
180: * @param appName is the name of to print in usage records.
181: */
182: public RCClient(String appName) {
183: super (appName);
184:
185: m_rc = null;
186: m_prefs = new HashMap();
187: m_batch = false;
188: m_total_lines_worked = 0;
189: m_total_lines_succ_worked = 0;
190: // private logger
191: m_log = Logger.getLogger(RCClient.class);
192: m_rls_logger = LogManager.getInstance();
193: m_log.debug("starting instance");
194: determineChunkFactor();
195: }
196:
197: /**
198: * Prints the usage string on stdout.
199: */
200: public void showUsage() {
201: String linefeed = System.getProperty("line.separator", "\r\n");
202: System.out
203: .println("$Id: RCClient.java 175 2007-06-01 00:24:29Z vahi $"
204: + linefeed
205: + "VDS version "
206: + Version.instance().toString() + linefeed);
207:
208: System.out
209: .println("Usage: "
210: + this .m_application
211: + " [-p k=v] [ [-f fn] | [-i|-d fn] | [cmd [args]] ]"
212: + linefeed
213: + " -h|--help print this help text"
214: + linefeed
215: + " -V|--version print some version identification string and exit"
216: + linefeed
217: + " -f|--file fn uses non-interactive mode, reading from file fn."
218: + linefeed
219: + " The special filename hyphen reads from pipes"
220: + linefeed
221: + " -p|--pref k=v enters the specified mapping into preferences (multi-use)."
222: + linefeed
223: + " remember quoting, e.g. -p 'format=%l %p %a'"
224: + linefeed
225: + " -i|--insert fn the path to the file containing the mappings to be inserted."
226: + linefeed
227: + " Each line in the file denotes one mapping of format <LFN> <PFN> [k=v [..]]"
228: + linefeed
229: + " -d|--delete fn the path to the file containing the mappings to be deleted."
230: + linefeed
231: + " Each line in the file denotes one mapping of format <LFN> <PFN> [k=v [..]]."
232: + linefeed
233: + " For now attributes are not matched to determine the entries to delete."
234: + linefeed
235: + " cmd [args] exactly one of the commands below with arguments.");
236:
237: showHelp();
238:
239: System.out
240: .println("FIXME list:"
241: + linefeed
242: + " o permit input to span multiple lines (format free input)"
243: + linefeed
244: + " o permit whitespaces within PFNs (but not in SITE nor LFN)"
245: + linefeed
246: + " o permit commands to deal with values that contain whitespaces (quoting)"
247: + linefeed
248: + " o add some missing out-of-bounds checks to the format string"
249: + linefeed);
250:
251: }
252:
253: /**
254: * Creates a set of GNU long options.
255: *
256: * @return an initialized array with the options
257: */
258: protected LongOpt[] generateValidOptions() {
259: LongOpt[] lo = new LongOpt[6];
260:
261: lo[0] = new LongOpt("help", LongOpt.NO_ARGUMENT, null, 'h');
262: lo[1] = new LongOpt("version", LongOpt.NO_ARGUMENT, null, 'V');
263: lo[2] = new LongOpt("file", LongOpt.REQUIRED_ARGUMENT, null,
264: 'f');
265: lo[3] = new LongOpt("pref", LongOpt.REQUIRED_ARGUMENT, null,
266: 'p');
267: lo[4] = new LongOpt("insert", LongOpt.REQUIRED_ARGUMENT, null,
268: 'i');
269: lo[5] = new LongOpt("delete", LongOpt.REQUIRED_ARGUMENT, null,
270: 'd');
271: return lo;
272: }
273:
274: /**
275: * Connects the interface with the replica catalog implementation. The
276: * choice of backend is configured through properties.
277: *
278: * @exception ClassNotFoundException if the schema for the database
279: * cannot be loaded. You might want to check your CLASSPATH, too.
280: * @exception NoSuchMethodException if the schema's constructor interface
281: * does not comply with the database driver API.
282: * @exception InstantiationException if the schema class is an abstract
283: * class instead of a concrete implementation.
284: * @exception IllegalAccessException if the constructor for the schema
285: * class it not publicly accessible to this package.
286: * @exception InvocationTargetException if the constructor of the schema
287: * throws an exception while being dynamically loaded.
288: * @exception IOException
289: * @exception MissingResourceException
290: *
291: * @see org.griphyn.vdl.util.ChimeraProperties
292: */
293: void connect() throws ClassNotFoundException, IOException,
294: NoSuchMethodException, InstantiationException,
295: IllegalAccessException, InvocationTargetException,
296: MissingResourceException {
297: m_rc = ReplicaFactory.loadInstance();
298:
299: // auto-disconnect, should we forget it, or die in an orderly fashion
300: Runtime.getRuntime().addShutdownHook(new Thread() {
301: public void run() {
302: try {
303: //log for the batch mode
304: if (m_batch) {
305: //log on stderr to prevent clobbing
306: System.err
307: .println("#Successfully worked on : "
308: + m_total_lines_succ_worked
309: + " lines.");
310: System.err
311: .println("#Worked on total number of : "
312: + m_total_lines_worked
313: + " lines.");
314: }
315: //disconnect from the replica catalog
316: close();
317: } catch (Exception e) {
318: e.printStackTrace();
319: }
320: }
321: });
322:
323: }
324:
325: /**
326: * Frees resources taken by the instance of the replica catalog. This
327: * method is safe to be called on failed or already closed catalogs.
328: */
329: void close() {
330: if (m_rc != null) {
331: m_rc.close();
332: m_rc = null;
333: }
334: }
335:
336: /**
337: * Escapes quotes and backslashes by backslashing them.
338: * Identity s == unescape(escape(s)) is preserved.
339: *
340: * @param s is the string to escape
341: * @return a string with escaped special characters.
342: * @see #unescape( String )
343: */
344: private String escape(String s) {
345: StringBuffer result = new StringBuffer(s.length());
346:
347: for (int i = 0; i < s.length(); ++i) {
348: char ch = s.charAt(i);
349: if (ch == '"' || ch == '\\')
350: result.append('\\');
351: result.append(ch);
352: }
353:
354: return result.toString();
355: }
356:
357: /**
358: * Unescapes previously backslashed characters.
359: * Identity s == unescape(escape(s)) is preserved.
360: *
361: * @param s is the string to escape
362: * @return a string with unescaped special characters.
363: * @see #escape( String )
364: */
365: private String unescape(String s) {
366: StringBuffer result = new StringBuffer(s.length());
367: int state = 0;
368:
369: for (int i = 0; i < s.length(); ++i) {
370: char ch = s.charAt(i);
371: if (state == 0) {
372: if (ch == '\\')
373: state = 1;
374: else
375: result.append(ch);
376: } else {
377: result.append(ch);
378: state = 0;
379: }
380: }
381:
382: return result.toString();
383: }
384:
385: /**
386: * Removes a pair of outer quotes, which are optional.
387: *
388: * @param s is a string which may start and end in quotes
389: * @return a string without the optional quotes, or the string itself.
390: */
391: private String noquote(String s) {
392: int len = s.length();
393:
394: // remove outer quotes, if they exist
395: return ((s.charAt(0) == '"' && s.charAt(len - 1) == '"') ? s
396: .substring(1, len - 1) : s);
397: }
398:
399: /**
400: * Preliminary implementation of output method.
401: *
402: * @param lfn is the logical filename to show
403: * @param rce is the replica catalog entry to show. It contains at
404: * minimum the physical filename, and may contain any number of
405: * key-value pairs.
406: */
407: private void show(String lfn, ReplicaCatalogEntry rce) {
408: System.out.print(lfn + " " + rce.getPFN());
409: for (Iterator i = rce.getAttributeIterator(); i.hasNext();) {
410: String key = (String) i.next();
411: Object val = rce.getAttribute(key);
412: System.out.print(" " + key + "=\"" + escape(val.toString())
413: + "\"");
414: }
415: System.out.println();
416: }
417:
418: /**
419: * Prints internal command help.
420: */
421: public void showHelp() {
422: String linefeed = System.getProperty("line.separator", "\r\n");
423: System.out
424: .println(linefeed
425: + "Commands and their respective arguments, line-by-line:"
426: + linefeed
427: + " help"
428: + linefeed
429: + " quit"
430: + linefeed
431: + " exit"
432: + linefeed
433: + " clear"
434: + linefeed
435: + " insert LFN PFN [k=v [..]]"
436: + linefeed
437: + " delete LFN PFN [k=v [..]]"
438: + linefeed
439: + " remove LFN [LFN [..]]"
440: + linefeed
441: + " lookup LFN [LFN [..]]"
442: + linefeed
443: + " list [lfn <pattern>] [pfn <pattern>] [<name> <pattern>]"
444: + linefeed + " set [var [value]]" + linefeed);
445: }
446:
447: /**
448: * Works on the command contained within chunk of lines.
449: *
450: * @param lines is a list of lines with each line being a list of words
451: * that is split appropriately
452: * @param command the command to be invoked.
453: *
454: * @return number of entries affected, or -1 to stop processing.
455: */
456: public int work(List lines, String command) {
457: //sanity checks
458: if (command == null)
459: throw new RuntimeException(
460: "The command to be applied to the file contents not specified");
461:
462: if (lines == null || lines.isEmpty())
463: return 0;
464:
465: String c_argnum = "Illegal number of arguments, ignoring!";
466: int result = 0;
467: //a map indexed by lfn
468: Map entries = new HashMap();
469: if (command.equals("insert") || command.equals("delete")) {
470: for (Iterator it = lines.iterator(); it.hasNext();) {
471: List words = (List) it.next();
472: if (words.size() < 2) {
473: m_log.warn(c_argnum);
474: } else {
475: Iterator i = words.listIterator();
476: String lfn = (String) i.next();
477: ReplicaCatalogEntry rce = new ReplicaCatalogEntry(
478: (String) i.next());
479:
480: while (i.hasNext()) {
481: String attr = (String) i.next();
482: int pos = attr.indexOf('=');
483: if (pos == -1) {
484: m_log.error("attribute \"" + attr
485: + "\" without assignment, "
486: + "assuming resource handle");
487: rce.setResourceHandle(attr);
488: } else {
489: rce.setAttribute(attr.substring(0, pos),
490: unescape(noquote(attr
491: .substring(pos + 1))));
492: }
493: }
494:
495: //check to see if the lfn is already there
496: //not doing a contains check as most of
497: //the times lfn is expected to be unique
498: //add all the old pfn's to the existing collection
499: Collection c = new ArrayList(1);
500: c.add(rce);
501: Object old = entries.put(lfn, c);
502: if (old != null)
503: c.addAll((Collection) old);
504: }
505: }//end of iteration over the lines
506: if (command.equals("insert")) {
507: result = m_rc.insert(entries);
508: m_log.info("inserted " + result + " entries");
509: } else {
510: result = m_rc.delete(entries, false);
511: m_log.info("deleted " + result + " entries");
512: }
513:
514: }
515: return result;
516: }
517:
518: /**
519: * Works on the command contained within one line.
520: *
521: * @param words is a list of the arguments, split appropriately
522: * @return number of entries affected, or -1 to stop processing.
523: */
524: public int work(List words) {
525: String c_argnum = "Illegal number of arguments, ignoring!";
526: int result = 0;
527:
528: // sanity check
529: if (words == null || words.size() == 0)
530: return result;
531:
532: // separate command from arguments
533: String cmd = ((String) words.remove(0)).toLowerCase();
534:
535: if (cmd.equals("help")) {
536: showHelp();
537: } else if (cmd.equals("lookup")) {
538: for (Iterator i = words.iterator(); i.hasNext();) {
539: String lfn = (String) i.next();
540: Collection c = m_rc.lookup(lfn);
541: m_log.info("found " + c.size() + " matches");
542:
543: for (Iterator j = c.iterator(); j.hasNext();) {
544: show(lfn, (ReplicaCatalogEntry) j.next());
545: result++;
546: }
547: }
548: } else if (cmd.equals("list")) {
549: Map m = new HashMap();
550: for (Iterator i = words.iterator(); i.hasNext();) {
551: String key = ((String) i.next()).toLowerCase();
552: if (i.hasNext()) {
553: String val = (String) i.next();
554: m.put(key, val);
555: }
556: }
557:
558: Map lfns = m_rc.lookup(m);
559: if (lfns.size() > 0) {
560: for (Iterator i = lfns.keySet().iterator(); i.hasNext();) {
561: String lfn = (String) i.next();
562: for (Iterator j = ((List) lfns.get(lfn)).iterator(); j
563: .hasNext();) {
564: show(lfn, (ReplicaCatalogEntry) j.next());
565: result++;
566: }
567: }
568: m_log.info("found " + result + " matches");
569: } else {
570: m_log.info("no matches found");
571: }
572: } else if (cmd.equals("insert") || cmd.equals("delete")) {
573: if (words.size() < 2) {
574: m_log.warn(c_argnum);
575: } else {
576: Iterator i = words.listIterator();
577: String lfn = (String) i.next();
578: ReplicaCatalogEntry rce = new ReplicaCatalogEntry(
579: (String) i.next());
580:
581: while (i.hasNext()) {
582: String attr = (String) i.next();
583: int pos = attr.indexOf('=');
584: if (pos == -1) {
585: m_log.error("attribute \"" + attr
586: + "\" without assignment, "
587: + "assuming resource handle");
588: rce.setResourceHandle(attr);
589: } else {
590: rce.setAttribute(attr.substring(0, pos),
591: unescape(noquote(attr
592: .substring(pos + 1))));
593: }
594: }
595:
596: if (cmd.equals("insert")) {
597: result = m_rc.insert(lfn, rce);
598: m_log.info("inserted " + result + " entries");
599: } else {
600: result = rce.getAttributeCount() == 0 ? m_rc
601: .delete(lfn, rce.getPFN()) : m_rc.delete(
602: lfn, rce);
603: m_log.info("deleted " + result + " entries");
604: }
605: }
606: } else if (cmd.equals("remove")) {
607: // do it the slow way, better debugging
608: for (Iterator i = words.iterator(); i.hasNext();) {
609: String lfn = (String) i.next();
610: int count = m_rc.remove(lfn);
611: result += count;
612: if (count > 0) {
613: m_log.info("removed LFN " + lfn);
614: } else {
615: m_log.info("ignoring unknown LFN " + lfn);
616: }
617: }
618: } else if (cmd.equals("clear")) {
619: result = m_rc.clear();
620: m_log.info("removed " + result + " entries");
621: } else if (cmd.equals("quit") || cmd.equals("exit")) {
622: result = -1;
623: m_log.info("Good-bye");
624: } else if (cmd.equals("set")) {
625: String key, value;
626: switch (words.size()) {
627: case 0: // show all
628: for (Iterator i = m_prefs.keySet().iterator(); i
629: .hasNext();) {
630: key = (String) i.next();
631: value = (String) m_prefs.get(key);
632: System.out.println("set " + key + " " + value);
633: result++;
634: }
635: break;
636: case 1: // show one
637: key = ((String) words.get(0)).toLowerCase();
638: if (m_prefs.containsKey(key)) {
639: value = (String) m_prefs.get(key);
640: System.out.println("set " + key + " " + value);
641: result++;
642: } else {
643: m_log.warn("no such preference");
644: }
645: break;
646: case 2: // set one
647: enter((String) words.get(0), (String) words.get(1));
648: result++;
649: break;
650: default: // other
651: m_log.warn(c_argnum);
652: break;
653: }
654: } else {
655: // unknown command
656: m_log.warn("Unknown command: " + cmd + ", ignoring!");
657: }
658:
659: return result;
660: }
661:
662: /**
663: * Consumes commands that control the replica management.
664: *
665: * @param filename is the file to read from. If null, use stdin.
666: * @exception IOException
667: */
668: public void parse(String filename) throws IOException {
669: boolean prompt = (filename == null);
670:
671: LineNumberReader lnr = null;
672: if (filename != null) {
673: // connect to file, use non-interactive mode
674: setLevel(Level.WARN);
675: if (filename.equals("-"))
676: // reading from a pipe, don't prompt
677: lnr = new LineNumberReader(new InputStreamReader(
678: System.in));
679: else
680: // reading from a file, don't prompt
681: lnr = new LineNumberReader(new FileReader(filename));
682: } else {
683: // connect to stdin
684: lnr = new LineNumberReader(new InputStreamReader(System.in));
685: }
686:
687: int pos, result = 0;
688: String line;
689: StringTokenizer st;
690: List words = new ArrayList();
691:
692: if (prompt)
693: System.out.print("rc> ");
694: while ((line = lnr.readLine()) != null) {
695: // do away with superflous whitespaces and comments
696: if ((pos = line.indexOf('#')) != -1)
697: line = line.substring(0, pos);
698: line = line.trim();
699:
700: // skip empty lines
701: if (line.length() == 0)
702: continue;
703:
704: // repeat what we are working on now
705: m_log.debug("LINE " + lnr.getLineNumber() + ": " + line);
706: words.clear();
707: st = new StringTokenizer(line);
708: while (st.hasMoreTokens())
709: words.add(st.nextToken());
710: try {
711: if (work(words) == -1)
712: break;
713: } catch (ReplicaCatalogException rce) {
714: do {
715: RCClient.log(Level.ERROR, rce.getMessage());
716: rce = (ReplicaCatalogException) rce
717: .getNextException();
718: } while (rce != null);
719: result = 1;
720: } catch (RuntimeException rte) {
721: RCClient.log(Level.ERROR, rte.getMessage());
722: result = 1;
723: }
724: if (prompt)
725: System.out.print("rc> ");
726: }
727:
728: // done
729: if (prompt && line == null)
730: System.out.println();
731: lnr.close();
732:
733: // telmi, if something went wrong
734: if (result == 1)
735: throw new RuntimeException(
736: "Errors while processing input file");
737: }
738:
739: /**
740: * Consumes commands that control the replica management.
741: *
742: * @param filename is the file to read from.
743: * @param command is the command that needs to be applied to the file contents
744: *
745: * @exception IOException
746: */
747: public void parse(String filename, String command)
748: throws IOException {
749: LineNumberReader lnr = null;
750: int chunk = m_chunk_factor;
751: int lines_succ_worked = 0;
752:
753: if (command == null) {
754: //throw an exception
755: throw new RuntimeException(
756: "The command to be applied to the file contents not specified");
757: }
758:
759: if (filename != null) {
760: // connect to file, use non-interactive mode
761: setLevel(Level.WARN);
762: // reading from a file
763: lnr = new LineNumberReader(new FileReader(filename));
764: } else {
765: //throw an exception
766: throw new RuntimeException(
767: "File containing the mappings not specified");
768: }
769:
770: int pos, result = 0;
771: String line = null;
772: StringTokenizer st;
773: List words;
774:
775: //set the batch mode to true
776: m_batch = true;
777:
778: //contains the number of valid lines read so far in the current block
779: int counter = 0;
780: List mappings = new ArrayList(chunk);
781:
782: while (true) {
783: while (counter < chunk && (line = lnr.readLine()) != null) {
784: // do away with superflous whitespaces and comments
785: if ((pos = line.indexOf('#')) != -1)
786: line = line.substring(0, pos);
787: line = line.trim();
788:
789: // skip empty lines
790: if (line.length() == 0)
791: continue;
792:
793: // repeat what we are working on now
794: m_total_lines_worked = lnr.getLineNumber();
795: m_log.debug("LINE " + m_total_lines_worked + ": "
796: + line);
797: words = new ArrayList(chunk);
798: st = new StringTokenizer(line);
799: while (st.hasMoreTokens())
800: words.add(st.nextToken());
801:
802: //add to the mappings
803: counter++;
804: mappings.add(words);
805: }
806:
807: //hand off the mappings for work
808: try {
809: lines_succ_worked = work(mappings, command);
810: m_total_lines_succ_worked += lines_succ_worked;
811: } catch (ReplicaCatalogException rce) {
812: do {
813: RCClient.log(Level.ERROR, rce.getMessage());
814: rce = (ReplicaCatalogException) rce
815: .getNextException();
816: } while (rce != null);
817: result = 1;
818: } catch (RuntimeException rte) {
819: RCClient.log(Level.ERROR, rte.getMessage());
820: result = 1;
821: } finally {
822: //log the number of lines successfully worked
823: m_log.info("Successfully worked on "
824: + m_total_lines_succ_worked + " lines.");
825: mappings.clear();
826: }
827: m_log.info("Worked till line " + m_total_lines_worked);
828: System.out.println();
829:
830: //get out of the loop if end
831: if (line == null)
832: break;
833: else
834: counter = 0;
835: }
836:
837: // done
838: lnr.close();
839:
840: // telmi, if something went wrong
841: if (result == 1)
842: throw new RuntimeException(
843: "Errors while processing input file");
844: }
845:
846: /**
847: * Manipulate entries in a given replica catalog implementation.
848: *
849: * @param args are the commandline arguments.
850: */
851: public static void main(String[] args) {
852: int result = 0;
853: RCClient me = null;
854:
855: try {
856: // create an instance of self
857: me = new RCClient("rc-client");
858:
859: // get the commandline options
860: Getopt opts = new Getopt(me.m_application, args,
861: "f:hp:Vi:d:", me.generateValidOptions());
862: opts.setOpterr(false);
863:
864: String arg;
865: String filename = null;
866: int pos, option = -1;
867: boolean interactive = false;
868: String command = null;
869: while ((option = opts.getopt()) != -1) {
870: switch (option) {
871: case 'V':
872: System.out
873: .println("$Id: RCClient.java 175 2007-06-01 00:24:29Z vahi $");
874: System.out.println("Pegasus version "
875: + Version.instance().toString());
876: return;
877:
878: case 'f':
879: arg = opts.getOptarg();
880: interactive = true;
881: if (arg != null)
882: filename = arg;
883: break;
884:
885: case 'p':
886: arg = opts.getOptarg();
887: if (arg != null && (pos = arg.indexOf('=')) != -1)
888: me.enter(arg.substring(0, pos), arg
889: .substring(pos + 1));
890: break;
891:
892: case 'i':
893: arg = opts.getOptarg();
894: command = "insert";
895: if (arg != null)
896: filename = arg;
897: break;
898:
899: case 'd':
900: arg = opts.getOptarg();
901: command = "delete";
902: if (arg != null)
903: filename = arg;
904: break;
905:
906: case 'h':
907: default:
908: me.showUsage();
909: return;
910: }
911: }
912:
913: // now work with me
914: me.connect();
915: RCClient.log(Level.DEBUG, "connected to backend");
916:
917: // are there any remaining CLI arguments?
918: if (opts.getOptind() < args.length) {
919: // there are CLI arguments
920: if (filename != null) {
921: // you must not use -f and CLI extra args
922: throw new RuntimeException(
923: "The -f|-i|-d option and CLI arguments "
924: + "are mutually exclusive");
925: } else {
926: // just work on one (virtual, already shell-spit) line
927: List words = new ArrayList();
928: for (int i = opts.getOptind(); i < args.length; ++i)
929: words.add(args[i]);
930: me.setLevel(Level.WARN);
931: me.work(words);
932: RCClient.log(Level.DEBUG, "done with CLI commands");
933: }
934: } else {
935: // no CLI args, use single command or interactive mode
936: if (interactive && command != null) {
937: throw new RuntimeException(
938: "The -f and -i|-d options are mutually exclusive");
939: }
940: //in interactive mode parse each line
941: if (interactive)
942: me.parse(filename);
943: //in the command mode parse chunks of lines together
944: else if (command != null)
945: me.parse(filename, command);
946:
947: RCClient.log(Level.DEBUG, "done parsing commands");
948: }
949:
950: } catch (ReplicaCatalogException rce) {
951: do {
952: RCClient.log(Level.ERROR, rce.getMessage());
953: rce = (ReplicaCatalogException) rce.getNextException();
954: } while (rce != null);
955: result = 1;
956: } catch (RuntimeException rte) {
957: RCClient.log(Level.ERROR, rte.getMessage());
958: result = 1;
959: } catch (Exception e) {
960: RCClient.log(Level.ERROR, e.getMessage());
961: e.printStackTrace();
962: result = 2;
963: } finally {
964: me.close();
965: RCClient.log(Level.DEBUG, "disconnected from backend");
966: }
967:
968: // get out
969: if (result != 0) {
970: RCClient.log(Level.WARN, "non-zero exit-code " + result);
971: System.exit(result);
972: }
973: }
974:
975: /**
976: * Sets the chunk factor for chunking up large input files.
977: *
978: */
979: private void determineChunkFactor() {
980: int size = this .DEFAULT_CHUNK_FACTOR;
981:
982: try {
983: Properties properties = VDSProperties.instance()
984: .matchingSubset(ReplicaCatalog.c_prefix, false);
985: String s = properties.getProperty(ReplicaCatalog.BATCH_KEY);
986: size = Integer.parseInt(s);
987: } catch (Exception e) {
988: }
989:
990: m_chunk_factor = size;
991: }
992:
993: }
|