private DatabusV3Registration findV3Registration(RegistrationId regId, DatabusRequest request)
      throws IOException, RequestProcessingException {
    Map<RegistrationId, DatabusV3Registration> regIdMap = _client.getRegistrationIdMap();
    if (null == regIdMap)
      throw new InvalidRequestParamValueException(
          request.getName(), REGISTRATION_KEY_PREFIX, "No registrations available !! ");

    DatabusV3Registration reg = regIdMap.get(regId);
    if (null == reg)
      throw new InvalidRequestParamValueException(
          request.getName(),
          REGISTRATION_KEY_PREFIX,
          "Registration with id " + regId + " not present !!");
    return reg;
  }
 private void processCluster(DatabusRequest request)
     throws IOException, RequestProcessingException {
   String category = request.getParams().getProperty(DatabusRequest.PATH_PARAM_NAME);
   String clusterName = category.substring(CLIENT_CLUSTER_KEY.length());
   Collection<PartitionInfo> clusters = getClusterPartitions(clusterName);
   writeJsonObjectToResponse(clusters, request);
 }
  /** Exposes the mapping between a mpRegistration -> Set of individual registrations */
  private void processMPRegistrations(DatabusRequest request)
      throws IOException, RequestProcessingException {
    Map<RegistrationId, DatabusV3Registration> registrationIdMap = _client.getRegistrationIdMap();

    if (null == registrationIdMap)
      throw new InvalidRequestParamValueException(
          request.getName(), REGISTRATIONS_KEY, "Present only for Databus V3 clients");

    Map<String, List<String>> ridList = new TreeMap<String, List<String>>();
    for (Map.Entry<RegistrationId, DatabusV3Registration> entry : registrationIdMap.entrySet()) {
      DatabusV3Registration reg = entry.getValue();
      if (reg instanceof DatabusV3MultiPartitionRegistration) {
        Collection<DatabusV3Registration> dvrList =
            ((DatabusV3MultiPartitionRegistration) reg).getPartionRegs().values();
        List<String> mpRegList = new ArrayList<String>();
        for (DatabusV3Registration dvr : dvrList) {
          mpRegList.add(dvr.getId().getId());
        }
        ridList.put(entry.getKey().getId(), mpRegList);
      }
    }

    writeJsonObjectToResponse(ridList, request);

    return;
  }
  private void processV3RegistrationInfo(String prefix, DatabusRequest request)
      throws IOException, RequestProcessingException {
    String category = request.getParams().getProperty(DatabusRequest.PATH_PARAM_NAME);
    String regIdStr = category.substring(prefix.length());
    RegistrationId regId = new RegistrationId(regIdStr);
    DatabusV3Registration reg = findV3Registration(regId, request);
    DatabusSourcesConnection sourcesConn = _client.getDatabusSourcesConnection(regIdStr);

    if (null == reg)
      throw new InvalidRequestParamValueException(
          request.getName(),
          REGISTRATION_KEY_PREFIX,
          "Registration with id " + regId + " not present !!");

    RegistrationStatsInfo regStatsInfo = new RegistrationStatsInfo(reg, sourcesConn);
    writeJsonObjectToResponse(regStatsInfo, request);
  }
 private void processPartition(DatabusRequest request)
     throws IOException, RequestProcessingException {
   String category = request.getParams().getProperty(DatabusRequest.PATH_PARAM_NAME);
   String clusterPartitionName = category.substring(CLIENT_CLUSTER_PARTITION_REG_KEY.length());
   String[] toks = clusterPartitionName.split("[:/]");
   if (toks.length != 2)
     throw new RequestProcessingException(
         "Cluster and partition info are expected to be in pattern = <cluster>[/:]<partition> but was "
             + clusterPartitionName);
   RegInfo reg = getPartitionRegistration(toks[0], new Long(toks[1]));
   writeJsonObjectToResponse(reg, request);
 }
  private DatabusRegistration findRegistration(DatabusRequest request, String prefix)
      throws RequestProcessingException {
    String category = request.getParams().getProperty(DatabusRequest.PATH_PARAM_NAME);
    String registrationIdStr = category.substring(prefix.length());
    RegistrationId regId = new RegistrationId(registrationIdStr);

    Collection<DatabusRegistration> regs = _client.getAllRegistrations();

    for (DatabusRegistration r : regs) {
      if (regId.equals(r.getRegistrationId())) return r;

      if (r instanceof DatabusMultiPartitionRegistration) {
        Map<DbusPartitionInfo, DatabusRegistration> childRegs =
            ((DatabusMultiPartitionRegistration) r).getPartitionRegs();
        for (Entry<DbusPartitionInfo, DatabusRegistration> e : childRegs.entrySet())
          if (regId.equals(e.getValue().getRegistrationId())) return e.getValue();
      }
    }
    throw new RequestProcessingException("Unable to find registration (" + regId + ") ");
  }
  @Override
  public DatabusRequest process(DatabusRequest request)
      throws IOException, RequestProcessingException {
    // Close the channel

    LOG.debug("Waiting for raw channel to close");

    ChannelFuture future =
        request.getResponseContent().getRawChannel().close().awaitUninterruptibly();

    try {
      future.await();
    } catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }

    LOG.debug("Done waiting for raw channel to close");

    return request;
  }
  private void processV3Registrations(DatabusRequest request)
      throws IOException, RequestProcessingException {
    Map<RegistrationId, DatabusV3Registration> registrationIdMap = _client.getRegistrationIdMap();

    if (null == registrationIdMap)
      throw new InvalidRequestParamValueException(
          request.getName(), REGISTRATIONS_KEY, "Present only for Databus V3 clients");

    Map<String, List<DatabusSubscription>> regIds =
        new TreeMap<String, List<DatabusSubscription>>();
    for (Map.Entry<RegistrationId, DatabusV3Registration> entry : registrationIdMap.entrySet()) {
      DatabusV3Registration reg = entry.getValue();
      if (reg instanceof DatabusV3MultiPartitionRegistration) continue;
      List<DatabusSubscription> dsl = reg.getSubscriptions();
      regIds.put(entry.getKey().getId(), dsl);
    }

    writeJsonObjectToResponse(regIds, request);

    return;
  }
  @Override
  public DatabusRequest process(DatabusRequest request)
      throws IOException, RequestProcessingException {

    String command = request.getParams().getProperty(DatabusRequest.PATH_PARAM_NAME);
    if (null == command) {
      throw new InvalidRequestParamValueException(COMMAND_NAME, "command", "null");
    }

    String reply = "Command " + command + " completed ";
    LOG.info("got relayCommand = " + command);
    if (command.equals(SAVE_META_STATE_PARAM)) {
      _relay.saveBufferMetaInfo(true);
    } else if (command.equals(SHUTDOWN_RELAY_PARAM)) {
      String msg =
          "received shutdown curl request from: "
              + request.getRemoteAddress()
              + ". Shutting down\n";
      LOG.warn(msg);
      request.getResponseContent().write(ByteBuffer.wrap(msg.getBytes("UTF-8")));
      request.getResponseContent().close();
      _relay.shutdown();
    } else if (command.equals(VALIDATE_RELAY_BUFFER_PARAM)) {
      _relay.validateRelayBuffers();
    } else if (command.equals(DISCONNECT_CLIENTS)) {
      Channel rspChannel = request.getResponseContent().getRawChannel();
      _relay.disconnectDBusClients(rspChannel);
    } else if (command.equals(RUN_GC_PARAM)) {
      Runtime rt = Runtime.getRuntime();
      long mem = rt.freeMemory();
      LOG.info("mem before gc = " + rt.freeMemory() + " out of " + rt.totalMemory());
      long time = System.currentTimeMillis();
      System.gc();
      time = System.currentTimeMillis() - time;
      mem = rt.freeMemory() - mem;
      reply =
          new String(
              "GC run. Took "
                  + time
                  + " millsecs. Freed "
                  + mem
                  + " bytes out of "
                  + rt.totalMemory());
    } else if (command.startsWith(RESET_RELAY_BUFFER_PARAM)) {
      // We expect the request to be of the format:
      //   resetRelayBuffer/<dbName>/<partitionId>?prevScn=<long>&binlogOffset=<long>
      String[] resetCommands = command.split("/");
      if (resetCommands.length != 3) {
        throw new InvalidRequestParamValueException(COMMAND_NAME, "command", command);
      }
      String dbName = resetCommands[1];
      String dbPart = resetCommands[2];
      long prevScn = request.getRequiredLongParam(PREV_SCN_PARAM);
      long binlogOffset = request.getOptionalLongParam(BINLOG_OFFSET_PARAM, 0L);
      LOG.info("reset command = " + dbName + " part =" + dbPart);
      try {
        _relay.resetBuffer(
            new PhysicalPartition(Integer.parseInt(dbPart), dbName), prevScn, binlogOffset);
      } catch (BufferNotFoundException e) {
        reply = new String("command " + command + ":" + e.getMessage());
      }
    } else if (command.startsWith(GET_BINLOG_OFFSET_PARAM)) {
      String[] getOfsArgs = command.split("/");
      if (getOfsArgs.length != 2) {
        throw new InvalidRequestParamValueException(GET_BINLOG_OFFSET_PARAM, "Server ID", "");
      }
      int serverId;
      try {
        serverId = Integer.parseInt(getOfsArgs[1]);
        int[] offset = _relay.getBinlogOffset(serverId);
        if (offset.length != 2) {
          reply = "Error getting binlog offset";
        } else {
          reply = new String("RelayLastEvent(" + offset[0] + "," + offset[1] + ")");
        }
      } catch (NumberFormatException e) {
        throw new InvalidRequestParamValueException(
            GET_BINLOG_OFFSET_PARAM, "Server ID", getOfsArgs[1]);
      } catch (DatabusException e) {
        reply = new String("command " + command + "failed with:" + e.getMessage());
      }
    } else if (command.startsWith(PRINT_RELAY_INFO_PARAM)) {
      try {
        Map<String, String> infoMap = _relay.printInfo();
        reply = makeJsonResponse(infoMap, request);
      } catch (Exception e) {
        reply = new String("command " + command + " failed with:" + e.getMessage());
      }
    } else {
      // invalid command
      reply =
          new String(
              "command "
                  + command
                  + " is invalid. Valid commands are: "
                  + SAVE_META_STATE_PARAM
                  + "|"
                  + SHUTDOWN_RELAY_PARAM
                  + "|"
                  + VALIDATE_RELAY_BUFFER_PARAM
                  + "|"
                  + RUN_GC_PARAM
                  + "|"
                  + RESET_RELAY_BUFFER_PARAM
                  + "|"
                  + GET_BINLOG_OFFSET_PARAM
                  + "|"
                  + PRINT_RELAY_INFO_PARAM
                  + "|"
                  + DISCONNECT_CLIENTS);
    }

    byte[] responseBytes = new byte[(reply.length() + 2)];

    System.arraycopy(reply.getBytes("UTF-8"), 0, responseBytes, 0, reply.length());
    int idx = reply.length();
    responseBytes[idx] = (byte) '\r';
    responseBytes[idx + 1] = (byte) '\n';

    request.getResponseContent().write(ByteBuffer.wrap(responseBytes));

    return request;
  }
  @Override
  protected DatabusRequest doProcess(DatabusRequest request)
      throws IOException, RequestProcessingException {
    BootstrapHttpStatsCollector bootstrapStatsCollector =
        _bootstrapServer.getBootstrapStatsCollector();
    long startTime = System.currentTimeMillis();
    String sources = request.getRequiredStringParam(SOURCES_PARAM);
    List<String> srcList = getSources(sources);

    Checkpoint ckpt = new Checkpoint(request.getRequiredStringParam(CHECKPOINT_PARAM));

    LOG.info("StartSCN requested for sources : (" + sources + "). CheckPoint is :" + ckpt);
    long sinceScn = ckpt.getBootstrapSinceScn();
    ObjectMapper mapper = new ObjectMapper();
    StringWriter out = new StringWriter(1024);
    long startSCN = -1;
    BootstrapSCNProcessor processor = null;

    try {
      processor =
          new BootstrapSCNProcessor(_config, _bootstrapServer.getInboundEventStatisticsCollector());
      List<SourceStatusInfo> srcStatusPairs = null;
      try {
        srcStatusPairs = processor.getSourceIdAndStatusFromName(srcList);
        startSCN = processor.getMinApplierWindowScn(sinceScn, srcStatusPairs);

        if (processor.shouldBypassSnapshot(sinceScn, startSCN, srcStatusPairs)) {
          LOG.info("Bootstrap Snapshot phase will be bypassed for startScn request :" + request);
          LOG.info(
              "Original startSCN is:"
                  + startSCN
                  + ", Setting startSCN to the sinceSCN:"
                  + sinceScn);
          startSCN = sinceScn;
        }

      } catch (BootstrapDatabaseTooOldException tooOldException) {
        if (bootstrapStatsCollector != null) {
          bootstrapStatsCollector.registerErrStartSCN();
          bootstrapStatsCollector.registerErrDatabaseTooOld();
        }

        LOG.error("The bootstrap database is too old!", tooOldException);
        throw new RequestProcessingException(tooOldException);
      } catch (SQLException e) {
        if (bootstrapStatsCollector != null) {
          bootstrapStatsCollector.registerErrStartSCN();
          bootstrapStatsCollector.registerErrSqlException();
        }
        LOG.error("Error encountered while fetching startSCN from database.", e);
        throw new RequestProcessingException(e);
      }
      mapper.writeValue(out, String.valueOf(startSCN));
      byte[] resultBytes = out.toString().getBytes();
      request.getResponseContent().write(ByteBuffer.wrap(resultBytes));
      LOG.info("startSCN: " + startSCN + "with server Info :" + _serverHostPort);
    } catch (Exception ex) {
      LOG.error("Got exception while calculating startSCN", ex);
      throw new RequestProcessingException(ex);
    } finally {
      if (null != processor) processor.shutdown();
    }

    if (bootstrapStatsCollector != null) {
      bootstrapStatsCollector.registerStartSCNReq(System.currentTimeMillis() - startTime);
    }
    return request;
  }