docs: private void onError(int statusCode) throws Exception {
  		// if status code is [200 300) range response body is accessible via getInputStream
  		// otherwise getErrorStream should be used
  		// trying to use getInputStream for status codes not in [200 300) range will rise IOException
  
  		switch (statusCode) {
  		case SC_FORBIDDEN:
  			// server understood the request but refuses to fulfill it
  			// compared with SC_UNAUTHORIZED, sending authentication will not grant access
  			// common SC_FORBIDDEN condition may be Tomcat filtering by remote address and client IP is not allowed
  			throw new RmiException("Server refuses to process request |%s|. Common cause may be Tomcat filtering by remote address and this IP is not allowed.", connection.getURL());
  
  		case SC_UNAUTHORIZED:
  			throw new RmiException("Attempt to access private remote method |%s| without authorization.", connection.getURL());
  
  		case SC_NOT_FOUND:
  			// not found may occur if front end Apache HTTP server does not recognize the protocol, e.g. trying to access
  			// securely a
  			// public method or because of misspelled extension; also virtual host configuration for remote context may be wrong
  			throw new RmiException("Method |%s| not found. Check URL spelling, protocol unmatched or unrecognized extension.", connection.getURL());
  
  		case SC_SERVICE_UNAVAILABLE:
  			// front end HTTP server is running but application server is down; front end server responds with 503
  			throw new RmiException("Front-end HTTP server is up but back-end is down. HTTP-RMI transaction |%s| aborted.", connection.getURL());
  
  		case SC_BAD_REQUEST:
  			if (isJSON(connection.getContentType())) {
  				// business constrain not satisfied
  				throw (BusinessException) readJsonObject(connection.getErrorStream(), BusinessException.class);
  			}
  			break;
  
  		case SC_INTERNAL_SERVER_ERROR:
  			if (isJSON(connection.getContentType())) {
  				RemoteException remoteException = (RemoteException) readJsonObject(connection.getErrorStream(), RemoteException.class);
  				log.error("HTTP-RMI error on |%s|: %s", connection.getURL(), remoteException);
  
  				// if remote exception is an exception declared by method signature we throw it in this virtual machine
  				if (exceptions.contains(getRemoteExceptionCause(remoteException))) {
  					Class<? extends Throwable> cause = Classes.forOptionalName(remoteException.getCause());
  					if (cause != null) {
  						String message = remoteException.getMessage();
  						if (message == null) {
  							throw (Exception) Classes.newInstance(cause);
  						}
  						throw (Exception) Classes.newInstance(cause, remoteException.getMessage());
  					}
  				}
  
  				// if received remote exception is not listed by method signature replace it with RmiException
  				throw new RmiException(connection.getURL(), remoteException);
  			}
  		}
  
  		final InputStream errorStream = connection.getErrorStream();
  		if (errorStream != null) {
  			String responseDump = Strings.load(errorStream, 100);
  			log.error("HTTP-RMI error on |%s|. Server returned |%d|. Response dump:\r\n\t%s", connection.getURL(), statusCode, responseDump);
  		} else {
  			log.error("HTTP-RMI error on |%s|. Server returned |%d|.", connection.getURL(), statusCode);
  		}
  		throw new RmiException("HTTP-RMI error on |%s|. Server returned |%d|.", connection.getURL(), statusCode);
  	}