docs: @Override
      public Object invoke(ObjectName name, String operationName, Object[] params,
                           String[] signature) throws InstanceNotFoundException, MBeanException, ReflectionException, IOException {
          final String sourceMethod = "invoke";
  
          try {
              //Look for routing MBean
              if (ClientProvider.CONNECTION_ROUTING_NAME.equals(name.getKeyProperty("name")) &&
                  ClientProvider.CONNECTION_ROUTING_DOMAIN.equals(name.getDomain())) {
  
                  //Handle server-level routing
                  if (ClientProvider.CONNECTION_ROUTING_OPERATION_ASSIGN_SERVER.equals(operationName)) {
                      if (params.length == 3) {
                          //routing at server level
                          this.mapRouting = new HashMap<String, Object>();
                          this.mapRouting.put(ClientProvider.ROUTING_KEY_HOST_NAME, params[0]);
                          this.mapRouting.put(ClientProvider.ROUTING_KEY_SERVER_USER_DIR, params[1]);
                          this.mapRouting.put(ClientProvider.ROUTING_KEY_SERVER_NAME, params[2]);
                          return Boolean.TRUE;
                      }
  
                      //Handle host-level routing
                  } else if (ClientProvider.CONNECTION_ROUTING_OPERATION_ASSIGN_HOST.equals(operationName)) {
                      if (params.length == 1) {
                          //routing at host level
                          this.mapRouting = new HashMap<String, Object>();
                          this.mapRouting.put(ClientProvider.ROUTING_KEY_HOST_NAME, params[0]);
                          return Boolean.TRUE;
                      }
                  }
              }
  
          } catch (Exception e) {
              throw new MBeanException(e);
          }
  
          checkConnection();
  
          //Special handling for file transfer MBean invocations
          if (ClientProvider.FILE_TRANSFER_NAME.equals(name.getKeyProperty("name")) &&
              ClientProvider.FILE_TRANSFER_DOMAIN.equals(name.getDomain())) {
              return fileTransferClient.handleOperation(operationName, params);
          }
  
          URL invokeURL = null;
          HttpsURLConnection connection = null;
          JSONConverter converter = JSONConverter.getConverter();
          try {
              // Get URL for invoke operation
              invokeURL = getOperationURL(name, operationName);
  
              // Get connection to server
              connection = getConnection(invokeURL, HttpMethod.POST);
  
              // Create Invocation object
              Invocation invocation = new Invocation();
              invocation.params = params;
              invocation.signature = signature;
  
              // Write Invocation JSON to connection output stream
              OutputStream output = connection.getOutputStream();
              converter.writeInvocation(output, invocation);
              output.flush();
              output.close();
          } catch (ConnectException ce) {
              recoverConnection(ce);
              // Server is down; not a client bug
              throw ce;
          } catch (IntrospectionException intro) {
              throw getRequestErrorException(sourceMethod, intro, invokeURL);
          } catch (IOException io) {
              throw getRequestErrorException(sourceMethod, io, invokeURL);
          } finally {
              JSONConverter.returnConverter(converter);
          }
  
          // Check response code from server
          int responseCode = 0;
          try {
              responseCode = connection.getResponseCode();
          } catch (ConnectException ce) {
              recoverConnection(ce);
              // Server is down; not a client bug
              throw ce;
          }
  
          switch (responseCode) {
              case HttpURLConnection.HTTP_OK:
                  converter = JSONConverter.getConverter();
                  try {
                      // Process and return server response, which should be a POJO
                      return converter.readPOJO(connection.getInputStream());
                  } catch (ClassNotFoundException cnf) {
                      // Not a REST connector bug per se; not need to log this case
                      throw new IOException(RESTClientMessagesUtil.getMessage(RESTClientMessagesUtil.SERVER_RESULT_EXCEPTION), cnf);
                  } catch (Exception e) {
                      throw getResponseErrorException(sourceMethod, e, invokeURL);
                  } finally {
                      JSONConverter.returnConverter(converter);
                  }
              case HttpURLConnection.HTTP_BAD_REQUEST:
              case HttpURLConnection.HTTP_INTERNAL_ERROR:
                  try {
                      // Server response should be a serialized Throwable
                      throw getServerThrowable(sourceMethod, connection);
                  } catch (InstanceNotFoundException inf) {
                      throw inf;
                  } catch (RuntimeMBeanException rme) {
                      throw rme;
                  } catch (MBeanException me) {
                      throw me;
                  } catch (ReflectionException re) {
                      throw re;
                  } catch (IOException io) {
                      throw io;
                  } catch (Throwable t) {
                      throw new IOException(RESTClientMessagesUtil.getMessage(RESTClientMessagesUtil.UNEXPECTED_SERVER_THROWABLE), t);
                  }
              case HttpURLConnection.HTTP_UNAUTHORIZED:
              case HttpURLConnection.HTTP_FORBIDDEN:
                  throw getBadCredentialsException(responseCode, connection);
              case HttpURLConnection.HTTP_GONE:
              case HttpURLConnection.HTTP_NOT_FOUND:
                  IOException ioe = getResponseCodeErrorException(sourceMethod, responseCode, connection);
                  recoverConnection(ioe);
                  throw ioe;
              default:
                  IOException e = getResponseCodeErrorException(sourceMethod, responseCode, connection);
                  throw e;
          }
      }