/** * Sends an RPC request to the given {@link InetSocketAddress}. * * @param remoteSocketAddress the remote address to send the request to * @param request the RPC request to send * @return the return value of the RPC call, possibly <code>null</code> * @throws Throwable any exception that is thrown by the remote receiver of the RPC call */ Object sendRPCRequest(final InetSocketAddress remoteSocketAddress, final RPCRequest request) throws Throwable { if (this.shutdownRequested.get()) throw new IOException("Shutdown of RPC service has already been requested"); final long start = System.currentTimeMillis(); final DatagramPacket[] packets = this.messageToPackets(remoteSocketAddress, request); final Integer messageID = Integer.valueOf(request.getMessageID()); final RPCRequestMonitor requestMonitor = new RPCRequestMonitor(); this.pendingRequests.put(messageID, requestMonitor); RPCResponse rpcResponse = null; int numberOfRetries; try { numberOfRetries = this.networkThread.send(packets); // Wait for the response synchronized (requestMonitor) { while (true) { if (requestMonitor.rpcResponse != null) { rpcResponse = requestMonitor.rpcResponse; break; } final long sleepTime = RPC_TIMEOUT - (System.currentTimeMillis() - start); if (sleepTime > 0L) requestMonitor.wait(sleepTime); else break; } } } finally { // Request is no longer pending this.pendingRequests.remove(messageID); } if (rpcResponse == null) throw new IOException( "Unable to complete RPC of method " + request.getMethodName() + " on " + remoteSocketAddress); // Report the successful call to the statistics module final String methodName = request.getMethodName(); this.statistics.reportSuccessfulTransmission(methodName, packets.length, numberOfRetries); this.statistics.reportRTT(methodName, (int) (System.currentTimeMillis() - start)); // TODO: Send clean up message if (rpcResponse instanceof RPCReturnValue) return ((RPCReturnValue) rpcResponse).getRetVal(); throw ((RPCThrowable) rpcResponse).getThrowable(); }
/** * Transforms the given {@link Throwable} into a string and wraps it into an {@link IOException}. * * @param request the RPC request which caused the {@link Throwable} to be wrapped * @param throwable the {@link Throwable} to be wrapped * @return the {@link} IOException created from the {@link Throwable} */ private static IOException wrapInIOException( final RPCRequest request, final Throwable throwable) { final StringBuilder sb = new StringBuilder("The remote procedure call of method "); sb.append(request.getInterfaceName()); sb.append('.'); sb.append(request.getMethodName()); sb.append(" caused an unregistered exception: "); sb.append(StringUtils.stringifyException(throwable)); return new IOException(sb.toString()); }
private void processIncomingRPCRequest( final InetSocketAddress remoteSocketAddress, final RPCRequest rpcRequest) { final Integer messageID = Integer.valueOf(rpcRequest.getMessageID()); if (this.requestsBeingProcessed.putIfAbsent(messageID, rpcRequest) != null) { Log.debug( "Request " + rpcRequest.getMessageID() + " is already being processed at the moment"); return; } final CachedResponse cachedResponse = this.cachedResponses.get(messageID); if (cachedResponse != null) { try { final int numberOfRetries = this.networkThread.send(cachedResponse.packets); this.statistics.reportSuccessfulTransmission( rpcRequest.getMethodName() + " (Response)", cachedResponse.packets.length, numberOfRetries); } catch (final Exception e) { Log.error("Caught exception while trying to send RPC response: ", e); } finally { this.requestsBeingProcessed.remove(messageID); } return; } final RPCProtocol callbackHandler = this.callbackHandlers.get(rpcRequest.getInterfaceName()); if (callbackHandler == null) { Log.error("Cannot find callback handler for protocol " + rpcRequest.getInterfaceName()); this.requestsBeingProcessed.remove(messageID); return; } try { final Method method = callbackHandler .getClass() .getMethod(rpcRequest.getMethodName(), rpcRequest.getParameterTypes()); RPCResponse rpcResponse = null; try { final Object retVal = method.invoke(callbackHandler, rpcRequest.getArgs()); rpcResponse = new RPCReturnValue(rpcRequest.getMessageID(), retVal); } catch (final InvocationTargetException ite) { Throwable targetException = ite.getTargetException(); // Make sure the stack trace is correctly filled targetException.getStackTrace(); if (!this.isThrowableRegistered(targetException.getClass())) targetException = wrapInIOException(rpcRequest, targetException); rpcResponse = new RPCThrowable(rpcRequest.getMessageID(), targetException); } final DatagramPacket[] packets = this.messageToPackets(remoteSocketAddress, rpcResponse); this.cachedResponses.put(messageID, new CachedResponse(System.currentTimeMillis(), packets)); final int numberOfRetries = this.networkThread.send(packets); this.statistics.reportSuccessfulTransmission( rpcRequest.getMethodName() + " (Response)", packets.length, numberOfRetries); } catch (final Exception e) { Log.error("Caught processing RPC request: ", e); } finally { this.requestsBeingProcessed.remove(messageID); } }