From f9ef226b7e37bada0e9afead46bd8378962b92aa Mon Sep 17 00:00:00 2001
From: "Endi S. Dewata" <edewata@redhat.com>
Date: Tue, 6 Aug 2013 02:29:50 -0400
Subject: [PATCH] Refactored CLI framework.

Some common CLI methods and attributes have been refactored into the CLI base
class. A new SubsystemCLI class was added as the base for subsystem CLI
modules. The MainCLI was modified such that it will only perform authentication
if the subsystem is specified in the server URI. If no subsystem is specified
in the URI, the authentication will be done by the subsystem CLI module.

Ticket #701
---
 .../src/com/netscape/cmstools/cert/CertCLI.java    | 35 +++-----
 .../com/netscape/cmstools/cert/CertFindCLI.java    | 12 +--
 .../com/netscape/cmstools/cert/CertHoldCLI.java    | 16 ++--
 .../netscape/cmstools/cert/CertReleaseHoldCLI.java | 16 ++--
 .../netscape/cmstools/cert/CertRequestFindCLI.java | 13 +--
 .../cmstools/cert/CertRequestReviewCLI.java        | 26 +++---
 .../netscape/cmstools/cert/CertRequestShowCLI.java | 12 +--
 .../cmstools/cert/CertRequestSubmitCLI.java        | 18 ++---
 .../com/netscape/cmstools/cert/CertRevokeCLI.java  | 18 ++---
 .../com/netscape/cmstools/cert/CertShowCLI.java    | 12 +--
 .../src/com/netscape/cmstools/cli/CLI.java         | 79 ++++++++++++++++++-
 .../src/com/netscape/cmstools/cli/MainCLI.java     | 21 ++---
 .../SubsystemCLI.java}                             | 50 +++++++-----
 .../src/com/netscape/cmstools/cli/TPSCLI.java      | 92 ++++++----------------
 .../com/netscape/cmstools/client/ClientCLI.java    | 34 +++-----
 .../cmstools/client/ClientFindCertCLI.java         | 16 ++--
 .../cmstools/client/ClientImportCertCLI.java       | 20 ++---
 .../cmstools/client/ClientRemoveCertCLI.java       | 14 ++--
 .../com/netscape/cmstools/group/GroupAddCLI.java   | 12 +--
 .../netscape/cmstools/group/GroupAddMemberCLI.java | 12 +--
 .../src/com/netscape/cmstools/group/GroupCLI.java  | 34 +++-----
 .../com/netscape/cmstools/group/GroupFindCLI.java  | 12 +--
 .../cmstools/group/GroupFindMemberCLI.java         | 12 +--
 .../netscape/cmstools/group/GroupModifyCLI.java    | 12 +--
 .../netscape/cmstools/group/GroupRemoveCLI.java    | 12 +--
 .../cmstools/group/GroupRemoveMemberCLI.java       | 12 +--
 .../com/netscape/cmstools/group/GroupShowCLI.java  | 12 +--
 .../cmstools/group/GroupShowMemberCLI.java         | 12 +--
 .../src/com/netscape/cmstools/key/KeyCLI.java      | 35 +++-----
 .../src/com/netscape/cmstools/key/KeyFindCLI.java  | 12 +--
 .../netscape/cmstools/key/KeyRequestFindCLI.java   | 12 +--
 .../netscape/cmstools/profile/ProfileAddCLI.java   | 13 +--
 .../com/netscape/cmstools/profile/ProfileCLI.java  | 38 +++------
 .../cmstools/profile/ProfileDisableCLI.java        | 12 +--
 .../cmstools/profile/ProfileEnableCLI.java         | 12 +--
 .../netscape/cmstools/profile/ProfileFindCLI.java  | 12 +--
 .../cmstools/profile/ProfileModifyCLI.java         | 12 +--
 .../cmstools/profile/ProfileRemoveCLI.java         | 12 +--
 .../netscape/cmstools/profile/ProfileShowCLI.java  | 14 ++--
 .../cmstools/system/KRAConnectorAddCLI.java        | 13 +--
 .../netscape/cmstools/system/KRAConnectorCLI.java  | 37 +++------
 .../cmstools/system/KRAConnectorRemoveCLI.java     | 13 +--
 .../cmstools/system/SecurityDomainCLI.java         | 37 +++------
 .../system/SecurityDomainGetInstallTokenCLI.java   | 12 +--
 .../cmstools/system/SecurityDomainShowCLI.java     | 12 +--
 .../src/com/netscape/cmstools/token/TokenCLI.java  | 79 ++++---------------
 .../src/com/netscape/cmstools/user/UserAddCLI.java | 12 +--
 .../com/netscape/cmstools/user/UserAddCertCLI.java | 12 +--
 .../cmstools/user/UserAddMembershipCLI.java        | 12 +--
 .../src/com/netscape/cmstools/user/UserCLI.java    | 35 +++-----
 .../com/netscape/cmstools/user/UserFindCLI.java    | 12 +--
 .../netscape/cmstools/user/UserFindCertCLI.java    | 12 +--
 .../cmstools/user/UserFindMembershipCLI.java       | 12 +--
 .../com/netscape/cmstools/user/UserModifyCLI.java  | 12 +--
 .../com/netscape/cmstools/user/UserRemoveCLI.java  | 12 +--
 .../netscape/cmstools/user/UserRemoveCertCLI.java  | 12 +--
 .../cmstools/user/UserRemoveMembershipCLI.java     | 12 +--
 .../com/netscape/cmstools/user/UserShowCLI.java    | 12 +--
 .../netscape/cmstools/user/UserShowCertCLI.java    | 12 +--
 59 files changed, 553 insertions(+), 659 deletions(-)
 copy base/java-tools/src/com/netscape/cmstools/{user/UserRemoveMembershipCLI.java => cli/SubsystemCLI.java} (52%)

diff --git a/base/java-tools/src/com/netscape/cmstools/cert/CertCLI.java b/base/java-tools/src/com/netscape/cmstools/cert/CertCLI.java
index 8abe6f22ad64a3f43b84b782051f166b82cdbbf3..9b69c992ca0e87d6491f108b00d69b1fc96627ef 100644
--- a/base/java-tools/src/com/netscape/cmstools/cert/CertCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/cert/CertCLI.java
@@ -21,7 +21,6 @@ package com.netscape.cmstools.cert;
 import java.text.SimpleDateFormat;
 import java.util.Arrays;
 
-import org.apache.commons.lang.StringUtils;
 import org.jboss.resteasy.plugins.providers.atom.Link;
 
 import com.netscape.certsrv.cert.CertClient;
