· 6 years ago · May 24, 2019, 06:00 PM
1import java.io.*;
2import java.net.InetSocketAddress;
3import java.util.*;
4
5import com.emc.nas.ccmd.cs_core.status.perfstats.*;
6/***********************************************************************
7 * Copyright (C) 1995-2005, All Rights Reserved, by
8 * EMC Corporation, Hopkinton, MA.
9 * This software is furnished under a license and may be used and copied
10 * only in accordance with the terms of such license and with the
11 * inclusion of the above copyright notice. This software or any other
12 * copies thereof may not be provided or otherwise made available to any
13 * other person. No title to and ownership of the software is hereby
14 * transferred.
15 *
16 * The information in this software is subject to change without notice
17 * and should not be construed as a commitment by EMC Corporation.
18 *
19 * EMC assumes no responsibility for the use or reliability of its
20 * software on equipment which is not supplied by EMC.
21 *
22 ***********************************************************************
23 * Version No. Description
24 * THIS IS TEMPORARY VERSION HISTORY. TO DELETE LATER.
25 * 4/17/2019 getStatResolve() modified to skip statsd
26 * 4/19/2019 getStatInfo() modified to skip statsd
27 *
28 ***********************************************************************/
29/**
30 * The main class for the <code>svc_topstats</code> command. Handles user input and starts threads necessary to display requested
31 * statistics information.
32 */
33public class svc_topstats {
34 private static boolean DEBUG = Global.DEBUG;
35 private static final boolean TRACKMEM = Global.TRACKMEM;
36 private static String USAGE_MESSAGE =
37 "USAGE:\n"
38 + "svc_topstats <movername>\n"
39 + " -list \n"
40 + " | -info [-all|<statpath_name>[,...]]\n"
41 + " |[\n"
42 + " [{ -monitor statpath_name[,...]\n"
43 + " | -monitor statpath_name\n"
44 + " [-sort <field_name>]\n"
45 + " [-order {asc|desc}]\n"
46 + " [-lines <lines_of_output>]\n"
47 + " }...]\n"
48 + " [-count <count>]\n"
49 + " [-interval <seconds>]\n"
50 + " [-terminationsummary {no|yes|only}]\n"
51 + " [-format {text [-titles {never|once|<repeat_frequency>}]|csv}]\n"
52 + " [-type {rate|diff|accu}]\n"
53 + " [-file <output_filepath> [-overwrite]]\n"
54 + " [-noresolve]\n"
55 + " ]\n";
56
57 // stats for -summary sets
58 private static final String BASIC_COUNTERS = "basic-std";
59 private static final String CIFS_COUNTERS = "cifs-std";
60 private static final String NFS_COUNTERS = "nfs-std";
61 private static final String CACHES_COUNTERS = "caches-std";
62 // stats for -table sets
63 private static final String TNET_COUNTER = "netDevices-std";
64 private static final String TDVOL_COUNTER = "diskVolumes-std";
65 private static final String TFSVOL_COUNTER = "metaVolumes-std";
66 private static final String TCIFS_COUNTER = "cifsOps-std";
67 private static final String TNFS_COUNTER = "nfsOps-std";
68 /*
69 * The names of the fields that can be selected from table sets for sorting by -sort option. The index of the field name in the array is
70 * used as the index of the column being sorted on in the table's output.
71 */
72 @SuppressWarnings("serial")
73 private static final Map<String,String> STR_TCIFS_FIELDS = new LinkedHashMap<String,String>(){
74 {
75 put("op", "op");
76 put("calls", "calls");
77 put("mintime", "minTime");
78 put("maxtime", "maxTime");
79 put("avgtime", "avgTime");
80 put("oppct", "opPct");
81 }
82 };
83
84 @SuppressWarnings("serial")
85 private static final Map<String,String> STR_TNFS_FIELDS = new LinkedHashMap<String,String>(){
86 {
87 put("op", "op");
88 put("calls", "calls");
89 put("failures", "failures");
90 put("avgtime", "avgTime");
91 put("oppct", "opPct");
92 }
93 };
94 //label for Etrace sort column
95 public static final String ETRACE_FIELD_LABEL = ".top_field:";
96 //label for Etrace lines limit
97 public static final String ETRACE_LISTLEN_LABEL = ".top_listLen:";
98 //label for Etrace sort order
99 public static final String ETRACE_ORDER_LABEL = ".top_sortOrder:";
100 /*
101 * statinfoMap holds information on stats from statmonService. This map is initalize before every exceution of svc_topstats command.
102 * This is also minimize number of request svc_topstats command code to statmon service.
103 */
104 protected static Map<String, StatInfo> statInfoMap = new LinkedHashMap<String, StatInfo>();
105
106 protected static Map<String, StatResolve> statResolveMap = new LinkedHashMap<String, StatResolve>();
107
108 // Data mover in active status.
109 private static final String DM_ACTIVE_STATUS = "online";
110 // boolean flag variable for syntax error of svc_topstats command
111 private static boolean isSyntaxError = true;
112 // whether statmon service is running or not
113 private static boolean isStatmonSerRun = true;
114 // whether a port argument is present in command or not
115 private static boolean isPortInCmd = false;
116 // Merge table counter for -ta/-table option with cifs/nfs of svc_topstats command
117 public static int mergeTableCount = 0;
118 // output format type i.e CSV or TEXT
119 public static int formatType;
120 // string used for complex elements in stats
121 public static StringBuffer element = new StringBuffer();
122 //maximum interval value set to be 2^32 for this is the highest statmon can handle
123 private static final long MAX_INTERVAL = 4294967296L;
124
125 //resolver
126 static ObjectResolver resolver = null;
127 //stastd resolve & info tags
128 static final char REQUESTED_STAT_TAG = '@';
129 static final char TITLE_TAG = 'T';
130 static final char SORTABLE_TAG = 'S';
131
132 /**
133 * Class that holds settings pertinant to svc_topstats
134 */
135 protected static class Settings {
136 private static final String BINPATH = "/bin"; // NAS_DB's bin path
137 /** Never display titles */
138 static final int SHOW_TITLES_NEVER = 0;
139 /** Show titles only once (once at start, once at summary if summary is displayed) */
140 static final int SHOW_TITLES_ONCE = 1;
141 /** Show titles at a specified frequency (and once at summary if summary is displayed) */
142 static final int SHOW_TITLES_REPEATING = 2;
143 // command-line options
144 /** User-visible datamover name */
145 static String datamover;
146 /** server_n hostname for datamover */
147 static String dmhostname;
148 /** Port number for statmon service on data mover, defaults to 7777 */
149 static int statmonPortNumber = 7777;
150 /** Port number for statsd on CS, defaults to 7777 */
151 static int statsdPortNumber = 7777;
152 /** Sample interval */
153 static long interval; // seconds
154 /** Whether or not an interval was specified or if we have to use the defaultd */
155 static boolean usingDefaultInterval = false;
156 /** Output format, defaults to text */
157 static int formatType = OutputFormatter.TEXT;
158 /** List of stats added by monitor to prevent duplicates */
159 static List<String> check_monitor_dups = new ArrayList<String>();
160 /** Output format, defaults to not raw data (calculatedrates) */
161 static int dataFormat = OutputFormatter.DEFAULT;
162 /** Whether to show termination summary */
163 static boolean showSummary = true;
164 /** Whether to show each sample collected */
165 static boolean showMonitor = true;
166 // different mode settings
167 /**
168 * Title display mode, defaults to -1 if the user did not choose a title mode, so an appropriate default can be chosen.
169 *
170 * @see #SHOW_TITLES_NEVER
171 * @see #SHOW_TITLES_ONCE
172 * @see #SHOW_TITLES_REPEATING
173 */
174 static int showTitlesMode = -1;
175 /**
176 * Title print frequency
177 */
178 static int printTitleFreq = 0;
179 /**
180 * Whether to send arguments directly to statmon and report text returned.
181 */
182 static boolean directMode = false;
183 /**
184 * Whether to print raw messages sent to/received from the statmonService
185 */
186 static boolean traceMode = false;
187 /**
188 * Modes to report back in, stats are our normal mode, info is for -info, list is for -list These modes are mutually exclusively.
189 */
190 static boolean statsmode = false;
191 static boolean infomode = false;
192 static boolean listmode = false;
193 static boolean servicemode = false;
194 static boolean actionmode = false;
195 /**
196 * sub mode of service mode These modes are mutually exclusively.
197 */
198 static boolean serviceStartMode = false;
199 static boolean serviceStopMode = false;
200 static boolean serviceDeleteMode = false;
201 static boolean serviceStatusMode = false;
202 /**
203 * This boolean helps differentiate between the method used for stats being added in at the time.
204 */
205 static boolean tableMode = false;
206 /** Track current session of svc_topstats whether collecting etrace statistic or not. */
207 static boolean etrace = false;
208 /** File output mode. */
209 static boolean fileMode = false;
210 /** Whether to overwrite the existing output file or not */
211 static boolean overwriteFileMode = false;
212 /** Whether to resolve elements or not */
213 static boolean noresolve = false;
214 private static boolean statmonPortSet = false;
215 private static boolean statsdPortSet = false;
216 /**
217 * This boolean is flagged when a setElement is requested by the user.
218 */
219 static boolean setElementMode = false;
220 /**
221 * Whether there are multiple stats or just one through -monitor
222 */
223 static boolean multipleStats = false;
224 /**
225 * StringBuffer to save all the arguments that set svc_topstats to go into statsmode for error output purposes.
226 */
227 static StringBuffer statArgs = new StringBuffer();
228 /**
229 * String of -monitor -action argument
230 */
231 static List<String> actionArg = null;
232 /** Whether to print svc_topstats timing trace information */
233 static boolean timingTrace = false;
234 /** Whether to print svc_topstats memory trace information */
235 static boolean memTrace = false;
236 /**
237 * How many samples to retreive, defaults to -1, which means sample until terminated by user.
238 */
239 static long requestedCount = -1;
240 /** Stat names/paths for sets requested by user */
241 static List<String> counters = new ArrayList<String>();
242 /** Options for table stat sets requested by user */
243 static Map<String,TableStat.Options> tableOpts = new HashMap<String,TableStat.Options>();
244 // info from CS environment
245 /** CS environment variables */
246 static Map<String, String> nasVars = new HashMap<String, String>();
247 /** The value of the NAS_DB environment variable */
248 static String NAS_DB;
249
250 /**
251 * Returns whether or not the <code>showTitlesMode</code> indicates that titles should be shown at all
252 *
253 * @return whether or not the <code>showTitlesMode</code> indicates that titles should be shown at all
254 * @see #showTitlesMode
255 */
256 static boolean showTitles() {
257 return(showTitlesMode != SHOW_TITLES_NEVER);
258 }
259
260 // Set the default visibility
261 static String VIS = "hidden";
262 static String allowIp;
263 static String portNumberInEof;
264 // store file path including file name.
265 static String filepath;
266 static String filedir;
267 }
268
269 /**
270 * Gets control station environment variables and populates <code>Settings.nasVars</code> map and sets <code>Settings.NAS_DB</code>
271 * value.
272 *
273 * @throws StatsException If unable to get CS environment information
274 * @see Settings#NAS_DB
275 * @see Settings#nasVars
276 */
277 private static void getNasVars() throws RuntimeException {
278 try {
279 Runtime r = Runtime.getRuntime();
280 Process p = r.exec("/usr/bin/env");
281 BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
282 String line;
283 while((line = br.readLine()) != null) {
284 int idx = line.indexOf('=');
285 if(idx > 0 && idx < (line.length() - 1)) {
286 String key = line.substring(0, idx);
287 String value = line.substring(idx + 1);
288 Settings.nasVars.put(key, value);
289 }
290 }
291 Settings.NAS_DB = Settings.nasVars.get("NAS_DB");
292 if(Settings.nasVars.get("VIS") != null) {
293 if(Settings.nasVars.get("VIS").equals("eng")) {
294 Settings.VIS = "eng";
295 } else if(Settings.nasVars.get("VIS").equals("support")) {
296 Settings.VIS = "support";
297 }
298 }
299 } catch(Throwable t) {
300 t.printStackTrace();
301 if(DEBUG) Global.err.println("Error initializing. Couldn't read system information.");
302 isSyntaxError = false;
303 throw new RuntimeException("Error initializing. Couldn't read system information.");
304 }
305 if(null == Settings.NAS_DB) {
306 if(DEBUG) Global.err.println("NAS_DB not defined");
307 throw new RuntimeException("NAS_DB not defined");
308 }
309 }
310
311 /**
312 * Resolves the data mover name given by the user to the server_n hostname that can be used to connect to the data mover.
313 *
314 * @param dmName User-supplied data mover name
315 * @return data mover hostname
316 * @throws StatsException If the user-supplied data mover name is invalid or unable to get information about data movers from
317 * <code>nas_server</code>
318 */
319 private static String resolveDatamover(final String dmName) throws StatsException {
320 final int[] minimumVers = { 6, 0, -1, -1 }; // -1 means anything is valid
321 final String MIN_VERS_STR = "6.0";
322 HashMap<String, DatamoverInfo> datamovers = new HashMap<String, DatamoverInfo>();
323 String dm = null;
324 if(dmName.equals("localhost")) {
325 dm = dmName;
326 } else {
327 final String[] cmd = {
328 Settings.NAS_DB + Settings.BINPATH + "/nas_server", "-query:*", "-format:%s %s %s %s %s\\n",
329 "-fields:Name,Slot,Version,Type,StatusActual" };
330 try {
331 Process p = Runtime.getRuntime().exec(cmd);
332 BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
333 for(String line; null != (line = in.readLine());) {
334 String[] fields = line.split(" ");
335 // attempt parseInt() slot field only if there is anything to parse
336 int slot;
337 if(fields[1].length() > 0) {
338 slot = Integer.parseInt(fields[1]);
339 } else {
340 slot = -1;
341 }
342 if(fields.length == 5) { // Data mover in boot or offline state
343 datamovers.put(fields[0], new DatamoverInfo(slot, fields[2], fields[3], fields[4]));
344 } else { // Data mover in online, ready or online, active state.
345 datamovers.put(fields[0], new DatamoverInfo(slot, fields[2], fields[3], fields[4].concat(fields[5])));
346 }
347 }
348 } catch(IOException ioe) {
349 if(DEBUG) Global.err.println("Unable to get system information.");
350 isSyntaxError = false;
351 throw new StatsException(MessageFactory.makeErrorInvalidNasQueryResults("nas_server"), ioe, StatsException.STATUS,
352 StatsException.NO_MOVER_NAME);
353 } catch(NumberFormatException nfe) {
354 if(DEBUG) Global.err.println("Got invalid data from system.");
355 isSyntaxError = false;
356 throw new StatsException(MessageFactory.makeErrorInvalidNasQueryResults("nas_server"), nfe, StatsException.STATUS,
357 StatsException.NO_MOVER_NAME);
358 }
359 if(datamovers.containsKey(dmName)) {
360 boolean validVersion = false;
361 DatamoverInfo info = (DatamoverInfo)datamovers.get(dmName);
362 String versstr_check = info.version.trim();
363 try {
364 versstr_check = versstr_check.substring(1);
365 } catch(StringIndexOutOfBoundsException sioobe) {
366 if(info.statusActual.startsWith(DM_ACTIVE_STATUS)) {
367 isSyntaxError = false;
368 throw new StatsException(MessageFactory.makeErrorInvalidNasQueryResults("nas_server"), StatsException.STATUS,
369 StatsException.NO_MOVER_NAME);
370 } else {
371 isSyntaxError = false;
372 throw new StatsException(MessageFactory.makeErrorInvalidMoverStatus(dmName), StatsException.STATUS,
373 StatsException.NO_MOVER_NAME);
374 }
375 }
376 String[] versstr = versstr_check.split("\\."); // trim off first char & split on .
377 int[] vers = new int[versstr.length];
378 for(int i = 0; i < versstr.length; i++) {
379 // remove any non-digits characters
380 vers[i] = Integer.parseInt(versstr[i].replaceAll("\\D", ""));
381 }
382 VERSION_CHECK: for(int i = 0; (i < minimumVers.length) && (i < vers.length); i++) {
383 if(minimumVers[i] < 0) {
384 validVersion = true;
385 dm = info.hostname;
386 break VERSION_CHECK;
387 } else if(minimumVers[i] < vers[i]) {
388 validVersion = true;
389 dm = info.hostname;
390 break VERSION_CHECK;
391 } else if(minimumVers[i] > vers[i]) {
392 validVersion = false;
393 break VERSION_CHECK;
394 }
395 // else minimumVers[i] == vers[i], so don't know, keep checking
396 }
397 if(!validVersion) {
398 isSyntaxError = false;
399 throw new StatsException(MessageFactory.makeErrorInvalidMoverVersion(dmName, info.version, MIN_VERS_STR),
400 StatsException.STATUS, StatsException.NO_MOVER_NAME); }
401 if(((DatamoverInfo)datamovers.get(dmName)).type.equalsIgnoreCase("vdm")) {
402 isSyntaxError = false;
403 throw new StatsException(MessageFactory.makeErrorVirtualDM(), StatsException.STATUS, StatsException.NO_MOVER_NAME);
404 } else if(((DatamoverInfo)datamovers.get(dmName)).type.equalsIgnoreCase("standby")) {
405 isSyntaxError = false;
406 throw new StatsException(MessageFactory.makeErrorStandbyMover(dmName),
407 StatsException.STATUS, StatsException.NO_MOVER_NAME); }
408 } else {
409 if(DEBUG) Global.err.println("Invalid server.");
410 isSyntaxError = false;
411 throw new StatsException(MessageFactory.makeErrorInvalidMover(dmName), StatsException.STATUS, StatsException.NO_MOVER_NAME);
412 }
413 }
414 if(DEBUG) Global.err.println("resolveDatamover::dm\t" + dm);
415 return dm;
416 }
417
418 /**
419 * Stores information about a data mover.
420 */
421 private static class DatamoverInfo {
422 /** DART version on data mover */
423 final String version;
424 /** server_n type of the data mover */
425 final String type;
426 /** server_n hostname for data mover */
427 final String hostname;
428 /** server_n actual status of the data mover */
429 final String statusActual;
430
431 /**
432 * Constructs a new instance of <code>DatamoverInfo</code>
433 *
434 * @param name User-visible name of data mover
435 * @param slot Data mover Slot
436 * @param version DART version on data mover
437 * @param type data mover type (nas, standby, etc)
438 * @param statusActual actual status of data mover (online ready,online active,boot_level=0 etc.)
439 */
440 public DatamoverInfo(int slot, String version, String type, String statusActual) {
441 this.version = version;
442 this.type = type;
443 hostname = "server_" + slot;
444 this.statusActual = statusActual;
445 }
446 }
447
448 /**
449 * Determines whether or not the given command-line argument is a table set option.
450 *
451 * @return <code>true</code> if <code>arg</code> is a table set option
452 */
453 private static boolean isTableOption(String arg) {
454 if(arg.equals("-sort") || arg.equals("-so") || arg.equals("-order") || arg.equals("-o") || arg.equals("-lines") || arg.equals("-l")) {
455 return true;
456 } else {
457 return false;
458 }
459 }
460
461 /**
462 * Gets the table set options for the last given table set.
463 *
464 * @param it <code>ListIterator</code> of command-line arguments, should be at position just after the table set specified. After this
465 * method exits (unless by way of exception), this iterator is positioned so that the next element is the first argument
466 * after the initial position that is not part of a table option.
467 * @param String table The modified stat that the user requested
468 * @param String userStatPath The unmodified statpath as the user typed it for error reporting purposes
469 * @param type The <code>ObjectResolver</code> type <code>int</code> for this table
470 * @return The table options specified by the user
471 * @throws StatsException If the command-line arguments are invalid
472 */
473 private static TableStat.Options parseTableOptions(ListIterator<String> it, String stat, int type)
474 throws StatsException {
475 StatResolve statResolve = statResolveMap.get(stat);
476 boolean isEtraceSet = statResolve.getType() == StatResolve.ESET;
477 List<String> fields = statResolve.getSortFields();
478 List<String> lcfields = statResolve.getLcSortFields();
479
480 if(stat.equalsIgnoreCase(TCIFS_COUNTER)) {
481 fields = new LinkedList<String>(STR_TCIFS_FIELDS.values());
482 lcfields = new LinkedList<String>(STR_TCIFS_FIELDS.keySet());
483 } else if(stat.equalsIgnoreCase(TNFS_COUNTER)) {
484 fields = new LinkedList<String>(STR_TNFS_FIELDS.values());
485 lcfields = new LinkedList<String>(STR_TNFS_FIELDS.keySet());
486 }
487
488 String sort = null;
489 String order = null;
490 String lines = null;
491 boolean sortParsed = false, orderParsed = false, linesParsed = false;
492 while(it.hasNext()) {
493 String opt = it.next();
494 if((opt.equals("-sort") || opt.equals("-so")) && !sortParsed) {
495 it.remove();
496 if(it.hasNext() && !((opt = it.next()).startsWith("-") && !opt.matches("-\\d+"))) {
497 it.remove();
498 sort = opt;
499 } else {
500 StringBuffer options = new StringBuffer();
501 for(Iterator<String> it2 = fields.iterator(); it2.hasNext();) {
502 options.append(it2.next());
503 if(it2.hasNext()) options.append(", ");
504 }
505 String details = "Valid -sort arguments for the \""+stat+"\" set statistic are: "+options.toString()+".";
506 throw new StatsException(MessageFactory.makeErrorMissingArgument("-sort", details), StatsException.STATUS,
507 StatsException.NO_MOVER_NAME);
508 }
509 sortParsed = true;
510 } else if((opt.equals("-order") || opt.equals("-o")) && !orderParsed) {
511 it.remove();
512 if(it.hasNext() && !((opt = it.next()).startsWith("-") && !opt.matches("-\\d+"))) {
513 it.remove();
514 order = opt;
515 } else {
516 throw new StatsException(MessageFactory.makeErrorMissingArgument("-order", ""), StatsException.STATUS,
517 StatsException.NO_MOVER_NAME);
518 }
519 orderParsed = true;
520 } else if((opt.equals("-lines") || opt.equals("-l")) && !linesParsed) {
521 it.remove();
522 if(it.hasNext() && !((opt = it.next()).startsWith("-") && !opt.matches("-\\d+"))) {
523 it.remove();
524 lines = opt;
525 } else {
526 throw new StatsException(MessageFactory.makeErrorMissingArgument("-lines", ""), StatsException.STATUS,
527 StatsException.NO_MOVER_NAME);
528 }
529 linesParsed = true;
530 } else {
531 /*
532 * if the argument isn't a table option, then move the iterator back one place so that the argument can be parsed elsewhere.
533 */
534 it.previous();
535 break;
536 }
537 }
538 int isort = -1;
539 int ilines = 0;
540 boolean boolOrder = true;
541 if(sort != null) {
542 String lcsort = sort.toLowerCase();
543 if(lcfields != null && lcfields.contains(lcsort)) {
544 isort = lcfields.indexOf(lcsort);
545 if(!statResolve.hasTitleSortField()) {
546 isort++;
547 }
548 } else {
549 if(DEBUG) Global.err.println("Invalid argument to -sort: " + sort);
550 StringBuffer options = new StringBuffer();
551 for(Iterator<String> it2 = fields.iterator(); it2.hasNext();) {
552 options.append(it2.next());
553 if(it2.hasNext()) options.append(", ");
554 }
555 //if no sortable fields, throw no sort fields error
556 if (options.length() == 0) {
557 isSyntaxError = false;
558 throw new StatsException(MessageFactory.makeErrorNoSortableFields(stat), StatsException.STATUS,
559 StatsException.NO_MOVER_NAME);
560 } else {
561 throw new StatsException(MessageFactory.makeErrorInvalidSort(options.toString(), stat), StatsException.STATUS,
562 StatsException.NO_MOVER_NAME);
563 }
564 }
565 }
566 if(lines != null) {
567 try {
568 ilines = Integer.parseInt(lines);
569 if((ilines <= 0) ||(isEtraceSet && ilines > Global.ESET_MAX_NUM_ROWS)) {
570 throw new NumberFormatException();
571 }
572 } catch(NumberFormatException e) {
573 if(DEBUG) Global.err.println("Invalid argument to -lines: " + lines);
574 throw new StatsException(MessageFactory.makeErrorInvalidEsetLines(stat),StatsException.STATUS, StatsException.NO_MOVER_NAME);
575 }
576 }
577 if(order != null) {
578 if(order.equals("asc") || order.equals("a")) {
579 boolOrder = true;
580 } else if(order.equals("desc") || order.equals("d")) {
581 boolOrder = false;
582 } else {
583 if(DEBUG) Global.err.println("Invalid argument to -order: " + order);
584 throw new StatsException(MessageFactory.makeErrorInvalidArgument("-order"), StatsException.STATUS,
585 StatsException.NO_MOVER_NAME);
586 }
587 }
588 //if -lines or -order is set but no sort option is set and this is not an etrace set
589 //set default sortcol to element name (0)
590
591 TableStat.Options tableOpt = lookupDefaultOptions(stat, type);
592 int defaultSortCol = tableOpt.getDefaultSortColumn();
593 if(!isEtraceSet && isort < 0 && (order != null || ilines > 0)) {
594 defaultSortCol = 0;
595 }
596
597 if(StatResolve.ESET == statResolve.getType()) {
598 if(isort == -1) {
599 isort = statResolve.getDefaultSortCol();
600 }
601 if(sort == null &&
602 1 == fields.size() &&
603 statResolve.getDefaultSortField() != null &&
604 !statResolve.getDefaultSortField().isEmpty()) {
605 /*
606 * if sort field is not set and there is only one
607 * possible sort option, then set that option as
608 * sort field
609 */
610 sort = statResolve.getDefaultSortField();
611 }
612 if(sort == null &&
613 tableOpt.getSortField() != null &&
614 !tableOpt.getSortField().isEmpty()) {
615 /*
616 * if sort field is not set then set the sort field to
617 * the default sort field as long as it is exists and
618 * it is valid
619 */
620 sort = tableOpt.getSortField();
621 }
622 if(isort == 0 && statResolve.hasTitleSortField()) {
623 /*
624 * if the sort index is set to sort titles and there
625 * is a title sort field then reset the sort field
626 * */
627 sort = tableOpt.getSortField();
628 }
629 }
630
631 if(order == null) {
632 tableOpt = new TableStat.Options(type, sort, isort, isEtraceSet, defaultSortCol, ilines);
633 } else {
634 tableOpt = new TableStat.Options(type, sort, isort, isEtraceSet, defaultSortCol, ilines, boolOrder);
635 }
636 return tableOpt;
637 }
638
639 /**
640 * Gets the table set options for the last given table set.
641 *
642 * @param String table The modified stat that the user requested
643 * @param String userStatPath The unmodified statpath as the user typed it for error reporting purposes
644 * @param type The <code>ObjectResolver</code> type <code>int</code> for this table
645 * @return The table options specified by the user
646 * @throws StatsException If the command-line arguments are invalid
647 */
648 private static TableStat.Options lookupDefaultOptions(String stat, int type) {
649 TableStat.Options tableOpts = null;
650 StatResolve statResolve = statResolveMap.get(stat);
651
652 String sort = null;
653 int isort = -1;
654 int defaultSortCol = -1;
655 boolean esetSort = (StatResolve.ESET == statResolve.type);
656 int ilines = 0;
657
658 if(esetSort && (statResolve.getSortFields().size() == 1 ||
659 (statResolve.getSortFields().size() == 2 && statResolve.hasTitleSortField()))) {
660 //this stat is a child of an eset, set the default sort column to '1'
661 tableOpts = new TableStat.Options(type);
662 //set default sort column
663 int sortCol = statResolve.getDefaultSortCol();
664 if(sortCol == -1 && statResolve.hasTitleSortField()) {
665 sortCol = 0;
666 }
667 tableOpts.setSortColumn(sortCol, esetSort);
668 //set sortfield
669 if(null != statResolve.getDefaultSortField() && !statResolve.getDefaultSortField().isEmpty()) {
670 tableOpts.setSortField(statResolve.getDefaultSortField().toLowerCase());
671 }
672 } else {
673 if(esetSort) {
674 isort = statResolve.getDefaultSortCol();
675 }
676 tableOpts = new TableStat.Options(type, sort, isort, esetSort, defaultSortCol, ilines);
677 }
678 return tableOpts;
679 }
680
681 /**
682 * Attempts to convert a String to int.
683 *
684 * @param s a String
685 * @return boolean that is true if the String value is an interger; otherwise, it returns false
686 */
687 public static boolean isNumber(String s) {
688 boolean isNumber = true;
689 try {
690 Integer.parseInt(s);
691 } catch(NumberFormatException nfe) {
692 isNumber = false;
693 }
694 return isNumber;
695 }
696
697 /**
698 * Sets the advanced usage with hidden options if vis is eng or support
699 */
700 public static void setAdvancedUsage() {
701 USAGE_MESSAGE =
702 "USAGE:\n"
703 + "svc_topstats <movername>\n"
704 + " -list \n"
705 + " | -info [-all|<statpath_name>[,...]]\n"
706 + " |[\n"
707 + " [{ -monitor {statpath_name|statgroup_name}[,...]\n"
708 + " | -monitor {statpath_name|statgroup_name}\n"
709 + " [-sort <field_name>]\n"
710 + " [-order {asc|desc}]\n"
711 + " [-lines <lines_of_output>]\n"
712 + " }...]\n"
713 + " [-count <count>]\n"
714 + " [-interval <seconds>]\n"
715 + " [-terminationsummary {no|yes|only}]\n"
716 + " [-format {text [-titles {never|once|<repeat_frequency>}]|csv}]\n"
717 + " [-type {rate|diff|accu|raw}]\n"
718 + " [-file <output_filepath> [-overwrite]]\n"
719 + " [-noresolve]\n"
720 + " ]\n"
721 + " [-vis {product|support|eng}]\n";
722 }
723
724 /**
725 * Scan for ambiguous options (could mean different things depending on the rest of syntax) and extend them to clear this ambiguity
726 * before passing the args to <code>CmdArgParser</code>.
727 *
728 * @param args The command-line arguments
729 * @return an array of String objects that is a modified copy of the args passed at the command-line
730 */
731 private static String[] extendAmbiguousOptions(final String[] args) {
732 String rtn[] = new String[args.length];
733 List<String> argsList = Arrays.asList(args);
734 for(int i = 0; i < args.length; i++) {
735 String arg = args[i];
736 if(0 == arg.compareTo("-l")) {
737 if((args.length == (i + 1)) || (!isNumber(args[i + 1]))) {
738 if(DEBUG) Global.err.println("Found -l --> -list");
739 arg = "-list";
740 } else {
741 if(DEBUG) Global.err.println("Found -l --> -lines");
742 arg = "-lines";
743 }
744 rtn[i] = arg;
745 } else if(0 == arg.compareTo("-i")) {
746 if(argsList.contains("-m") || argsList.contains("-monitor")
747 || ((args.length > (i + 1)) && ((0 == args[i + 1].compareTo("-")) || isNumber(args[i + 1])))) {
748 if(DEBUG) Global.err.println("Found -i --> -interval");
749 arg = "-interval";
750 } else {
751 if(DEBUG) Global.err.println("Found -i --> -info");
752 arg = "-info";
753 }
754 rtn[i] = arg;
755 } else {
756 rtn[i] = args[i];
757 }
758 if(DEBUG) Global.err.println("rtn[" + i + "]\t" + rtn[i]);
759 } // for loop
760 return rtn;
761 }
762
763 /**
764 * Parse the command-line arguments specified by the user
765 *
766 * @param p The <code>CmdArgParser</code> for the command-line arguments
767 * @see CmdArgParser
768 * @throws StatsException If the command-line arguments are invalid
769 */
770 private static void parseArgs(final CmdArgParser p) throws StatsException {
771 // reused containers
772 String arg = null;
773 // get movername
774 arg = p.getArg();
775 if(null != arg) {
776 // TEMPORARY datamover name validation. Needs more sophisticated way.
777 if(!arg.equals("SVDM_A") && !arg.equals("SVDM_B") && !arg.equals("server_2") && !arg.equals("server_3")) {
778 Global.err.println("ERROR: Unknown datamover");
779 System.exit(1);
780 }
781 Settings.datamover = arg;
782 //Settings.dmhostname = resolveDatamover(arg);
783 Settings.dmhostname = arg;
784 } else {
785 if(Settings.VIS.equals("support") || Settings.VIS.equals("eng")) {
786 setAdvancedUsage();
787 }
788 printUsage();
789 }
790 List<String> optsList;
791 try {
792 optsList = p.getSwitchMultiArg("-DEBUG");
793 } catch(IllegalArgumentException iae) {
794 if(iae.getMessage().contains("Duplicate") || iae.getMessage().contains("duplicated")) {
795 throw new StatsException(MessageFactory.makeErrorDuplicateOption("-DEBUG"), StatsException.STATUS,
796 StatsException.NO_MOVER_NAME);
797 } else {
798 throw new StatsException(MessageFactory.makeErrorMissingArgument("-DEBUG", ""), StatsException.STATUS,
799 StatsException.NO_MOVER_NAME);
800 }
801 }
802 if(null != optsList) {
803 for(Iterator<String> it = optsList.iterator(); it.hasNext();) {
804 String classToDebug = it.next();
805 if(classToDebug.equalsIgnoreCase("APLTaskHandler")) {
806 APLTaskHandler.DEBUG = true;
807 } else if (classToDebug.equalsIgnoreCase("BDBHandler")) {
808 BDBHandler.DEBUG = true;
809 } else if (classToDebug.equalsIgnoreCase("CifsNfsMergeTable")) {
810 CifsNfsMergeTable.DEBUG = true;
811 } else if (classToDebug.equalsIgnoreCase("ComputedStat")) {
812 BDBHandler.DEBUG = true;
813 } else if (classToDebug.equalsIgnoreCase("DMStatCollector")) {
814 DMStatCollector.DEBUG = true;
815 } else if (classToDebug.equalsIgnoreCase("Global")) {
816 //svc_topstats already created, too late to depend on
817 //svc_topstats.DEBUG to be set to Global.DEBUG,
818 //need to set it manually
819 svc_topstats.DEBUG = true;
820 Global.DEBUG = true;
821 } else if (classToDebug.equalsIgnoreCase("InodeXMLHandler")) {
822 InodeXMLHandler.DEBUG = true;
823 } else if (classToDebug.equalsIgnoreCase("LinePrinter")) {
824 LinePrinter.DEBUG = true;
825 } else if (classToDebug.equalsIgnoreCase("MACXMLHandler")) {
826 MACXMLHandler.DEBUG = true;
827 } else if (classToDebug.equalsIgnoreCase("MemMonitor")) {
828 MemMonitor.DEBUG = true;
829 } else if (classToDebug.equalsIgnoreCase("nas_stats")) {
830 nas_stats.DEBUG = true;
831 } else if (classToDebug.equalsIgnoreCase("CifsNfsTable")) {
832 CifsNfsTable.DEBUG = true;
833 } else if (classToDebug.equalsIgnoreCase("ObjectResolver")) {
834 ObjectResolver.DEBUG = true;
835 } else if (classToDebug.equalsIgnoreCase("OutputFormatter")) {
836 OutputFormatter.DEBUG = true;
837 } else if (classToDebug.equalsIgnoreCase("svc_topstats")) {
838 svc_topstats.DEBUG = true;
839 } else if (classToDebug.equalsIgnoreCase("ShutdownEnv")) {
840 ShutdownEnv.DEBUG = true;
841 } else if (classToDebug.equalsIgnoreCase("ShutdownSummary")) {
842 ShutdownSummary.DEBUG = true;
843 } else if (classToDebug.equalsIgnoreCase("TableStat")) {
844 TableStat.DEBUG = true;
845 } else if (classToDebug.equalsIgnoreCase("TfsvolTable")) {
846 TfsvolTable.DEBUG = true;
847 } else {
848 throw new StatsException(MessageFactory.makeErrorInvalidArgument("-DEBUG"), StatsException.STATUS,
849 StatsException.NO_MOVER_NAME);
850 }
851 }
852 }
853 // check for duplicate tableopts
854 boolean hasSort = false, hasOrder = false, hasLines = false;
855 for(Iterator<String> it = p.iterator(); it.hasNext();) {
856 String opt = it.next();
857 if((opt.equals("-sort") || opt.equals("-so")) && hasSort) {
858 // Table option is a duplicate
859 throw new StatsException(MessageFactory.makeErrorDuplicateOption("-sort"), StatsException.STATUS,
860 StatsException.NO_MOVER_NAME);
861 } else if((opt.equals("-order") || opt.equals("-o")) && hasOrder) {
862 // Table option is a duplicate
863 throw new StatsException(MessageFactory.makeErrorDuplicateOption("-order"), StatsException.STATUS,
864 StatsException.NO_MOVER_NAME);
865 } else if((opt.equals("-lines") || opt.equals("-l")) && hasLines) {
866 // Table option is a duplicate
867 throw new StatsException(MessageFactory.makeErrorDuplicateOption("-lines"), StatsException.STATUS,
868 StatsException.NO_MOVER_NAME);
869 }
870 if(opt.equals("-sort") || opt.equals("-so")) {
871 hasSort = true;
872 } else if(opt.equals("-order") || opt.equals("-o")) {
873 hasOrder = true;
874 } else if(opt.equals("-lines") || opt.equals("-l")) {
875 hasLines = true;
876 } else if(opt.equals("-monitor") || opt.equals("-m") || opt.equals("-table") || opt.equals("-ta")) {
877 hasSort = hasOrder = hasLines = false;
878 }
879 }
880 // options
881 // visibility shouldn't generate any errors
882 // if it's used the wrong way, it should silently be reset to "product"
883 try {
884 if(p.optExists("-vis", null)) {
885 arg = p.getSwitch1Arg("-vis");
886 } else {
887 p.getSwitchBoolean("-vis");
888 arg = null;
889 }
890 } catch(IllegalArgumentException iae) {
891 if(iae.getMessage().contains("Duplicate") || iae.getMessage().contains("duplicated")) { throw new StatsException(MessageFactory
892 .makeErrorDuplicateOption("-vis"), StatsException.STATUS, StatsException.NO_MOVER_NAME); }
893 // do nothing, but nothing should ever get caught due to conditionals above
894 /*
895 * throw new StatsException(MessageFactory.makeErrorMissingArgument("-vis"), StatsException.STATUS,
896 * StatsException.NO_MOVER_NAME);
897 */
898 }
899 if(null != arg || !Settings.VIS.equals("hidden")) {
900 // Settings.VIS defaults to hidden by default
901 if(null != arg) {
902 if(arg.equals("support")) {
903 Settings.VIS = "support";
904 } else if(arg.equals("eng")) {
905 Settings.VIS = "eng";
906 } else if(arg.equals("hidden")) {
907 Settings.VIS = "hidden";
908 }
909 }
910 if(Settings.VIS.equals("support") || Settings.VIS.equals("eng")) {
911 setAdvancedUsage();
912 }
913 }
914 try {
915 arg = p.getSwitch1Arg("-terminationsummary", "-te");
916 } catch(IllegalArgumentException iae) {
917 if(iae.getMessage().contains("Duplicate") || iae.getMessage().contains("duplicated")) {
918 throw new StatsException(MessageFactory.makeErrorDuplicateOption("-terminationsummary"), StatsException.STATUS,
919 StatsException.NO_MOVER_NAME);
920 } else {
921 throw new StatsException(MessageFactory.makeErrorMissingArgument("-terminationsummary", ""), StatsException.STATUS,
922 StatsException.NO_MOVER_NAME);
923 }
924 }
925 if(null != arg) {
926 Settings.statsmode = true;
927 Settings.statArgs.append(",-terminationsummary");
928 if(arg.equals("yes")) {
929 Settings.showSummary = true;
930 Settings.showMonitor = true;
931 } else if(arg.equals("no")) {
932 Settings.showSummary = false;
933 Settings.showMonitor = true;
934 } else if(arg.equals("only")) {
935 Settings.showSummary = true;
936 Settings.showMonitor = false;
937 } else {
938 if(DEBUG) Global.err.println("Invalid argument for -terminationsummary");
939 throw new StatsException(MessageFactory.makeErrorInvalidArgument("-terminationsummary"), StatsException.STATUS,
940 StatsException.NO_MOVER_NAME);
941 }
942 }
943 try {
944 arg = p.getSwitch1Arg("-count", "-c");
945 } catch(IllegalArgumentException iae) {
946 if(iae.getMessage().contains("Duplicate") || iae.getMessage().contains("duplicated")) {
947 throw new StatsException(MessageFactory.makeErrorDuplicateOption("-count"), StatsException.STATUS,
948 StatsException.NO_MOVER_NAME);
949 } else {
950 throw new StatsException(MessageFactory.makeErrorMissingArgument("-count", ""), StatsException.STATUS,
951 StatsException.NO_MOVER_NAME);
952 }
953 }
954 if(null != arg) {
955 Settings.statsmode = true;
956 Settings.statArgs.append(",-count");
957 if(arg.equals("-")) {
958 Settings.requestedCount = -1;
959 } else {
960 try {
961 Settings.requestedCount = Long.parseLong(arg);
962 if(Settings.requestedCount <= 0) { throw new NumberFormatException("Count must be greater than 0"); }
963 if(Settings.requestedCount == Long.MAX_VALUE) { throw new NumberFormatException("Interval must be less than "
964 + Long.MAX_VALUE); }
965 } catch(NumberFormatException nfe) {
966 if(DEBUG) Global.err.println("Invalid argument for -count");
967 throw new StatsException(MessageFactory.makeErrorInvalidArgument("-count"), StatsException.STATUS,
968 StatsException.NO_MOVER_NAME);
969 }
970 }
971 }
972 try {
973 arg = p.getSwitch1Arg("-interval");
974 } catch(IllegalArgumentException iae) {
975 if(iae.getMessage().contains("Duplicate") || iae.getMessage().contains("duplicated")) {
976 throw new StatsException(MessageFactory.makeErrorDuplicateOption("-interval"), StatsException.STATUS,
977 StatsException.NO_MOVER_NAME);
978 } else {
979 throw new StatsException(MessageFactory.makeErrorMissingArgument("-interval", ""), StatsException.STATUS,
980 StatsException.NO_MOVER_NAME);
981 }
982 }
983 if(null != arg) {
984 Settings.statsmode = true;
985 Settings.statArgs.append(",-interval");
986 try {
987 Settings.interval = Long.parseLong(arg);
988 if(Settings.interval <= 0 || Settings.interval > MAX_INTERVAL) { throw new NumberFormatException(); }
989 } catch(NumberFormatException nfe) {
990 throw new StatsException(MessageFactory.makeErrorInvalidArgument("-interval"), StatsException.STATUS,
991 StatsException.NO_MOVER_NAME);
992 }
993 } else { // if interval is not specified
994 Settings.usingDefaultInterval = true;
995 }
996 try {
997 arg = p.getSwitch1Arg("-format", "-f");
998 } catch(IllegalArgumentException iae) {
999 if(iae.getMessage().contains("Duplicate") || iae.getMessage().contains("duplicated")) {
1000 throw new StatsException(MessageFactory.makeErrorDuplicateOption("-format"), StatsException.STATUS,
1001 StatsException.NO_MOVER_NAME);
1002 } else {
1003 throw new StatsException(MessageFactory.makeErrorMissingArgument("-format", ""), StatsException.STATUS,
1004 StatsException.NO_MOVER_NAME);
1005 }
1006 }
1007 if(null != arg) {
1008 Settings.statsmode = true;
1009 Settings.statArgs.append(",-format");
1010 if(arg.equals("text")) {
1011 Settings.formatType = OutputFormatter.TEXT;
1012 } else if(arg.equals("csv")) {
1013 Settings.formatType = OutputFormatter.CSV;
1014 } else {
1015 if(DEBUG) Global.err.println("Invalid argument for -format");
1016 throw new StatsException(MessageFactory.makeErrorInvalidArgument("-format"), StatsException.STATUS,
1017 StatsException.NO_MOVER_NAME);
1018 }
1019 }
1020 try {
1021 arg = p.getSwitch1Arg("-type", "-ty");
1022 } catch(IllegalArgumentException iae) {
1023 if(iae.getMessage().contains("Duplicate") || iae.getMessage().contains("duplicated")) {
1024 throw new StatsException(MessageFactory.makeErrorDuplicateOption("-type"), StatsException.STATUS,
1025 StatsException.NO_MOVER_NAME);
1026 } else {
1027 throw new StatsException(MessageFactory.makeErrorMissingArgument("-type", ""), StatsException.STATUS,
1028 StatsException.NO_MOVER_NAME);
1029 }
1030 }
1031 if(null != arg) {
1032 Settings.statsmode = true;
1033 Settings.statArgs.append(",-type");
1034 if(arg.equals("accu")) {
1035 Settings.dataFormat = OutputFormatter.ACCU;
1036 } else if(arg.equals("diff")) {
1037 Settings.dataFormat = OutputFormatter.DIFF;
1038 } else if(arg.equals("raw")) {
1039 Settings.dataFormat = OutputFormatter.RAW;
1040 } else if(arg.equals("rate")) {
1041 Settings.dataFormat = OutputFormatter.RATE;
1042 } else {
1043 if(DEBUG) Global.err.println("Invalid argument for -type");
1044 throw new StatsException(MessageFactory.makeErrorInvalidArgument("-type"), StatsException.STATUS,
1045 StatsException.NO_MOVER_NAME);
1046 }
1047 }
1048 try {
1049 arg = p.getSwitch1Arg("-titles", "-ti");
1050 } catch(IllegalArgumentException iae) {
1051 if(iae.getMessage().contains("Duplicate") || iae.getMessage().contains("duplicated")) {
1052 throw new StatsException(MessageFactory.makeErrorDuplicateOption("-titles"), StatsException.STATUS,
1053 StatsException.NO_MOVER_NAME);
1054 } else {
1055 throw new StatsException(MessageFactory.makeErrorMissingArgument("-titles", ""), StatsException.STATUS,
1056 StatsException.NO_MOVER_NAME);
1057 }
1058 }
1059 if(null != arg) {
1060 Settings.statsmode = true;
1061 Settings.statArgs.append(",-titles");
1062 if(arg.equals("once")) {
1063 Settings.showTitlesMode = Settings.SHOW_TITLES_ONCE;
1064 } else if(arg.equals("never")) {
1065 Settings.showTitlesMode = Settings.SHOW_TITLES_NEVER;
1066 } else if(arg.matches("\\d+")) {
1067 try {
1068 Settings.showTitlesMode = Settings.SHOW_TITLES_REPEATING;
1069 Settings.printTitleFreq = Integer.parseInt(arg);
1070 } catch(NumberFormatException e) {
1071 if(DEBUG) Global.err.println("Invalid argument to -titles");
1072 throw new StatsException(MessageFactory.makeErrorInvalidArgument("-titles"), StatsException.STATUS,
1073 StatsException.NO_MOVER_NAME);
1074 }
1075 } else {
1076 if(DEBUG) Global.err.println("Invalid argument to -titles");
1077 throw new StatsException(MessageFactory.makeErrorInvalidArgument("-titles"), StatsException.STATUS,
1078 StatsException.NO_MOVER_NAME);
1079 }
1080 }
1081 // -file option for store output in the given file
1082 for(ListIterator<String> it = p.iterator(); it.hasNext();) {
1083 String opt = it.next();
1084 if(opt.equals("-file") || opt.equals("-fi")) {
1085 if(Settings.fileMode) {// duplicate -file option
1086 throw new StatsException(MessageFactory.makeErrorDuplicateOption("-file"), StatsException.STATUS,
1087 StatsException.NO_MOVER_NAME);
1088 }
1089 Settings.statsmode = true;
1090 Settings.statArgs.append(",-file");
1091 Settings.fileMode = true;
1092 it.remove();
1093 if(it.hasNext() && !((opt = it.next()).startsWith("-") && !opt.matches("-\\d+"))) {
1094 if(DEBUG) Global.err.println("-file arg " + opt);
1095 Settings.filepath = opt;
1096 it.remove();
1097 while(it.hasNext()) {
1098 opt = it.next();
1099 if(opt.equals("-overwrite") || opt.equals("-ov")) {
1100 if(Settings.overwriteFileMode) {// duplicate -overwrite option
1101 throw new StatsException(MessageFactory.makeErrorDuplicateOption("-overwrite"), StatsException.STATUS,
1102 StatsException.NO_MOVER_NAME);
1103 } else {
1104 Settings.overwriteFileMode = true;
1105 it.remove();
1106 }
1107 } else {
1108 /*
1109 * if the argument isn't a overwrite option, then move the iterator back one place so that the argument can be
1110 * parsed elsewhere.
1111 */
1112 if(it.hasPrevious()) {
1113 it.previous();
1114 }
1115 break;
1116 }
1117 }
1118 } else {
1119 if(DEBUG) Global.err.println("exception -file arg " + opt);
1120 throw new StatsException(MessageFactory.makeErrorMissingArgument("-file", ""), StatsException.STATUS,
1121 StatsException.NO_MOVER_NAME);
1122 }
1123 }
1124 }
1125 // Ignore duplicate option error for -TRACE option
1126 while(p.getArgsList().contains("-TRACE")) {
1127 Settings.traceMode = p.getArgsList().remove("-TRACE");
1128 }
1129 try {
1130 Settings.listmode = p.getSwitchBoolean("-list");
1131 } catch(IllegalArgumentException iae) {
1132 if(iae.getMessage().contains("Duplicate") || iae.getMessage().contains("duplicated")) {
1133 throw new StatsException(MessageFactory.makeErrorDuplicateOption("-list"), StatsException.STATUS,
1134 StatsException.NO_MOVER_NAME);
1135 } else {
1136 throw new StatsException(MessageFactory.makeErrorMissingArgument("-list", ""), StatsException.STATUS,
1137 StatsException.NO_MOVER_NAME);
1138 }
1139 }
1140 try {
1141 if(p.argExists("-info", null)) {
1142 // normal -info [statpath] case
1143 if(p.optExists("-info", null)) {
1144 arg = p.getSwitch1Arg("-info");
1145 } else { // either -info -all or just -info
1146 // if -all is next arg, do a p.getSwitchBoolean() to remove it
1147 String peek = p.peekAtNextArg("-info", null);
1148 if(peek != null && peek.equals("-all")) {
1149 p.getSwitchBoolean("-all");
1150 }
1151 // in either case, -all is the intended arg option
1152 p.getSwitchBoolean("-info");
1153 arg = "-all";
1154 }
1155 } else {
1156 arg = null;
1157 }
1158 } catch(IllegalArgumentException iae) {
1159 if(iae.getMessage().contains("Duplicate") || iae.getMessage().contains("duplicated")) {
1160 throw new StatsException(MessageFactory.makeErrorDuplicateOption("-info"), StatsException.STATUS,
1161 StatsException.NO_MOVER_NAME);
1162 } else {
1163 throw new StatsException(MessageFactory.makeErrorMissingArgument("-info", ""), StatsException.STATUS,
1164 StatsException.NO_MOVER_NAME);
1165 }
1166 }
1167 if(null != arg) {
1168 Settings.infomode = true;
1169 Settings.counters.addAll(Arrays.asList(splitOnComma(arg, true)));
1170 }
1171 try {
1172 if(p.argExists("-service", "-se")) {
1173 Settings.servicemode = p.getSwitchBoolean("-service", "-se");
1174 if(p.isEmpty()) {
1175 if(DEBUG) Global.err.println("Invalid argument for -service");
1176 throw new StatsException(MessageFactory.makeErrorMissingArgument("-service", ""), StatsException.STATUS,
1177 StatsException.NO_MOVER_NAME);
1178 }
1179 for(ListIterator<String> it = p.iterator(); it.hasNext();) {
1180 String opt = it.next();
1181 if(opt.equals("-start")) {
1182 if(Settings.serviceStartMode) { throw new StatsException(MessageFactory.makeErrorDuplicateOption("-start"),
1183 StatsException.STATUS, StatsException.NO_MOVER_NAME); }
1184 Settings.serviceStartMode = true;
1185 it.remove();
1186 // parse port number
1187 while(it.hasNext()) {
1188 opt = it.next();
1189 if(opt.equals("-port") || opt.equals("-p")) {
1190 it.remove();
1191 if(it.hasNext() && !((opt = it.next()).startsWith("-") && !opt.matches("-\\d+"))) {
1192 it.remove();
1193 try {
1194 if(isPortInCmd) { throw new StatsException(MessageFactory.makeErrorDuplicateOption("-port"),
1195 StatsException.STATUS, StatsException.NO_MOVER_NAME); }
1196 Settings.statmonPortNumber = Integer.parseInt(opt);
1197 isPortInCmd = true;
1198 try {
1199 /*
1200 * use a throwaway InetSocketAddress object to check validity of port number. I'm offloading
1201 * this error checking to Java instead of hardcoding anything. The warning suppresion is to
1202 * suppress the 'local variable is never read' warning for the InetSocketAddress object.
1203 */
1204 @SuppressWarnings("unused")
1205 InetSocketAddress isa = new InetSocketAddress(Settings.statmonPortNumber);
1206 } catch(IllegalArgumentException iae) {
1207 if(DEBUG) Global.err.println(iae.getLocalizedMessage());
1208 throw new NumberFormatException();
1209 }
1210 } catch(NumberFormatException nfe) {
1211 if(DEBUG) Global.err.println("Invalid argument for -port: " + arg);
1212 throw new StatsException(MessageFactory.makeErrorInvalidArgument("-port"), StatsException.STATUS,
1213 StatsException.NO_MOVER_NAME);
1214 }
1215 } else {
1216 throw new StatsException(MessageFactory.makeErrorMissingArgument("-port", ""), StatsException.STATUS,
1217 StatsException.NO_MOVER_NAME);
1218 }
1219 } else {
1220 if(it.hasPrevious()) {
1221 it.previous();
1222 }
1223 break;
1224 }
1225 }
1226 } else if(opt.equals("-stop")) {
1227 if(Settings.serviceStopMode) { throw new StatsException(MessageFactory.makeErrorDuplicateOption("-stop"),
1228 StatsException.STATUS, StatsException.NO_MOVER_NAME); }
1229 Settings.serviceStopMode = true;
1230 it.remove();
1231 } else if(opt.equals("-delete")) {
1232 if(Settings.serviceDeleteMode) { throw new StatsException(MessageFactory.makeErrorDuplicateOption("-delete"),
1233 StatsException.STATUS, StatsException.NO_MOVER_NAME); }
1234 Settings.serviceDeleteMode = true;
1235 it.remove();
1236 } else if(opt.equals("-status")) {
1237 if(Settings.serviceStatusMode) { throw new StatsException(MessageFactory.makeErrorDuplicateOption("-status"),
1238 StatsException.STATUS, StatsException.NO_MOVER_NAME); }
1239 Settings.serviceStatusMode = true;
1240 it.remove();
1241 }
1242 }
1243 }
1244 } catch(IllegalArgumentException iae) {
1245 if(iae.getMessage().contains("Duplicate") || iae.getMessage().contains("duplicated")) {
1246 throw new StatsException(MessageFactory.makeErrorDuplicateOption("-service"), StatsException.STATUS,
1247 StatsException.NO_MOVER_NAME);
1248 } else {
1249 throw new StatsException(MessageFactory.makeErrorInvalidArgument("-service"), StatsException.STATUS,
1250 StatsException.NO_MOVER_NAME);
1251 }
1252 }
1253 try {
1254 if(p.getSwitchBoolean("-noresolve", "-no")) {
1255 arg = "-noresolve";
1256 } else {
1257 arg = null;
1258 }
1259 } catch(IllegalArgumentException iae) {
1260 if(iae.getMessage().contains("Duplicate") || iae.getMessage().contains("duplicated")) {
1261 throw new StatsException(MessageFactory.makeErrorDuplicateOption("-noresolve"), StatsException.STATUS,
1262 StatsException.NO_MOVER_NAME);
1263 } else {
1264 throw new StatsException(MessageFactory.makeErrorMissingArgument("-noresolve", ""), StatsException.STATUS,
1265 StatsException.NO_MOVER_NAME);
1266 }
1267 }
1268 if(null != arg) {
1269 Settings.noresolve = true;
1270 }
1271 Set<String> addedStats = new HashSet<String>();
1272 // get summary counters in user order, then table counters in user order
1273 for(ListIterator<String> it = p.iterator(); it.hasNext();) {
1274 String opt = it.next();
1275 if(opt.equals("-summary") || opt.equals("-su")) {
1276 Settings.statsmode = true;
1277 Settings.statArgs.append(",-summary");
1278 it.remove();
1279 if(it.hasNext() && !((opt = it.next()).startsWith("-") && !opt.matches("-\\d+"))) {
1280 it.remove();
1281 String[] opts = opt.split(",");
1282 for(int i = 0; i < opts.length; i++) {
1283 opt = opts[i];
1284 if(opt.equals("basic")) {
1285 opts[i] = BASIC_COUNTERS;
1286 } else if(opt.equals("cifs")) {
1287 opts[i] = CIFS_COUNTERS;
1288 } else if(opt.equals("nfs")) {
1289 opts[i] = NFS_COUNTERS;
1290 } else if(opt.equals("caches")) {
1291 opts[i] = CACHES_COUNTERS;
1292 } else {
1293 if(DEBUG) Global.err.println("Invalid argument to -summary: " + opt);
1294 throw new StatsException(MessageFactory.makeErrorInvalidArgument("-summary"), StatsException.STATUS,
1295 StatsException.NO_MOVER_NAME);
1296 }
1297 if(!addedStats.add(opt)) {
1298 if(DEBUG) Global.err.println("Duplicate stat set specified: " + opt);
1299 throw new StatsException(MessageFactory.makeErrorDuplicateStatSet(opt), StatsException.STATUS,
1300 StatsException.NO_MOVER_NAME);
1301 }
1302 }
1303 List<String> sumList = Arrays.asList(opts);
1304 getStatsResolve(sumList, Settings.VIS);
1305 for(Iterator<String> it2 = sumList.iterator(); it2.hasNext();) {
1306 StatResolve statResolve = statResolveMap.get(it2.next());
1307 List<String> resolvedStatPaths = statResolve.getResolvedStats();
1308 List<String> lcResolvedStatPaths = new LinkedList<String>();
1309 for(Iterator<String> it3 = resolvedStatPaths.iterator(); it3.hasNext();) {
1310 lcResolvedStatPaths.add(it3.next().toLowerCase());
1311 }
1312 Settings.counters.addAll(resolvedStatPaths);
1313 Settings.check_monitor_dups.addAll(lcResolvedStatPaths);
1314 }
1315 } else {
1316 if(DEBUG) Global.err.println("-summary needs arguments");
1317 throw new StatsException(MessageFactory.makeErrorMissingArgument("-summary", ""), StatsException.STATUS,
1318 StatsException.NO_MOVER_NAME);
1319 }
1320 }
1321 }
1322 addedStats.clear();
1323 for(ListIterator<String> it = p.iterator(); it.hasNext();) {
1324 String opt = it.next();
1325 if(opt.equals("-table") || opt.equals("-ta")) {
1326 Settings.statsmode = true;
1327 Settings.statArgs.append(",-table");
1328 it.remove();
1329 if(it.hasNext() && !((opt = it.next()).startsWith("-") && !opt.matches("-\\d+"))) {
1330 it.remove();
1331 String[] opts = opt.split(",");
1332 if(opts.length > 1) {
1333 Settings.multipleStats = true;
1334 }
1335 boolean canHaveTableOpts = (opts.length == 1) && (Settings.formatType == OutputFormatter.TEXT);
1336 for(int i = 0; i < opts.length; i++) {
1337 String statopt = opts[i];
1338 if(statopt.equals("net")) {
1339 opts[i] = TNET_COUNTER;
1340 } else if(statopt.equals("dvol")) {
1341 opts[i] = TDVOL_COUNTER;
1342 } else if(statopt.equals("cifs")) {
1343 opts[i] = TCIFS_COUNTER;
1344 } else if(statopt.equals("nfs")) {
1345 opts[i] = TNFS_COUNTER;
1346 } else if(statopt.equals("fsvol")) {
1347 opts[i] = TFSVOL_COUNTER;
1348 } else {
1349 if(DEBUG) Global.err.println("Unknown argument to -table: " + statopt);
1350 throw new StatsException(MessageFactory.makeErrorInvalidArgument("-table"), StatsException.STATUS,
1351 StatsException.NO_MOVER_NAME);
1352 }
1353 }
1354 List<String> tableList = Arrays.asList(opts);
1355 getStatsResolve(tableList, Settings.VIS);
1356 for(Iterator<String> it2 = tableList.iterator(); it2.hasNext();) {
1357 String stat = it2.next();
1358 StatResolve statResolve = statResolveMap.get(stat);
1359 List<String> resolvedStatPaths = statResolve.getResolvedStats();
1360 List<String> lcResolvedStatPaths = new LinkedList<String>();
1361 for(Iterator<String> it3 = resolvedStatPaths.iterator(); it3.hasNext();) {
1362 String lcstat = it3.next().toLowerCase();
1363 lcResolvedStatPaths.add(lcstat);
1364 }
1365
1366 Settings.counters.addAll(resolvedStatPaths);
1367 Settings.check_monitor_dups.addAll(lcResolvedStatPaths);
1368
1369 TableStat.Options tableOpts = null;
1370
1371 if(stat.equals(TCIFS_COUNTER)) {
1372 if(canHaveTableOpts) {
1373 tableOpts = parseTableOptions(it, stat, ObjectResolver.CIFSNFSMERGE);
1374 } else {
1375 tableOpts = new TableStat.Options(ObjectResolver.CIFSNFSMERGE);
1376 }
1377 Settings.tableOpts.put(lcResolvedStatPaths.get(0),tableOpts);
1378 Settings.tableOpts.put(lcResolvedStatPaths.get(1),tableOpts);
1379 mergeTableCount++;
1380 Settings.tableMode = true;
1381 } else if(stat.equals(TNFS_COUNTER)) {
1382 if(canHaveTableOpts) {
1383 tableOpts = parseTableOptions(it, stat, ObjectResolver.CIFSNFSMERGE);
1384 } else {
1385 tableOpts = new TableStat.Options(ObjectResolver.CIFSNFSMERGE);
1386 }
1387 Settings.tableOpts.put(lcResolvedStatPaths.get(0),tableOpts);
1388 Settings.tableOpts.put(lcResolvedStatPaths.get(1),tableOpts);
1389 Settings.tableOpts.put(lcResolvedStatPaths.get(2),tableOpts);
1390 mergeTableCount+=2;
1391 Settings.tableMode = true;
1392 } else {
1393 if(canHaveTableOpts) {
1394 tableOpts = parseTableOptions(it, stat, ObjectResolver.NO_RESOLVE);
1395 } else {
1396 tableOpts = new TableStat.Options(ObjectResolver.NO_RESOLVE);
1397 }
1398 Settings.tableOpts.put(lcResolvedStatPaths.get(0),tableOpts);
1399 Settings.tableMode = true;
1400 }
1401 if(!addedStats.add(stat)) {
1402 if(DEBUG) Global.err.println("Duplicate stat set specified: " + stat);
1403 throw new StatsException(MessageFactory.makeErrorDuplicateStatSet(stat), StatsException.STATUS,
1404 StatsException.NO_MOVER_NAME);
1405 }
1406 }
1407 } else {
1408 if(DEBUG) Global.err.println("-table needs arguments");
1409 throw new StatsException(MessageFactory.makeErrorMissingArgument("-table", ""), StatsException.STATUS,
1410 StatsException.NO_MOVER_NAME);
1411 }
1412 }
1413 }
1414 for(ListIterator<String> it = p.iterator(); it.hasNext();) {
1415 String opt = it.next();
1416 if(opt.equals("-monitor") || opt.equals("-m")) {
1417 boolean truncate = (Settings.formatType == OutputFormatter.TEXT);
1418 if(null == resolver) {
1419 resolver = new ObjectResolver(Settings.datamover, Settings.NAS_DB, Settings.BINPATH, truncate);
1420 }
1421 it.remove();
1422 if(it.hasNext() && !((opt = it.next()).startsWith("-") && !opt.matches("-\\d+"))) {
1423 if(!Settings.statArgs.toString().contains("-monitor")) {
1424 Settings.statArgs.append(",-monitor");
1425 Settings.statsmode = true;
1426 }
1427 it.remove();
1428 String[] opts = splitOnComma(opt, true);
1429
1430 for(int i = 0; i < opts.length; i++) {
1431 opts[i] = opts[i].replaceAll("id=", "");
1432 }
1433 getStatsResolve(Arrays.asList(opts), Settings.VIS);
1434 boolean canHaveTableOpts = (opts.length == 1) && (Settings.formatType == OutputFormatter.TEXT);
1435 for(int i = 0; i < opts.length; i++) {
1436 String statopt = opts[i];
1437 TableStat.Options tableOpts = null;
1438 StatResolve statResolve = statResolveMap.get(statopt);
1439 List<String> resolvedStatPaths = statResolve.getResolvedStats();
1440 boolean oneResolved = resolvedStatPaths.size() == 1;
1441 String resolvedStatPath = "";
1442 String lcResolvedStatPath = "";
1443 if(oneResolved) {
1444 resolvedStatPath = resolvedStatPaths.get(0);
1445 lcResolvedStatPath = resolvedStatPath.toLowerCase();
1446 }
1447
1448 if(opts.length == 1) {
1449 Settings.multipleStats = false;
1450 if(statResolve.getType() != StatResolve.NONSET && statResolve.isSortable()) {
1451 // is a table
1452 if(DEBUG) Global.err.println(statopt + " is a table stat/table Element!");
1453 Settings.tableMode = true;
1454 } else if(statResolve.getType() != StatResolve.NONSET && !statResolve.isSortable()) {
1455 // treat as a table that cannot have options
1456 Settings.tableMode = true;
1457 Settings.setElementMode = true;
1458 canHaveTableOpts = false;
1459 } else {
1460 // not a table, can't have table options
1461 Settings.tableMode = false;
1462 canHaveTableOpts = false;
1463 }
1464 if(statResolve.getType() == StatResolve.ESET) {
1465 Settings.etrace = true;
1466 canHaveTableOpts = true;
1467 } else {
1468 Settings.etrace = false;
1469 }
1470 } else {
1471 Settings.multipleStats = true;
1472 Settings.tableMode = false;
1473 Settings.etrace = false;
1474 Settings.setElementMode = false;
1475 }
1476
1477 if(statopt.equalsIgnoreCase(TCIFS_COUNTER)) {
1478 if(canHaveTableOpts) {
1479 tableOpts = parseTableOptions(it, statopt, ObjectResolver.CIFSNFSMERGE);
1480 } else {
1481 tableOpts = new TableStat.Options(ObjectResolver.CIFSNFSMERGE);
1482 }
1483 List<String> lcResolvedStatPaths = new LinkedList<String>();
1484 for(Iterator<String> it2 = resolvedStatPaths.iterator(); it2.hasNext();) {
1485 String stat = it2.next().toLowerCase();
1486 lcResolvedStatPaths.add(stat);
1487 checkDupTable(stat,tableOpts);
1488 }
1489 if(!Settings.check_monitor_dups.containsAll(lcResolvedStatPaths)) {
1490 Settings.check_monitor_dups.addAll(lcResolvedStatPaths);
1491 Settings.counters.addAll(resolvedStatPaths);
1492 Settings.tableOpts.put(lcResolvedStatPaths.get(0),tableOpts);
1493 Settings.tableOpts.put(lcResolvedStatPaths.get(1),tableOpts);
1494 mergeTableCount++;
1495 Settings.tableMode = true;
1496 }
1497 } else if(statopt.equalsIgnoreCase(TNFS_COUNTER)) {
1498 if(canHaveTableOpts) {
1499 tableOpts = parseTableOptions(it, statopt, ObjectResolver.CIFSNFSMERGE);
1500 } else {
1501 tableOpts = new TableStat.Options(ObjectResolver.CIFSNFSMERGE);
1502 }
1503 List<String> lcResolvedStatPaths = new LinkedList<String>();
1504 for(Iterator<String> it2 = resolvedStatPaths.iterator(); it2.hasNext();) {
1505 String stat = it2.next().toLowerCase();
1506 lcResolvedStatPaths.add(stat);
1507 checkDupTable(stat,tableOpts);
1508 }
1509 if(!Settings.check_monitor_dups.containsAll(lcResolvedStatPaths)) {
1510 Settings.check_monitor_dups.addAll(lcResolvedStatPaths);
1511 Settings.counters.addAll(resolvedStatPaths);
1512 Settings.tableOpts.put(lcResolvedStatPaths.get(0),tableOpts);
1513 Settings.tableOpts.put(lcResolvedStatPaths.get(1),tableOpts);
1514 Settings.tableOpts.put(lcResolvedStatPaths.get(2),tableOpts);
1515 mergeTableCount+=2;
1516 Settings.tableMode = true;
1517 }
1518 } else {
1519 // add stats that are not known tables
1520 if(statResolve.getType() != StatResolve.NONSET && statResolve.isSortable()) {
1521 // is a table
1522 if(DEBUG) Global.err.println(statopt + " is a table stat!");
1523 if(canHaveTableOpts) {
1524 tableOpts = parseTableOptions(it, statopt, ObjectResolver.NO_RESOLVE);
1525 } else if(statResolve.getType() == StatResolve.ESET) {
1526 tableOpts = lookupDefaultOptions(statopt, ObjectResolver.NO_RESOLVE);
1527 }
1528 checkDupTable(lcResolvedStatPath,tableOpts);
1529 Settings.tableOpts.put(lcResolvedStatPath,tableOpts);
1530 } else {
1531 Settings.tableMode = false;
1532 }
1533
1534 if(statResolve.getType() == StatResolve.ESET) {
1535 String statpath = statResolve.getResolvedStats().get(0);
1536 StringBuffer sb = new StringBuffer(statpath);
1537 String lcstatpath = statpath.toLowerCase();
1538 if(!Settings.tableOpts.isEmpty() && Settings.tableOpts.containsKey(lcstatpath)) {
1539 //has table options, append them
1540 String sortField;
1541 if((sortField = Settings.tableOpts.get(lcstatpath).getSortField()) != null
1542 && !sortField.isEmpty()) {
1543 //if sortField is defined, send to statmon
1544 sb.append(ETRACE_FIELD_LABEL);
1545 sb.append(sortField);
1546 }
1547 int numRows;
1548 if((numRows = Settings.tableOpts.get(lcstatpath).getNumRows()) > 0) {
1549 //if numRows is greater than zero, send to statmon
1550 sb.append(ETRACE_LISTLEN_LABEL);
1551 sb.append(numRows);
1552 //reset numRows to prevent applying it to the top level set
1553 Settings.tableOpts.get(lcstatpath).resetNumRows();
1554 }
1555 int sortOrder = Settings.tableOpts.get(lcstatpath).getSortOrder();
1556 if(sortOrder != 0) {
1557 if(sortOrder < 0) {
1558 sb.append(ETRACE_ORDER_LABEL);
1559 sb.append("desc");
1560 } else if(sortOrder > 0) {
1561 sb.append(ETRACE_ORDER_LABEL);
1562 sb.append("asc");
1563 }
1564 }
1565 }
1566
1567 resolvedStatPath = sb.toString();
1568 statResolve.setResolvedStat(resolvedStatPath);
1569 lcResolvedStatPath = resolvedStatPath.toLowerCase();
1570 }
1571
1572 for(Iterator<String> it2 = resolvedStatPaths.iterator(); it2.hasNext();) {
1573 String resolved = it2.next();
1574 String lcresolved = resolved.toLowerCase();
1575 if(!Settings.check_monitor_dups.contains(lcresolved)) {
1576 Settings.check_monitor_dups.add(lcresolved);
1577 Settings.counters.add(resolved);
1578 }
1579 }
1580 }
1581 }
1582 } else if(opt.equals("-a") || opt.equals("-action")) {
1583 try {
1584 if(p.peekAtNextArg("-action", "-a") == null) {
1585 throw new StatsException(MessageFactory.makeErrorMissingArgument("-action", ""), StatsException.STATUS,
1586 StatsException.NO_MOVER_NAME);
1587 } else if(!p.peekAtNextArg("-action", "-a").equals("enable") && !p.peekAtNextArg("-action", "-a").equals("disable")
1588 && !p.peekAtNextArg("-action", "-a").equals("status")
1589 && !(p.peekAtNextArg("-action", "-a").equals("reset") && !Settings.VIS.equals("hidden"))) { throw new StatsException(
1590 MessageFactory.makeErrorInvalidArgument("-action"), StatsException.STATUS, StatsException.NO_MOVER_NAME); }
1591 Settings.actionmode = true;
1592 Settings.actionArg = new ArrayList<String>();
1593 if(Settings.VIS.equals("hidden")) {
1594 // remove -a/-action
1595 it.remove();
1596 // add enable/disable/reset/status
1597 Settings.actionArg.add(it.next());
1598 // remove enable/disable/reset/status
1599 it.remove();
1600 } else {
1601 // remove -a/-action
1602 it.remove();
1603 // add enable/disable/reset/status to actionArgs
1604 Settings.actionArg.add(it.next());
1605 // remove enable/disable/reset/status from option List
1606 it.remove();
1607 // if there are control groups, add them to actionArgs and remove from option list,
1608 // (comma delimited so should be one iteration)
1609 if(it.hasNext()) {
1610 Settings.actionArg.add(it.next());
1611 it.remove();
1612 }
1613 // if there are more options, back up one spot
1614 if(it.hasPrevious()) it.previous();
1615 if(Settings.actionArg.size() > 2) { throw new StatsException(MessageFactory
1616 .makeErrorUnknownOption(Settings.actionArg.get(2)), StatsException.STATUS, StatsException.NO_MOVER_NAME); }
1617 }
1618 } catch(IllegalArgumentException iae) {
1619 if(iae.getMessage().contains("Duplicate") || iae.getMessage().contains("duplicated")) { throw new StatsException(
1620 MessageFactory.makeErrorDuplicateOption("-action"), StatsException.STATUS, StatsException.NO_MOVER_NAME); }
1621 }
1622 } else {
1623 if(DEBUG) Global.err.println("-monitor needs arguments");
1624 throw new StatsException(MessageFactory.makeErrorMissingArgument("-monitor", ""), StatsException.STATUS,
1625 StatsException.NO_MOVER_NAME);
1626 }
1627 } else if(isTableOption(opt)) {
1628 if(Settings.formatType == OutputFormatter.CSV && !Settings.etrace && !Settings.multipleStats) {
1629 if(DEBUG) Global.err.println("Table options are not valid if -format csv is set");
1630 throw new StatsException(MessageFactory.makeErrorTableOptsWhenNotValid(opt, "-format csv"), StatsException.STATUS,
1631 StatsException.NO_MOVER_NAME);
1632 } else if((Settings.tableMode || Settings.multipleStats) && !Settings.setElementMode) {
1633 if(DEBUG) Global.err.println("Table options may only be set for -table or -monitor with one set as an argument");
1634 throw new StatsException(MessageFactory.makeErrorTableOptsWithMultipleSets(), StatsException.STATUS,
1635 StatsException.NO_MOVER_NAME);
1636 } else if(Settings.statArgs.toString().contains("-monitor")) {
1637 throw new StatsException(MessageFactory
1638 .makeErrorTableOptWithoutSet(opt), StatsException.STATUS, StatsException.NO_MOVER_NAME); }
1639 }
1640 }
1641 // if showTitlesMode isn't set, set it to once
1642 if(Settings.showTitlesMode == -1) {
1643 Settings.showTitlesMode = Settings.SHOW_TITLES_ONCE;
1644 } else {
1645 // Disable -titles option for -format csv
1646 if(Settings.formatType == OutputFormatter.CSV) {
1647 if(DEBUG) Global.err.println("-titles option is not valid if -format csv is set");
1648 throw new StatsException(MessageFactory.makeErrorTableOptsWhenNotValid("-titles", "-format csv"), StatsException.STATUS,
1649 StatsException.NO_MOVER_NAME);
1650 }
1651 }
1652 // specify manual stats
1653 List<String> opts = new ArrayList<String>();
1654 try {
1655 opts = p.getSwitchMultiArg("-overrideStats");
1656 } catch(IllegalArgumentException iae) {
1657 if(iae.getMessage().contains("Duplicate") || iae.getMessage().contains("duplicated")) {
1658 throw new StatsException(MessageFactory.makeErrorDuplicateOption("-overrideStats"), StatsException.STATUS,
1659 StatsException.NO_MOVER_NAME);
1660 } else {
1661 throw new StatsException(MessageFactory.makeErrorMissingArgument("-overrideStats", ""), StatsException.STATUS,
1662 StatsException.NO_MOVER_NAME);
1663 }
1664 }
1665 if(null != opts) {
1666 Settings.counters.clear();
1667 Settings.check_monitor_dups.clear();
1668 Settings.counters.addAll(opts);
1669 }
1670 try {
1671 opts = p.getSwitchMultiArg("-DIRECT");
1672 } catch(IllegalArgumentException iae) {
1673 if(iae.getMessage().contains("Duplicate") || iae.getMessage().contains("duplicated")) {
1674 throw new StatsException(MessageFactory.makeErrorDuplicateOption("-DIRECT"), StatsException.STATUS,
1675 StatsException.NO_MOVER_NAME);
1676 } else {
1677 throw new StatsException(MessageFactory.makeErrorMissingArgument("-DIRECT", ""), StatsException.STATUS,
1678 StatsException.NO_MOVER_NAME);
1679 }
1680 }
1681 if(null != opts) {
1682 Settings.counters.clear();
1683 Settings.check_monitor_dups.clear();
1684 Settings.counters.addAll(opts);
1685 Settings.directMode = true;
1686 }
1687 try {
1688 Settings.timingTrace = p.getSwitchBoolean("-TIMINGTRACE");
1689 } catch(IllegalArgumentException iae) {
1690 if(iae.getMessage().contains("Duplicate") || iae.getMessage().contains("duplicated")) {
1691 throw new StatsException(MessageFactory.makeErrorDuplicateOption("-TIMINGTRACE"), StatsException.STATUS,
1692 StatsException.NO_MOVER_NAME);
1693 } else {
1694 throw new StatsException(MessageFactory.makeErrorMissingArgument("-TIMINGTRACE", ""), StatsException.STATUS,
1695 StatsException.NO_MOVER_NAME);
1696 }
1697 }
1698 try {
1699 Settings.memTrace = p.getSwitchBoolean("-MEMTRACE");
1700 } catch(IllegalArgumentException iae) {
1701 if(iae.getMessage().contains("Duplicate") || iae.getMessage().contains("duplicated")) {
1702 throw new StatsException(MessageFactory.makeErrorDuplicateOption("-MEMTRACE"), StatsException.STATUS,
1703 StatsException.NO_MOVER_NAME);
1704 } else {
1705 throw new StatsException(MessageFactory.makeErrorMissingArgument("-MEMTRACE", ""), StatsException.STATUS,
1706 StatsException.NO_MOVER_NAME);
1707 }
1708 }
1709 if(Settings.counters.isEmpty() && (Settings.statsmode ||
1710 (!Settings.actionmode && !Settings.directMode && !Settings.infomode &&
1711 !Settings.listmode && !Settings.servicemode))) {
1712 // default to -su basic
1713 List<String> basic_list = new LinkedList<String>();
1714 basic_list.add(BASIC_COUNTERS);
1715 getStatsResolve(basic_list, Settings.VIS);
1716 StatResolve statResolve = statResolveMap.get(BASIC_COUNTERS);
1717 Settings.counters.addAll(statResolve.getResolvedStats());
1718 }
1719 if(!p.isEmpty()) {
1720 String invalidArg = p.getArg();
1721 if(DEBUG) Global.err.println("Invalid/Unknown argument: " + invalidArg);
1722 throw new StatsException(MessageFactory.makeErrorUnknownOption(invalidArg), StatsException.STATUS, StatsException.NO_MOVER_NAME);
1723 }
1724 }
1725
1726 private static void checkDupTable(String statopt,TableStat.Options current) throws StatsException {
1727 if(current == null) {
1728 return;
1729 }
1730 TableStat.Options prev;
1731 if(Settings.tableOpts.containsKey(statopt.toLowerCase())) {
1732 prev = Settings.tableOpts.get(statopt.toLowerCase());
1733 if(prev.getSortColumn() != current.getSortColumn()
1734 || prev.getSortOrder() != current.getSortOrder()
1735 || prev.getNumRows() != current.getNumRows()) {
1736 throw new StatsException(MessageFactory.makeErrorMonOptsForDuplicateStat(statopt), StatsException.STATUS,
1737 StatsException.NO_MOVER_NAME);
1738 }
1739 }
1740 }
1741
1742 /** Print usage string and exit */
1743 private static void printUsage() {
1744 Global.err.println(USAGE_MESSAGE);
1745 System.exit(1); // usage exit code is traditionally 1
1746 }
1747
1748 public static boolean getStatsResolve(List<String> stats, String vis) {
1749 return getStatsResolve(Settings.dmhostname, Settings.NAS_DB, stats, vis, true, true);
1750 }
1751
1752 public static boolean getStatsResolve(String dmhostname, String NAS_DB, List<String> stats, String vis,
1753 boolean getStatmonPort, boolean exitOnError) {
1754
1755 // Make a Statmon request
1756 String cmd = "version=6 visibility=" + vis + " info";
1757 for(Iterator<String> it = stats.iterator(); it.hasNext();) {
1758 cmd += " " + it.next();
1759 }
1760 cmd += "\n";
1761
1762 // Send the request and receive a response from Statmon
1763 String[] resp = DMStatCollector.getRawResponse(dmhostname, Settings.statmonPortNumber, cmd, vis, false, false, true);
1764
1765 // TODO: ERROR HANDLING NEEDED HERE.
1766 // connection error?
1767 // invalid statpath?
1768 if(resp==null || resp.length<2) {
1769 if(exitOnError) {
1770 Global.err.println("ERROR: Connection failed to statmon");
1771 System.exit(1);
1772 } else {
1773 return false;
1774 }
1775 }
1776 else if(resp[1].startsWith("ERROR")) {
1777 if(exitOnError) {
1778 Global.err.println("ERROR: Unknown Stat");
1779 System.exit(1);
1780 } else {
1781 return false;
1782 }
1783 }
1784
1785 if(Settings.traceMode) {
1786 Global.err.println("==== Message sent to statmon ====");
1787 Global.err.println(cmd);
1788 Global.err.println("==== Message received from statmon ====");
1789 for(int i = 0; i < resp.length; i++)
1790 Global.err.println(resp[i]);
1791 }
1792
1793 // Set index to 1 to skip the title line
1794 int index = 1;
1795 for(Iterator<String> it = stats.iterator(); it.hasNext();) {
1796 List<String> sortFields = new LinkedList<String>();
1797 List<String> resolvedStats = new LinkedList<String>();
1798 int type;
1799 String defaultSortField = "";
1800 boolean hasTitleSortField = false;
1801 String stat = "";
1802
1803 String[] respField = resp[index].split(",");
1804 stat = respField[0];
1805 String statFromUser = it.next();
1806 // TODO: ERROR HANDLING NEEDED HERE.
1807 // Do stat and statFromUser match?
1808
1809 type = StatResolve.findType(respField[2]);
1810
1811 if(type == StatResolve.NONSET) {
1812 String line = "";
1813 //while(index+1 < response.length && (line = response[++index]).charAt(0) != REQUESTED_STAT_TAG) { /// SHIN
1814 // resolvedStats.add(line); // supposed to put member stats (as is)
1815 //}
1816
1817 // Member stats
1818 while(index+1 < resp.length) {
1819 line = resp[++index];
1820 String[] lineField = line.split(",");
1821 if(lineField[0].indexOf(stat) == -1) break; // The line is for a different statpath
1822 /** If a member stat satisfies the following conditions, put it into resolvedStats.
1823 - No '*' in statpath
1824 - type != family
1825 - type != setElement
1826 - type != cmpd */
1827 if(lineField[0].indexOf("*") == -1 &&
1828 !lineField[2].equals("family") &&
1829 !lineField[2].equals("setElement") &&
1830 !lineField[2].equals("cmpd"))
1831 resolvedStats.add(lineField[0]);
1832 }
1833 } else if(type == StatResolve.SET) {
1834 resolvedStats.add(stat);
1835 hasTitleSortField = true;
1836 String[] statField = stat.split("\\.");
1837 if(statField.length>=2)
1838 sortFields.add(statField[1]);
1839
1840 } else if(type == StatResolve.ESET) {
1841 String sortID = respField[respField.length-1];
1842 if(stat.indexOf("*") != -1 && sortID.equals("0")) {
1843 hasTitleSortField = true;
1844 String[] statField = stat.split("\\.");
1845 if(statField.length>=2)
1846 sortFields.add(statField[1]);
1847 }
1848
1849 String line;
1850 while(index+1 < resp.length) {
1851 line = resp[++index];
1852 String[] lineField = line.split(",");
1853 if(lineField[0].indexOf(stat) == -1) break;
1854
1855 // the last field of the statpath
1856 String field = lineField[0].substring(lineField[0].lastIndexOf('.')+1);
1857 if(!field.isEmpty()) {
1858 if(lineField[0].indexOf(stat+".*.") != -1) {
1859 if (defaultSortField == "") {
1860 defaultSortField = field;
1861 }
1862 if(!field.isEmpty())
1863 sortFields.add(field);
1864 }
1865 }
1866 }
1867 resolvedStats.add(stat);
1868 }
1869
1870 StatResolve statResolve = new StatResolve(stat, resolvedStats, type, defaultSortField, sortFields, hasTitleSortField);
1871 statResolveMap.put(stat, statResolve);
1872
1873 // TODO: for testing purpose. Delete this later.
1874 if(Settings.traceMode) {
1875 Global.err.println("==========Parsing result===========");
1876 Global.err.println("stat = " + stat);
1877 Global.err.println("resolvedStats = " + Arrays.toString(resolvedStats.toArray()));
1878 Global.err.println("type = " + type);
1879 Global.err.println("defaultSortField = " + defaultSortField);
1880 Global.err.println("sortFields = " + Arrays.toString(sortFields.toArray()));
1881 Global.err.println("hasTitleSortField = " + hasTitleSortField);
1882 }
1883 }
1884 return true;
1885 }
1886
1887 protected static boolean getStatsInfo(List<String> stats, String vis) {
1888 return getStatsInfo(Settings.datamover, Settings.NAS_DB, stats, vis, true);
1889 }
1890
1891 protected static boolean getStatsInfo(String dmhostname, String NAS_DB, List<String> stats, String vis,
1892 boolean exitOnError) {
1893
1894 // SHINNNNNNN
1895 // Make sure to remove "." or ".*" at the end of stat!!!!!
1896
1897 // Make a Statmon request
1898 String cmd = "version=6 visibility=" + vis + " info";
1899 boolean isAll = stats.contains("all");
1900 if(!isAll) {
1901 for(Iterator<String> it = stats.iterator(); it.hasNext();) {
1902 cmd += " " + it.next();
1903 }
1904 }
1905 cmd += "\n";
1906
1907 // Send the request and receive a response from Statmon
1908 String[] resp = DMStatCollector.getRawResponse(dmhostname, Settings.statmonPortNumber, cmd, vis, false, false, true);
1909
1910 // TODO: ERROR HANDLING NEEDED HERE.
1911 // connection error?
1912 // invalid statpath?
1913
1914 if(resp==null || resp.length<2) {
1915 if(exitOnError) {
1916 Global.err.println("ERROR: Connection failed to statmon");
1917 System.exit(1);
1918 } else {
1919 return false;
1920 }
1921 }
1922 else if(resp[1].startsWith("ERROR")) {
1923 if(exitOnError) {
1924 Global.err.println("ERROR: Unknown Stat");
1925 System.exit(1);
1926 } else {
1927 return false;
1928 }
1929 }
1930
1931 if(Settings.traceMode) {
1932 Global.err.println("==== Message sent to statmon ====");
1933 Global.err.println(cmd);
1934 Global.err.println("==== Message received from statmon ====");
1935 for(int i = 0; i < resp.length; i++)
1936 Global.err.println(resp[i]);
1937 }
1938
1939 int index = 0; // title line will be skipped.
1940 while(index+1 < resp.length) {
1941 index++;
1942 String type = "";
1943 String title = "";
1944 String description = "";
1945 String parent = "";
1946 String operation = "";
1947 boolean isCounter = false;
1948 boolean isResetting = false;
1949 boolean isError = false;
1950 List<String> children = new LinkedList<String>();
1951 List<String> elements = new LinkedList<String>();
1952
1953 String stat;
1954 String[] respField = resp[index].split(",");
1955 stat = respField[0];
1956 type = respField[2];
1957
1958 // In case that stat is 'all', skip elements.
1959 if(isAll && type.equals("setElement")) continue;
1960
1961 title = respField[3].replaceAll("^\"|\"$", "");
1962 description = respField[4].replaceAll("^\"|\"$", "");
1963
1964 // get parent stat
1965 if(!stat.contains(".")) {
1966 parent = ""; // there is no parent
1967 } else {
1968 String[] statField = stat.split("\\.");
1969 parent = statField[0];
1970 if(statField.length>2) {
1971 for(int i=1; i<statField.length-2; i++) {
1972 parent += "." + statField[i];
1973 }
1974 if(!statField[statField.length-2].equals("*")) {
1975 parent += "." + statField[statField.length-2];
1976 }
1977 }
1978 }
1979
1980 if(type.equals("computed")) {
1981 operation = StatInfo.findOperation(respField[7]);
1982 }
1983
1984 if(type.equals("c64") || type.equals("tc64") || type.equals("tec64") || type.equals("ec64")) {
1985 isCounter = true;
1986 }
1987
1988 if(type.equals("tc64") || type.equals("tec64")) {
1989 isResetting = true;
1990 }
1991
1992 if(type.equals("ec64") || type.equals("tec64")) {
1993 isError = true;
1994 }
1995
1996 if(type.equals("s") || type.equals("es") || type.equals("family") || type.equals("cmpd")) {
1997 int childIndex = index;
1998 while(childIndex+1 < resp.length) {
1999 String line = resp[++childIndex];
2000 String[] lineField = line.split(",");
2001 if(lineField[0].indexOf(stat) == -1) { // the line is for a different stat
2002 --childIndex;
2003 break;
2004 }
2005
2006 // Element
2007 if((type.equals("s") || type.equals("es")) && lineField[2].equals("setElement")) {
2008 elements.add(lineField[0]);
2009 } else {
2010 // Children
2011 String[] statSplit = lineField[0].split(stat+".");
2012 if(statSplit.length!=2) break;
2013 String subStat = statSplit[1];
2014 String[] subStatField = subStat.split("\\.");
2015 String childStat = "";
2016 if(subStatField[0].equals("*") && subStatField.length==2) {
2017 childStat = "*." + subStatField[1];
2018 }
2019 else if(subStatField.length==1) {
2020 childStat = subStatField[0];
2021 }
2022 if(!childStat.isEmpty()) {
2023 children.add(stat + "." + childStat);
2024 }
2025 }
2026 }
2027 if(!isAll) {
2028 index = childIndex;
2029 }
2030 }
2031
2032 StatInfo statInfo = new StatInfo(stat,
2033 type,
2034 title,
2035 description,
2036 parent,
2037 operation,
2038 isCounter,
2039 isResetting,
2040 isError,
2041 children,
2042 elements);
2043 statInfoMap.put(stat, statInfo);
2044
2045
2046 // TODO: for testing purpose. Delete this later.
2047 if(Settings.traceMode) {
2048 Global.err.println("==========Parsing result===========");
2049 Global.err.println("stat = " + stat);
2050 Global.err.println("type = " + type);
2051 Global.err.println("title = " + title);
2052 Global.err.println("description = " + description);
2053 Global.err.println("parent = " + parent);
2054 Global.err.println("operation = " + operation);
2055 Global.err.println("isCounter = " + isCounter);
2056 Global.err.println("isResetting = " + isResetting);
2057 Global.err.println("isError = " + isError);
2058 Global.err.println("children = " + Arrays.toString(children.toArray()));
2059 Global.err.println("elements = " + Arrays.toString(elements.toArray()));
2060 }
2061 }
2062 return true;
2063 }
2064
2065
2066 /**
2067 * Check Statmon service setting is present in eof file or not. If yes, return true otherwise return false.
2068 *
2069 * @throws StatsException
2070 */
2071 public static boolean isStatmonSettingInEof() throws StatsException {
2072 String eofFilePath = Settings.NAS_DB + "/server/slot_" + Settings.dmhostname.split("_")[1] + "/eof";
2073 if(DEBUG) Global.err.println("isStatmonSettingInEof:Settings.dmhostname\t" + Settings.dmhostname);
2074 File eofFile = new File(eofFilePath);
2075 if(!eofFile.exists() || !eofFile.canRead()) {// check permission of file
2076 throw new StatsException(MessageFactory.makeErrorStatmonConfigFile(Settings.datamover), StatsException.STATUS,
2077 StatsException.NO_MOVER_NAME);
2078 }
2079 try {
2080 BufferedReader input = new BufferedReader(new FileReader(eofFile));
2081 try {
2082 String line = null;
2083 while((line = input.readLine()) != null) {
2084 if(line.startsWith("statmonService start")) {
2085 String setting[] = line.split(" ");
2086 for(int i = 0; i < setting.length; i++) {
2087 if(setting[i].startsWith("port")) {
2088 if(!isPortInCmd) {// port is not specified in command
2089 try {
2090 Settings.statmonPortNumber = Integer.parseInt(setting[i].split("=")[1]);
2091 } catch(NumberFormatException nfe) {
2092 if(!Settings.serviceDeleteMode) { // throw invalid statmon configuration other than -delete option
2093 throw new StatsException(MessageFactory
2094 .makeErrorInvalidStatmonServiceConfig(Settings.datamover), StatsException.STATUS,
2095 StatsException.NO_MOVER_NAME);
2096 }
2097 }
2098 } else {
2099 // this port number used during update operation of eof file
2100 Settings.portNumberInEof = setting[i].split("=")[1];
2101 }
2102 } else if(setting[i].startsWith("allow")) {
2103 Settings.allowIp = setting[i].split("=")[1];
2104 }
2105 }
2106 return true;
2107 }
2108 }
2109 } finally {
2110 input.close();
2111 }
2112 } catch(IOException ex) {
2113 if(DEBUG) ex.printStackTrace();
2114 }
2115 return false;
2116 }
2117
2118 /**
2119 * To start/stop/status/delete statmon service as per service option.
2120 *
2121 * @param cmdArray is string array of .server_config command which interact with statmon service.
2122 * @throws StatsException
2123 */
2124 public static void runServiceOpt(String[] cmdArray) throws StatsException {
2125 boolean isFirstLine = false;
2126 try {
2127 Runtime r = Runtime.getRuntime();
2128 Process p = r.exec(cmdArray);
2129 String cmd = Arrays.asList(cmdArray).toString();
2130 cmd = cmd.substring(1, cmd.length() - 1).replaceAll(",", " ");
2131 if(Settings.traceMode) Global.err.println("ran: '" + cmd + "'");
2132 BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
2133 String line;
2134 while((line = br.readLine()) != null) {
2135 if(Settings.traceMode) Global.err.println("received: '" + line + "'");
2136 if(Settings.serviceStartMode) {
2137 if(line.indexOf("An invalid allow address was specified") > -1) {// check invalid configuration error
2138 throw new StatsException(MessageFactory.makeErrorInvalidStatmonServiceConfig(Settings.datamover),
2139 StatsException.STATUS, StatsException.NO_MOVER_NAME);
2140 } else if(line.indexOf("started on port:") > -1) {// started statmon service sucessfully
2141 Global.out.println(Settings.datamover + " : statmonService " + line.substring(line.indexOf("started on port:"))
2142 + ".");
2143 break;
2144 } else if(line.indexOf("Unknown command") > -1) {// DM doesn't support command
2145 throw new StatsException(MessageFactory.makeErrorIncompatibleDMVersion(Settings.datamover), StatsException.STATUS,
2146 StatsException.NO_MOVER_NAME);
2147 } if(line.indexOf("The statmonService could not bind to the network with the specified port and interface.") > -1) {
2148 throw new StatsException(com.emc.nas.ccmd.dart.status.perfstats.MessageFactory.makeErrorBind_failed(),
2149 StatsException.STATUS, StatsException.NO_MOVER_NAME);
2150 } if(line.indexOf("The statmonService could not open a network stream to listen for requests.") > -1) {
2151 throw new StatsException(com.emc.nas.ccmd.dart.status.perfstats.MessageFactory.makeErrorOpenStream_failed(),
2152 StatsException.STATUS, StatsException.NO_MOVER_NAME);
2153 } if(line.indexOf("The statmonService encountered an error when listening for a connection.") > -1) {
2154 throw new StatsException(com.emc.nas.ccmd.dart.internal.perfstats.MessageFactory.makeErrorListen_failed(),
2155 StatsException.STATUS, StatsException.NO_MOVER_NAME);
2156 } else if(line.startsWith("ERROR:") || line.indexOf("ERROR") > -1 || line.indexOf("Error") > -1) {
2157 if(line.startsWith("Error 13422428165")) {
2158 //if user is not authorized
2159 throw new StatsException(com.emc.nas.ccmd.cs_core.status.adminrole.MessageFactory.makeErrorUser_not_authorized(),
2160 StatsException.STATUS, StatsException.NO_MOVER_NAME);
2161 } else {
2162 // Time out error/DM contact is lost
2163 throw new StatsException(MessageFactory.makeErrorMoverLostContact(Settings.datamover), StatsException.STATUS,
2164 StatsException.NO_MOVER_NAME);
2165 }
2166 }
2167 } else if(Settings.serviceStopMode) {
2168 if(line.indexOf("statmonManager service stop") > -1) {// statmon service stopped sucessfully
2169 if(!Settings.serviceDeleteMode) {
2170 Global.out.println(Settings.datamover + " : done.");
2171 }
2172 break;
2173 } else if(line.indexOf("Unknown command") > -1) {// DM doesn't support command
2174 throw new StatsException(MessageFactory.makeErrorIncompatibleDMVersion(Settings.datamover), StatsException.STATUS,
2175 StatsException.NO_MOVER_NAME);
2176 } else if(line.startsWith("ERROR:") || line.indexOf("ERROR") > -1 || line.indexOf("Error") > -1) {
2177 if(line.startsWith("Error 13422428165")) {
2178 //if user is not authorized
2179 throw new StatsException(com.emc.nas.ccmd.cs_core.status.adminrole.MessageFactory.makeErrorUser_not_authorized(),
2180 StatsException.STATUS, StatsException.NO_MOVER_NAME);
2181 } else {
2182 // Time out error/DM contact is lost
2183 throw new StatsException(MessageFactory.makeErrorMoverLostContact(Settings.datamover), StatsException.STATUS,
2184 StatsException.NO_MOVER_NAME);
2185 }
2186 }
2187 } else if(Settings.serviceStatusMode) {
2188 if(line.indexOf("ERROR:") > -1 || line.indexOf("ERROR") > -1 || line.indexOf("Error") > -1) {
2189 if(line.startsWith("Error 13422428165")) {
2190 //if user is not authorized
2191 throw new StatsException(com.emc.nas.ccmd.cs_core.status.adminrole.MessageFactory.makeErrorUser_not_authorized(),
2192 StatsException.STATUS, StatsException.NO_MOVER_NAME);
2193 } else {
2194 // Time out error/DM contact is lost
2195 throw new StatsException(MessageFactory.makeErrorMoverLostContact(Settings.datamover), StatsException.STATUS,
2196 StatsException.NO_MOVER_NAME);
2197 }
2198 } else if(line.indexOf("Unknown command") > -1) {// DM doesn't support command
2199 throw new StatsException(MessageFactory.makeErrorIncompatibleDMVersion(Settings.datamover), StatsException.STATUS,
2200 StatsException.NO_MOVER_NAME);
2201 } else if(line.indexOf("PERFSTATS: 6:") > -1 || line.indexOf("format=sar") > -1) {
2202 if(line.indexOf("Start options:") > -1) {// parse start option details
2203 String startOpts[] = line.split(" ");
2204 for(int i = 0; i < startOpts.length; i++) {
2205 if(startOpts[i].startsWith("interface=") || startOpts[i].startsWith("port=")
2206 || startOpts[i].startsWith("allow=")) {
2207 Global.out.println(startOpts[i]);
2208 }
2209 }
2210 } else if(line.indexOf("format=sar") > -1) {
2211 Global.out.println(line.trim());
2212 } else {
2213 if(!isFirstLine) {// check whether first line or not.
2214 Global.out.print(Settings.datamover + " : ");
2215 isFirstLine = true;
2216 }
2217 Global.out.println(line.substring(line.indexOf("PERFSTATS: 6:") + 13).trim());
2218 }
2219 }
2220 } else {
2221 if(line.indexOf("ERROR:") > -1 || line.indexOf("ERROR") > -1 || line.indexOf("Error") > -1) {
2222 if(line.startsWith("Error 13422428165")) {
2223 //if user is not authorized
2224 throw new StatsException(com.emc.nas.ccmd.cs_core.status.adminrole.MessageFactory.makeErrorUser_not_authorized(),
2225 StatsException.STATUS, StatsException.NO_MOVER_NAME);
2226 } else {
2227 // Time out error/DM contact is lost
2228 throw new StatsException(MessageFactory.makeErrorMoverLostContact(Settings.datamover), StatsException.STATUS,
2229 StatsException.NO_MOVER_NAME);
2230 }
2231 } else if(line.indexOf("the statmonService is not running") > -1
2232 || line.indexOf("statmonService is shutting down") > -1) {
2233 // statmon service is not running
2234 isStatmonSerRun = false;
2235 break;
2236 } else if(line.indexOf("Unknown command") > -1) {// DM doesn't support command
2237 throw new StatsException(MessageFactory.makeErrorIncompatibleDMVersion(Settings.datamover), StatsException.STATUS,
2238 StatsException.NO_MOVER_NAME);
2239 } else if(line.indexOf("Start options:") > -1) {
2240 // statmon service is currently running
2241 isStatmonSerRun = true;
2242 String startOpts[] = line.split(" ");
2243 for(int i = 0; i < startOpts.length; i++) {
2244 if(startOpts[i].startsWith("port=")) {
2245 String portOpts[] = startOpts[i].split("=");
2246 Settings.statmonPortNumber = Integer.parseInt(portOpts[1]);
2247 }
2248 }
2249 }
2250 }
2251 }
2252 } catch(IOException ioe) {
2253 if(DEBUG) ioe.printStackTrace();
2254 }
2255 }
2256
2257 /**
2258 * Add/Update/Delete settings of statmon service in eof configuration file.
2259 *
2260 * @param option is current operation with eof configuration file.
2261 * @throws StatsException
2262 */
2263 public static void updateStatmonSettingInEof(String option) throws StatsException {
2264 String eofFilePath = Settings.NAS_DB + "/server/slot_" + Settings.dmhostname.split("_")[1] + "/eof";
2265 File eofFile = new File(eofFilePath);
2266 if(!eofFile.exists() || !eofFile.canRead() || !eofFile.canWrite()) { throw new StatsException(MessageFactory
2267 .makeErrorStatmonConfigFile(Settings.datamover), StatsException.STATUS, StatsException.NO_MOVER_NAME); }
2268 try {
2269 if(option.equals("startupdate")) {// update port in eof file
2270 String textBuffer = getContentsOfEof(eofFile, "startupdate");
2271 textBuffer = textBuffer.replace("port=" + Settings.portNumberInEof, "port=" + Settings.statmonPortNumber);
2272 setContentsOfEof(eofFile, textBuffer);
2273 } else if(option.equals("startadd")) {// add statmon service configuration in eof file
2274 setContentsOfEof(eofFile, getContentsOfEof(eofFile, "startadd"));
2275 } else if(option.equals("delete")) {// delete statmon service configuration in eof file
2276 setContentsOfEof(eofFile, getContentsOfEof(eofFile, "delete"));
2277 }
2278 } catch(IOException ioe) {
2279 if(DEBUG) ioe.printStackTrace();
2280 }
2281 }
2282
2283 /**
2284 * Fetch the entire contents of a text file, and return it in a String.
2285 *
2286 * @param aFile is a file which already exists and can be read.
2287 * @param option is current operation with eof configuration file.
2288 */
2289 static public String getContentsOfEof(File aFile, String option) {
2290 StringBuilder contents = new StringBuilder();
2291 try {
2292 // use buffering, reading one line at a time
2293 BufferedReader input = new BufferedReader(new FileReader(aFile));
2294 try {
2295 String line = null;
2296 while((line = input.readLine()) != null) {
2297 if(option.equals("delete")) {// delete statmon service configuration in eof file
2298 if(!line.startsWith("statmonService start port")) {
2299 contents.append(line);
2300 contents.append(System.getProperty("line.separator"));
2301 }
2302 } else if(option.equals("startadd")) {// add statmon service configuration in eof file
2303 if(line.startsWith("dpinit")) {
2304 contents.append(line);
2305 contents.append(System.getProperty("line.separator"));
2306 contents.append("statmonService start port=" + Settings.statmonPortNumber
2307 + " allow=128.221.252.100:128.221.252.101:128.221.253.100:128.221.253.101");
2308 contents.append(System.getProperty("line.separator"));
2309 } else {
2310 contents.append(line);
2311 contents.append(System.getProperty("line.separator"));
2312 }
2313 } else { // update port in eof file
2314 contents.append(line);
2315 contents.append(System.getProperty("line.separator"));
2316 }
2317 }
2318 } finally {
2319 input.close();
2320 }
2321 } catch(IOException ex) {
2322 if(DEBUG) ex.printStackTrace();
2323 }
2324 return contents.toString();
2325 }
2326
2327 /**
2328 * Change the contents of text file in its entirety, overwriting any existing text.
2329 *
2330 * @param aFile is an existing file which can be written to.
2331 * @throws IOException if problem encountered during write.
2332 */
2333 static public void setContentsOfEof(File aFile, String aContents) throws IOException {
2334 // use buffering
2335 Writer output = new BufferedWriter(new FileWriter(aFile));
2336 try {
2337 output.write(aContents);
2338 } finally {
2339 output.close();
2340 }
2341 }
2342
2343 /**
2344 * Get port number of Statmon service using .server_config command.
2345 *
2346 * @param datamover is the actual host name of the specified data mover.
2347 * @param NAS_DB is the value of the NAS_DB environment variable
2348 * @param BINPATH NAS_DB's bin path
2349 * @param returnOnError is true if this method is called from nas_stats class otherwise false;
2350 * @return port number of statmon service.
2351 * @throws StatsException
2352 */
2353 public static int getStatmonPort(String datamover, String NAS_DB, String BINPATH, boolean returnOnError) throws StatsException {
2354 int portNumber = -1;
2355 String[] statusCmdArray = { NAS_DB + BINPATH + "/" + ".server_config", datamover, "-v", "-t", "60", "\"statmonManager service stat\"" };
2356 try {
2357 Runtime r = Runtime.getRuntime();
2358 Process p = r.exec(statusCmdArray);
2359 String cmd = Arrays.asList(statusCmdArray).toString();
2360 cmd = cmd.substring(1, cmd.length() - 1).replaceAll(",", " ");
2361 if(Settings.traceMode) Global.err.println("ran: '" + cmd + "'");
2362 BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
2363 String line;
2364 while((line = br.readLine()) != null) {
2365 if(line.indexOf("Start options:") > -1) {// statmon service is running
2366 if(Settings.traceMode) Global.err.println("received: '" + line + "'");
2367 try {
2368 portNumber = Integer.parseInt(line.substring(line.indexOf("port=") + 5, line
2369 .indexOf(" ", line.indexOf("port=") + 1)));
2370 try {
2371 /*
2372 * use a throwaway InetSocketAddress object to check validity of port number. I'm offloading this error checking
2373 * to Java instead of hardcoding anything. The warning suppresion is to suppress the 'local variable is never
2374 * read' warning for the InetSocketAddress object.
2375 */
2376 @SuppressWarnings("unused")
2377 InetSocketAddress isa = new InetSocketAddress(portNumber);
2378 } catch(IllegalArgumentException iae) {
2379 if(DEBUG) Global.err.println(iae.getLocalizedMessage());
2380 throw new NumberFormatException();
2381 }
2382 } catch(NumberFormatException nfe) {
2383 /**
2384 * iscallForNas_Stats is true if this method is called from nas_stats class. For nas_stats class getPortNumber()
2385 * method should return port number instead of error to continue the execution of nas_stats command while validating
2386 * the stat paths.
2387 */
2388 if(returnOnError) { return portNumber; }
2389 isSyntaxError = false;
2390 throw new StatsException(com.emc.nas.ccmd.cs_core.internal.perfstats.MessageFactory
2391 .makeErrorInternalError("Statmon service is running on invalid port number"), StatsException.INTERNAL,
2392 StatsException.NO_MOVER_NAME);
2393 }
2394 break;
2395 } else if(line.indexOf("Unknown command") > -1) {// DM doesn't support statmonManager service interface
2396 /**
2397 * iscallForNas_Stats is true if this method is called from nas_stats class. For nas_stats class getPortNumber() method
2398 * should return port number instead of error to continue the execution of nas_stats command while validating the stat
2399 * paths.
2400 */
2401 if(returnOnError) { return portNumber; }
2402 isSyntaxError = false;
2403 throw new StatsException(MessageFactory.makeErrorIncompatibleDMVersion(Settings.datamover), StatsException.STATUS,
2404 StatsException.NO_MOVER_NAME);
2405 } else if(line.startsWith("ERROR:") || line.indexOf("ERROR") > -1 || line.indexOf("Error") > -1) {
2406 isSyntaxError = false;
2407 /**
2408 * iscallForNas_Stats is true if this method is called from nas_stats class. For nas_stats class getPortNumber() method
2409 * should return port number instead of error to continue the execution of nas_stats command while validating the stat
2410 * paths.
2411 */
2412 //if user is not authorized
2413 if(line.startsWith("Error 13422428165")) {
2414 throw new StatsException(com.emc.nas.ccmd.cs_core.status.adminrole.MessageFactory.makeErrorUser_not_authorized(),
2415 StatsException.STATUS, StatsException.NO_MOVER_NAME);
2416 }
2417 // Time out error/DM contact is lost
2418 if(returnOnError) { return portNumber; }
2419 throw new StatsException(MessageFactory.makeErrorMoverLostContact(Settings.datamover), StatsException.STATUS,
2420 StatsException.NO_MOVER_NAME);
2421 }
2422 }
2423 if(portNumber == -1) {
2424 /**
2425 * iscallForNas_Stats is true if this method is called from nas_stats class. For nas_stats class getPortNumber() method
2426 * should return port number instead of error to continue the execution of nas_stats command while validating the stat
2427 * paths.
2428 */
2429 if(returnOnError) { return portNumber; }
2430 isSyntaxError = false;
2431 throw new StatsException(MessageFactory.makeErrorMoverConnectFailed(Settings.dmhostname), StatsException.STATUS,
2432 StatsException.NO_MOVER_NAME);
2433 }
2434 } catch(IOException ioe) {
2435 if(DEBUG) ioe.printStackTrace();
2436 }
2437 return portNumber;
2438 }
2439
2440 public static int getStatsdPort(String NAS_DB, boolean exitOnError) {
2441 int port = Settings.statsdPortNumber;
2442 String file = NAS_DB + "/stats/statsd/statsd.conf";
2443 StatsException se = null;
2444 try {
2445 BufferedReader port_reader = new BufferedReader(new FileReader(file));
2446 String str;
2447 while((str = port_reader.readLine()) != null) {
2448 if(str.matches("port=\\d++")) {
2449 port = Integer.parseInt(str.split("=")[1]);
2450 }
2451 }
2452 port_reader.close();
2453 } catch(NumberFormatException e) {
2454 se = new StatsException(com.emc.nas.ccmd.cs_core.internal.perfstats.
2455 MessageFactory.makeErrorConfigFileFailure(file, "invalid format"), e,
2456 StatsException.STATUS, StatsException.NO_MOVER_NAME);
2457 } catch(FileNotFoundException e) {
2458 se = new StatsException(com.emc.nas.ccmd.cs_core.internal.perfstats.
2459 MessageFactory.makeErrorConfigFileFailure(file, "file not found"), e,
2460 StatsException.STATUS, StatsException.NO_MOVER_NAME);
2461 } catch(IOException e) {
2462 se = new StatsException(com.emc.nas.ccmd.cs_core.internal.perfstats.
2463 MessageFactory.makeErrorConfigFileFailure(file, "unable to open"),
2464 StatsException.STATUS, StatsException.NO_MOVER_NAME);
2465 }
2466
2467 if(null != se && exitOnError) {
2468 Global.err.println(OutputFormatter.getCCMDMessage(se, null));
2469 System.exit(se.getExitCode());
2470 }
2471 return port;
2472 }
2473
2474 /**
2475 * Main method for the program.
2476 *
2477 * @param args Command-line arguments
2478 */
2479 public static void main(String[] args) {
2480 MemMonitor memmon = null;
2481 if(DEBUG || TRACKMEM || Arrays.asList(args).contains("-MEMTRACE")) {
2482 memmon = new MemMonitor();
2483 memmon.start();
2484 }
2485 boolean printUsage = false;
2486 try {
2487 getNasVars();
2488 String[] newArgs = extendAmbiguousOptions(args);
2489 CmdArgParser argParser = new CmdArgParser(newArgs);
2490 try {
2491 parseArgs(argParser);
2492 // throw the error if -type accu is used with eset
2493 if(Settings.dataFormat == OutputFormatter.ACCU && StatResolve.eSetExists) {
2494 throw new StatsException(MessageFactory.makeErrorNoAccuTypeSupportForEtrace(),
2495 StatsException.STATUS, StatsException.NO_MOVER_NAME); }
2496 } catch(StatsException se) {
2497 if(isSyntaxError) {
2498 printUsage = true;
2499 }
2500 throw se;
2501 }
2502 ObjectResolver.noresolve = Settings.noresolve;
2503 // store formatype to check formatype in Average, Product and Sum operation for table stat in computed stat
2504 formatType = Settings.formatType;
2505 boolean truncate = (Settings.formatType == OutputFormatter.TEXT);
2506 if(null == resolver) {
2507 resolver = new ObjectResolver(Settings.datamover, Settings.NAS_DB, Settings.BINPATH, truncate);
2508 }
2509 } catch(StatsException se) {
2510 Global.err.println(OutputFormatter.getCCMDMessage(se, null));
2511 if(printUsage) {
2512 Global.err.println(USAGE_MESSAGE);
2513 }
2514 System.exit(se.getExitCode());
2515 }
2516 try {
2517 // hold the conflicting options of the mutually exclusive error
2518 String opts = "";
2519 List<String> options = new ArrayList<String>();
2520 if(Settings.actionmode) {
2521 options.add("-action");
2522 }
2523 if(Settings.listmode) {
2524 options.add("-list");
2525 }
2526 if(Settings.infomode) {
2527 options.add("-info");
2528 }
2529 if(Settings.servicemode) {
2530 options.add("-service");
2531 }
2532 if(Settings.statsmode) {
2533 String statargs = Settings.statArgs.toString().replaceFirst(",", "");
2534 if(statargs.contains(",")) {
2535 statargs = "{" + statargs + "}";
2536 }
2537 options.add(statargs);
2538 }
2539 if(Settings.servicemode && (!Settings.listmode && !Settings.infomode && !Settings.actionmode && !Settings.statsmode)) {
2540 // remove element in list before adding -service mutually
2541 // exclusive options
2542 options.clear();
2543 if(Settings.serviceStartMode) {
2544 options.add("-start");
2545 }
2546 if(Settings.serviceStopMode) {
2547 options.add("-stop");
2548 }
2549 if(Settings.serviceDeleteMode) {
2550 options.add("-delete");
2551 }
2552 if(Settings.serviceStatusMode) {
2553 options.add("-status");
2554 }
2555 }
2556 if(options.size() > 1) {
2557 StringBuffer sb = new StringBuffer();
2558 for(int i = 0; i <= options.size() - 1; i++) {
2559 sb.append(options.get(i));
2560 sb.append(",");
2561 }
2562 opts = sb.toString().substring(0, sb.length() - 1);
2563 if(DEBUG) Global.err.println("The following options are mutually exclusive: " + opts);
2564 throw new StatsException(MessageFactory.makeErrorMutuallyExclusiveOptions(opts), StatsException.STATUS,
2565 StatsException.NO_MOVER_NAME);
2566 }
2567 } catch(StatsException se) {
2568 try {
2569 Global.err.println(OutputFormatter.getCCMDMessage(se, Settings.datamover));
2570 } catch(Exception e) {
2571 if(DEBUG) e.printStackTrace();
2572 } finally {
2573 if(isSyntaxError) {
2574 Global.err.println(USAGE_MESSAGE);
2575 }
2576 System.exit(se.getExitCode());
2577 }
2578 }
2579 if(Settings.directMode) {// debug mode, send command as is to statmon
2580 StringBuffer cmd = new StringBuffer();
2581 for(Iterator<String> it = Settings.counters.iterator(); it.hasNext();) {
2582 cmd.append(it.next());
2583 if(it.hasNext()) cmd.append(' ');
2584 }
2585 String[] resp = DMStatCollector.getRawResponse(Settings.dmhostname, Settings.statmonPortNumber, cmd.toString(), Settings.VIS, false,
2586 false, true);
2587 for(int i = 0; i < resp.length; i++) {
2588 Global.out.println(resp[i]);
2589 }
2590 } else if(Settings.infomode) {// info mode
2591 if(Settings.counters.get(0).equals("-all")) {
2592 Settings.counters.remove(0);
2593 Settings.counters.add("all");
2594 }
2595 if(getStatsInfo(Settings.counters, Settings.VIS)) {
2596 Global.out.println(Settings.datamover + " : ");
2597 for(Iterator<StatInfo> it = statInfoMap.values().iterator(); it.hasNext();) {
2598 it.next().printInfo();
2599 }
2600 }
2601 } else if(Settings.listmode) {// list mode
2602 List<String> all = new LinkedList<String>();
2603 all.add("all");
2604 if(getStatsInfo(all, Settings.VIS)) {
2605 Global.out.println(Settings.datamover + " : ");
2606 Global.out.println("Type Stat Name");
2607 for(Iterator<StatInfo> it = statInfoMap.values().iterator(); it.hasNext();) {
2608 it.next().printList();
2609 }
2610 }
2611 } else if(Settings.servicemode) {// service mode
2612 try {
2613 if(Settings.serviceStartMode) {
2614 String[] statusCmdArray = {
2615 Settings.NAS_DB + Settings.BINPATH + "/" + ".server_config", Settings.datamover, "-v",
2616 "\"statmonManager service stat\"" };
2617 Settings.serviceStartMode = false;
2618 // get status of statmon service
2619 runServiceOpt(statusCmdArray);
2620 Settings.serviceStartMode = true;
2621 if(isStatmonSerRun) {// statmon service is running
2622 throw new StatsException(MessageFactory.makeErrorStatmonServiceRunning(Settings.datamover, Settings.statmonPortNumber),
2623 StatsException.STATUS, StatsException.NO_MOVER_NAME);
2624 } else {
2625 if(isStatmonSettingInEof()) {// statmon service setting exists in eof file
2626 String[] startCmdArrayWithSaveSetting = {
2627 Settings.NAS_DB + Settings.BINPATH + "/" + ".server_config",
2628 Settings.datamover,
2629 "-v",
2630 "\"statmonManager service start port=" + ((Integer)Settings.statmonPortNumber).toString() + " allow="
2631 + Settings.allowIp + "\"" };
2632 runServiceOpt(startCmdArrayWithSaveSetting);
2633 if(isPortInCmd) {// port is specified in command
2634 updateStatmonSettingInEof("startupdate");
2635 }
2636 } else {
2637 String[] startCmdArrayWithDefaultSetting = {
2638 Settings.NAS_DB + Settings.BINPATH + "/" + ".server_config",
2639 Settings.datamover,
2640 "-v",
2641 "\"statmonManager service start port=" + ((Integer)Settings.statmonPortNumber).toString()
2642 + " allow=128.221.252.100:128.221.252.101:128.221.253.100:128.221.253.101" + "\"" };
2643 runServiceOpt(startCmdArrayWithDefaultSetting);
2644 // save settings in eof file.
2645 updateStatmonSettingInEof("startadd");
2646 }
2647 }
2648 } else if(Settings.serviceStopMode) {
2649 String[] statusCmdArray = {
2650 Settings.NAS_DB + Settings.BINPATH + "/" + ".server_config", Settings.datamover, "-v",
2651 "\"statmonManager service stat\"" };
2652 Settings.serviceStopMode = false;
2653 // get status of statmon service
2654 runServiceOpt(statusCmdArray);
2655 Settings.serviceStopMode = true;
2656 String[] stopCmdArray = {
2657 Settings.NAS_DB + Settings.BINPATH + "/" + ".server_config", Settings.datamover, "-v",
2658 "\"statmonManager service stop\"" };
2659 if(isStatmonSerRun) {// statmon service is running
2660 runServiceOpt(stopCmdArray);
2661 } else {
2662 // throw error when attempt to stop statmon service which is already stopped.
2663 throw new StatsException(MessageFactory.makeErrorStatmonServiceStop(Settings.datamover), StatsException.STATUS,
2664 StatsException.NO_MOVER_NAME);
2665 }
2666 } else if(Settings.serviceDeleteMode) {
2667 String[] statusCmdArray = {
2668 Settings.NAS_DB + Settings.BINPATH + "/" + ".server_config", Settings.datamover, "-v",
2669 "\"statmonManager service stat\"" };
2670 // get status of statmon service
2671 runServiceOpt(statusCmdArray);
2672 String[] stopCmdArray = {
2673 Settings.NAS_DB + Settings.BINPATH + "/" + ".server_config", Settings.datamover, "-v",
2674 "\"statmonManager service stop\"" };
2675 if(isStatmonSerRun) {// statmon service is running
2676 // warning message stopping statmon service.
2677 StatsException se = new StatsException(MessageFactory.makeWarningStopStatmonService(Settings.datamover),
2678 StatsException.STATUS, StatsException.NO_MOVER_NAME);
2679 String msg = OutputFormatter.getCCMDMessage(se, Settings.datamover);
2680 Global.err.println(msg);
2681 Settings.serviceStopMode = true;
2682 runServiceOpt(stopCmdArray);
2683 Settings.serviceStopMode = false;
2684 }
2685 // delete operation to delete file settings
2686 if(isStatmonSettingInEof()) {// statmon service setting exists in eof file
2687 updateStatmonSettingInEof("delete");
2688 Global.out.println(Settings.datamover + " : done.");
2689 } else {
2690 // throw error when statmon service setting is not exist in eof file
2691 throw new StatsException(MessageFactory.makeErrorDeleteStatmonServiceConfig(Settings.datamover),
2692 StatsException.STATUS, StatsException.NO_MOVER_NAME);
2693 }
2694 } else if(Settings.serviceStatusMode) {// get status of statmon service
2695 String[] statusCmdArray = {
2696 Settings.NAS_DB + Settings.BINPATH + "/" + ".server_config", Settings.datamover, "-v",
2697 "\"statmonManager service stat\"" };
2698 runServiceOpt(statusCmdArray);
2699 }
2700 } catch(StatsException se) {
2701 try {
2702 Global.err.println(OutputFormatter.getCCMDMessage(se, Settings.datamover));
2703 } catch(Exception e) {
2704 if(DEBUG) e.printStackTrace();
2705 } finally {
2706 System.exit(se.getExitCode());
2707 }
2708 }
2709 } else if(Settings.actionmode) {
2710 String option;
2711 StringBuffer arguments = new StringBuffer();
2712 List<String> splitArgs;
2713 option = Settings.actionArg.remove(0);
2714 if(option.equals("status")) option = "list";
2715 if(!Settings.actionArg.isEmpty()) {
2716 splitArgs = Arrays.asList(Settings.actionArg.remove(0).split(","));
2717 for(Iterator<String> it = splitArgs.iterator(); it.hasNext();) {
2718 arguments.append(it.next());
2719 arguments.append(" ");
2720 }
2721 } else {
2722 arguments.append("all");
2723 }
2724 try {
2725 String[] cmdArray = {
2726 Settings.NAS_DB + Settings.BINPATH + "/" + ".server_config", Settings.datamover, "-v",
2727 "\"statmonManager admin visibility=" + Settings.VIS + " " + option + " " + arguments.toString() + "\"" };
2728 Runtime r = Runtime.getRuntime();
2729 Process p = r.exec(cmdArray);
2730 if(Settings.traceMode)
2731 Global.err.println("ran: '" + Settings.NAS_DB + Settings.BINPATH + "/" + ".server_config " + Settings.datamover
2732 + " -v " + "\"statmonManager admin visibility=" + Settings.VIS + " " + option + " " + arguments.toString() + "\""
2733 + "'");
2734 BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
2735 String line;
2736 while((line = br.readLine()) != null) {
2737 if(Settings.traceMode) Global.err.println("received: '" + line + "'");
2738 if(line.startsWith("ERROR:") || line.startsWith("Error")) {
2739 if(line.startsWith("Error 13422428165")) {
2740 //if user is not authorized
2741 throw new StatsException(com.emc.nas.ccmd.cs_core.status.adminrole.MessageFactory.makeErrorUser_not_authorized(),
2742 StatsException.STATUS, StatsException.NO_MOVER_NAME);
2743 } else {
2744 throw new StatsException(com.emc.nas.ccmd.cs_core.internal.perfstats.MessageFactory.makeErrorInternalError(line
2745 .substring(line.indexOf(':') + 2)), StatsException.STATUS, StatsException.NO_MOVER_NAME);
2746 }
2747 } else if(line.toLowerCase().startsWith("all control group")) {
2748 Global.err.println(Settings.datamover + " : done.");
2749 break;
2750 } else if(line.startsWith("Control Group")){
2751 if(!Settings.VIS.equals("hidden")){
2752 Global.err.println(Settings.datamover+" : ");
2753 }
2754 boolean enabled = true;
2755 while(line != null && !line.equals("")) {
2756 if(Settings.VIS.equals("hdden")) {
2757 String strarr[] = line.split(",");
2758 if(!strarr[0].contains("Dynamic") && !strarr[0].contains("Control Group") && !strarr[1].equals("Enabled")) {
2759 enabled = false;
2760 break;
2761 }
2762 } else {
2763 String strarr[] = line.split(",");
2764 StringBuffer sb = new StringBuffer();
2765 sb.append(strarr[0]);
2766 for(int i = strarr[0].length(); i < 20; i++) {
2767 sb.append(" ");
2768 }
2769 sb.append(strarr[1]);
2770 for(int i = strarr[1].length(); i < 15; i++) {
2771 sb.append(" ");
2772 }
2773 sb.append(strarr[2]);
2774 Global.out.println(sb.toString());
2775 }
2776 line = br.readLine();
2777 if(Settings.traceMode) Global.err.println("received: '" + line + "'");
2778 }
2779 if(Settings.VIS.equals("hidden")) {
2780 if(enabled) {
2781 Global.out.println(Settings.datamover + " : Statistics are enabled.");
2782 } else {
2783 Global.out.println(Settings.datamover + " : Statistics are disabled.");
2784 }
2785 }
2786 break;
2787 } else if(line.startsWith("'")) {
2788 Global.out.println(Settings.datamover + " : " + line + ".");
2789 }
2790 }
2791 } catch(StatsException se) {
2792 try {
2793 Global.err.println(OutputFormatter.getCCMDMessage(se, Settings.datamover));
2794 } catch(Exception e) {
2795 if(DEBUG) e.printStackTrace();
2796 } finally {
2797 System.exit(se.getExitCode());
2798 }
2799 } catch(IOException ioe) {
2800 StatsException se = new StatsException(com.emc.nas.ccmd.cs_core.internal.perfstats.MessageFactory
2801 .makeErrorInternalError(ioe.getMessage()), ioe, StatsException.INTERNAL, StatsException.NO_MOVER_NAME);
2802 Global.err.println(OutputFormatter.getCCMDMessage(se, Settings.datamover));
2803 System.exit(se.getExitCode());
2804 }
2805 } else {
2806 File outputFile = null, tempOutputFile = null;
2807 String tmpOutputFileName = null, mainCopyFileName = null;
2808 try {
2809 if(Settings.fileMode) {
2810 outputFile = new File(Settings.filepath);
2811 Settings.filedir = outputFile.getAbsolutePath().substring(0, outputFile.getAbsolutePath().lastIndexOf("/")+1);
2812 if(outputFile.exists()) {
2813 if(!outputFile.isFile()) {
2814 throw new StatsException(MessageFactory.makeErrorInvalidArgument("-file"), StatsException.STATUS,
2815 StatsException.NO_MOVER_NAME);
2816 } else if(!outputFile.canWrite()) { throw new StatsException(MessageFactory
2817 .makeErrorFileWritePermission(Settings.filepath), StatsException.STATUS, StatsException.NO_MOVER_NAME);
2818 }
2819 if(Settings.overwriteFileMode) {// delete the existing output file
2820 outputFile.delete();
2821 } else if(Settings.formatType == OutputFormatter.CSV) {
2822 mainCopyFileName = "orig_"+outputFile.getName() + new Date().getTime();
2823 //cat outputFile
2824 try {
2825 String[] cmdCp = { "/bin/sh", "-c", "/bin/cp " + outputFile.getAbsolutePath() + " "+ Settings.filedir + mainCopyFileName };
2826 Process proc = Runtime.getRuntime().exec(cmdCp);
2827 BufferedReader in = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
2828 String error = in.readLine();
2829 if(null != error) {
2830 throw new StatsException(com.emc.nas.ccmd.cs_core.internal.perfstats.MessageFactory
2831 .makeErrorInternalError(error), null, StatsException.INTERNAL, StatsException.NO_MOVER_NAME);
2832 }
2833 } catch(IOException ioe) {
2834 if(DEBUG) ioe.printStackTrace();
2835 throw new StatsException(com.emc.nas.ccmd.cs_core.internal.perfstats.MessageFactory.makeErrorInternalError(ioe
2836 .getMessage()), ioe, StatsException.INTERNAL, StatsException.NO_MOVER_NAME);
2837 }
2838 }
2839 } else {
2840 try {
2841 // create empty file
2842 outputFile.createNewFile();
2843 } catch(IOException ioe) {
2844 String errMsg = "";
2845 if(outputFile.getParent() != null) {
2846 errMsg = outputFile.getParent();
2847 } else {
2848 // get current directory path
2849 errMsg = System.getProperty("user.dir");
2850 }
2851 errMsg = errMsg + ": " + ioe.getMessage();
2852 throw new StatsException(com.emc.nas.ccmd.cs_core.internal.perfstats.MessageFactory
2853 .makeErrorInternalError(errMsg), ioe, StatsException.INTERNAL, StatsException.NO_MOVER_NAME);
2854 }
2855 }
2856 if(Settings.formatType == OutputFormatter.CSV) {
2857 tmpOutputFileName = "temp_"+outputFile.getName() + new Date().getTime();
2858 tempOutputFile = new File(Settings.filedir + tmpOutputFileName);
2859 try {
2860 Global.out = new MultiWrite(outputFile, tempOutputFile, true);
2861 Global.err = Global.out;
2862 } catch(FileNotFoundException fnf) {
2863 if(DEBUG) Global.err.println(fnf.getMessage().substring(fnf.getMessage().indexOf(": ")) + " cannot be created");
2864 throw new StatsException(MessageFactory.makeErrorCreateFileFailed(fnf.getMessage().substring(fnf.getMessage().indexOf(": "))),
2865 StatsException.STATUS, StatsException.NO_MOVER_NAME);
2866 }
2867 } else {
2868 try {
2869 Global.out = new PrintStream(new FileOutputStream(outputFile, true));
2870 Global.err = Global.out;
2871 } catch(FileNotFoundException fnf) {
2872 if(DEBUG) Global.err.println(outputFile.getName() + " cannot be created");
2873 throw new StatsException(MessageFactory.makeErrorCreateFileFailed(outputFile.getName()),
2874 StatsException.STATUS, StatsException.NO_MOVER_NAME);
2875 }
2876 }
2877 }
2878 } catch(StatsException se) {
2879 try {
2880 Global.err.println(OutputFormatter.getCCMDMessage(se, Settings.datamover));
2881 } catch(Exception e) {
2882 if(DEBUG) e.printStackTrace();
2883 } finally {
2884 System.exit(se.getExitCode());
2885 }
2886 }
2887 // Handle the case of Fake DM. Fake DM doesnot requier name resolver functionality.
2888 if(!Settings.dmhostname.equals("localhost")) {
2889 // if we ever see the pattern "cifs.smb1.op,cifs.smb2.op"
2890 // then remove either of those stats before that pattern
2891 for(int i = 0; i < (Settings.counters.size() - 1); i++) {
2892 if(Settings.counters.get(i).equalsIgnoreCase("cifs.smb1.op")
2893 && Settings.counters.get(i + 1).equalsIgnoreCase("cifs.smb2.op")) {
2894 for(int j = 0; j < i; j++) {
2895 if(Settings.counters.get(j).equalsIgnoreCase("cifs.smb1.op")
2896 || Settings.counters.get(j).equalsIgnoreCase("cifs.smb2.op")) {
2897 Settings.counters.remove(j);
2898 // when we remove from the list, our indexes need to be corrected
2899 i--;
2900 j--;
2901 }
2902 }
2903 // DART will remove any other duplicates, we just wanted to
2904 // remove duplicates before the pattern, so break out of loop
2905 break;
2906 }
2907 }
2908 // if we ever see the pattern "nfs.v2.op,nfs.v3.op,nfs.v4.op"
2909 // then remove any of those stats before that pattern
2910 for(int i = 0; i < (Settings.counters.size() - 2); i++) {
2911 if(Settings.counters.get(i).equalsIgnoreCase("nfs.v2.op") && Settings.counters.get(i + 1).equalsIgnoreCase("nfs.v3.op")
2912 && Settings.counters.get(i + 2).equalsIgnoreCase("nfs.v4.op")) {
2913 for(int j = 0; j < i; j++) {
2914 if(Settings.counters.get(j).equalsIgnoreCase("nfs.v2.op")
2915 || Settings.counters.get(j).equalsIgnoreCase("nfs.v3.op")
2916 || Settings.counters.get(j).equalsIgnoreCase("nfs.v4.op")) {
2917 Settings.counters.remove(j);
2918 // when we remove from the list, our indexes need to be corrected
2919 i--;
2920 j--;
2921 }
2922 }
2923 // DART will remove any other duplicates, we just wanted to
2924 // remove duplicates before the pattern, so break out of loop
2925 break;
2926 }
2927 }
2928 }
2929 // clear statinfomap because control goes to shutdown summary thread.
2930 OutputFormatter outFormat = new OutputFormatter(Settings.counters, Settings.formatType, Settings.dataFormat,
2931 Settings.datamover, Settings.showMonitor);
2932 DMStatCollector col = new DMStatCollector(Settings.dmhostname, Settings.datamover, Settings.statmonPortNumber, Settings.counters,
2933 outFormat, Settings.usingDefaultInterval, Settings.interval, Settings.requestedCount, Settings.tableOpts, resolver,
2934 Settings.traceMode, Settings.timingTrace, Settings.memTrace, Settings.VIS);
2935 LinePrinter lpr = new LinePrinter(outFormat, Settings.showTitles(), Settings.showMonitor, Settings.printTitleFreq);
2936 Thread colThread = new Thread(col);
2937 colThread.setName("DMStatCollector");
2938 ShutdownSummary sum = new ShutdownSummary(colThread, lpr, memmon, outFormat, Settings.showSummary, Settings.showTitles(),
2939 Settings.filepath, tmpOutputFileName, mainCopyFileName, Settings.datamover);
2940 try {
2941 Runtime.getRuntime().addShutdownHook(sum);
2942 } catch (IllegalStateException ise) { }
2943 lpr.start();
2944 colThread.start();
2945 }
2946 // clear statinfomap for other cases except statistic collection
2947 }
2948
2949 /**
2950 * This function splits given string on comma and ingore the comma which is a part of statpath
2951 *
2952 * @param base base string to split on command delemeter
2953 * @param isRemoveEscapCharWithComma boolean flag to decide whether esacpae charcter with comma to be removed or not.
2954 */
2955 public static String[] splitOnComma(String base, boolean isRemoveEscapCharWithComma) {
2956 List<String> strList = new ArrayList<String>();
2957 int commaIndex = base.indexOf(',');
2958 int startIndex = 0;
2959 String element;
2960 while(commaIndex > -1) {
2961 if(commaIndex > 1 && base.charAt(commaIndex - 1) != '\\') {
2962 element = base.substring(startIndex, commaIndex);
2963 if(isRemoveEscapCharWithComma) {
2964 element = element.replace("\\,", ",");
2965 }
2966 strList.add(element);
2967 startIndex = commaIndex + 1;
2968 }
2969 commaIndex = base.indexOf(',', commaIndex + 1);
2970 }
2971 // add last element in list or add element in list if there is only one element.
2972 if(commaIndex == -1 && startIndex < base.length()) {
2973 String lastElement = base.substring(startIndex);
2974 if(isRemoveEscapCharWithComma) {
2975 lastElement = lastElement.replace("\\,", ",");
2976 }
2977 strList.add(lastElement);
2978 }
2979 String[] retval = new String[strList.size()];
2980 // Convert list to String array
2981 strList.toArray(retval);
2982 return retval;
2983 }
2984
2985 protected static class StatResolve {
2986
2987 private String stat;
2988 private List<String> resolvedStats;
2989 private String defaultSortField;
2990 private int defaultSortCol;
2991 private int type;
2992 private List<String> sortFields;
2993 private List<String> lcSortFields;
2994 private boolean hasTitleSortField;
2995
2996 static final int UNKNOWN = 0;
2997 static final int NONSET = 1;
2998 static final int SET = 2;
2999 static final int ESET = 3;
3000
3001 static boolean eSetExists = false;
3002
3003 public StatResolve(String stat,
3004 List<String> resolvedStats,
3005 int type,
3006 String defaultSortField,
3007 List<String> sortFields,
3008 boolean hasTitleSortField) {
3009 this.stat = stat;
3010 this.resolvedStats = resolvedStats;
3011 this.type = type;
3012 this.defaultSortField = defaultSortField;
3013
3014 if(stat.equalsIgnoreCase("store.logicalvolume.metavolume") ||
3015 stat.equalsIgnoreCase("metavolumes-std")) {
3016 sortFields.add(0, "fsName");
3017 }
3018 this.sortFields = sortFields;
3019 lcSortFields = new LinkedList<String>();
3020 for(Iterator<String> it = sortFields.iterator(); it.hasNext();) {
3021 lcSortFields.add(it.next().toLowerCase());
3022 }
3023 if(sortFields.size() > 0) {
3024 if(type == SET) {
3025 this.defaultSortCol = 0;
3026 this.defaultSortField = sortFields.get(0);
3027 } else if(type == ESET) {
3028 this.defaultSortCol = sortFields.indexOf(defaultSortField);
3029 if(!hasTitleSortField) {
3030 this.defaultSortCol++;
3031 }
3032 eSetExists = true;
3033 }
3034 }
3035 this.hasTitleSortField = hasTitleSortField;
3036 }
3037
3038 public void setResolvedStat(String resolvedStatPath) {
3039 if(resolvedStats.size() == 1) {
3040 resolvedStats.remove(0);
3041 resolvedStats.add(resolvedStatPath);
3042 }
3043
3044 }
3045
3046 // Modified to work with statmon response instead of statsd.
3047 public static int findType(String typeStr) {
3048 if(typeStr.equals("setElement") || typeStr.equals("c64") || typeStr.equals("f") || typeStr.equals("computed") ||
3049 typeStr.equals("tc64") || typeStr.equals("family") || typeStr.equals("tf") || typeStr.equals("ec64") ||
3050 typeStr.equals("cmpd") || typeStr.equals("tec64")) {
3051 return NONSET;
3052 } else if(typeStr.equals("s")) {
3053 return SET;
3054 } else if(typeStr.equals("es")) {
3055 return ESET;
3056 } else {
3057 return UNKNOWN;
3058 }
3059 }
3060
3061 public String getStat() {
3062 return stat;
3063 }
3064
3065 public List<String> getResolvedStats() {
3066 return resolvedStats;
3067 }
3068
3069 public int getType() {
3070 if(stat.equalsIgnoreCase(TCIFS_COUNTER)
3071 || stat.equalsIgnoreCase(TNFS_COUNTER)) {
3072 return SET;
3073 } else {
3074 return type;
3075 }
3076 }
3077
3078 public String getDefaultSortField() {
3079 return defaultSortField;
3080 }
3081
3082 public int getDefaultSortCol() {
3083 return defaultSortCol;
3084 }
3085
3086 public List<String> getSortFields() {
3087 return sortFields;
3088 }
3089
3090 public List<String> getLcSortFields() {
3091 return lcSortFields;
3092 }
3093
3094 public boolean isSortable() {
3095 if(stat.equalsIgnoreCase(TCIFS_COUNTER)
3096 || stat.equalsIgnoreCase(TNFS_COUNTER)) {
3097 return true;
3098 } else {
3099 return (sortFields.size() > 0);
3100 }
3101 }
3102
3103 public boolean hasTitleSortField() {
3104 return hasTitleSortField;
3105 }
3106
3107 public void printDebugOutput() {
3108 Global.out.println("unresolved:\t"+stat);
3109 Global.out.println("resolved:\t"+resolvedStats);
3110 Global.out.println("type:\t\t"+type);
3111 if(sortFields!=null){
3112 Global.out.println("defaultSort:\t"+defaultSortField);
3113 Global.out.println("sortFields:\t"+sortFields.toString());
3114 }
3115 }
3116 }
3117
3118 protected static class StatInfo {
3119
3120 private String name;
3121 private String type;
3122 private String title;
3123 private String description;
3124 private String parent;
3125 private String operation;
3126 private boolean isCounter;
3127 private boolean isResetting;
3128 private boolean isError;
3129 private List<String> children;
3130 private List<String> elements;
3131
3132 public StatInfo(String name,
3133 String type,
3134 String title,
3135 String description,
3136 String parent,
3137 String operation,
3138 boolean isCounter,
3139 boolean isResetting,
3140 boolean isError,
3141 List<String> children,
3142 List<String> elements) {
3143 this.name = name;
3144 this.type = type;
3145 this.title = title;
3146 this.description = description;
3147 this.parent = parent;
3148 this.operation = operation;
3149 this.isCounter = isCounter;
3150 this.isResetting = isResetting;
3151 this.isError = isError;
3152 this.children = children;
3153 this.elements = elements;
3154 }
3155
3156 public static String findOperation(String opStr) {
3157 if(opStr.indexOf("add") != -1) {
3158 return "Addition";
3159 } else if(opStr.indexOf("sub") != -1) {
3160 return "Subtraction";
3161 } else if(opStr.indexOf("mult") != -1) {
3162 return "Multiplication";
3163 } else if(opStr.indexOf("div") != -1) {
3164 return "Division";
3165 } else if(opStr.indexOf("pct") != -1) {
3166 return "Percent";
3167 } else if(opStr.indexOf("pdct") != -1) {
3168 return "Product";
3169 } else if(opStr.indexOf("sum") != -1) {
3170 return "Summation";
3171 } else if(opStr.indexOf("avg") != -1) {
3172 return "Average";
3173 } else {
3174 return "unknown";
3175 }
3176 }
3177
3178 public String getName() {
3179 return name.replaceAll("\\*", "ALL-ELEMENTS");
3180 }
3181
3182 public String getType() {
3183 return type;
3184 }
3185
3186 public String getTitle() {
3187 return title;
3188 }
3189
3190 public String getDescription() {
3191 return description;
3192 }
3193
3194 public String getParent() {
3195 return parent;
3196 }
3197
3198 public String getChildren() {
3199 StringBuffer childrenStr = new StringBuffer();
3200 for(Iterator<String> it = children.iterator(); it.hasNext();) {
3201 childrenStr.append(it.next().replaceAll("\\*", "ALL-ELEMENTS"));
3202 if(it.hasNext()) {
3203 childrenStr.append(',');
3204 }
3205 }
3206 return childrenStr.toString();
3207 }
3208
3209 public String getElements() {
3210 StringBuffer elementsStr = new StringBuffer();
3211 for(Iterator<String> it = elements.iterator(); it.hasNext();) {
3212 elementsStr.append(it.next().replaceAll("\\*", "ALL-ELEMENTS"));
3213 if(it.hasNext()) {
3214 elementsStr.append(',');
3215 }
3216 }
3217 return elementsStr.toString();
3218 }
3219
3220 /**
3221 * Get the stat type
3222 *
3223 * @return stat type, if the type is computed, also include the operation
3224 */
3225 public String getTypeString() {
3226
3227 if(type.endsWith("c64")) {
3228 return "Counter";
3229 } else if(type.equals("f")) {
3230 return "Fact";
3231 } else if(type.equals("computed")) {
3232 return "Computed - " + operation;
3233 } else if(type.equals("cmpd")) {
3234 return "Compound";
3235 } else if(type.equals("family")) {
3236 return "Family";
3237 } else if(type.equals("s")) {
3238 return "Set";
3239 } else if(type.equals("es")) {
3240 return "Correlated Set";
3241 } else if(type.equals("setElement")) {
3242 return "Element";
3243 } else if(type.equals("System-Defined")) {
3244 return type;
3245 } else if(type.equals("User-Defined")) {
3246 return type;
3247 } else {
3248 return " ";
3249 }
3250 }
3251
3252 public String getListTypeString(){
3253 if(type.endsWith("c64")) {
3254 return "Counter ";
3255 } else if(type.equals("f")) {
3256 return "Fact ";
3257 } else if(type.equals("computed")) {
3258 return "Computed ";
3259 } else if(type.equals("cmpd")) {
3260 return "Compound ";
3261 } else if(type.equals("family")) {
3262 return "Family ";
3263 } else if(type.equals("s")) {
3264 return "Set ";
3265 } else if(type.equals("es")) {
3266 return "Correlated Set ";
3267 } else if(type.equals("setElement")) {
3268 return "Element ";
3269 } else if(type.equals("System-Defined")) {
3270 return "System ";
3271 } else if(type.equals("User-Defined")) {
3272 return "User ";
3273 } else {
3274 return " ";
3275 }
3276 }
3277
3278 public void printInfo() {
3279 Global.out.println("\nname = "+getName());
3280 Global.out.println("description = "+getDescription());
3281 Global.out.println("type = "+getTypeString());
3282 Global.out.println("member_stats = "+getChildren());
3283 Global.out.println("member_elements = "+getElements());
3284 Global.out.println("member_of = "+getParent());
3285 }
3286
3287 public void printList() {
3288 Global.out.println(getListTypeString()+getName());
3289 }
3290 }
3291
3292 /**
3293 * Return position of last occurence of dot in given string excluding dot which is part of elementname
3294 *
3295 * @param bass is a string.
3296 * @return integer position of last occurence of dot in given string.
3297 */
3298 public static int dotLastIndexOf(String base) {
3299 // Handle element name contains dot. The dot is followed by slash to identify that dot
3300 // is a part of element name.
3301 int dotPos = base.lastIndexOf('.');
3302 while(dotPos > -1) {
3303 // Ignore dot which is a part of element name.
3304 if(dotPos > -1 && base.charAt(dotPos - 1) != '\\') {
3305 break;
3306 } else {
3307 dotPos = base.lastIndexOf('.', dotPos - 1);
3308 }
3309 }
3310 return dotPos;
3311 }
3312
3313 /**
3314 * Return position of first occurence of dot in given string excluding dot which is part of elementname
3315 *
3316 * @param bass is a string.
3317 * @return integer position of first occurence of dot in given string.
3318 */
3319 public static int indexOfDot(String base) {
3320 return indexOfDot(base, 0);
3321 }
3322
3323 /**
3324 * Return position of first occurence of dot in given string excluding dot which is part of elementname
3325 *
3326 * @param bass is a string.
3327 * @return integer position of first occurence of dot in given string.
3328 */
3329 public static int indexOfDot(String base, int startFrom) {
3330 // Handle element name contains dot. The dot is followed by slash to identify that dot
3331 // is a part of element name.
3332 int dotPos = base.indexOf('.', startFrom);
3333 while(dotPos > -1) {
3334 // Ignore dot which is a part of element name.
3335 if(dotPos > -1 && base.charAt(dotPos - 1) != '\\') {
3336 break;
3337 } else {
3338 dotPos = base.indexOf('.', dotPos + 1);
3339 }
3340 }
3341 return dotPos;
3342 }
3343
3344 /**
3345 * This function return element list of given statpath
3346 *
3347 * @param statpath is statistic path to be split on dot.
3348 * @return element list of given statpath.
3349 *
3350 */
3351 public static List<String> splitStatpathOnDot(String statPath) {
3352 List<String> elementList = new ArrayList<String>();
3353 int dotIndex = statPath.indexOf('.');
3354 int startIndex = 0;
3355 String element;
3356 // split statpath on dot. so we can determine start and end of element.
3357 while(dotIndex > -1) {
3358 if(dotIndex > 1 && statPath.charAt(dotIndex - 1) != '\\') {
3359 element = statPath.substring(startIndex, dotIndex);
3360 elementList.add(element);
3361 startIndex = dotIndex + 1;
3362 }
3363 dotIndex = statPath.indexOf('.', dotIndex + 1);
3364 }
3365 // add last element in list or add element in list if there is only one element.
3366 if(dotIndex == -1 && startIndex < statPath.length()) {
3367 String lastElement = statPath.substring(startIndex);
3368 elementList.add(lastElement);
3369 }
3370 return elementList;
3371 }
3372}