private void gc() throws Exception {
   sendRequest(
       ServerRequest.newBuilder()
           .setRequestId(nextRequestId.getAndIncrement())
           .setGcRequest(GcRequest.getDefaultInstance())
           .build());
 }
 private void preloadClasspathCache() throws Exception {
   sendRequest(
       ServerRequest.newBuilder()
           .setRequestId(nextRequestId.getAndIncrement())
           .setPreloadClasspathCacheRequest(PreloadClasspathCacheRequest.getDefaultInstance())
           .build());
 }
 private void updateAgentConfig(AgentConfig agentConfig) throws Exception {
   sendRequest(
       ServerRequest.newBuilder()
           .setRequestId(nextRequestId.getAndIncrement())
           .setAgentConfigUpdateRequest(
               AgentConfigUpdateRequest.newBuilder().setAgentConfig(agentConfig))
           .build());
 }
 private List<Trace.Entry> getEntries(String traceId) throws Exception {
   ClientResponse response =
       sendRequest(
           ServerRequest.newBuilder()
               .setRequestId(nextRequestId.getAndIncrement())
               .setEntriesRequest(EntriesRequest.newBuilder().setTraceId(traceId))
               .build());
   return response.getEntriesResponse().getEntryList();
 }
 private int reweave() throws Exception {
   ClientResponse response =
       sendRequest(
           ServerRequest.newBuilder()
               .setRequestId(nextRequestId.getAndIncrement())
               .setReweaveRequest(ReweaveRequest.getDefaultInstance())
               .build());
   return response.getReweaveResponse().getClassUpdateCount();
 }
 private GlobalMeta globalMeta() throws Exception {
   ClientResponse response =
       sendRequest(
           ServerRequest.newBuilder()
               .setRequestId(nextRequestId.getAndIncrement())
               .setGlobalMetaRequest(GlobalMetaRequest.getDefaultInstance())
               .build());
   return response.getGlobalMetaResponse().getGlobalMeta();
 }
 private MBeanMeta mbeanMeta(String objectName) throws Exception {
   ClientResponse response =
       sendRequest(
           ServerRequest.newBuilder()
               .setRequestId(nextRequestId.getAndIncrement())
               .setMbeanMetaRequest(MBeanMetaRequest.newBuilder().setObjectName(objectName))
               .build());
   return response.getMbeanMetaResponse().getMbeanMeta();
 }
 private HeapDumpFileInfo heapDump(String directory) throws Exception {
   ClientResponse response =
       sendRequest(
           ServerRequest.newBuilder()
               .setRequestId(nextRequestId.getAndIncrement())
               .setHeapDumpRequest(HeapDumpRequest.newBuilder().setDirectory(directory))
               .build());
   return response.getHeapDumpResponse().getHeapDumpFileInfo();
 }
 private ThreadDump threadDump() throws Exception {
   ClientResponse response =
       sendRequest(
           ServerRequest.newBuilder()
               .setRequestId(nextRequestId.getAndIncrement())
               .setThreadDumpRequest(ThreadDumpRequest.getDefaultInstance())
               .build());
   return response.getThreadDumpResponse().getThreadDump();
 }
 private Capabilities capabilities() throws Exception {
   ClientResponse response =
       sendRequest(
           ServerRequest.newBuilder()
               .setRequestId(nextRequestId.getAndIncrement())
               .setCapabilitiesRequest(CapabilitiesRequest.getDefaultInstance())
               .build());
   return response.getCapabilitiesResponse().getCapabilities();
 }
 private long availableDiskSpaceBytes(String directory) throws Exception {
   ClientResponse response =
       sendRequest(
           ServerRequest.newBuilder()
               .setRequestId(nextRequestId.getAndIncrement())
               .setAvailableDiskSpaceRequest(
                   AvailableDiskSpaceRequest.newBuilder().setDirectory(directory))
               .build());
   return response.getAvailableDiskSpaceResponse().getAvailableBytes();
 }
 private List<String> matchingClassNames(String partialClassName, int limit) throws Exception {
   ClientResponse response =
       sendRequest(
           ServerRequest.newBuilder()
               .setRequestId(nextRequestId.getAndIncrement())
               .setMatchingClassNamesRequest(
                   MatchingClassNamesRequest.newBuilder()
                       .setPartialClassName(partialClassName)
                       .setLimit(limit))
               .build());
   return response.getMatchingClassNamesResponse().getClassNameList();
 }
 private List<MethodSignature> methodSignatures(String className, String methodName)
     throws Exception {
   ClientResponse response =
       sendRequest(
           ServerRequest.newBuilder()
               .setRequestId(nextRequestId.getAndIncrement())
               .setMethodSignaturesRequest(
                   MethodSignaturesRequest.newBuilder()
                       .setClassName(className)
                       .setMethodName(methodName))
               .build());
   return response.getMethodSignaturesResponse().getMethodSignatureList();
 }
 private MBeanDump mbeanDump(MBeanDumpKind mbeanDumpKind, List<String> objectNames)
     throws Exception {
   ClientResponse response =
       sendRequest(
           ServerRequest.newBuilder()
               .setRequestId(nextRequestId.getAndIncrement())
               .setMbeanDumpRequest(
                   MBeanDumpRequest.newBuilder()
                       .setKind(mbeanDumpKind)
                       .addAllObjectName(objectNames))
               .build());
   return response.getMbeanDumpResponse().getMbeanDump();
 }
 private @Nullable Trace getFullTrace(String traceId) throws Exception {
   ClientResponse response =
       sendRequest(
           ServerRequest.newBuilder()
               .setRequestId(nextRequestId.getAndIncrement())
               .setFullTraceRequest(FullTraceRequest.newBuilder().setTraceId(traceId))
               .build());
   if (response.getFullTraceResponse().hasTrace()) {
     return response.getFullTraceResponse().getTrace();
   } else {
     return null;
   }
 }
 private ClientResponse sendRequest(ServerRequest request) throws Exception {
   ResponseHolder responseHolder = new ResponseHolder();
   responseHolders.put(request.getRequestId(), responseHolder);
   requestObserver.onNext(request);
   // timeout is in case agent never responds
   // passing ClientResponse.getDefaultInstance() is just dummy (non-null) value
   ClientResponse response =
       responseHolder.response.exchange(ClientResponse.getDefaultInstance(), 1, HOURS);
   if (response.getMessageCase() == MessageCase.UNKNOWN_REQUEST_RESPONSE) {
     throw new OutdatedAgentException();
   }
   if (response.getMessageCase() == MessageCase.EXCEPTION_RESPONSE) {
     throw new AgentException();
   }
   return response;
 }
 @Override
 public void onNext(ClientResponse value) {
   if (value.getMessageCase() == MessageCase.HELLO) {
     agentId = value.getHello().getAgentId();
     connectedAgents.put(agentId, ConnectedAgent.this);
     requestObserver.onNext(
         ServerRequest.newBuilder().setHelloAck(HelloAck.getDefaultInstance()).build());
     return;
   }
   long requestId = value.getRequestId();
   ResponseHolder responseHolder = responseHolders.getIfPresent(requestId);
   responseHolders.invalidate(requestId);
   if (responseHolder == null) {
     logger.error("no response holder for request id: {}", requestId);
     return;
   }
   try {
     responseHolder.response.exchange(value);
   } catch (InterruptedException e) {
     Thread.currentThread().interrupt();
     logger.error(e.getMessage(), e);
   }
 }