@@ -39,12 +38,10 @@ public class CertCLI extends CLI {
 
     public static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
 
-    public MainCLI parent;
-    public CertClient client;
+    public CertClient certClient;
 
-    public CertCLI(MainCLI parent) {
-        super("cert", "Certificate management commands");
-        this.parent = parent;
+    public CertCLI(CLI parent) {
+        super("cert", "Certificate management commands", parent);
 
         addModule(new CertFindCLI(this));
         addModule(new CertShowCLI(this));
@@ -58,30 +55,18 @@ public class CertCLI extends CLI {
         addModule(new CertRequestReviewCLI(this));
     }
 
-    public void printHelp() {
-
-        System.out.println("Commands:");
-
-        int leftPadding = 1;
-        int rightPadding = 25;
-
-        for (CLI module : modules.values()) {
-            String label = name + "-" + module.getName();
-
-            int padding = rightPadding - leftPadding - label.length();
-            if (padding < 1)
-                padding = 1;
-
-            System.out.print(StringUtils.repeat(" ", leftPadding));
-            System.out.print(label);
-            System.out.print(StringUtils.repeat(" ", padding));
-            System.out.println(module.getDescription());
+    public String getFullName() {
+        if (parent instanceof MainCLI) {
+            // do not include MainCLI's name
+            return name;
+        } else {
+            return parent.getFullName() + "-" + name;
         }
     }
 
     public void execute(String[] args) throws Exception {
 
-        client = new CertClient(parent.client);
+        certClient = new CertClient(parent.getClient());
 
         if (args.length == 0) {
             printHelp();
diff --git a/base/java-tools/src/com/netscape/cmstools/cert/CertFindCLI.java b/base/java-tools/src/com/netscape/cmstools/cert/CertFindCLI.java
index 590d7959866740a5adbfa74c75f8cdebada6672f..7f8eb75f1c8576e8972190eac32b4fa407d85d47 100644
--- a/base/java-tools/src/com/netscape/cmstools/cert/CertFindCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/cert/CertFindCLI.java
@@ -41,15 +41,15 @@ import com.netscape.cmstools.cli.MainCLI;
  */
 public class CertFindCLI extends CLI {
 
-    public CertCLI parent;
+    public CertCLI certCLI;
 
-    public CertFindCLI(CertCLI parent) {
-        super("find", "Find certificates");
-        this.parent = parent;
+    public CertFindCLI(CertCLI certCLI) {
+        super("find", "Find certificates", certCLI);
+        this.certCLI = certCLI;
     }
 
     public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " [OPTIONS...]", options);
+        formatter.printHelp(getFullName() + " [OPTIONS...]", options);
     }
 
     public void execute(String[] args) throws Exception {
@@ -120,7 +120,7 @@ public class CertFindCLI extends CLI {
 
         CertDataInfos certs = null;
         try {
-            certs = parent.client.findCerts(searchData, start, size);
+            certs = certCLI.certClient.findCerts(searchData, start, size);
         } catch (PKIException e) {
             System.err.println("Error: Cannot list certificates. " + e.getMessage());
             System.exit(1);
diff --git a/base/java-tools/src/com/netscape/cmstools/cert/CertHoldCLI.java b/base/java-tools/src/com/netscape/cmstools/cert/CertHoldCLI.java
index b6b5fcde73a5eefb8b44912044a589f5fe99bee6..2ebdb0ecf466fb76ec8d204dc65857ac3f9cf945 100644
--- a/base/java-tools/src/com/netscape/cmstools/cert/CertHoldCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/cert/CertHoldCLI.java
@@ -39,15 +39,15 @@ import com.netscape.cmstools.cli.MainCLI;
  */
 public class CertHoldCLI extends CLI {
 
-    public CertCLI parent;
+    public CertCLI certCLI;
 
-    public CertHoldCLI(CertCLI parent) {
-        super("hold", "Place certificate on-hold");
-        this.parent = parent;
+    public CertHoldCLI(CertCLI certCLI) {
+        super("hold", "Place certificate on-hold", certCLI);
+        this.certCLI = certCLI;
     }
 
     public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <Serial Number> [OPTIONS...]", options);
+        formatter.printHelp(getFullName() + " <Serial Number> [OPTIONS...]", options);
     }
 
     public void execute(String[] args) throws Exception {
@@ -77,7 +77,7 @@ public class CertHoldCLI extends CLI {
         }
 
         CertId certID = new CertId(cmdArgs[0]);
-        CertData certData = parent.client.reviewCert(certID);
+        CertData certData = certCLI.certClient.reviewCert(certID);
 
         if (!cmd.hasOption("force")) {
 
@@ -101,7 +101,7 @@ public class CertHoldCLI extends CLI {
         request.setComments(cmd.getOptionValue("comments"));
         request.setNonce(certData.getNonce());
 
-        CertRequestInfo certRequestInfo = parent.client.revokeCert(certID, request);
+        CertRequestInfo certRequestInfo = certCLI.certClient.revokeCert(certID, request);
 
         if (verbose) {
             CertCLI.printCertRequestInfo(certRequestInfo);
@@ -116,7 +116,7 @@ public class CertHoldCLI extends CLI {
                 MainCLI.printMessage("Could not place certificate \"" + certID.toHexString() + "\" on-hold");
             } else {
                 MainCLI.printMessage("Placed certificate \"" + certID.toHexString() + "\" on-hold");
-                certData = parent.client.getCert(certID);
+                certData = certCLI.certClient.getCert(certID);
                 CertCLI.printCertData(certData, false, false);
             }
         } else {
diff --git a/base/java-tools/src/com/netscape/cmstools/cert/CertReleaseHoldCLI.java b/base/java-tools/src/com/netscape/cmstools/cert/CertReleaseHoldCLI.java
index 5158505390286221e0572995626ed1524664404f..aa58539b84ec751507da849c9e4a43a49713f10c 100644
--- a/base/java-tools/src/com/netscape/cmstools/cert/CertReleaseHoldCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/cert/CertReleaseHoldCLI.java
@@ -36,15 +36,15 @@ import com.netscape.cmstools.cli.MainCLI;
  */
 public class CertReleaseHoldCLI extends CLI {
 
-    public CertCLI parent;
+    public CertCLI certCLI;
 
-    public CertReleaseHoldCLI(CertCLI parent) {
-        super("release-hold", "Place certificate off-hold");
-        this.parent = parent;
+    public CertReleaseHoldCLI(CertCLI certCLI) {
+        super("release-hold", "Place certificate off-hold", certCLI);
+        this.certCLI = certCLI;
     }
 
     public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <Serial Number> [OPTIONS...]", options);
+        formatter.printHelp(getFullName() + " <Serial Number> [OPTIONS...]", options);
     }
 
     public void execute(String[] args) throws Exception {
@@ -73,7 +73,7 @@ public class CertReleaseHoldCLI extends CLI {
 
         if (!cmd.hasOption("force")) {
 
-            CertData certData = parent.client.getCert(certID);
+            CertData certData = certCLI.certClient.getCert(certID);
 
             System.out.println("Placing certificate off-hold:");
 
@@ -91,7 +91,7 @@ public class CertReleaseHoldCLI extends CLI {
 
         CertUnrevokeRequest request = new CertUnrevokeRequest();
 
-        CertRequestInfo certRequestInfo = parent.client.unrevokeCert(certID, request);
+        CertRequestInfo certRequestInfo = certCLI.certClient.unrevokeCert(certID, request);
 
         if (verbose) {
             CertCLI.printCertRequestInfo(certRequestInfo);
@@ -106,7 +106,7 @@ public class CertReleaseHoldCLI extends CLI {
                 MainCLI.printMessage("Could not place certificate \"" + certID.toHexString() + "\" off-hold");
             } else {
                 MainCLI.printMessage("Placed certificate \"" + certID.toHexString() + "\" off-hold");
-                CertData certData = parent.client.getCert(certID);
+                CertData certData = certCLI.certClient.getCert(certID);
                 CertCLI.printCertData(certData, false, false);
             }
         } else {
diff --git a/base/java-tools/src/com/netscape/cmstools/cert/CertRequestFindCLI.java b/base/java-tools/src/com/netscape/cmstools/cert/CertRequestFindCLI.java
index fe54e70898f47e6c14301d8cffabd6e531874cc4..dbfc0ee87c40a96ee11526a200955852f652de73 100644
--- a/base/java-tools/src/com/netscape/cmstools/cert/CertRequestFindCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/cert/CertRequestFindCLI.java
@@ -33,15 +33,16 @@ import com.netscape.cmstools.cli.MainCLI;
  * @author Ade Lee
  */
 public class CertRequestFindCLI extends CLI {
-    public CertCLI parent;
 
-    public CertRequestFindCLI(CertCLI parent) {
-        super("request-find", "Find certificate requests");
-        this.parent = parent;
+    public CertCLI certCLI;
+
+    public CertRequestFindCLI(CertCLI certCLI) {
+        super("request-find", "Find certificate requests", certCLI);
+        this.certCLI = certCLI;
     }
 
     public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " [OPTIONS...]", options);
+        formatter.printHelp(getFullName() + " [OPTIONS...]", options);
     }
 
     public void execute(String[] args) throws Exception {
@@ -82,7 +83,7 @@ public class CertRequestFindCLI extends CLI {
         if (requestType != null && requestType.equals("all")) requestType = null;
 
         try {
-            certRequests = parent.client.certRequestResource.listRequests(requestState, requestType, start, size, maxResults, maxTime);
+            certRequests = certCLI.certClient.certRequestResource.listRequests(requestState, requestType, start, size, maxResults, maxTime);
         } catch (PKIException e) {
             System.err.println("Error: Cannot list certificate requests. " + e.getMessage());
             System.exit(-1);
diff --git a/base/java-tools/src/com/netscape/cmstools/cert/CertRequestReviewCLI.java b/base/java-tools/src/com/netscape/cmstools/cert/CertRequestReviewCLI.java
index 3891508bd99baf231bd107154add691dcadba3c6..d303b2edb59b844adee919af2aab080cad537eea 100644
--- a/base/java-tools/src/com/netscape/cmstools/cert/CertRequestReviewCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/cert/CertRequestReviewCLI.java
@@ -24,19 +24,19 @@ import com.netscape.cmstools.cli.MainCLI;
 
 public class CertRequestReviewCLI extends CLI {
 
-    CertCLI parent;
+    CertCLI certCLI;
     List<String> actions = Arrays.asList(
         "approve", "reject", "cancel", "update", "validate", "assign", "unassign"
     );
 
-    public CertRequestReviewCLI(CertCLI parent) {
-        super("request-review", "Review certificate request");
-        this.parent = parent;
+    public CertRequestReviewCLI(CertCLI certCLI) {
+        super("request-review", "Review certificate request", certCLI);
+        this.certCLI = certCLI;
     }
 
     @Override
     public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <Request ID> [OPTIONS...]", options);
+        formatter.printHelp(getFullName() + " <Request ID> [OPTIONS...]", options);
     }
 
     @Override
@@ -96,7 +96,7 @@ public class CertRequestReviewCLI extends CLI {
         // Retrieve certificate request.
         CertReviewResponse reviewInfo = null;
         try {
-            reviewInfo = parent.client.reviewRequest(requestId);
+            reviewInfo = certCLI.certClient.reviewRequest(requestId);
         } catch (PKIException e) {
             System.err.println(e.getMessage());
             System.exit(-1);
@@ -135,31 +135,31 @@ public class CertRequestReviewCLI extends CLI {
         }
 
         if (action.equalsIgnoreCase("approve")) {
-            parent.client.approveRequest(reviewInfo.getRequestId(), reviewInfo);
+            certCLI.certClient.approveRequest(reviewInfo.getRequestId(), reviewInfo);
             MainCLI.printMessage("Approved certificate request " + requestId);
 
         } else if (action.equalsIgnoreCase("reject")) {
-            parent.client.rejectRequest(reviewInfo.getRequestId(), reviewInfo);
+            certCLI.certClient.rejectRequest(reviewInfo.getRequestId(), reviewInfo);
             MainCLI.printMessage("Rejected certificate request " + requestId);
 
         } else if (action.equalsIgnoreCase("cancel")) {
-            parent.client.cancelRequest(reviewInfo.getRequestId(), reviewInfo);
+            certCLI.certClient.cancelRequest(reviewInfo.getRequestId(), reviewInfo);
             MainCLI.printMessage("Canceled certificate request " + requestId);
 
         } else if (action.equalsIgnoreCase("update")) {
-            parent.client.updateRequest(reviewInfo.getRequestId(), reviewInfo);
+            certCLI.certClient.updateRequest(reviewInfo.getRequestId(), reviewInfo);
             MainCLI.printMessage("Updated certificate request " + requestId);
 
         } else if (action.equalsIgnoreCase("validate")) {
-            parent.client.validateRequest(reviewInfo.getRequestId(), reviewInfo);
+            certCLI.certClient.validateRequest(reviewInfo.getRequestId(), reviewInfo);
             MainCLI.printMessage("Validated certificate request " + requestId);
 
         } else if (action.equalsIgnoreCase("assign")) {
-            parent.client.assignRequest(reviewInfo.getRequestId(), reviewInfo);
+            certCLI.certClient.assignRequest(reviewInfo.getRequestId(), reviewInfo);
             MainCLI.printMessage("Assigned certificate request " + requestId);
 
         } else if (action.equalsIgnoreCase("unassign")) {
-            parent.client.unassignRequest(reviewInfo.getRequestId(), reviewInfo);
+            certCLI.certClient.unassignRequest(reviewInfo.getRequestId(), reviewInfo);
             MainCLI.printMessage("Unassigned certificate request " + requestId);
 
         } else {
diff --git a/base/java-tools/src/com/netscape/cmstools/cert/CertRequestShowCLI.java b/base/java-tools/src/com/netscape/cmstools/cert/CertRequestShowCLI.java
index edabb2296db130c866605ef281d58b3e32420094..ca8fcb25cc893726232dec7deb803af838127494 100644
--- a/base/java-tools/src/com/netscape/cmstools/cert/CertRequestShowCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/cert/CertRequestShowCLI.java
@@ -10,16 +10,16 @@ import com.netscape.cmstools.cli.MainCLI;
 
 public class CertRequestShowCLI extends CLI {
 
-    CertCLI parent;
+    CertCLI certCLI;
 
-    public CertRequestShowCLI(CertCLI parent) {
-        super("request-show", "Show certificate request");
-        this.parent = parent;
+    public CertRequestShowCLI(CertCLI certCLI) {
+        super("request-show", "Show certificate request", certCLI);
+        this.certCLI = certCLI;
     }
 
     @Override
     public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <Request ID>", options);
+        formatter.printHelp(getFullName() + " <Request ID>", options);
     }
 
     @Override
@@ -49,7 +49,7 @@ public class CertRequestShowCLI extends CLI {
             System.exit(-1);
         }
 
-        CertRequestInfo certRequest = parent.client.getRequest(requestId);
+        CertRequestInfo certRequest = certCLI.certClient.getRequest(requestId);
 
         MainCLI.printMessage("Certificate request \"" + requestId + "\"");
         CertCLI.printCertRequestInfo(certRequest);
diff --git a/base/java-tools/src/com/netscape/cmstools/cert/CertRequestSubmitCLI.java b/base/java-tools/src/com/netscape/cmstools/cert/CertRequestSubmitCLI.java
index 3562d48f0206ebaecdc919563688043d1e0848e9..917a697b6dee5a15a69ca69dce0c9118b96fc228 100644
--- a/base/java-tools/src/com/netscape/cmstools/cert/CertRequestSubmitCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/cert/CertRequestSubmitCLI.java
@@ -19,11 +19,15 @@ import com.netscape.cmstools.cli.MainCLI;
 
 public class CertRequestSubmitCLI extends CLI {
 
-    CertCLI parent;
+    CertCLI certCLI;
 
-    public CertRequestSubmitCLI(CertCLI parent) {
-        super("request-submit", "Submit certificate request");
-        this.parent = parent;
+    public CertRequestSubmitCLI(CertCLI certCLI) {
+        super("request-submit", "Submit certificate request", certCLI);
+        this.certCLI = certCLI;
+    }
+
+    public void printHelp() {
+        formatter.printHelp(getFullName() + " <filename>", options);
     }
 
     @Override
@@ -50,7 +54,7 @@ public class CertRequestSubmitCLI extends CLI {
 
         try {
             erd = getEnrollmentRequest(cLineArgs[0]);
-            CertRequestInfos cri = parent.client.enrollRequest(erd);
+            CertRequestInfos cri = certCLI.certClient.enrollRequest(erd);
             MainCLI.printMessage("Submitted certificate request");
             printRequestInformation(cri);
         } catch (FileNotFoundException e) {
@@ -78,8 +82,4 @@ public class CertRequestSubmitCLI extends CLI {
         }
         System.out.println();
     }
-
-    public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <filename>", options);
-    }
 }
diff --git a/base/java-tools/src/com/netscape/cmstools/cert/CertRevokeCLI.java b/base/java-tools/src/com/netscape/cmstools/cert/CertRevokeCLI.java
index 8727655f51373d7e34af38932ce487e5a509d0fa..49ec889e2771321440af34001e158c45ee9787fa 100644
--- a/base/java-tools/src/com/netscape/cmstools/cert/CertRevokeCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/cert/CertRevokeCLI.java
@@ -39,15 +39,15 @@ import com.netscape.cmstools.cli.MainCLI;
  */
 public class CertRevokeCLI extends CLI {
 
-    public CertCLI parent;
+    public CertCLI certCLI;
 
-    public CertRevokeCLI(CertCLI parent) {
-        super("revoke", "Revoke certificate");
-        this.parent = parent;
+    public CertRevokeCLI(CertCLI certCLI) {
+        super("revoke", "Revoke certificate", certCLI);
+        this.certCLI = certCLI;
     }
 
     public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <Serial Number> [OPTIONS...]", options);
+        formatter.printHelp(getFullName() + " <Serial Number> [OPTIONS...]", options);
     }
 
     public void execute(String[] args) throws Exception {
@@ -105,7 +105,7 @@ public class CertRevokeCLI extends CLI {
             return;
         }
 
-        CertData certData = parent.client.reviewCert(certID);
+        CertData certData = certCLI.certClient.reviewCert(certID);
 
         if (!cmd.hasOption("force")) {
 
@@ -138,9 +138,9 @@ public class CertRevokeCLI extends CLI {
         CertRequestInfo certRequestInfo;
 
         if (cmd.hasOption("ca")) {
-            certRequestInfo = parent.client.revokeCACert(certID, request);
+            certRequestInfo = certCLI.certClient.revokeCACert(certID, request);
         } else {
-            certRequestInfo = parent.client.revokeCert(certID, request);
+            certRequestInfo = certCLI.certClient.revokeCert(certID, request);
         }
 
         if (verbose) {
@@ -163,7 +163,7 @@ public class CertRevokeCLI extends CLI {
                     MainCLI.printMessage("Revoked certificate \"" + certID.toHexString() + "\"");
                 }
 
-                certData = parent.client.getCert(certID);
+                certData = certCLI.certClient.getCert(certID);
                 CertCLI.printCertData(certData, false, false);
             }
         } else {
diff --git a/base/java-tools/src/com/netscape/cmstools/cert/CertShowCLI.java b/base/java-tools/src/com/netscape/cmstools/cert/CertShowCLI.java
index 798514814efde6ecbd72333d4961d25bd7c781fa..d1d6132ae597baeb00ad124d1e96e9756e4f87b6 100644
--- a/base/java-tools/src/com/netscape/cmstools/cert/CertShowCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/cert/CertShowCLI.java
@@ -34,15 +34,15 @@ import com.netscape.cmstools.cli.MainCLI;
  */
 public class CertShowCLI extends CLI {
 
-    public CertCLI parent;
+    public CertCLI certCLI;
 
-    public CertShowCLI(CertCLI parent) {
-        super("show", "Show certificate");
-        this.parent = parent;
+    public CertShowCLI(CertCLI certCLI) {
+        super("show", "Show certificate", certCLI);
+        this.certCLI = certCLI;
     }
 
     public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <Serial Number> [OPTIONS...]", options);
+        formatter.printHelp(getFullName() + " <Serial Number> [OPTIONS...]", options);
     }
 
     public void execute(String[] args) throws Exception {
@@ -78,7 +78,7 @@ public class CertShowCLI extends CLI {
         CertId certID = new CertId(cmdArgs[0]);
         String file = cmd.getOptionValue("output");
 
-        CertData certData = parent.client.getCert(certID);
+        CertData certData = certCLI.certClient.getCert(certID);
 
         String encoded = certData.getEncoded();
         if (encoded != null && file != null) {
diff --git a/base/java-tools/src/com/netscape/cmstools/cli/CLI.java b/base/java-tools/src/com/netscape/cmstools/cli/CLI.java
index 40ac517af761e90789fe624598e466f5a9aa7b14..ecece0a09203b477e829d745da41f39a12c52509 100644
--- a/base/java-tools/src/com/netscape/cmstools/cli/CLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/cli/CLI.java
@@ -25,6 +25,9 @@ import org.apache.commons.cli.CommandLineParser;
 import org.apache.commons.cli.HelpFormatter;
 import org.apache.commons.cli.Options;
 import org.apache.commons.cli.PosixParser;
+import org.apache.commons.lang.StringUtils;
+
+import com.netscape.certsrv.client.PKIClient;
 
 
 /**
@@ -37,14 +40,15 @@ public class CLI {
     public static CommandLineParser parser = new PosixParser();
     public static HelpFormatter formatter = new HelpFormatter();
 
-    public CLI parent;
-
     public String name;
     public String description;
+    public CLI parent;
 
     public Options options = new Options();
     public Map<String, CLI> modules = new LinkedHashMap<String, CLI>();
 
+    public PKIClient client;
+
     public CLI(String name, String description) {
         this(name, description, null);
     }
@@ -87,10 +91,79 @@ public class CLI {
         return modules.get(name);
     }
 
-    public void execute(String[] args) throws Exception {
+    public PKIClient getClient() {
+        return client;
+    }
+
+    public Object getClient(String name) {
+        return null;
     }
 
     public void printHelp() {
+
+        System.out.println("Commands:");
+
+        int leftPadding = 1;
+        int rightPadding = 25;
+
+        for (CLI module : modules.values()) {
+            String label = getFullName() + "-" + module.getName();
+
+            int padding = rightPadding - leftPadding - label.length();
+            if (padding < 1)
+                padding = 1;
+
+            System.out.print(StringUtils.repeat(" ", leftPadding));
+            System.out.print(label);
+            System.out.print(StringUtils.repeat(" ", padding));
+            System.out.println(module.getDescription());
+        }
+    }
+
+    public void execute(String[] args) throws Exception {
+
+        if (args.length == 0) {
+            printHelp();
+            System.exit(1);
+        }
+
+        String command = args[0];
+        String moduleName;
+        String moduleCommand;
+
+        // If a command contains a '-' sign it will be
+        // split into module name and module command.
+        // Otherwise it's a single command.
+        int i = command.indexOf('-');
+        if (i >= 0) { // <module name>-<module command>
+            moduleName = command.substring(0, i);
+            moduleCommand = command.substring(i+1);
+
+        } else { // <command>
+            moduleName = command;
+            moduleCommand = null;
+        }
+
+        // get command module
+        if (verbose) System.out.println("Module: " + moduleName);
+        CLI module = getModule(moduleName);
+        if (module == null) {
+            throw new Error("Invalid module \"" + moduleName + "\".");
+        }
+
+        // prepare module arguments
+        String[] moduleArgs;
+        if (moduleCommand != null) {
+            moduleArgs = new String[args.length];
+            moduleArgs[0] = moduleCommand;
+            System.arraycopy(args, 1, moduleArgs, 1, args.length-1);
+
+        } else {
+            moduleArgs = new String[args.length-1];
+            System.arraycopy(args, 1, moduleArgs, 0, args.length-1);
+        }
+
+        module.execute(moduleArgs);
     }
 
     public static boolean isVerbose() {
diff --git a/base/java-tools/src/com/netscape/cmstools/cli/MainCLI.java b/base/java-tools/src/com/netscape/cmstools/cli/MainCLI.java
index 257f0bcfbd5418c2cc8332c13ce287fb7748817c..7625e2f47b34b2114a5537f46bdfbc96fe227a39 100644
--- a/base/java-tools/src/com/netscape/cmstools/cli/MainCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/cli/MainCLI.java
@@ -60,8 +60,6 @@ public class MainCLI extends CLI {
 
     public File certDatabase;
 
-    public PKIClient client;
-    public PKIConnection connection;
     public AccountClient accountClient;
 
     String output;
@@ -275,7 +273,7 @@ public class MainCLI extends CLI {
         client = new PKIClient(config);
         client.setVerbose(verbose);
 
-        connection = client.getConnection();
+        PKIConnection connection = client.getConnection();
         connection.setRejectedCertStatuses(rejectedCertStatuses);
         connection.setIgnoredCertStatuses(ignoredCertStatuses);
 
@@ -285,7 +283,12 @@ public class MainCLI extends CLI {
             connection.setOutput(file);
         }
 
-        accountClient = new AccountClient(client);
+        String subsystem = config.getSubsystem();
+        if (subsystem != null) {
+            // if server URI includes subsystem, perform authentication
+            // against that subsystem
+            accountClient = new AccountClient(client, subsystem);
+        }
     }
 
     public void execute(String[] args) throws Exception {
@@ -374,14 +377,13 @@ public class MainCLI extends CLI {
         if (verbose) System.out.println("Server URI: "+config.getServerURI());
 
         // execute command
-        boolean loggedIn = false;
         try {
             init();
 
-            // login if username or nickname is specified
-            if (config.getUsername() != null || config.getCertNickname() != null) {
+            // login if subsystem and username/nickname is specified
+            if (config.getSubsystem() != null &&
+                    (config.getUsername() != null || config.getCertNickname() != null)) {
                 accountClient.login();
-                loggedIn = true;
             }
 
             // execute module command
@@ -396,7 +398,8 @@ public class MainCLI extends CLI {
             System.exit(1);
 
         } finally {
-            if (loggedIn) accountClient.logout();
+            // logout if subsystem is specified
+            if (config.getSubsystem() != null) accountClient.logout();
         }
     }
 
diff --git a/base/java-tools/src/com/netscape/cmstools/user/UserRemoveMembershipCLI.java b/base/java-tools/src/com/netscape/cmstools/cli/SubsystemCLI.java
similarity index 52%
copy from base/java-tools/src/com/netscape/cmstools/user/UserRemoveMembershipCLI.java
copy to base/java-tools/src/com/netscape/cmstools/cli/SubsystemCLI.java
index 26a5a6eec5222b98718df1f5a524d364970ac3ed..310a4c29c5c394f3f2bae4e887f9322df54cde0d 100644
--- a/base/java-tools/src/com/netscape/cmstools/user/UserRemoveMembershipCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/cli/SubsystemCLI.java
@@ -16,39 +16,49 @@
 // All rights reserved.
 // --- END COPYRIGHT BLOCK ---
 
-package com.netscape.cmstools.user;
+package com.netscape.cmstools.cli;
+
+import com.netscape.certsrv.client.ClientConfig;
 
-import com.netscape.cmstools.cli.CLI;
-import com.netscape.cmstools.cli.MainCLI;
 
 /**
  * @author Endi S. Dewata
  */
-public class UserRemoveMembershipCLI extends CLI {
+public class SubsystemCLI extends CLI {
 
-    public UserCLI parent;
+    public SubsystemCLI(String name, String description, CLI parent) {
+        super(name, description, parent);
+    }
+
+    public String getFullName() {
+        // do not include parent's name
+        return name;
+    }
+
+    public void init() throws Exception {
+    }
 
-    public UserRemoveMembershipCLI(UserCLI parent) {
-        super("remove-membership", "Remove user membership");
-        this.parent = parent;
+    public void login() throws Exception {
     }
 
-    public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <User ID> <Group ID>", options);
+    public void logout() throws Exception {
     }
 
     public void execute(String[] args) throws Exception {
 
-        if (args.length != 2) {
-            printHelp();
-            System.exit(1);
+        init();
+
+        try {
+            // login if username or nickname is specified
+            ClientConfig config = getClient().getConfig();
+            if (config.getUsername() != null || config.getCertNickname() != null) {
+                login();
+            }
+
+            super.execute(args);
+
+        } finally {
+            logout();
         }
-
-        String userID = args[0];
-        String groupID = args[1];
-
-        parent.client.removeUserMembership(userID, groupID);
-
-        MainCLI.printMessage("Deleted membership in group \""+groupID+"\"");
     }
 }
diff --git a/base/java-tools/src/com/netscape/cmstools/cli/TPSCLI.java b/base/java-tools/src/com/netscape/cmstools/cli/TPSCLI.java
index 4dd7e208cd73894f7abecf487baeafb863c32f4c..1f10e959a31bed16a440d1867e4f0909ab98ccb5 100644
--- a/base/java-tools/src/com/netscape/cmstools/cli/TPSCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/cli/TPSCLI.java
@@ -18,92 +18,46 @@
 
 package com.netscape.cmstools.cli;
 
-import org.apache.commons.lang.StringUtils;
-
+import com.netscape.certsrv.client.Client;
 import com.netscape.certsrv.tps.TPSClient;
 import com.netscape.cmstools.token.TokenCLI;
 
 /**
  * @author Endi S. Dewata
  */
-public class TPSCLI extends CLI {
+public class TPSCLI extends SubsystemCLI {
 
-    public MainCLI mainCLI;
     public TPSClient tpsClient;
 
     public TPSCLI(MainCLI mainCLI) {
         super("tps", "TPS management commands", mainCLI);
-        this.mainCLI = mainCLI;
 
         addModule(new TokenCLI(this));
     }
 
-    public void printHelp() {
-
-        System.out.println("Commands:");
-
-        int leftPadding = 1;
-        int rightPadding = 25;
-
-        for (CLI module : modules.values()) {
-            String label = name + "-" + module.getName();
-
-            int padding = rightPadding - leftPadding - label.length();
-            if (padding < 1)
-                padding = 1;
-
-            System.out.print(StringUtils.repeat(" ", leftPadding));
-            System.out.print(label);
-            System.out.print(StringUtils.repeat(" ", padding));
-            System.out.println(module.getDescription());
-        }
-    }
-
-    public void execute(String[] args) throws Exception {
-
-        tpsClient = new TPSClient(mainCLI.client);
-
-        if (args.length == 0) {
-            printHelp();
-            System.exit(1);
-        }
-
-        String command = args[0];
-        String moduleName;
-        String moduleCommand;
-
-        // If a command contains a '-' sign it will be
-        // split into module name and module command.
-        // Otherwise it's a single command.
-        int i = command.indexOf('-');
-        if (i >= 0) { // <module name>-<module command>
-            moduleName = command.substring(0, i);
-            moduleCommand = command.substring(i+1);
-
-        } else { // <command>
-            moduleName = command;
-            moduleCommand = null;
-        }
-
-        // get command module
-        if (verbose) System.out.println("Module: " + moduleName);
-        CLI module = getModule(moduleName);
-        if (module == null) {
-            throw new Error("Invalid module \"" + moduleName + "\".");
-        }
-
-        // prepare module arguments
-        String[] moduleArgs;
-        if (moduleCommand != null) {
-            moduleArgs = new String[args.length];
-            moduleArgs[0] = moduleCommand;
-            System.arraycopy(args, 1, moduleArgs, 1, args.length-1);
-
+    public String getFullName() {
+        if (parent instanceof MainCLI) {
+            // do not include MainCLI's name
+            return name;
         } else {
-            moduleArgs = new String[args.length-1];
-            System.arraycopy(args, 1, moduleArgs, 0, args.length-1);
+            return parent.getFullName() + "-" + name;
         }
+    }
 
-        module.execute(moduleArgs);
+    public void init() throws Exception {
+        client = parent.getClient();
+        tpsClient = new TPSClient(client);
+    }
+
+    public void login() {
+        tpsClient.login();
+    }
+
+    public void logout() {
+        tpsClient.logout();
+    }
+
+    public Client getClient(String name) {
+        return tpsClient.getClient(name);
     }
 }
diff --git a/base/java-tools/src/com/netscape/cmstools/client/ClientCLI.java b/base/java-tools/src/com/netscape/cmstools/client/ClientCLI.java
index 34d09f33ca442d888285e00703c6016084ab76bc..1b54bff8d378d5ef6808f6251585e38d99df3eb7 100644
--- a/base/java-tools/src/com/netscape/cmstools/client/ClientCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/client/ClientCLI.java
@@ -20,7 +20,6 @@ package com.netscape.cmstools.client;
 
 import java.util.Arrays;
 
-import org.apache.commons.lang.StringUtils;
 import org.mozilla.jss.crypto.X509Certificate;
 
 import com.netscape.certsrv.dbs.certdb.CertId;
@@ -32,40 +31,27 @@ import com.netscape.cmstools.cli.MainCLI;
  */
 public class ClientCLI extends CLI {
 
-    public MainCLI parent;
-
-    public ClientCLI(MainCLI parent) {
-        super("client", "Client management commands");
-        this.parent = parent;
+    public ClientCLI(CLI parent) {
+        super("client", "Client management commands", parent);
 
         addModule(new ClientFindCertCLI(this));
         addModule(new ClientImportCertCLI(this));
         addModule(new ClientRemoveCertCLI(this));
     }
 
-    public void printHelp() {
-
-        System.out.println("Commands:");
-
-        int leftPadding = 1;
-        int rightPadding = 25;
-
-        for (CLI module : modules.values()) {
-            String label = name + "-" + module.getName();
-
-            int padding = rightPadding - leftPadding - label.length();
-            if (padding < 1)
-                padding = 1;
-
-            System.out.print(StringUtils.repeat(" ", leftPadding));
-            System.out.print(label);
-            System.out.print(StringUtils.repeat(" ", padding));
-            System.out.println(module.getDescription());
+    public String getFullName() {
+        if (parent instanceof MainCLI) {
+            // do not include MainCLI's name
+            return name;
+        } else {
+            return parent.getFullName() + "-" + name;
         }
     }
 
     public void execute(String[] args) throws Exception {
 
+        client = parent.getClient();
+
         if (args.length == 0) {
             printHelp();
             System.exit(1);
diff --git a/base/java-tools/src/com/netscape/cmstools/client/ClientFindCertCLI.java b/base/java-tools/src/com/netscape/cmstools/client/ClientFindCertCLI.java
index 80690b7d09874740ee96b818a6c9258eee067565..f4057c67a66c0d5c2266fb35223db3623d5e2a18 100644
--- a/base/java-tools/src/com/netscape/cmstools/client/ClientFindCertCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/client/ClientFindCertCLI.java
@@ -29,19 +29,21 @@ import com.netscape.cmstools.cli.MainCLI;
  */
 public class ClientFindCertCLI extends CLI {
 
-    public ClientCLI parent;
+    public ClientCLI clientCLI;
 
-    public ClientFindCertCLI(ClientCLI parent) {
-        super("find-cert", "Find certificates in client security database");
-        this.parent = parent;
+    public ClientFindCertCLI(ClientCLI clientCLI) {
+        super("find-cert", "Find certificates in client security database", clientCLI);
+        this.clientCLI = clientCLI;
     }
 
     public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " [OPTIONS]", options);
+        formatter.printHelp(getFullName() + " [OPTIONS]", options);
     }
 
     public void execute(String[] args) throws Exception {
 
+        client = clientCLI.getClient();
+
         options.addOption(null, "ca", false, "Find CA certificates only");
 
         CommandLine cmd = null;
@@ -56,9 +58,9 @@ public class ClientFindCertCLI extends CLI {
 
         X509Certificate[] certs;
         if (cmd.hasOption("ca")) {
-            certs = parent.parent.client.getCACerts();
+            certs = client.getCACerts();
         } else {
-            certs = parent.parent.client.getCerts();
+            certs = client.getCerts();
         }
 
         if (certs == null || certs.length == 0) {
diff --git a/base/java-tools/src/com/netscape/cmstools/client/ClientImportCertCLI.java b/base/java-tools/src/com/netscape/cmstools/client/ClientImportCertCLI.java
index e89f954bb5fc4a4b54cd811d730d82a217e00b27..cbd55079a9b5fa194b7257f567be032976007d8b 100644
--- a/base/java-tools/src/com/netscape/cmstools/client/ClientImportCertCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/client/ClientImportCertCLI.java
@@ -34,19 +34,21 @@ import com.netscape.cmstools.cli.MainCLI;
  */
 public class ClientImportCertCLI extends CLI {
 
-    public ClientCLI parent;
+    public ClientCLI clientCLI;
 
-    public ClientImportCertCLI(ClientCLI parent) {
-        super("import-cert", "Import certificate into client security database");
-        this.parent = parent;
+    public ClientImportCertCLI(ClientCLI clientCLI) {
+        super("import-cert", "Import certificate into client security database", clientCLI);
+        this.clientCLI = clientCLI;
     }
 
     public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " [OPTIONS]", options);
+        formatter.printHelp(getFullName() + " [OPTIONS]", options);
     }
 
     public void execute(String[] args) throws Exception {
 
+        client = clientCLI.getClient();
+
         Option option = new Option(null, "cert", true, "Import certificate file");
         option.setArgName("path");
         options.addOption(option);
@@ -90,11 +92,11 @@ public class ClientImportCertCLI extends CLI {
             isCACert = true;
 
         } else if (importFromCAServer) {
-            ClientConfig config = parent.parent.config;
+            ClientConfig config = client.getConfig();
             String caServerURI = "http://" + config.getServerURI().getHost() + ":8080/ca";
 
             if (verbose) System.out.println("Downloading CA certificate from " + caServerURI + ".");
-            bytes = parent.parent.client.downloadCACertChain(caServerURI);
+            bytes = client.downloadCACertChain(caServerURI);
 
             isCACert = true;
 
@@ -107,11 +109,11 @@ public class ClientImportCertCLI extends CLI {
         // import the certificate
         if (isCACert) {
             if (verbose) System.out.println("Importing CA certificate.");
-            cert = parent.parent.client.importCACertPackage(bytes);
+            cert = client.importCACertPackage(bytes);
 
         } else {
             if (verbose) System.out.println("Importing certificate.");
-            cert = parent.parent.client.importCertPackage(bytes, parent.parent.client.config.getCertNickname());
+            cert = client.importCertPackage(bytes, client.config.getCertNickname());
         }
 
         MainCLI.printMessage("Imported certificate \"" + cert.getNickname() + "\"");
diff --git a/base/java-tools/src/com/netscape/cmstools/client/ClientRemoveCertCLI.java b/base/java-tools/src/com/netscape/cmstools/client/ClientRemoveCertCLI.java
index fab4296314243c21ad6f718452d357c4dec1799f..be4456115f05df7947803893438132e81d1dcf94 100644
--- a/base/java-tools/src/com/netscape/cmstools/client/ClientRemoveCertCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/client/ClientRemoveCertCLI.java
@@ -28,15 +28,15 @@ import com.netscape.cmstools.cli.MainCLI;
  */
 public class ClientRemoveCertCLI extends CLI {
 
-    public ClientCLI parent;
+    public ClientCLI clientCLI;
 
-    public ClientRemoveCertCLI(ClientCLI parent) {
-        super("remove-cert", "Remove certificate from client security database");
-        this.parent = parent;
+    public ClientRemoveCertCLI(ClientCLI clientCLI) {
+        super("remove-cert", "Remove certificate from client security database", clientCLI);
+        this.clientCLI = clientCLI;
     }
 
     public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <nickname>", options);
+        formatter.printHelp(getFullName() + " <nickname>", options);
     }
 
     public void execute(String[] args) throws Exception {
@@ -58,8 +58,10 @@ public class ClientRemoveCertCLI extends CLI {
             System.exit(1);
         }
 
+        client = clientCLI.getClient();
+
         String nickname = cmdArgs[0];
-        parent.parent.client.removeCert(nickname);
+        client.removeCert(nickname);
 
         MainCLI.printMessage("Removed certificate \"" + nickname + "\"");
    }
diff --git a/base/java-tools/src/com/netscape/cmstools/group/GroupAddCLI.java b/base/java-tools/src/com/netscape/cmstools/group/GroupAddCLI.java
index b4814fbcc378be55575ec06132a493d9a1c64cfb..a29ce62ef048750c79f7768ed89e62dfc7d198ff 100644
--- a/base/java-tools/src/com/netscape/cmstools/group/GroupAddCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/group/GroupAddCLI.java
@@ -30,15 +30,15 @@ import com.netscape.cmstools.cli.MainCLI;
  */
 public class GroupAddCLI extends CLI {
 
-    public GroupCLI parent;
+    public GroupCLI groupCLI;
 
-    public GroupAddCLI(GroupCLI parent) {
-        super("add", "Add group");
-        this.parent = parent;
+    public GroupAddCLI(GroupCLI groupCLI) {
+        super("add", "Add group", groupCLI);
+        this.groupCLI = groupCLI;
     }
 
     public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <Group ID> [OPTIONS...]", options);
+        formatter.printHelp(getFullName() + " <Group ID> [OPTIONS...]", options);
     }
 
     public void execute(String[] args) throws Exception {
@@ -72,7 +72,7 @@ public class GroupAddCLI extends CLI {
         groupData.setID(groupID);
         groupData.setDescription(cmd.getOptionValue("description"));
 
-        groupData = parent.client.addGroup(groupData);
+        groupData = groupCLI.groupClient.addGroup(groupData);
 
         MainCLI.printMessage("Added group \""+groupID+"\"");
 
diff --git a/base/java-tools/src/com/netscape/cmstools/group/GroupAddMemberCLI.java b/base/java-tools/src/com/netscape/cmstools/group/GroupAddMemberCLI.java
index 36d3c06fd2f87f860ac26b1d5a5fb83960187059..eb2f9bedefe29ed5f57a143ce91b36b1b01a16a2 100644
--- a/base/java-tools/src/com/netscape/cmstools/group/GroupAddMemberCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/group/GroupAddMemberCLI.java
@@ -27,15 +27,15 @@ import com.netscape.cmstools.cli.MainCLI;
  */
 public class GroupAddMemberCLI extends CLI {
 
-    public GroupCLI parent;
+    public GroupCLI groupCLI;
 
-    public GroupAddMemberCLI(GroupCLI parent) {
-        super("add-member", "Add group member");
-        this.parent = parent;
+    public GroupAddMemberCLI(GroupCLI groupCLI) {
+        super("add-member", "Add group member", groupCLI);
+        this.groupCLI = groupCLI;
     }
 
     public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <Group ID> <Member ID>", options);
+        formatter.printHelp(getFullName() + " <Group ID> <Member ID>", options);
     }
 
     public void execute(String[] args) throws Exception {
@@ -48,7 +48,7 @@ public class GroupAddMemberCLI extends CLI {
         String groupID = args[0];
         String memberID = args[1];
 
-        GroupMemberData groupMemberData = parent.client.addGroupMember(groupID, memberID);
+        GroupMemberData groupMemberData = groupCLI.groupClient.addGroupMember(groupID, memberID);
 
         MainCLI.printMessage("Added group member \""+memberID+"\"");
 
diff --git a/base/java-tools/src/com/netscape/cmstools/group/GroupCLI.java b/base/java-tools/src/com/netscape/cmstools/group/GroupCLI.java
index bd8cec7735f8802328d99ae07cbbda3bdbfd8637..d691c432b569de11c03470dde9e816633b90f435 100644
--- a/base/java-tools/src/com/netscape/cmstools/group/GroupCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/group/GroupCLI.java
@@ -34,12 +34,10 @@ import com.netscape.cmstools.cli.MainCLI;
  */
 public class GroupCLI extends CLI {
 
-    public MainCLI parent;
-    public GroupClient client;
+    public GroupClient groupClient;
 
-    public GroupCLI(MainCLI parent) {
-        super("group", "Group management commands");
-        this.parent = parent;
+    public GroupCLI(CLI parent) {
+        super("group", "Group management commands", parent);
 
         addModule(new GroupFindCLI(this));
         addModule(new GroupShowCLI(this));
@@ -53,29 +51,19 @@ public class GroupCLI extends CLI {
         addModule(new GroupRemoveMemberCLI(this));
     }
 
-    public void printHelp() {
-
-        System.out.println("Commands:");
-
-        int leftPadding = 1;
-        int rightPadding = 25;
-
-        for (CLI module : modules.values()) {
-            String label = name+"-"+module.getName();
-
-            int padding = rightPadding - leftPadding - label.length();
-            if (padding < 1) padding = 1;
-
-            System.out.print(StringUtils.repeat(" ", leftPadding));
-            System.out.print(label);
-            System.out.print(StringUtils.repeat(" ", padding));
-            System.out.println(module.getDescription());
+    public String getFullName() {
+        if (parent instanceof MainCLI) {
+            // do not include MainCLI's name
+            return name;
+        } else {
+            return parent.getFullName() + "-" + name;
         }
     }
 
     public void execute(String[] args) throws Exception {
 
-        client = new GroupClient(parent.client);
+        client = parent.getClient();
+        groupClient = new GroupClient(client);
 
         if (args.length == 0) {
             printHelp();
diff --git a/base/java-tools/src/com/netscape/cmstools/group/GroupFindCLI.java b/base/java-tools/src/com/netscape/cmstools/group/GroupFindCLI.java
index 272e3a8fda0e4c1b2e5610d5b37e089f61e79f2a..7c2361da325841b77fcdcccd0210a8c161511cd2 100644
--- a/base/java-tools/src/com/netscape/cmstools/group/GroupFindCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/group/GroupFindCLI.java
@@ -33,15 +33,15 @@ import com.netscape.cmstools.cli.MainCLI;
  */
 public class GroupFindCLI extends CLI {
 
-    public GroupCLI parent;
+    public GroupCLI groupCLI;
 
-    public GroupFindCLI(GroupCLI parent) {
-        super("find", "Find groups");
-        this.parent = parent;
+    public GroupFindCLI(GroupCLI groupCLI) {
+        super("find", "Find groups", groupCLI);
+        this.groupCLI = groupCLI;
     }
 
     public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " [FILTER] [OPTIONS...]", options);
+        formatter.printHelp(getFullName() + " [FILTER] [OPTIONS...]", options);
     }
 
     public void execute(String[] args) throws Exception {
@@ -74,7 +74,7 @@ public class GroupFindCLI extends CLI {
         s = cmd.getOptionValue("size");
         Integer size = s == null ? null : Integer.valueOf(s);
 
-        GroupCollection response = parent.client.findGroups(filter, start, size);
+        GroupCollection response = groupCLI.groupClient.findGroups(filter, start, size);
 
         Collection<GroupData> entries = response.getGroups();
 
diff --git a/base/java-tools/src/com/netscape/cmstools/group/GroupFindMemberCLI.java b/base/java-tools/src/com/netscape/cmstools/group/GroupFindMemberCLI.java
index f0498f0d274227b8b0835a5d6e9895cc32c4f079..383e547f31a6656f071d88edbc471b4ab501ee9b 100644
--- a/base/java-tools/src/com/netscape/cmstools/group/GroupFindMemberCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/group/GroupFindMemberCLI.java
@@ -33,15 +33,15 @@ import com.netscape.cmstools.cli.MainCLI;
  */
 public class GroupFindMemberCLI extends CLI {
 
-    public GroupCLI parent;
+    public GroupCLI groupCLI;
 
-    public GroupFindMemberCLI(GroupCLI parent) {
-        super("find-member", "Find group members");
-        this.parent = parent;
+    public GroupFindMemberCLI(GroupCLI groupCLI) {
+        super("find-member", "Find group members", groupCLI);
+        this.groupCLI = groupCLI;
     }
 
     public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <Group ID> [OPTIONS...]", options);
+        formatter.printHelp(getFullName() + " <Group ID> [OPTIONS...]", options);
     }
 
     public void execute(String[] args) throws Exception {
@@ -80,7 +80,7 @@ public class GroupFindMemberCLI extends CLI {
         s = cmd.getOptionValue("size");
         Integer size = s == null ? null : Integer.valueOf(s);
 
-        GroupMemberCollection response = parent.client.findGroupMembers(groupID, start, size);
+        GroupMemberCollection response = groupCLI.groupClient.findGroupMembers(groupID, start, size);
 
         Collection<GroupMemberData> entries = response.getMembers();
 
diff --git a/base/java-tools/src/com/netscape/cmstools/group/GroupModifyCLI.java b/base/java-tools/src/com/netscape/cmstools/group/GroupModifyCLI.java
index 2869ce19df1007309871c00a62210736e0da9bb1..b0974d3251356178daed45e8914236589142e233 100644
--- a/base/java-tools/src/com/netscape/cmstools/group/GroupModifyCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/group/GroupModifyCLI.java
@@ -30,15 +30,15 @@ import com.netscape.cmstools.cli.MainCLI;
  */
 public class GroupModifyCLI extends CLI {
 
-    public GroupCLI parent;
+    public GroupCLI groupCLI;
 
-    public GroupModifyCLI(GroupCLI parent) {
-        super("mod", "Modify group");
-        this.parent = parent;
+    public GroupModifyCLI(GroupCLI groupCLI) {
+        super("mod", "Modify group", groupCLI);
+        this.groupCLI = groupCLI;
     }
 
     public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <Group ID> [OPTIONS...]", options);
+        formatter.printHelp(getFullName() + " <Group ID> [OPTIONS...]", options);
     }
 
     public void execute(String[] args) throws Exception {
@@ -71,7 +71,7 @@ public class GroupModifyCLI extends CLI {
         groupData.setID(groupID);
         groupData.setDescription(cmd.getOptionValue("description"));
 
-        groupData = parent.client.modifyGroup(groupID, groupData);
+        groupData = groupCLI.groupClient.modifyGroup(groupID, groupData);
 
         MainCLI.printMessage("Modified group \""+groupID+"\"");
 
diff --git a/base/java-tools/src/com/netscape/cmstools/group/GroupRemoveCLI.java b/base/java-tools/src/com/netscape/cmstools/group/GroupRemoveCLI.java
index fd9c08893d9d28ac38027b1be9da0c6466c1291b..cc64ed8412952cef995c3a24321a4f940458064c 100644
--- a/base/java-tools/src/com/netscape/cmstools/group/GroupRemoveCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/group/GroupRemoveCLI.java
@@ -27,15 +27,15 @@ import com.netscape.cmstools.cli.MainCLI;
  */
 public class GroupRemoveCLI extends CLI {
 
-    public GroupCLI parent;
+    public GroupCLI groupCLI;
 
-    public GroupRemoveCLI(GroupCLI parent) {
-        super("del", "Remove group");
-        this.parent = parent;
+    public GroupRemoveCLI(GroupCLI groupCLI) {
+        super("del", "Remove group", groupCLI);
+        this.groupCLI = groupCLI;
     }
 
     public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <Group ID>", options);
+        formatter.printHelp(getFullName() + " <Group ID>", options);
     }
 
     public void execute(String[] args) throws Exception {
@@ -47,7 +47,7 @@ public class GroupRemoveCLI extends CLI {
 
         String groupID = args[0];
 
-        parent.client.removeGroup(groupID);
+        groupCLI.groupClient.removeGroup(groupID);
 
         MainCLI.printMessage("Deleted group \""+groupID+"\"");
     }
diff --git a/base/java-tools/src/com/netscape/cmstools/group/GroupRemoveMemberCLI.java b/base/java-tools/src/com/netscape/cmstools/group/GroupRemoveMemberCLI.java
index c12cc892e5d0f0fdef107571c51c7b4b0a8c7d02..ef348404586997cc9f4b9d52e3afc22bd7852699 100644
--- a/base/java-tools/src/com/netscape/cmstools/group/GroupRemoveMemberCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/group/GroupRemoveMemberCLI.java
@@ -26,15 +26,15 @@ import com.netscape.cmstools.cli.MainCLI;
  */
 public class GroupRemoveMemberCLI extends CLI {
 
-    public GroupCLI parent;
+    public GroupCLI groupCLI;
 
-    public GroupRemoveMemberCLI(GroupCLI parent) {
-        super("remove-member", "Remove group member");
-        this.parent = parent;
+    public GroupRemoveMemberCLI(GroupCLI groupCLI) {
+        super("remove-member", "Remove group member", groupCLI);
+        this.groupCLI = groupCLI;
     }
 
     public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <Group ID> <Member ID>", options);
+        formatter.printHelp(getFullName() + " <Group ID> <Member ID>", options);
     }
 
     public void execute(String[] args) throws Exception {
@@ -47,7 +47,7 @@ public class GroupRemoveMemberCLI extends CLI {
         String groupID = args[0];
         String memberID = args[1];
 
-        parent.client.removeGroupMember(groupID, memberID);
+        groupCLI.groupClient.removeGroupMember(groupID, memberID);
 
         MainCLI.printMessage("Deleted group member \""+memberID+"\"");
     }
diff --git a/base/java-tools/src/com/netscape/cmstools/group/GroupShowCLI.java b/base/java-tools/src/com/netscape/cmstools/group/GroupShowCLI.java
index 4e8e444210e1978ac711768af0707fa79569c227..c25306a271ed7a3aeb68d92d6a57ae676eba47a2 100644
--- a/base/java-tools/src/com/netscape/cmstools/group/GroupShowCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/group/GroupShowCLI.java
@@ -27,15 +27,15 @@ import com.netscape.cmstools.cli.MainCLI;
  */
 public class GroupShowCLI extends CLI {
 
-    public GroupCLI parent;
+    public GroupCLI groupCLI;
 
-    public GroupShowCLI(GroupCLI parent) {
-        super("show", "Show group");
-        this.parent = parent;
+    public GroupShowCLI(GroupCLI groupCLI) {
+        super("show", "Show group", groupCLI);
+        this.groupCLI = groupCLI;
     }
 
     public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <Group ID>", options);
+        formatter.printHelp(getFullName() + " <Group ID>", options);
     }
 
     public void execute(String[] args) throws Exception {
@@ -47,7 +47,7 @@ public class GroupShowCLI extends CLI {
 
         String groupID = args[0];
 
-        GroupData groupData = parent.client.getGroup(groupID);
+        GroupData groupData = groupCLI.groupClient.getGroup(groupID);
 
         MainCLI.printMessage("Group \""+groupID+"\"");
 
diff --git a/base/java-tools/src/com/netscape/cmstools/group/GroupShowMemberCLI.java b/base/java-tools/src/com/netscape/cmstools/group/GroupShowMemberCLI.java
index 47ca43c8f1a8d42a6261001c6b5d62cdc4240329..2f50a6a080bd8a22b485316779ac05a02447e220 100644
--- a/base/java-tools/src/com/netscape/cmstools/group/GroupShowMemberCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/group/GroupShowMemberCLI.java
@@ -27,15 +27,15 @@ import com.netscape.cmstools.cli.MainCLI;
  */
 public class GroupShowMemberCLI extends CLI {
 
-    public GroupCLI parent;
+    public GroupCLI groupCLI;
 
-    public GroupShowMemberCLI(GroupCLI parent) {
-        super("show-member", "Show group member");
-        this.parent = parent;
+    public GroupShowMemberCLI(GroupCLI groupCLI) {
+        super("show-member", "Show group member", groupCLI);
+        this.groupCLI = groupCLI;
     }
 
     public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <Group ID> <Member ID>", options);
+        formatter.printHelp(getFullName() + " <Group ID> <Member ID>", options);
     }
 
     public void execute(String[] args) throws Exception {
@@ -48,7 +48,7 @@ public class GroupShowMemberCLI extends CLI {
         String groupID = args[0];
         String memberID = args[1];
 
-        GroupMemberData groupMemberData = parent.client.getGroupMember(groupID, memberID);
+        GroupMemberData groupMemberData = groupCLI.groupClient.getGroupMember(groupID, memberID);
 
         MainCLI.printMessage("Group member \""+memberID+"\"");
 
diff --git a/base/java-tools/src/com/netscape/cmstools/key/KeyCLI.java b/base/java-tools/src/com/netscape/cmstools/key/KeyCLI.java
index 0d239624329c4c66cd56b28b00babeb81fdc11ea..de52613eef2db6ff015a7a3f03ec2b32ff506567 100644
--- a/base/java-tools/src/com/netscape/cmstools/key/KeyCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/key/KeyCLI.java
@@ -20,8 +20,6 @@ package com.netscape.cmstools.key;
 
 import java.util.Arrays;
 
-import org.apache.commons.lang.StringUtils;
-
 import com.netscape.certsrv.key.KeyClient;
 import com.netscape.certsrv.key.KeyDataInfo;
 import com.netscape.certsrv.key.KeyRequestInfo;
@@ -33,41 +31,28 @@ import com.netscape.cmstools.cli.MainCLI;
  */
 public class KeyCLI extends CLI {
 
-    public MainCLI parent;
     public KeyClient keyClient;
 
-    public KeyCLI(MainCLI parent) {
-        super("key", "Key management commands");
-        this.parent = parent;
+    public KeyCLI(CLI parent) {
+        super("key", "Key management commands", parent);
 
         addModule(new KeyFindCLI(this));
         addModule(new KeyRequestFindCLI(this));
     }
 
-    public void printHelp() {
-
-        System.out.println("Commands:");
-
-        int leftPadding = 1;
-        int rightPadding = 25;
-
-        for (CLI module : modules.values()) {
-            String label = name + "-" + module.getName();
-
-            int padding = rightPadding - leftPadding - label.length();
-            if (padding < 1)
-                padding = 1;
-
-            System.out.print(StringUtils.repeat(" ", leftPadding));
-            System.out.print(label);
-            System.out.print(StringUtils.repeat(" ", padding));
-            System.out.println(module.getDescription());
+    public String getFullName() {
+        if (parent instanceof MainCLI) {
+            // do not include MainCLI's name
+            return name;
+        } else {
+            return parent.getFullName() + "-" + name;
         }
     }
 
     public void execute(String[] args) throws Exception {
 
-        keyClient = new KeyClient(parent.client);
+        client = parent.getClient();
+        keyClient = new KeyClient(client);
 
         if (args.length == 0) {
             printHelp();
diff --git a/base/java-tools/src/com/netscape/cmstools/key/KeyFindCLI.java b/base/java-tools/src/com/netscape/cmstools/key/KeyFindCLI.java
index 014a9b60e3067cf32eb89793554accb8ca590166..9a91f37e2b4bf8f4a78670a1aa2cfc5aa0b10bde 100644
--- a/base/java-tools/src/com/netscape/cmstools/key/KeyFindCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/key/KeyFindCLI.java
@@ -34,15 +34,15 @@ import com.netscape.cmstools.cli.MainCLI;
  */
 public class KeyFindCLI extends CLI {
 
-    public KeyCLI parent;
+    public KeyCLI keyCLI;
 
-    public KeyFindCLI(KeyCLI parent) {
-        super("find", "Find keys");
-        this.parent = parent;
+    public KeyFindCLI(KeyCLI keyCLI) {
+        super("find", "Find keys", keyCLI);
+        this.keyCLI = keyCLI;
     }
 
     public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " [OPTIONS...]", options);
+        formatter.printHelp(getFullName() + " [OPTIONS...]", options);
     }
 
     public void execute(String[] args) {
@@ -83,7 +83,7 @@ public class KeyFindCLI extends CLI {
         s = cmd.getOptionValue("maxTime");
         Integer maxTime = s == null ? null : Integer.valueOf(s);
 
-        KeyDataInfos keys = parent.keyClient.findKeys(clientID, status, maxResults, maxTime);
+        KeyDataInfos keys = keyCLI.keyClient.findKeys(clientID, status, maxResults, maxTime);
 
         Collection<KeyDataInfo> entries = keys.getKeyInfos();
 
diff --git a/base/java-tools/src/com/netscape/cmstools/key/KeyRequestFindCLI.java b/base/java-tools/src/com/netscape/cmstools/key/KeyRequestFindCLI.java
index 83ce4231837f205375c2da5ebfce82876e811a70..14770efdb59db75c329e327fb5a5ce39fd14aac9 100644
--- a/base/java-tools/src/com/netscape/cmstools/key/KeyRequestFindCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/key/KeyRequestFindCLI.java
@@ -35,15 +35,15 @@ import com.netscape.cmstools.cli.MainCLI;
  */
 public class KeyRequestFindCLI extends CLI {
 
-    public KeyCLI parent;
+    public KeyCLI keyCLI;
 
-    public KeyRequestFindCLI(KeyCLI parent) {
-        super("request-find", "Find key requests");
-        this.parent = parent;
+    public KeyRequestFindCLI(KeyCLI keyCLI) {
+        super("request-find", "Find key requests", keyCLI);
+        this.keyCLI = keyCLI;
     }
 
     public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " [OPTIONS...]", options);
+        formatter.printHelp(getFullName() + " [OPTIONS...]", options);
     }
 
     public void execute(String[] args) {
@@ -95,7 +95,7 @@ public class KeyRequestFindCLI extends CLI {
         s = cmd.getOptionValue("maxTime");
         Integer maxTime = s == null ? null : Integer.valueOf(s);
 
-        KeyRequestInfos keys = parent.keyClient.findKeyRequests(
+        KeyRequestInfos keys = keyCLI.keyClient.findKeyRequests(
                 status, type, clientID, start, pageSize, maxResults, maxTime);
 
         Collection<KeyRequestInfo> entries = keys.getRequests();
diff --git a/base/java-tools/src/com/netscape/cmstools/profile/ProfileAddCLI.java b/base/java-tools/src/com/netscape/cmstools/profile/ProfileAddCLI.java
index 2c30fdbd7cb693d556600061abc712acdc2439ba..17f7998f9aa8a9ef12ed131bdc6c40f97a08fd8c 100644
--- a/base/java-tools/src/com/netscape/cmstools/profile/ProfileAddCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/profile/ProfileAddCLI.java
@@ -12,15 +12,16 @@ import com.netscape.cmstools.cli.CLI;
 import com.netscape.cmstools.cli.MainCLI;
 
 public class ProfileAddCLI extends CLI {
-    public ProfileCLI parent;
 
-    public ProfileAddCLI(ProfileCLI parent) {
-        super("add", "Add profiles");
-        this.parent = parent;
+    public ProfileCLI profileCLI;
+
+    public ProfileAddCLI(ProfileCLI profileCLI) {
+        super("add", "Add profiles", profileCLI);
+        this.profileCLI = profileCLI;
     }
 
     public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <file>", options);
+        formatter.printHelp(getFullName() + " <file>", options);
     }
 
     public void execute(String[] args) {
@@ -50,7 +51,7 @@ public class ProfileAddCLI extends CLI {
 
         try {
             ProfileData data = ProfileCLI.readProfileFromFile(filename);
-            parent.client.createProfile(data);
+            profileCLI.profileClient.createProfile(data);
             MainCLI.printMessage("Added profile " + data.getId());
         } catch (FileNotFoundException | JAXBException  e) {
             System.err.println("Error: " + e.getMessage());
diff --git a/base/java-tools/src/com/netscape/cmstools/profile/ProfileCLI.java b/base/java-tools/src/com/netscape/cmstools/profile/ProfileCLI.java
index ba41a3da1c3fee1957dcd816e2a21d2a0eceafd4..59f63c7e9f2109a52978f6e11d8e6f534c576bdd 100644
--- a/base/java-tools/src/com/netscape/cmstools/profile/ProfileCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/profile/ProfileCLI.java
@@ -12,8 +12,6 @@ import javax.xml.bind.JAXBException;
 import javax.xml.bind.Marshaller;
 import javax.xml.bind.Unmarshaller;
 
-import org.apache.commons.lang.StringUtils;
-
 import com.netscape.certsrv.profile.ProfileAttribute;
 import com.netscape.certsrv.profile.ProfileClient;
 import com.netscape.certsrv.profile.ProfileData;
@@ -24,12 +22,11 @@ import com.netscape.cmstools.cli.CLI;
 import com.netscape.cmstools.cli.MainCLI;
 
 public class ProfileCLI extends CLI {
-    public MainCLI parent;
-    public ProfileClient client;
 
-    public ProfileCLI(MainCLI parent) {
-        super("profile", "Profile management commands");
-        this.parent = parent;
+    public ProfileClient profileClient;
+
+    public ProfileCLI(CLI parent) {
+        super("profile", "Profile management commands", parent);
 
         addModule(new ProfileFindCLI(this));
         addModule(new ProfileShowCLI(this));
@@ -40,30 +37,19 @@ public class ProfileCLI extends CLI {
         addModule(new ProfileDisableCLI(this));
     }
 
-    public void printHelp() {
-
-        System.out.println("Commands:");
-
-        int leftPadding = 1;
-        int rightPadding = 25;
-
-        for (CLI module : modules.values()) {
-            String label = name + "-" + module.getName();
-
-            int padding = rightPadding - leftPadding - label.length();
-            if (padding < 1)
-                padding = 1;
-
-            System.out.print(StringUtils.repeat(" ", leftPadding));
-            System.out.print(label);
-            System.out.print(StringUtils.repeat(" ", padding));
-            System.out.println(module.getDescription());
+    public String getFullName() {
+        if (parent instanceof MainCLI) {
+            // do not include MainCLI's name
+            return name;
+        } else {
+            return parent.getFullName() + "-" + name;
         }
     }
 
     public void execute(String[] args) throws Exception {
 
-        client = new ProfileClient(parent.client);
+        client = parent.getClient();
+        profileClient = new ProfileClient(client);
 
         if (args.length == 0) {
             printHelp();
diff --git a/base/java-tools/src/com/netscape/cmstools/profile/ProfileDisableCLI.java b/base/java-tools/src/com/netscape/cmstools/profile/ProfileDisableCLI.java
index 0279cf36a879accd885c6aa3834f9e89fe8e71c1..4fc640d75f4f9ecf7eac8422faba50530010209b 100644
--- a/base/java-tools/src/com/netscape/cmstools/profile/ProfileDisableCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/profile/ProfileDisableCLI.java
@@ -5,15 +5,15 @@ import com.netscape.cmstools.cli.MainCLI;
 
 public class ProfileDisableCLI extends CLI {
 
-    public ProfileCLI parent;
+    public ProfileCLI profileCLI;
 
-    public ProfileDisableCLI(ProfileCLI parent) {
-        super("disable", "Disable profiles");
-        this.parent = parent;
+    public ProfileDisableCLI(ProfileCLI profileCLI) {
+        super("disable", "Disable profiles", profileCLI);
+        this.profileCLI = profileCLI;
     }
 
     public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <profile_id>", options);
+        formatter.printHelp(getFullName() + " <Profile ID>", options);
     }
 
     public void execute(String[] args) throws Exception {
@@ -25,7 +25,7 @@ public class ProfileDisableCLI extends CLI {
 
         String profileId = args[0];
 
-        parent.client.disableProfile(profileId);
+        profileCLI.profileClient.disableProfile(profileId);
 
         MainCLI.printMessage("Disabled profile \"" + profileId + "\"");
     }
diff --git a/base/java-tools/src/com/netscape/cmstools/profile/ProfileEnableCLI.java b/base/java-tools/src/com/netscape/cmstools/profile/ProfileEnableCLI.java
index 727e49b0ac429f38f3b5336e17214bdcb3027e9a..88c96c52b6de6ab389ef52a829c76c1c037555b0 100644
--- a/base/java-tools/src/com/netscape/cmstools/profile/ProfileEnableCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/profile/ProfileEnableCLI.java
@@ -5,15 +5,15 @@ import com.netscape.cmstools.cli.MainCLI;
 
 public class ProfileEnableCLI extends CLI {
 
-    public ProfileCLI parent;
+    public ProfileCLI profileCLI;
 
-    public ProfileEnableCLI(ProfileCLI parent) {
-        super("enable", "Enable profiles");
-        this.parent = parent;
+    public ProfileEnableCLI(ProfileCLI profileCLI) {
+        super("enable", "Enable profiles", profileCLI);
+        this.profileCLI = profileCLI;
     }
 
     public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <profile_id>", options);
+        formatter.printHelp(getFullName() + " <Profile ID>", options);
     }
 
     public void execute(String[] args) throws Exception {
@@ -25,7 +25,7 @@ public class ProfileEnableCLI extends CLI {
 
         String profileId = args[0];
 
-        parent.client.enableProfile(profileId);
+        profileCLI.profileClient.enableProfile(profileId);
 
         MainCLI.printMessage("Enabled profile \"" + profileId + "\"");
     }
diff --git a/base/java-tools/src/com/netscape/cmstools/profile/ProfileFindCLI.java b/base/java-tools/src/com/netscape/cmstools/profile/ProfileFindCLI.java
index 9ced7c0b8174be186b0942b7a2b43183d65609b5..1370319f9e59e74080bef1c638290a10eb728f95 100644
--- a/base/java-tools/src/com/netscape/cmstools/profile/ProfileFindCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/profile/ProfileFindCLI.java
@@ -8,20 +8,20 @@ import com.netscape.cmstools.cli.MainCLI;
 
 public class ProfileFindCLI extends CLI {
 
-    public ProfileCLI parent;
+    public ProfileCLI profileCLI;
 
-    public ProfileFindCLI(ProfileCLI parent) {
-        super("find", "Find profiles");
-        this.parent = parent;
+    public ProfileFindCLI(ProfileCLI profileCLI) {
+        super("find", "Find profiles", profileCLI);
+        this.profileCLI = profileCLI;
     }
 
     public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " [FILTER] [OPTIONS...]", options);
+        formatter.printHelp(getFullName() + " [FILTER] [OPTIONS...]", options);
     }
 
     public void execute(String[] args) throws Exception {
 
-        Collection<ProfileDataInfo> infos = parent.client.listProfiles().getProfileInfos();
+        Collection<ProfileDataInfo> infos = profileCLI.profileClient.listProfiles().getProfileInfos();
         boolean first = true;
 
         for (ProfileDataInfo info: infos) {
diff --git a/base/java-tools/src/com/netscape/cmstools/profile/ProfileModifyCLI.java b/base/java-tools/src/com/netscape/cmstools/profile/ProfileModifyCLI.java
index 5259a7fe7a92e2e5212a9855b7faf3e13b6824a2..e1c5436724c5df627947744999faf6523794e7b6 100644
--- a/base/java-tools/src/com/netscape/cmstools/profile/ProfileModifyCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/profile/ProfileModifyCLI.java
@@ -13,15 +13,15 @@ import com.netscape.cmstools.cli.MainCLI;
 
 public class ProfileModifyCLI extends CLI {
 
-    public ProfileCLI parent;
+    public ProfileCLI profileCLI;
 
-    public ProfileModifyCLI(ProfileCLI parent) {
-        super("mod", "Modify profiles");
-        this.parent = parent;
+    public ProfileModifyCLI(ProfileCLI profileCLI) {
+        super("mod", "Modify profiles", profileCLI);
+        this.profileCLI = profileCLI;
     }
 
     public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <file>", options);
+        formatter.printHelp(getFullName() + " <file>", options);
     }
 
     public void execute(String[] args) {
@@ -51,7 +51,7 @@ public class ProfileModifyCLI extends CLI {
 
         try {
             ProfileData data = ProfileCLI.readProfileFromFile(filename);
-            parent.client.modifyProfile(data);
+            profileCLI.profileClient.modifyProfile(data);
             MainCLI.printMessage("Modified profile " + data.getId());
         } catch (FileNotFoundException | JAXBException  e) {
             System.err.println("Error: " + e.getMessage());
diff --git a/base/java-tools/src/com/netscape/cmstools/profile/ProfileRemoveCLI.java b/base/java-tools/src/com/netscape/cmstools/profile/ProfileRemoveCLI.java
index c2e3eae53f4879869fd474af99fbd2221a60ac59..92c99ede8544d953ec95af733237ef0e0434ff05 100644
--- a/base/java-tools/src/com/netscape/cmstools/profile/ProfileRemoveCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/profile/ProfileRemoveCLI.java
@@ -5,15 +5,15 @@ import com.netscape.cmstools.cli.MainCLI;
 
 public class ProfileRemoveCLI extends CLI {
 
-    public ProfileCLI parent;
+    public ProfileCLI profileCLI;
 
-    public ProfileRemoveCLI(ProfileCLI parent) {
-        super("del", "Remove profiles");
-        this.parent = parent;
+    public ProfileRemoveCLI(ProfileCLI profileCLI) {
+        super("del", "Remove profiles", profileCLI);
+        this.profileCLI = profileCLI;
     }
 
     public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <profile_id>", options);
+        formatter.printHelp(getFullName() + " <Profile ID>", options);
     }
 
     public void execute(String[] args) throws Exception {
@@ -25,7 +25,7 @@ public class ProfileRemoveCLI extends CLI {
 
         String profileId = args[0];
 
-        parent.client.deleteProfile(profileId);
+        profileCLI.profileClient.deleteProfile(profileId);
 
         MainCLI.printMessage("Deleted profile \"" + profileId + "\"");
     }
diff --git a/base/java-tools/src/com/netscape/cmstools/profile/ProfileShowCLI.java b/base/java-tools/src/com/netscape/cmstools/profile/ProfileShowCLI.java
index c3f8675f2e11a870d5d19020a2432a39bc1fb033..6b09d7f9d67ca4b02500e25309dd41609b2d232e 100644
--- a/base/java-tools/src/com/netscape/cmstools/profile/ProfileShowCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/profile/ProfileShowCLI.java
@@ -10,15 +10,15 @@ import com.netscape.cmstools.cli.MainCLI;
 
 public class ProfileShowCLI extends CLI {
 
-    public ProfileCLI parent;
+    public ProfileCLI profileCLI;
 
-    public ProfileShowCLI(ProfileCLI parent) {
-        super("show", "Show profiles");
-        this.parent = parent;
+    public ProfileShowCLI(ProfileCLI profileCLI) {
+        super("show", "Show profiles", profileCLI);
+        this.profileCLI = profileCLI;
     }
 
     public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <profile_id>", options);
+        formatter.printHelp(getFullName() + " <Profile ID>", options);
     }
 
     public void execute(String[] args) throws Exception {
@@ -56,14 +56,14 @@ public class ProfileShowCLI extends CLI {
             }
         }
 
-        ProfileData profileData = parent.client.retrieveProfile(profileId);
+        ProfileData profileData = profileCLI.profileClient.retrieveProfile(profileId);
 
         MainCLI.printMessage("Profile \"" + profileId + "\"");
 
         if (filename != null) {
             ProfileCLI.saveProfileToFile(filename, profileData);
         } else {
-            ProfileCLI.printProfile(profileData, parent.parent.config.getServerURI());
+            ProfileCLI.printProfile(profileData, profileCLI.getClient().getConfig().getServerURI());
         }
     }
 
diff --git a/base/java-tools/src/com/netscape/cmstools/system/KRAConnectorAddCLI.java b/base/java-tools/src/com/netscape/cmstools/system/KRAConnectorAddCLI.java
index cc163341b0448ea13b8e9ab8d49ba9613fd5f30a..cc08d7513f56e4bec539d9367cb230ec4651c916 100644
--- a/base/java-tools/src/com/netscape/cmstools/system/KRAConnectorAddCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/system/KRAConnectorAddCLI.java
@@ -33,15 +33,16 @@ import com.netscape.cmstools.cli.MainCLI;
  * @author Ade Lee
  */
 public class KRAConnectorAddCLI extends CLI {
-    public KRAConnectorCLI parent;
 
-    public KRAConnectorAddCLI(KRAConnectorCLI parent) {
-        super("add", "Add KRA Connector");
-        this.parent = parent;
+    public KRAConnectorCLI kraConnectorCLI;
+
+    public KRAConnectorAddCLI(KRAConnectorCLI kraConnectorCLI) {
+        super("add", "Add KRA Connector", kraConnectorCLI);
+        this.kraConnectorCLI = kraConnectorCLI;
     }
 
     public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <File Name>", options);
+        formatter.printHelp(getFullName() + " <File Name>", options);
     }
 
     public void execute(String[] args) throws Exception {
@@ -70,7 +71,7 @@ public class KRAConnectorAddCLI extends CLI {
         Unmarshaller unmarshaller = context.createUnmarshaller();
         KRAConnectorInfo info = (KRAConnectorInfo) unmarshaller.unmarshal(fis);
 
-        parent.client.addConnector(info);
+        kraConnectorCLI.kraConnectorClient.addConnector(info);
 
         MainCLI.printMessage("Added KRA Connector");
     }
diff --git a/base/java-tools/src/com/netscape/cmstools/system/KRAConnectorCLI.java b/base/java-tools/src/com/netscape/cmstools/system/KRAConnectorCLI.java
index 03db762d41f17ee6fc4f1ab21d209e920a44c4de..a24a4fd00a304ded72061d53e3f9b3ab1f7c95cc 100644
--- a/base/java-tools/src/com/netscape/cmstools/system/KRAConnectorCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/system/KRAConnectorCLI.java
@@ -19,8 +19,6 @@ package com.netscape.cmstools.system;
 
 import java.util.Arrays;
 
-import org.apache.commons.lang.StringUtils;
-
 import com.netscape.certsrv.system.KRAConnectorClient;
 import com.netscape.cmstools.cli.CLI;
 import com.netscape.cmstools.cli.MainCLI;
@@ -30,39 +28,28 @@ import com.netscape.cmstools.cli.MainCLI;
  */
 public class KRAConnectorCLI extends CLI {
 
-    public MainCLI parent;
-    public KRAConnectorClient client;
+    public KRAConnectorClient kraConnectorClient;
+
+    public KRAConnectorCLI(CLI parent) {
+        super("kraconnector", "KRA Connector management commands", parent);
 
-    public KRAConnectorCLI(MainCLI parent) {
-        super("kraconnector", "KRA Connector management commands");
-        this.parent = parent;
         addModule(new KRAConnectorAddCLI(this));
         addModule(new KRAConnectorRemoveCLI(this));
     }
 
-    public void printHelp() {
-
-        System.out.println("Commands:");
-
-        int leftPadding = 1;
-        int rightPadding = 25;
-
-        for (CLI module : modules.values()) {
-            String label = name+"-"+module.getName();
-
-            int padding = rightPadding - leftPadding - label.length();
-            if (padding < 1) padding = 1;
-
-            System.out.print(StringUtils.repeat(" ", leftPadding));
-            System.out.print(label);
-            System.out.print(StringUtils.repeat(" ", padding));
-            System.out.println(module.getDescription());
+    public String getFullName() {
+        if (parent instanceof MainCLI) {
+            // do not include MainCLI's name
+            return name;
+        } else {
+            return parent.getFullName() + "-" + name;
         }
     }
 
     public void execute(String[] args) throws Exception {
 
-        client = new KRAConnectorClient(parent.client);
+        client = parent.getClient();
+        kraConnectorClient = new KRAConnectorClient(client);
 
         if (args.length == 0) {
             printHelp();
diff --git a/base/java-tools/src/com/netscape/cmstools/system/KRAConnectorRemoveCLI.java b/base/java-tools/src/com/netscape/cmstools/system/KRAConnectorRemoveCLI.java
index d69e08ed4ee6a0f5c0e680d0033359d95c1590d0..550b661d22df1b93d29c2ac0438ddbd8c15f8538 100644
--- a/base/java-tools/src/com/netscape/cmstools/system/KRAConnectorRemoveCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/system/KRAConnectorRemoveCLI.java
@@ -24,15 +24,16 @@ import com.netscape.cmstools.cli.MainCLI;
  * @author Ade Lee
  */
 public class KRAConnectorRemoveCLI extends CLI {
-    public KRAConnectorCLI parent;
 
-    public KRAConnectorRemoveCLI(KRAConnectorCLI parent) {
-        super("del", "Remove KRA connector from CA");
-        this.parent = parent;
+    public KRAConnectorCLI kraConnectorCLI;
+
+    public KRAConnectorRemoveCLI(KRAConnectorCLI kraConnectorCLI) {
+        super("del", "Remove KRA connector from CA", kraConnectorCLI);
+        this.kraConnectorCLI = kraConnectorCLI;
     }
 
     public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <KRA Host> <KRA Port>", options);
+        formatter.printHelp(getFullName() + " <KRA Host> <KRA Port>", options);
     }
 
     public void execute(String[] args) throws Exception {
@@ -45,7 +46,7 @@ public class KRAConnectorRemoveCLI extends CLI {
         String kraHost = args[0];
         String kraPort = args[1];
 
-        parent.client.removeConnector(kraHost, kraPort);
+        kraConnectorCLI.kraConnectorClient.removeConnector(kraHost, kraPort);
 
         MainCLI.printMessage("Removed KRA connector \""+kraHost + ":" + kraPort +"\"");
     }
diff --git a/base/java-tools/src/com/netscape/cmstools/system/SecurityDomainCLI.java b/base/java-tools/src/com/netscape/cmstools/system/SecurityDomainCLI.java
index fc23a5257a389f256060d7a610c10c2b9c98ac53..3ea3e78dee65d91b287ec418159d4e0e8f37f754 100644
--- a/base/java-tools/src/com/netscape/cmstools/system/SecurityDomainCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/system/SecurityDomainCLI.java
@@ -20,8 +20,6 @@ package com.netscape.cmstools.system;
 
 import java.util.Arrays;
 
-import org.apache.commons.lang.StringUtils;
-
 import com.netscape.certsrv.system.DomainInfo;
 import com.netscape.certsrv.system.SecurityDomainClient;
 import com.netscape.certsrv.system.SecurityDomainHost;
@@ -34,41 +32,28 @@ import com.netscape.cmstools.cli.MainCLI;
  */
 public class SecurityDomainCLI extends CLI {
 
-    public MainCLI parent;
-    public SecurityDomainClient client;
+    public SecurityDomainClient securityDomainClient;
 
-    public SecurityDomainCLI(MainCLI parent) {
-        super("securitydomain", "Security domain commands");
-        this.parent = parent;
+    public SecurityDomainCLI(CLI parent) {
+        super("securitydomain", "Security domain commands", parent);
 
         addModule(new SecurityDomainGetInstallTokenCLI(this));
         addModule(new SecurityDomainShowCLI(this));
     }
 
-    public void printHelp() {
-
-        System.out.println("Commands:");
-
-        int leftPadding = 1;
-        int rightPadding = 25;
-
-        for (CLI module : modules.values()) {
-            String label = name + "-" + module.getName();
-
-            int padding = rightPadding - leftPadding - label.length();
-            if (padding < 1)
-                padding = 1;
-
-            System.out.print(StringUtils.repeat(" ", leftPadding));
-            System.out.print(label);
-            System.out.print(StringUtils.repeat(" ", padding));
-            System.out.println(module.getDescription());
+    public String getFullName() {
+        if (parent instanceof MainCLI) {
+            // do not include MainCLI's name
+            return name;
+        } else {
+            return parent.getFullName() + "-" + name;
         }
     }
 
     public void execute(String[] args) throws Exception {
 
-        client = new SecurityDomainClient(parent.client);
+        client = parent.getClient();
+        securityDomainClient = new SecurityDomainClient(client);
 
         if (args.length == 0) {
             printHelp();
diff --git a/base/java-tools/src/com/netscape/cmstools/system/SecurityDomainGetInstallTokenCLI.java b/base/java-tools/src/com/netscape/cmstools/system/SecurityDomainGetInstallTokenCLI.java
index 2d21f733d79c6fe0ace74f95c9257c8d82873807..f05535c94afdceb49ff235b3eb947d1db2efaa72 100644
--- a/base/java-tools/src/com/netscape/cmstools/system/SecurityDomainGetInstallTokenCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/system/SecurityDomainGetInstallTokenCLI.java
@@ -32,15 +32,15 @@ import com.netscape.cmstools.cli.MainCLI;
  */
 public class SecurityDomainGetInstallTokenCLI extends CLI {
 
-    public SecurityDomainCLI parent;
+    public SecurityDomainCLI securityDomainCLI;
 
-    public SecurityDomainGetInstallTokenCLI(SecurityDomainCLI parent) {
-        super("get-install-token", "Get install token");
-        this.parent = parent;
+    public SecurityDomainGetInstallTokenCLI(SecurityDomainCLI securityDomainCLI) {
+        super("get-install-token", "Get install token", securityDomainCLI);
+        this.securityDomainCLI = securityDomainCLI;
     }
 
     public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " [OPTIONS...]", options);
+        formatter.printHelp(getFullName() + " [OPTIONS...]", options);
     }
 
     public void execute(String[] args) throws Exception {
@@ -79,7 +79,7 @@ public class SecurityDomainGetInstallTokenCLI extends CLI {
 
         String subsystem = cmd.getOptionValue("subsystem");
 
-        InstallToken token = parent.client.getInstallToken(hostname, subsystem);
+        InstallToken token = securityDomainCLI.securityDomainClient.getInstallToken(hostname, subsystem);
 
         MainCLI.printMessage("Install token: \"" + token.getToken() + "\"");
     }
diff --git a/base/java-tools/src/com/netscape/cmstools/system/SecurityDomainShowCLI.java b/base/java-tools/src/com/netscape/cmstools/system/SecurityDomainShowCLI.java
index 14664dbcf94181ca46c6954cdb51cf2c426c04f5..c0efa9f83ab406fa77786e9c392e9184c3224405 100644
--- a/base/java-tools/src/com/netscape/cmstools/system/SecurityDomainShowCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/system/SecurityDomainShowCLI.java
@@ -28,15 +28,15 @@ import com.netscape.cmstools.cli.CLI;
  */
 public class SecurityDomainShowCLI extends CLI {
 
-    public SecurityDomainCLI parent;
+    public SecurityDomainCLI securityDomainCLI;
 
-    public SecurityDomainShowCLI(SecurityDomainCLI parent) {
-        super("show", "Show domain info");
-        this.parent = parent;
+    public SecurityDomainShowCLI(SecurityDomainCLI securityDomainCLI) {
+        super("show", "Show domain info", securityDomainCLI);
+        this.securityDomainCLI = securityDomainCLI;
     }
 
     public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name, options);
+        formatter.printHelp(getFullName(), options);
     }
 
     public void execute(String[] args) throws Exception {
@@ -59,7 +59,7 @@ public class SecurityDomainShowCLI extends CLI {
             System.exit(1);
         }
 
-        DomainInfo domain = parent.client.getDomainInfo();
+        DomainInfo domain = securityDomainCLI.securityDomainClient.getDomainInfo();
 
         SecurityDomainCLI.printSecurityDomain(domain);
     }
diff --git a/base/java-tools/src/com/netscape/cmstools/token/TokenCLI.java b/base/java-tools/src/com/netscape/cmstools/token/TokenCLI.java
index 539ce7bae01dc8cd9a8a91583a09d348e1fba8fb..4584a5ef7d99d201780319566498569d41a77c0f 100644
--- a/base/java-tools/src/com/netscape/cmstools/token/TokenCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/token/TokenCLI.java
@@ -18,25 +18,24 @@
 
 package com.netscape.cmstools.token;
 
-import org.apache.commons.lang.StringUtils;
+import java.util.Arrays;
+
 import org.jboss.resteasy.plugins.providers.atom.Link;
 
 import com.netscape.certsrv.token.TokenClient;
 import com.netscape.certsrv.token.TokenData;
 import com.netscape.cmstools.cli.CLI;
-import com.netscape.cmstools.cli.TPSCLI;
+import com.netscape.cmstools.cli.SubsystemCLI;
 
 /**
  * @author Endi S. Dewata
  */
 public class TokenCLI extends CLI {
 
-    public TPSCLI tpsCLI;
     public TokenClient tokenClient;
 
-    public TokenCLI(TPSCLI tpsCLI) {
-        super("token", "Token management commands", tpsCLI);
-        this.tpsCLI = tpsCLI;
+    public TokenCLI(SubsystemCLI subsystemCLI) {
+        super("token", "Token management commands", subsystemCLI);
 
         addModule(new TokenAddCLI(this));
         addModule(new TokenFindCLI(this));
@@ -45,34 +44,10 @@ public class TokenCLI extends CLI {
         addModule(new TokenShowCLI(this));
     }
 
-    public String getFullName() {
-        return parent.getName() + "-" + name;
-    }
-
-    public void printHelp() {
-
-        System.out.println("Commands:");
-
-        int leftPadding = 1;
-        int rightPadding = 25;
-
-        for (CLI module : modules.values()) {
-            String label = getFullName() + "-" + module.getName();
-
-            int padding = rightPadding - leftPadding - label.length();
-            if (padding < 1)
-                padding = 1;
-
-            System.out.print(StringUtils.repeat(" ", leftPadding));
-            System.out.print(label);
-            System.out.print(StringUtils.repeat(" ", padding));
-            System.out.println(module.getDescription());
-        }
-    }
-
     public void execute(String[] args) throws Exception {
 
-        tokenClient = new TokenClient(tpsCLI.mainCLI.client);
+        client = parent.getClient();
+        tokenClient = (TokenClient)parent.getClient("token");
 
         if (args.length == 0) {
             printHelp();
@@ -80,42 +55,22 @@ public class TokenCLI extends CLI {
         }
 
         String command = args[0];
-        String moduleName;
-        String moduleCommand;
+        String[] commandArgs = Arrays.copyOfRange(args, 1, args.length);
 
-        // If a command contains a '-' sign it will be
-        // split into module name and module command.
-        // Otherwise it's a single command.
-        int i = command.indexOf('-');
-        if (i >= 0) { // <module name>-<module command>
-            moduleName = command.substring(0, i);
-            moduleCommand = command.substring(i+1);
-
-        } else { // <command>
-            moduleName = command;
-            moduleCommand = null;
-        }
-
-        // get command module
-        if (verbose) System.out.println("Module: " + moduleName);
-        CLI module = getModule(moduleName);
-        if (module == null) {
-            throw new Error("Invalid module \"" + moduleName + "\".");
+        if (command == null) {
+            printHelp();
+            System.exit(1);
         }
 
-        // prepare module arguments
-        String[] moduleArgs;
-        if (moduleCommand != null) {
-            moduleArgs = new String[args.length];
-            moduleArgs[0] = moduleCommand;
-            System.arraycopy(args, 1, moduleArgs, 1, args.length-1);
+        CLI module = getModule(command);
+        if (module != null) {
+            module.execute(commandArgs);
 
         } else {
-            moduleArgs = new String[args.length-1];
-            System.arraycopy(args, 1, moduleArgs, 0, args.length-1);
+            System.err.println("Error: Invalid command \"" + command + "\"");
+            printHelp();
+            System.exit(1);
         }
-
-        module.execute(moduleArgs);
     }
 
     public static void printToken(TokenData token) {
diff --git a/base/java-tools/src/com/netscape/cmstools/user/UserAddCLI.java b/base/java-tools/src/com/netscape/cmstools/user/UserAddCLI.java
index 3db8fe5332713e45a936453bf89b8340e8e32a27..33a6786e7ffdd91835782747c5b365e21a30a4fe 100644
--- a/base/java-tools/src/com/netscape/cmstools/user/UserAddCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/user/UserAddCLI.java
@@ -30,15 +30,15 @@ import com.netscape.cmstools.cli.MainCLI;
  */
 public class UserAddCLI extends CLI {
 
-    public UserCLI parent;
+    public UserCLI userCLI;
 
-    public UserAddCLI(UserCLI parent) {
-        super("add", "Add user");
-        this.parent = parent;
+    public UserAddCLI(UserCLI userCLI) {
+        super("add", "Add user", userCLI);
+        this.userCLI = userCLI;
     }
 
     public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <User ID> [OPTIONS...]", options);
+        formatter.printHelp(getFullName() + " <User ID> [OPTIONS...]", options);
     }
 
     public void execute(String[] args) throws Exception {
@@ -97,7 +97,7 @@ public class UserAddCLI extends CLI {
         userData.setType(cmd.getOptionValue("type"));
         userData.setState(cmd.getOptionValue("state"));
 
-        userData = parent.client.addUser(userData);
+        userData = userCLI.userClient.addUser(userData);
 
         MainCLI.printMessage("Added user \"" + userId + "\"");
 
diff --git a/base/java-tools/src/com/netscape/cmstools/user/UserAddCertCLI.java b/base/java-tools/src/com/netscape/cmstools/user/UserAddCertCLI.java
index 7bec2ff19905438070ca86a3f56bffc86d74f2e8..e3271c022a355a4002601d8af953ea52c7970d7a 100644
--- a/base/java-tools/src/com/netscape/cmstools/user/UserAddCertCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/user/UserAddCertCLI.java
@@ -33,15 +33,15 @@ import com.netscape.cmstools.cli.MainCLI;
  */
 public class UserAddCertCLI extends CLI {
 
-    public UserCLI parent;
+    public UserCLI userCLI;
 
-    public UserAddCertCLI(UserCLI parent) {
-        super("add-cert", "Add user cert");
-        this.parent = parent;
+    public UserAddCertCLI(UserCLI userCLI) {
+        super("add-cert", "Add user cert", userCLI);
+        this.userCLI = userCLI;
     }
 
     public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <User ID> [OPTIONS...]", options);
+        formatter.printHelp(getFullName() + " <User ID> [OPTIONS...]", options);
     }
 
     public void execute(String[] args) throws Exception {
@@ -88,7 +88,7 @@ public class UserAddCertCLI extends CLI {
             System.out.println(userCertData);
         }
 
-        userCertData = parent.client.addUserCert(userId, userCertData);
+        userCertData = userCLI.userClient.addUserCert(userId, userCertData);
 
         MainCLI.printMessage("Added certificate \"" + userCertData.getID() + "\"");
 
diff --git a/base/java-tools/src/com/netscape/cmstools/user/UserAddMembershipCLI.java b/base/java-tools/src/com/netscape/cmstools/user/UserAddMembershipCLI.java
index 224f2266d319a788dc9c47eccffced9c68a07cb7..ab8e61fe185397db7fb2e8546c58d0e21fe1130d 100644
--- a/base/java-tools/src/com/netscape/cmstools/user/UserAddMembershipCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/user/UserAddMembershipCLI.java
@@ -27,15 +27,15 @@ import com.netscape.cmstools.cli.MainCLI;
  */
 public class UserAddMembershipCLI extends CLI {
 
-    public UserCLI parent;
+    public UserCLI userCLI;
 
-    public UserAddMembershipCLI(UserCLI parent) {
-        super("add-membership", "Add user membership");
-        this.parent = parent;
+    public UserAddMembershipCLI(UserCLI userCLI) {
+        super("add-membership", "Add user membership", userCLI);
+        this.userCLI = userCLI;
     }
 
     public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <User ID> <Group ID>", options);
+        formatter.printHelp(getFullName() + " <User ID> <Group ID>", options);
     }
 
     public void execute(String[] args) throws Exception {
@@ -48,7 +48,7 @@ public class UserAddMembershipCLI extends CLI {
         String userID = args[0];
         String groupID = args[1];
 
-        UserMembershipData userMembershipData = parent.client.addUserMembership(userID, groupID);
+        UserMembershipData userMembershipData = userCLI.userClient.addUserMembership(userID, groupID);
 
         MainCLI.printMessage("Added membership in \""+groupID+"\"");
 
diff --git a/base/java-tools/src/com/netscape/cmstools/user/UserCLI.java b/base/java-tools/src/com/netscape/cmstools/user/UserCLI.java
index 2343d1989e412b7d06102cbb6773a4dde2a0b319..7f9f534846a3a321381c35924a7cf713a9d6a9f9 100644
--- a/base/java-tools/src/com/netscape/cmstools/user/UserCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/user/UserCLI.java
@@ -35,12 +35,10 @@ import com.netscape.cmstools.cli.MainCLI;
  */
 public class UserCLI extends CLI {
 
-    public MainCLI parent;
-    public UserClient client;
+    public UserClient userClient;
 
-    public UserCLI(MainCLI parent) {
-        super("user", "User management commands");
-        this.parent = parent;
+    public UserCLI(CLI parent) {
+        super("user", "User management commands", parent);
 
         addModule(new UserFindCLI(this));
         addModule(new UserShowCLI(this));
@@ -58,30 +56,19 @@ public class UserCLI extends CLI {
         addModule(new UserRemoveMembershipCLI(this));
     }
 
-    public void printHelp() {
-
-        System.out.println("Commands:");
-
-        int leftPadding = 1;
-        int rightPadding = 25;
-
-        for (CLI module : modules.values()) {
-            String label = name + "-" + module.getName();
-
-            int padding = rightPadding - leftPadding - label.length();
-            if (padding < 1)
-                padding = 1;
-
-            System.out.print(StringUtils.repeat(" ", leftPadding));
-            System.out.print(label);
-            System.out.print(StringUtils.repeat(" ", padding));
-            System.out.println(module.getDescription());
+    public String getFullName() {
+        if (parent instanceof MainCLI) {
+            // do not include MainCLI's name
+            return name;
+        } else {
+            return parent.getFullName() + "-" + name;
         }
     }
 
     public void execute(String[] args) throws Exception {
 
-        client = new UserClient(parent.client);
+        client = parent.getClient();
+        userClient = new UserClient(client);
 
         if (args.length == 0) {
             printHelp();
diff --git a/base/java-tools/src/com/netscape/cmstools/user/UserFindCLI.java b/base/java-tools/src/com/netscape/cmstools/user/UserFindCLI.java
index 187d4596d91421f1f14e2ca3d772f73e8ef35ceb..4b081920eee32b3a32de72d6221104be620bca14 100644
--- a/base/java-tools/src/com/netscape/cmstools/user/UserFindCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/user/UserFindCLI.java
@@ -33,15 +33,15 @@ import com.netscape.cmstools.cli.MainCLI;
  */
 public class UserFindCLI extends CLI {
 
-    public UserCLI parent;
+    public UserCLI userCLI;
 
-    public UserFindCLI(UserCLI parent) {
-        super("find", "Find users");
-        this.parent = parent;
+    public UserFindCLI(UserCLI userCLI) {
+        super("find", "Find users", userCLI);
+        this.userCLI = userCLI;
     }
 
     public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " [FILTER] [OPTIONS...]", options);
+        formatter.printHelp(getFullName() + " [FILTER] [OPTIONS...]", options);
     }
 
     public void execute(String[] args) throws Exception {
@@ -74,7 +74,7 @@ public class UserFindCLI extends CLI {
         s = cmd.getOptionValue("size");
         Integer size = s == null ? null : Integer.valueOf(s);
 
-        UserCollection response = parent.client.findUsers(filter, start, size);
+        UserCollection response = userCLI.userClient.findUsers(filter, start, size);
 
         Collection<UserData> entries = response.getUsers();
 
diff --git a/base/java-tools/src/com/netscape/cmstools/user/UserFindCertCLI.java b/base/java-tools/src/com/netscape/cmstools/user/UserFindCertCLI.java
index 08f6879331f389b78fc0df4126967da6f293d7ed..15bc4f753f9bf9b98905e074b545af8959aba201 100644
--- a/base/java-tools/src/com/netscape/cmstools/user/UserFindCertCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/user/UserFindCertCLI.java
@@ -33,15 +33,15 @@ import com.netscape.cmstools.cli.MainCLI;
  */
 public class UserFindCertCLI extends CLI {
 
-    public UserCLI parent;
+    public UserCLI userCLI;
 
-    public UserFindCertCLI(UserCLI parent) {
-        super("find-cert", "Find user certs");
-        this.parent = parent;
+    public UserFindCertCLI(UserCLI userCLI) {
+        super("find-cert", "Find user certs", userCLI);
+        this.userCLI = userCLI;
     }
 
     public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <User ID> [OPTIONS...]", options);
+        formatter.printHelp(getFullName() + " <User ID> [OPTIONS...]", options);
     }
 
     public void execute(String[] args) throws Exception {
@@ -80,7 +80,7 @@ public class UserFindCertCLI extends CLI {
         s = cmd.getOptionValue("size");
         Integer size = s == null ? null : Integer.valueOf(s);
 
-        UserCertCollection response = parent.client.findUserCerts(userID, start, size);
+        UserCertCollection response = userCLI.userClient.findUserCerts(userID, start, size);
 
         Collection<UserCertData> entries = response.getCerts();
 
diff --git a/base/java-tools/src/com/netscape/cmstools/user/UserFindMembershipCLI.java b/base/java-tools/src/com/netscape/cmstools/user/UserFindMembershipCLI.java
index 494c3c323ba7fdf717636eb93ebf764e9246d114..0c41635dd1624e8982eea45d26ee2bedde121b95 100644
--- a/base/java-tools/src/com/netscape/cmstools/user/UserFindMembershipCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/user/UserFindMembershipCLI.java
@@ -33,15 +33,15 @@ import com.netscape.cmstools.cli.MainCLI;
  */
 public class UserFindMembershipCLI extends CLI {
 
-    public UserCLI parent;
+    public UserCLI userCLI;
 
-    public UserFindMembershipCLI(UserCLI parent) {
-        super("find-membership", "Find user memberships");
-        this.parent = parent;
+    public UserFindMembershipCLI(UserCLI userCLI) {
+        super("find-membership", "Find user memberships", userCLI);
+        this.userCLI = userCLI;
     }
 
     public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <User ID> [OPTIONS...]", options);
+        formatter.printHelp(getFullName() + " <User ID> [OPTIONS...]", options);
     }
 
     public void execute(String[] args) throws Exception {
@@ -80,7 +80,7 @@ public class UserFindMembershipCLI extends CLI {
         s = cmd.getOptionValue("size");
         Integer size = s == null ? null : Integer.valueOf(s);
 
-        UserMembershipCollection response = parent.client.findUserMemberships(userID, start, size);
+        UserMembershipCollection response = userCLI.userClient.findUserMemberships(userID, start, size);
 
         Collection<UserMembershipData> entries = response.getMemberships();
 
diff --git a/base/java-tools/src/com/netscape/cmstools/user/UserModifyCLI.java b/base/java-tools/src/com/netscape/cmstools/user/UserModifyCLI.java
index 706224ef9385a9350efff50af528cfdb0c85de61..a09e0fcdfab270e68ff793a6942b851ac01744c7 100644
--- a/base/java-tools/src/com/netscape/cmstools/user/UserModifyCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/user/UserModifyCLI.java
@@ -30,15 +30,15 @@ import com.netscape.cmstools.cli.MainCLI;
  */
 public class UserModifyCLI extends CLI {
 
-    public UserCLI parent;
+    public UserCLI userCLI;
 
-    public UserModifyCLI(UserCLI parent) {
-        super("mod", "Modify user");
-        this.parent = parent;
+    public UserModifyCLI(UserCLI userCLI) {
+        super("mod", "Modify user", userCLI);
+        this.userCLI = userCLI;
     }
 
     public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <User ID> [OPTIONS...]", options);
+        formatter.printHelp(getFullName() + " <User ID> [OPTIONS...]", options);
     }
 
     public void execute(String[] args) throws Exception {
@@ -98,7 +98,7 @@ public class UserModifyCLI extends CLI {
         // userData.setType(cmd.getOptionValue("type"));
         userData.setState(cmd.getOptionValue("state"));
 
-        userData = parent.client.modifyUser(userId, userData);
+        userData = userCLI.userClient.modifyUser(userId, userData);
 
         MainCLI.printMessage("Modified user \"" + userId + "\"");
 
diff --git a/base/java-tools/src/com/netscape/cmstools/user/UserRemoveCLI.java b/base/java-tools/src/com/netscape/cmstools/user/UserRemoveCLI.java
index e7a9ad5d178a569e917d703600118912b7edb2e2..b26b4ae8a7b314f3b720e976fff14be3cb513caa 100644
--- a/base/java-tools/src/com/netscape/cmstools/user/UserRemoveCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/user/UserRemoveCLI.java
@@ -26,15 +26,15 @@ import com.netscape.cmstools.cli.MainCLI;
  */
 public class UserRemoveCLI extends CLI {
 
-    public UserCLI parent;
+    public UserCLI userCLI;
 
-    public UserRemoveCLI(UserCLI parent) {
-        super("del", "Remove user");
-        this.parent = parent;
+    public UserRemoveCLI(UserCLI userCLI) {
+        super("del", "Remove user", userCLI);
+        this.userCLI = userCLI;
     }
 
     public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <User ID>", options);
+        formatter.printHelp(getFullName() + " <User ID>", options);
     }
 
     public void execute(String[] args) throws Exception {
@@ -46,7 +46,7 @@ public class UserRemoveCLI extends CLI {
 
         String userID = args[0];
 
-        parent.client.removeUser(userID);
+        userCLI.userClient.removeUser(userID);
 
         MainCLI.printMessage("Deleted user \"" + userID + "\"");
     }
diff --git a/base/java-tools/src/com/netscape/cmstools/user/UserRemoveCertCLI.java b/base/java-tools/src/com/netscape/cmstools/user/UserRemoveCertCLI.java
index 264458b7f38a2fd150df30b2dc4dd6de49236dfa..5758c4ccd593226f0f5639f3f121d57939c6735e 100644
--- a/base/java-tools/src/com/netscape/cmstools/user/UserRemoveCertCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/user/UserRemoveCertCLI.java
@@ -29,15 +29,15 @@ import com.netscape.cmstools.cli.MainCLI;
  */
 public class UserRemoveCertCLI extends CLI {
 
-    public UserCLI parent;
+    public UserCLI userCLI;
 
-    public UserRemoveCertCLI(UserCLI parent) {
-        super("remove-cert", "Remove user cert");
-        this.parent = parent;
+    public UserRemoveCertCLI(UserCLI userCLI) {
+        super("remove-cert", "Remove user cert", userCLI);
+        this.userCLI = userCLI;
     }
 
     public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <User ID> <Cert ID>", options);
+        formatter.printHelp(getFullName() + " <User ID> <Cert ID>", options);
     }
 
     public void execute(String[] args) throws Exception {
@@ -54,7 +54,7 @@ public class UserRemoveCertCLI extends CLI {
             System.out.println("Removing cert "+certID+" from user "+userID+".");
         }
 
-        parent.client.removeUserCert(userID, URLEncoder.encode(certID, "UTF-8"));
+        userCLI.userClient.removeUserCert(userID, URLEncoder.encode(certID, "UTF-8"));
 
         MainCLI.printMessage("Deleted certificate \"" + certID + "\"");
     }
diff --git a/base/java-tools/src/com/netscape/cmstools/user/UserRemoveMembershipCLI.java b/base/java-tools/src/com/netscape/cmstools/user/UserRemoveMembershipCLI.java
index 26a5a6eec5222b98718df1f5a524d364970ac3ed..62091efb00b32c7178a8cca9da67bb85a8f00d43 100644
--- a/base/java-tools/src/com/netscape/cmstools/user/UserRemoveMembershipCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/user/UserRemoveMembershipCLI.java
@@ -26,15 +26,15 @@ import com.netscape.cmstools.cli.MainCLI;
  */
 public class UserRemoveMembershipCLI extends CLI {
 
-    public UserCLI parent;
+    public UserCLI userCLI;
 
-    public UserRemoveMembershipCLI(UserCLI parent) {
-        super("remove-membership", "Remove user membership");
-        this.parent = parent;
+    public UserRemoveMembershipCLI(UserCLI userCLI) {
+        super("remove-membership", "Remove user membership", userCLI);
+        this.userCLI = userCLI;
     }
 
     public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <User ID> <Group ID>", options);
+        formatter.printHelp(getFullName() + " <User ID> <Group ID>", options);
     }
 
     public void execute(String[] args) throws Exception {
@@ -47,7 +47,7 @@ public class UserRemoveMembershipCLI extends CLI {
         String userID = args[0];
         String groupID = args[1];
 
-        parent.client.removeUserMembership(userID, groupID);
+        userCLI.userClient.removeUserMembership(userID, groupID);
 
         MainCLI.printMessage("Deleted membership in group \""+groupID+"\"");
     }
diff --git a/base/java-tools/src/com/netscape/cmstools/user/UserShowCLI.java b/base/java-tools/src/com/netscape/cmstools/user/UserShowCLI.java
index a04cd6da283a5c5a1f91a2c5caca0f6b7b018526..ce0623e3b893c4fad0b3386967b9d1671654cad5 100644
--- a/base/java-tools/src/com/netscape/cmstools/user/UserShowCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/user/UserShowCLI.java
@@ -27,15 +27,15 @@ import com.netscape.cmstools.cli.MainCLI;
  */
 public class UserShowCLI extends CLI {
 
-    public UserCLI parent;
+    public UserCLI userCLI;
 
-    public UserShowCLI(UserCLI parent) {
-        super("show", "Show user");
-        this.parent = parent;
+    public UserShowCLI(UserCLI userCLI) {
+        super("show", "Show user", userCLI);
+        this.userCLI = userCLI;
     }
 
     public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <User ID>", options);
+        formatter.printHelp(getFullName() + " <User ID>", options);
     }
 
     public void execute(String[] args) throws Exception {
@@ -47,7 +47,7 @@ public class UserShowCLI extends CLI {
 
         String userId = args[0];
 
-        UserData userData = parent.client.getUser(userId);
+        UserData userData = userCLI.userClient.getUser(userId);
 
         MainCLI.printMessage("User \"" + userId + "\"");
 
diff --git a/base/java-tools/src/com/netscape/cmstools/user/UserShowCertCLI.java b/base/java-tools/src/com/netscape/cmstools/user/UserShowCertCLI.java
index f30c72327410dc9552a9999011029d772abf2c4b..87e535f6a93f143d1c1bcf2a4c25bfcf0d09d1ea 100644
--- a/base/java-tools/src/com/netscape/cmstools/user/UserShowCertCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/user/UserShowCertCLI.java
@@ -34,15 +34,15 @@ import com.netscape.cmstools.cli.MainCLI;
  */
 public class UserShowCertCLI extends CLI {
 
-    public UserCLI parent;
+    public UserCLI userCLI;
 
-    public UserShowCertCLI(UserCLI parent) {
-        super("show-cert", "Show user cert");
-        this.parent = parent;
+    public UserShowCertCLI(UserCLI userCLI) {
+        super("show-cert", "Show user cert", userCLI);
+        this.userCLI = userCLI;
     }
 
     public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <User ID> <Cert ID> [OPTIONS...]", options);
+        formatter.printHelp(getFullName() + " <User ID> <Cert ID> [OPTIONS...]", options);
     }
 
     public void execute(String[] args) throws Exception {
@@ -79,7 +79,7 @@ public class UserShowCertCLI extends CLI {
         String certID = cmdArgs[1];
         String file = cmd.getOptionValue("output");
 
-        UserCertData userCertData = parent.client.getUserCert(userID, URLEncoder.encode(certID, "UTF-8"));
+        UserCertData userCertData = userCLI.userClient.getUserCert(userID, URLEncoder.encode(certID, "UTF-8"));
 
         String encoded = userCertData.getEncoded();
         if (encoded != null && file != null) {
-- 
1.8.1.4

