@@ -20,13 +20,14 @@ public final class CliArgumentParser
2020 static final int MAX_LIMIT = 10000 ;
2121 static final int DEFAULT_TREE_DEPTH = 8 ;
2222 static final int DEFAULT_AGENT_TREE_DEPTH = 4 ;
23+ static final int DEFAULT_INSPECT_OBJECT_TREE_DEPTH = 3 ;
2324
2425 public CliArguments parse (String [] args ) throws CliException
2526 {
2627 if (args == null || args .length == 0 )
2728 return new CliArguments (null , null , null , null , CliArguments .OutputProfile .DEFAULT ,
2829 CliArguments .OutputFormat .TEXT , false , true , DEFAULT_LIMIT , DEFAULT_TREE_DEPTH , null , null ,
29- null );
30+ null , null , false , null , null );
3031
3132 CliCommand command = null ;
3233 CliCommand subjectCommand = null ;
@@ -42,6 +43,10 @@ public CliArguments parse(String[] args) throws CliException
4243 int treeDepthLimit = DEFAULT_TREE_DEPTH ;
4344 boolean treeDepthExplicit = false ;
4445 String objectAddress = null ;
46+ String className = null ;
47+ String selectField = null ;
48+ String fieldPath = null ;
49+ boolean includeSubclasses = false ;
4550 String oqlQuery = null ;
4651 String oqlQueryFile = null ;
4752 boolean oqlQueryStdin = false ;
@@ -106,6 +111,34 @@ else if ("--object".equals(arg)) //$NON-NLS-1$
106111 {
107112 objectAddress = nextArg (args , ++ii , "--object" ); //$NON-NLS-1$
108113 }
114+ else if (arg .startsWith ("--class=" )) //$NON-NLS-1$
115+ {
116+ className = arg .substring ("--class=" .length ()); //$NON-NLS-1$
117+ }
118+ else if ("--class" .equals (arg )) //$NON-NLS-1$
119+ {
120+ className = nextArg (args , ++ii , "--class" ); //$NON-NLS-1$
121+ }
122+ else if (arg .startsWith ("--select-field=" )) //$NON-NLS-1$
123+ {
124+ selectField = arg .substring ("--select-field=" .length ()); //$NON-NLS-1$
125+ }
126+ else if ("--select-field" .equals (arg )) //$NON-NLS-1$
127+ {
128+ selectField = nextArg (args , ++ii , "--select-field" ); //$NON-NLS-1$
129+ }
130+ else if (arg .startsWith ("--field-path=" )) //$NON-NLS-1$
131+ {
132+ fieldPath = arg .substring ("--field-path=" .length ()); //$NON-NLS-1$
133+ }
134+ else if ("--field-path" .equals (arg )) //$NON-NLS-1$
135+ {
136+ fieldPath = nextArg (args , ++ii , "--field-path" ); //$NON-NLS-1$
137+ }
138+ else if ("--include-subclasses" .equals (arg )) //$NON-NLS-1$
139+ {
140+ includeSubclasses = true ;
141+ }
109142 else if (arg .startsWith ("--query=" )) //$NON-NLS-1$
110143 {
111144 oqlQuery = arg .substring ("--query=" .length ()); //$NON-NLS-1$
@@ -179,19 +212,21 @@ else if (command.requiresSnapshot() && heapFile == null)
179212
180213 if (profile == CliArguments .OutputProfile .AGENT && !formatExplicit )
181214 format = CliArguments .OutputFormat .JSON ;
182- if (!treeDepthExplicit )
183- treeDepthLimit = defaultTreeDepth (profile );
184215
185216 if (command == null )
186217 {
187218 if (help )
188219 {
189220 return new CliArguments (null , null , null , null , profile , format , verbose , true , limit ,
190- treeDepthLimit , objectAddress , oqlQuery , queryCommand );
221+ treeDepthLimit , objectAddress , className , selectField , fieldPath , includeSubclasses ,
222+ oqlQuery , queryCommand );
191223 }
192224 throw CliException .usage ("Missing command" ); //$NON-NLS-1$
193225 }
194226
227+ if (!treeDepthExplicit )
228+ treeDepthLimit = defaultTreeDepth (command , profile );
229+
195230 if (command == CliCommand .OQL )
196231 oqlQuery = resolveExclusiveInput ("oql" , "--query" , oqlQuery , "--query-file" , oqlQueryFile , //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
197232 "--query-stdin" , oqlQueryStdin ); //$NON-NLS-1$
@@ -203,7 +238,8 @@ else if (command == CliCommand.QUERY)
203238 limit = defaultLimit (command , queryCommand );
204239
205240 CliArguments parsed = new CliArguments (command , subjectCommand , subjectName , heapFile , profile , format , verbose ,
206- help , limit , treeDepthLimit , objectAddress , oqlQuery , queryCommand );
241+ help , limit , treeDepthLimit , objectAddress , className , selectField , fieldPath ,
242+ includeSubclasses , oqlQuery , queryCommand );
207243 validate (parsed );
208244 return parsed ;
209245 }
@@ -298,8 +334,23 @@ private void validate(CliArguments arguments) throws CliException
298334 switch (arguments .getCommand ())
299335 {
300336 case PATH2GC :
337+ case INSPECT_OBJECT :
301338 if (isEmpty (arguments .getObjectAddress ()))
302- throw CliException .usage ("path2gc requires --object 0x..." ); //$NON-NLS-1$
339+ throw CliException .usage (arguments .getCommand ().getToken () + " requires --object 0x..." ); //$NON-NLS-1$
340+ if (!isEmpty (arguments .getSelectField ()) && !isEmpty (arguments .getFieldPath ()))
341+ throw CliException .usage ("inspect-object accepts only one of --select-field or --field-path" ); //$NON-NLS-1$
342+ if (arguments .getSelectField () != null && isEmpty (arguments .getSelectField ()))
343+ throw CliException .usage ("inspect-object requires a non-empty --select-field" ); //$NON-NLS-1$
344+ if (arguments .getFieldPath () != null && isEmpty (arguments .getFieldPath ()))
345+ throw CliException .usage ("inspect-object requires a non-empty --field-path" ); //$NON-NLS-1$
346+ if (!isEmpty (arguments .getSelectField ()) && arguments .getSelectField ().indexOf ('.' ) >= 0 )
347+ throw CliException .usage ("--select-field accepts one field name. Use --field-path for dotted paths." ); //$NON-NLS-1$
348+ if (!isEmpty (arguments .getFieldPath ()) && hasEmptyPathSegment (arguments .getFieldPath ()))
349+ throw CliException .usage ("Invalid --field-path: " + arguments .getFieldPath ()); //$NON-NLS-1$
350+ break ;
351+ case INSTANCES :
352+ if (isEmpty (arguments .getClassName ()))
353+ throw CliException .usage ("instances requires --class <fqcn>" ); //$NON-NLS-1$
303354 break ;
304355 case OQL :
305356 if (isEmpty (arguments .getOqlQuery ()))
@@ -420,9 +471,14 @@ public CliArguments partialParse(String[] args, CliArguments.OutputProfile profi
420471 File heapFile = null ;
421472 boolean help = args == null || args .length == 0 ;
422473 String objectAddress = null ;
474+ String className = null ;
475+ String selectField = null ;
476+ String fieldPath = null ;
477+ boolean includeSubclasses = false ;
423478 String oqlQuery = null ;
424479 String queryCommand = null ;
425- int treeDepthLimit = defaultTreeDepth (profile );
480+ int treeDepthLimit = defaultTreeDepth (null , profile );
481+ boolean treeDepthExplicit = false ;
426482
427483 if (args != null )
428484 {
@@ -440,8 +496,17 @@ else if (expectsValue(arg))
440496 String value = args [++ii ];
441497 if ("--object" .equals (arg )) //$NON-NLS-1$
442498 objectAddress = value ;
499+ else if ("--class" .equals (arg )) //$NON-NLS-1$
500+ className = value ;
501+ else if ("--select-field" .equals (arg )) //$NON-NLS-1$
502+ selectField = value ;
503+ else if ("--field-path" .equals (arg )) //$NON-NLS-1$
504+ fieldPath = value ;
443505 else if ("--depth" .equals (arg )) //$NON-NLS-1$
506+ {
444507 treeDepthLimit = safePartialDepth (value , treeDepthLimit );
508+ treeDepthExplicit = true ;
509+ }
445510 else if ("--query" .equals (arg )) //$NON-NLS-1$
446511 oqlQuery = value ;
447512 else if ("--command" .equals (arg )) //$NON-NLS-1$
@@ -452,18 +517,35 @@ else if (arg.startsWith("--object=")) //$NON-NLS-1$
452517 {
453518 objectAddress = arg .substring ("--object=" .length ()); //$NON-NLS-1$
454519 }
520+ else if (arg .startsWith ("--class=" )) //$NON-NLS-1$
521+ {
522+ className = arg .substring ("--class=" .length ()); //$NON-NLS-1$
523+ }
455524 else if (arg .startsWith ("--query=" )) //$NON-NLS-1$
456525 {
457526 oqlQuery = arg .substring ("--query=" .length ()); //$NON-NLS-1$
458527 }
528+ else if (arg .startsWith ("--select-field=" )) //$NON-NLS-1$
529+ {
530+ selectField = arg .substring ("--select-field=" .length ()); //$NON-NLS-1$
531+ }
532+ else if (arg .startsWith ("--field-path=" )) //$NON-NLS-1$
533+ {
534+ fieldPath = arg .substring ("--field-path=" .length ()); //$NON-NLS-1$
535+ }
459536 else if (arg .startsWith ("--depth=" )) //$NON-NLS-1$
460537 {
461538 treeDepthLimit = safePartialDepth (arg .substring ("--depth=" .length ()), treeDepthLimit ); //$NON-NLS-1$
539+ treeDepthExplicit = true ;
462540 }
463541 else if (arg .startsWith ("--command=" )) //$NON-NLS-1$
464542 {
465543 queryCommand = arg .substring ("--command=" .length ()); //$NON-NLS-1$
466544 }
545+ else if ("--include-subclasses" .equals (arg )) //$NON-NLS-1$
546+ {
547+ includeSubclasses = true ;
548+ }
467549 else if (arg .startsWith ("--" )) //$NON-NLS-1$
468550 {
469551 continue ;
@@ -502,8 +584,12 @@ else if (command.requiresSnapshot() && heapFile == null)
502584 }
503585 }
504586
587+ if (!treeDepthExplicit )
588+ treeDepthLimit = defaultTreeDepth (command , profile );
589+
505590 return new CliArguments (command , subjectCommand , subjectName , heapFile , profile , format , false , help ,
506- defaultLimit (command , queryCommand ), treeDepthLimit , objectAddress , oqlQuery , queryCommand );
591+ defaultLimit (command , queryCommand ), treeDepthLimit , objectAddress , className , selectField ,
592+ fieldPath , includeSubclasses , oqlQuery , queryCommand );
507593 }
508594
509595 private int defaultLimit (CliCommand command , String queryCommand )
@@ -535,15 +621,25 @@ private boolean expectsValue(String option)
535621 {
536622 return "--profile" .equals (option ) || "--format" .equals (option ) || "--limit" .equals (option ) //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
537623 || "--depth" .equals (option ) //$NON-NLS-1$
538- || "--object" .equals (option ) || "--query" .equals (option ) || "--query-file" .equals (option ) //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
624+ || "--object" .equals (option ) || "--class" .equals (option ) //$NON-NLS-1$ //$NON-NLS-2$
625+ || "--select-field" .equals (option ) || "--field-path" .equals (option ) //$NON-NLS-1$ //$NON-NLS-2$
626+ || "--query" .equals (option ) //$NON-NLS-1$
627+ || "--query-file" .equals (option ) //$NON-NLS-1$
539628 || "--command" .equals (option ) || "--command-file" .equals (option ); //$NON-NLS-1$ //$NON-NLS-2$
540629 }
541630
542- private int defaultTreeDepth (CliArguments .OutputProfile profile )
631+ private int defaultTreeDepth (CliCommand command , CliArguments .OutputProfile profile )
543632 {
633+ if (command == CliCommand .INSPECT_OBJECT )
634+ return DEFAULT_INSPECT_OBJECT_TREE_DEPTH ;
544635 return profile == CliArguments .OutputProfile .AGENT ? DEFAULT_AGENT_TREE_DEPTH : DEFAULT_TREE_DEPTH ;
545636 }
546637
638+ private boolean hasEmptyPathSegment (String fieldPath )
639+ {
640+ return fieldPath .startsWith ("." ) || fieldPath .endsWith ("." ) || fieldPath .indexOf (".." ) >= 0 ; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
641+ }
642+
547643 private int safePartialDepth (String value , int fallback )
548644 {
549645 try
0 commit comments