docs: @SuppressWarnings("unchecked")
  	@Override
  	public Object invoke(Object proxy, Method method, Object[] arguments) throws Exception {
  		// do not try to reuse remote invocation transaction; creates a new transaction instance for every invocation
  		HttpRmiTransaction transaction = createTransaction(connectionFactory, implementationURL);
  
  		String declaringClassName = method.getDeclaringClass().getCanonicalName();
  		String packageName = method.getDeclaringClass().getPackage().getName();
  		if (packageName.endsWith(CLIENT_PACKAGE_SUFIX)) {
  			// if remote class is declared into client package just use parent package instead
  			declaringClassName = declaringClassName.replace(CLIENT_PACKAGE_SUFIX, "");
  		}
  		transaction.setMethod(declaringClassName, method.getName());
  
  		Type returnType = method.getGenericReturnType();
  		Callback<Object> callback = null;
  
  		// excerpt from Java API regarding this method third argument:
  		// arguments - an array of objects containing the values of the arguments passed in the method invocation
  		// on the Proxy instance or null if interface method takes no arguments.
  		// to be on safe side test both null and empty conditions
  
  		if (arguments != null && arguments.length > 0) {
  			List<Object> remoteArguments = new ArrayList<Object>();
  
  			for (int i = 0; i < arguments.length; ++i) {
  				if (!(arguments[i] instanceof Callback)) {
  					remoteArguments.add(arguments[i]);
  					continue;
  				}
  
  				// here argument is the callback
  				// it is expected to have a single callback; if more, uses the last one
  				assert callback == null;
  				callback = (Callback<Object>) arguments[i];
  
  				// if callback is present uses its parameterized type as return type for the remote method
  				// extract type parameter from actual argument instance, not from method signature that can contain wild card
  				Type callbackType = arguments[i].getClass().getGenericInterfaces()[0];
  				if (!(callbackType instanceof ParameterizedType)) {
  					throw new BugError("Missing callback generic type. Cannot infer return type for |%s|.", method);
  				}
  				returnType = ((ParameterizedType) callbackType).getActualTypeArguments()[0];
  			}
  
  			if (!remoteArguments.isEmpty()) {
  				transaction.setArguments(remoteArguments.toArray());
  			}
  		}
  
  		transaction.setReturnType(returnType);
  		transaction.setExceptions(method.getExceptionTypes());
  
  		if (transaction.isSynchronousForced() || (!Types.isVoid(returnType) && callback == null)) {
  			// force synchronous execution if specialized transaction request synchronous mode
  			// also execute synchronous if remote method is not void but there is no callback
  			// uses null callback to force synchronous
  			return transaction.exec(null);
  		}
  
  		// usually user code does not provide callbacks when invoking void methods, although it may happen to want to know when
  		// execution is complete in order, for example, to chain another
  		// anyway, if no callback is provided uses the default void callback
  		if (callback == null) {
  			callback = VOID_CALLBACK;
  		}
  
  		transaction.exec(callback);
  		return null;
  	}