docs: private void registerClient(ActionBean action) throws ActionException {
          if (!securityContext.hasPermission(PermissionType.clientAdmin, action.getOrganizationId()))
              throw ExceptionFactory.notAuthorizedException();
  
          ClientVersionBean versionBean;
          List<ContractSummaryBean> contractBeans;
          try {
              versionBean = orgs.getClientVersion(action.getOrganizationId(), action.getEntityId(), action.getEntityVersion());
          } catch (ClientVersionNotFoundException e) {
              throw ExceptionFactory.actionException(Messages.i18n.format("clientVersionDoesNotExist", action.getEntityId(), action.getEntityVersion())); //$NON-NLS-1$
          }
          try {
              contractBeans = query.getClientContracts(action.getOrganizationId(), action.getEntityId(), action.getEntityVersion());
          } catch (StorageException e) {
              throw ExceptionFactory.actionException(Messages.i18n.format("ClientNotFound"), e); //$NON-NLS-1$
          }
  
          boolean isReregister = false;
  
          // Validate that it's ok to perform this action
          if (versionBean.getStatus() == ClientStatus.Registered) {
              Date modOn = versionBean.getModifiedOn();
              Date publishedOn = versionBean.getPublishedOn();
              int c = modOn.compareTo(publishedOn);
              if (c <= 0) {
                  throw ExceptionFactory.actionException(Messages.i18n.format("ClientReRegisterNotRequired")); //$NON-NLS-1$
              }
              isReregister = true;
          }
  
          Client client = new Client();
          client.setOrganizationId(versionBean.getClient().getOrganization().getId());
          client.setClientId(versionBean.getClient().getId());
          client.setVersion(versionBean.getVersion());
          client.setApiKey(versionBean.getApikey());
  
          Set<Contract> contracts = new HashSet<>();
          for (ContractSummaryBean contractBean : contractBeans) {
              Contract contract = new Contract();
              contract.setPlan(contractBean.getPlanId());
              contract.setApiId(contractBean.getApiId());
              contract.setApiOrgId(contractBean.getApiOrganizationId());
              contract.setApiVersion(contractBean.getApiVersion());
              contract.getPolicies().addAll(aggregateContractPolicies(contractBean));
              contracts.add(contract);
          }
          client.setContracts(contracts);
  
          // Next, register the client with *all* relevant gateways.  This is done by
          // looking up all referenced APIs and getting the gateway information for them.
          // Each of those gateways must be told about the client.
          try {
              storage.beginTx();
              Map<String, IGatewayLink> links = new HashMap<>();
              for (Contract contract : client.getContracts()) {
                  ApiVersionBean svb = storage.getApiVersion(contract.getApiOrgId(), contract.getApiId(), contract.getApiVersion());
                  Set<ApiGatewayBean> gateways = svb.getGateways();
                  if (gateways == null) {
                      throw new PublishingException("No gateways specified for API: " + svb.getApi().getName()); //$NON-NLS-1$
                  }
                  for (ApiGatewayBean apiGatewayBean : gateways) {
                      if (!links.containsKey(apiGatewayBean.getGatewayId())) {
                          IGatewayLink gatewayLink = createGatewayLink(apiGatewayBean.getGatewayId());
                          links.put(apiGatewayBean.getGatewayId(), gatewayLink);
                      }
                  }
              }
              if (isReregister) {
                  // Once we figure out which gateways to register with, make sure we also "unregister"
                  // the client app from all other gateways.  This is necessary because we may have broken
                  // contracts we previously had on APIs that are published to other gateways.  And thus
                  // it's possible we need to remove a contract from a Gateway that is not otherwise/currently
                  // referenced.
                  //
                  // This is a fix for:  https://issues.jboss.org/browse/APIMAN-895
  
                  Iterator<GatewayBean> gateways = storage.getAllGateways();
                  while (gateways.hasNext()) {
                      GatewayBean gbean = gateways.next();
                      if (!links.containsKey(gbean.getId())) {
                          IGatewayLink gatewayLink = createGatewayLink(gbean.getId());
                          
                          try {
                              gatewayLink.unregisterClient(client);
                          } catch (Exception e) {
                              // We need to catch the error, but ignore it,
                              // in the event that the gateway is invalid.
                          }
                          
                          gatewayLink.close();
                      }
                  }
              }
              for (IGatewayLink gatewayLink : links.values()) {
                  gatewayLink.registerClient(client);
                  gatewayLink.close();
              }
              storage.commitTx();
          } catch (Exception e) {
              storage.rollbackTx();
              throw ExceptionFactory.actionException(Messages.i18n.format("RegisterError"), e); //$NON-NLS-1$
          }
  
          versionBean.setStatus(ClientStatus.Registered);
          versionBean.setPublishedOn(new Date());
  
          try {
              storage.beginTx();
              storage.updateClientVersion(versionBean);
              storage.createAuditEntry(AuditUtils.clientRegistered(versionBean, securityContext));
              storage.commitTx();
          } catch (Exception e) {
              storage.rollbackTx();
              throw ExceptionFactory.actionException(Messages.i18n.format("RegisterError"), e); //$NON-NLS-1$
          }
  
          log.debug(String.format("Successfully registered Client %s on specified gateways: %s", //$NON-NLS-1$
                  versionBean.getClient().getName(), versionBean.getClient()));
      }