package com.linkedin.databus.client.request; /* * * Copyright 2013 LinkedIn Corp. All rights reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.TreeMap; import java.util.Map.Entry; import java.util.concurrent.ExecutorService; import org.apache.log4j.Logger; import com.linkedin.databus.client.DatabusHttpClientImpl; import com.linkedin.databus.client.DatabusSourcesConnection; import com.linkedin.databus.client.DbusPartitionInfoImpl; import com.linkedin.databus.client.monitoring.RegistrationStatsInfo; import com.linkedin.databus.client.pub.DatabusRegistration; import com.linkedin.databus.client.pub.DatabusV3MultiPartitionRegistration; import com.linkedin.databus.client.pub.DatabusV3Registration; import com.linkedin.databus.client.pub.DbusClusterInfo; import com.linkedin.databus.client.pub.DbusPartitionInfo; import com.linkedin.databus.client.pub.RegistrationId; import com.linkedin.databus.client.pub.RegistrationState; import com.linkedin.databus.client.registration.DatabusMultiPartitionRegistration; import com.linkedin.databus.client.registration.DatabusV2ClusterRegistrationImpl; import com.linkedin.databus.core.DatabusComponentStatus; import com.linkedin.databus.core.data_model.DatabusSubscription; import com.linkedin.databus.core.data_model.PhysicalPartition; import com.linkedin.databus2.core.container.request.AbstractStatsRequestProcessor; import com.linkedin.databus2.core.container.request.DatabusRequest; import com.linkedin.databus2.core.container.request.InvalidRequestParamValueException; import com.linkedin.databus2.core.container.request.RequestProcessingException; import com.linkedin.databus2.core.filter.DbusKeyCompositeFilterConfig; /** * * Request processor to support REST API for * * (a) Listing the registration ids (both V2/V3 top and partition level registrations). * (b) Inspecting the status of a given registration by id (c) Listing all the client * clusters (both V2 and V3) registered to the client instance. (d) List all the active * partitions for a given V2/V3 client cluster. (e) Pause/Resume a given V2/V3 * registration (both top-level and partition (child) level). (f) Pause/Resume all the V2 * and V3 registrations (both top-level and partition (child) level) (g) List all the * MPRegistrations (V3). * * Please note that Top-level registrations are those that were created as a result of one * of "registerXXX()" calls on databus-client. In the case of multi-partition * registrations (like MPRegistration, V2/V3 CLB), only the parent registration is * considered the top-level registration. Per-partition (child) registrations which were * created as part of partition migration are NOT top-level registrations. */ public class ClientStateRequestProcessor extends AbstractStatsRequestProcessor { public static final String MODULE = ClientStateRequestProcessor.class.getName(); public static final Logger LOG = Logger.getLogger(MODULE); public static final String COMMAND_NAME = "clientState"; private final DatabusHttpClientImpl _client; /** All first-level registrations listed **/ private final static String REGISTRATIONS_KEY = "registrations"; /** First-level registration info listed **/ private final static String REGISTRATION_KEY_PREFIX = "registration/"; /** All Client Clusters supported by this client instance **/ private final static String CLIENT_CLUSTERS_KEY = "clientClusters"; /** Partitions supported by this client cluster with their registrations **/ private final static String CLIENT_CLUSTER_KEY = "clientPartitions/"; /** Registration info supported by this client cluster with their registrations **/ private final static String CLIENT_CLUSTER_PARTITION_REG_KEY = "clientPartition/"; /** Multi Partition Registrations active in this client instance **/ private final static String MP_REGISTRATIONS_KEY = "mpRegistrations"; /** Pause all registrations active in this client instance **/ private final static String PAUSE_ALL_REGISTRATIONS = "registrations/pause"; /** Pause registration identified by the registration id **/ private final static String PAUSE_REGISTRATION = "registration/pause"; /** Resume all registrations paused in this client instance **/ private final static String RESUME_ALL_REGISTRATIONS = "registrations/resume"; /** Resume registration identified by the registration id **/ private final static String RESUME_REGISTRATION = "registration/resume"; public ClientStateRequestProcessor(ExecutorService executorService, DatabusHttpClientImpl client) { super(COMMAND_NAME, executorService); _client = client; } @Override protected boolean doProcess(String category, DatabusRequest request) throws IOException, RequestProcessingException { boolean success = true; if (category.equals(REGISTRATIONS_KEY)) { processRegistrations(request); } else if (category.startsWith(PAUSE_REGISTRATION)) { pauseResumeRegistration(request, true); } else if (category.startsWith(RESUME_REGISTRATION)) { pauseResumeRegistration(request, false); } else if (category.startsWith(REGISTRATION_KEY_PREFIX)) { processRegistrationInfo(request); } else if (category.startsWith(CLIENT_CLUSTERS_KEY)) { processClusters(request); } else if (category.startsWith(CLIENT_CLUSTER_KEY)) { processCluster(request); } else if (category.startsWith(CLIENT_CLUSTER_PARTITION_REG_KEY)) { processPartition(request); } else if (category.equals(MP_REGISTRATIONS_KEY)) { processMPRegistrations(request); } else if (category.equals(PAUSE_ALL_REGISTRATIONS)) { pauseAllRegistrations(request); } else if (category.equals(RESUME_ALL_REGISTRATIONS)) { resumeAllRegistrations(request); } else { success = false; } return success; } /** * 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.getRegistrationId().getId()); } ridList.put(entry.getKey().getId(), mpRegList); } } writeJsonObjectToResponse(ridList, request); return; } /** * Provides an individual registrations details. The individual registration can be * either that of V2/V3 and top-level or child. Top-level registrations are those that * were created as a result of one of "registerXXX()" calls on databus-client. In the * case of multi-partition registrations (like MPRegistration, V2/V3 CLB), only the * parent registration is considered the top-level registration. Per-partition (child) * registrations which were created as part of partition migration are NOT top-level * registrations. The output format can be different depending on whether it is a V2/V3 * as we are dumping the entire Registration in the case of V2. In the case of V3, we * create an intermediate objects. These are legacy formats which when changed could * cause the integ-tests to fail. * * @param request * DatabusRequest corresponding to the REST call. * @throws IOException * if unable to write to output channel. * @throws RequestProcessingException * when registration could not be located. */ private void processRegistrationInfo(DatabusRequest request) throws IOException, RequestProcessingException { boolean found = true; // V2 Registration lookup first RegistrationStatsInfo regStatsInfo = null; try { DatabusRegistration r = findV2Registration(request, REGISTRATION_KEY_PREFIX); writeJsonObjectToResponse(r, request); } catch (RequestProcessingException ex) { found = false; } // V3 Registration lookup if not found if (!found) { DatabusV3Registration reg = findV3Registration(request, REGISTRATION_KEY_PREFIX); // if // reg // is // null, // the // callee // throws // an // exception. DatabusSourcesConnection sourcesConn = _client.getDatabusSourcesConnection(reg.getRegistrationId().getId()); regStatsInfo = new RegistrationStatsInfo(reg, sourcesConn); writeJsonObjectToResponse(regStatsInfo, request); } } /** * Displays all top-level registrations registered to the client (both V2 and V3). * Top-level registrations are those that were created as a result of one of * "registerXXX()" calls on databus-client. In the case of multi-partition registrations * (like MPRegistration, V2/V3 CLB), only the parent registration is considered the * top-level registration. Per-partition (child) registrations which were created as * part of partition migration are NOT top-level registrations. * * @param request * DatabusRequest corresponding to the REST API. * @throws IOException * when unable to write to ourput channel */ private void processRegistrations(DatabusRequest request) throws IOException { Map<String, Collection<DatabusSubscription>> regIds = new TreeMap<String, Collection<DatabusSubscription>>(); // V2 Registration Collection<RegInfo> regs = getAllTopLevelV2Registrations(); if (null != regs) { for (RegInfo r : regs) { regIds.put(r.getRegId().getId(), r.getSubs()); } } Map<RegistrationId, DatabusV3Registration> registrationIdMap = _client.getRegistrationIdMap(); // V3 Registration if (null != registrationIdMap) { for (Map.Entry<RegistrationId, DatabusV3Registration> entry : registrationIdMap.entrySet()) { DatabusV3Registration reg = entry.getValue(); List<DatabusSubscription> dsl = reg.getSubscriptions(); regIds.put(entry.getKey().getId(), dsl); } } writeJsonObjectToResponse(regIds, request); } /** * * Proved list of V2 and V3 Client clusters which are used (registered). * * @param request * DatabusRequest corresponding to the REST call. * @throws IOException * when unable to write to output channel. */ private void processClusters(DatabusRequest request) throws IOException { Map<RegistrationId, DbusClusterInfo> clusters = _client.getAllClientClusters(); writeJsonObjectToResponse(clusters.values(), request); } /** * Provide the list of partitions corresponding to the V2/V3 client cluster. * * @param request * DatabusRequest corresponding to the REST call. * @throws IOException * when unable to write to output channel. * @throws RequestProcessingException * when cluster not found. */ 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()); List<PartitionInfo> clusters = new ArrayList<PartitionInfo>(); RequestProcessingException rEx = null; Collection<PartitionInfo> v2Clusters = null; // Check as if this is V2 Cluster first boolean found = true; try { v2Clusters = getV2ClusterPartitions(clusterName); clusters.addAll(v2Clusters); } catch (RequestProcessingException ex) { found = false; rEx = ex; } // Try as V3 cluster if it is not V2. if (!found) { Collection<PartitionInfo> v3Clusters = null; try { v3Clusters = getV3ClusterPartitions(clusterName); clusters.addAll(v3Clusters); found = true; } catch (RequestProcessingException ex) { found = false; rEx = ex; } } if (!found) throw rEx; writeJsonObjectToResponse(clusters, request); } /** * Provide a partition information belonging to a V2/V3 client cluster and hosted in * this client instance * * @param request * DatabusRequest corresponding to the REST call. * @throws IOException * when unable to write to output channel. * @throws RequestProcessingException * when cluster not found or when partition is not hosted in this instance */ 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()); /** * API: curl * http://<HOST>:<PORT>/clientState/clientPartition/<CLUSTER_NAME>/<PARTITION> curl * http://<HOST>:<PORT>/clientState/clientPartition/<CLUSTER_NAME>:<PARTITION> */ 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 = null; boolean found = true; // Try as a V2 Partition try { reg = getV2PartitionRegistration(toks[0], new Long(toks[1])); } catch (RequestProcessingException ex) { found = false; } // If not found, try as V3 if (!found) { reg = getV3PartitionRegistration(toks[0], new Long(toks[1])); } writeJsonObjectToResponse(reg, request); } private DatabusV2ClusterRegistrationImpl getV2ClusterRegistration(String clusterName) throws RequestProcessingException { Collection<DatabusMultiPartitionRegistration> regs = _client.getAllClientClusterRegistrations(); for (DatabusMultiPartitionRegistration reg : regs) { if (reg instanceof DatabusV2ClusterRegistrationImpl) { DatabusV2ClusterRegistrationImpl r = (DatabusV2ClusterRegistrationImpl) reg; if (clusterName.equals(r.getClusterInfo().getName())) return r; } } throw new RequestProcessingException("No Registration found for cluster (" + clusterName + ") !!"); } private DatabusV3MultiPartitionRegistration getV3ClusterRegistration(String clusterName) throws RequestProcessingException { // There is a one-to-one mapping between clusterName to // DatabusV3MultiPartitionRegistration Map<RegistrationId, DbusClusterInfo> clusterMap = _client.getAllClientClusters(); for (Entry<RegistrationId, DbusClusterInfo> e : clusterMap.entrySet()) { if (clusterName.equalsIgnoreCase(e.getValue().getName())) { DatabusV3Registration reg = _client.getRegistration(e.getKey()); if (reg instanceof DatabusV3MultiPartitionRegistration) { return (DatabusV3MultiPartitionRegistration) reg; } break; } } throw new RequestProcessingException("No Registration found for cluster (" + clusterName + ") !!"); } /** * Pause or resume a V2 or V3 registration. The registration can be a top-level or * child-level registration Top-level registrations are those that were created as a * result of one of "registerXXX()" calls on databus-client. In the case of * multi-partition registrations (like MPRegistration, V2/V3 CLB), only the parent * registration is considered the top-level registration. Per-partition (child) * registrations which were created as part of partition migration are NOT top-level * registrations. * * @param request * Databus request corresponding to the REST call. * @param doPause * true if wanted to pause, false if to be resumed * @throws IOException * if unable to write output to channel * @throws RequestProcessingException * when registration could not be found. */ private void pauseResumeRegistration(DatabusRequest request, boolean doPause) throws IOException, RequestProcessingException { DatabusRegistration r = null; DatabusV3Registration r2 = null; boolean found = true; boolean isRunning = false; boolean isPaused = false; boolean isSuspended = false; RegistrationId regId = null; RequestProcessingException rEx = null; RegStatePair regStatePair = null; try { r = findV2Registration(request, PAUSE_REGISTRATION); isRunning = r.getState().isRunning(); isPaused = (r.getState() == DatabusRegistration.RegistrationState.PAUSED); isSuspended = (r.getState() == DatabusRegistration.RegistrationState.SUSPENDED_ON_ERROR); regId = r.getRegistrationId(); } catch (RequestProcessingException ex) { found = false; rEx = ex; } if (!found) { try { r2 = findV3Registration(request, PAUSE_REGISTRATION); found = true; isRunning = r2.getState().isRunning(); isPaused = (r2.getState() == RegistrationState.PAUSED); isSuspended = (r2.getState() == RegistrationState.SUSPENDED_ON_ERROR); regId = r.getRegistrationId(); } catch (RequestProcessingException ex) { found = false; rEx = ex; } } if (!found) throw rEx; LOG.info("REST call to pause registration : " + regId); if (isRunning) { if (doPause) { if (!isPaused) { if (null != r) { r.pause(); regStatePair = new RegStatePair(r.getState(), r.getRegistrationId()); } else { r2.pause(); regStatePair = new RegStatePair(r2.getState().name(), r2.getRegistrationId()); } } } else { if (isPaused || isSuspended) { if (null != r) { r.resume(); regStatePair = new RegStatePair(r.getState(), r.getRegistrationId()); } else { r2.resume(); regStatePair = new RegStatePair(r2.getState().name(), r2.getRegistrationId()); } } } } writeJsonObjectToResponse(regStatePair, request); } /** * Pause all registrations (both V2 and V3 in this client instance) which are in running * state. * * @param request * DatabusRequest corresponding to the REST call. * @throws IOException * when unable to write the output. */ private void pauseAllRegistrations(DatabusRequest request) throws IOException { LOG.info("REST call to pause all registrations"); /** * Get the top-level V2 registrations and pause them. The child-level registrations by * the top-level registrations that aggregates them. */ Collection<DatabusRegistration> regs = _client.getAllRegistrations(); if (null != regs) { for (DatabusRegistration r : regs) { if (r.getState().isRunning()) { if (r.getState() != DatabusRegistration.RegistrationState.PAUSED) r.pause(); } } } /** * Get the top-level V3 registrations and pause them. The child-level registrations by * the top-level registrations that aggregates them. */ Map<RegistrationId, DatabusV3Registration> regMap = _client.getRegistrationIdMap(); Collection<RegInfo> topLevelRegs = getAllTopLevelV3Registrations(); /** * Important Note: There is an important implementation difference on which * registrations are stored in the global registration data-structure maintained by * the client (DatabusHttp[V3]ClientImpls) between V2 and V3. * * 1. In the case of V2, only top-level registrations are stored in the global * data-structure (DatabusHttpClientImpl.regList 2. In the case of V3, all * registrations are stored in the global data-structure. * * In the case of V3, this is needed so that all registrations can act on the relay * external view change. This can be refactored in the future by moving the * relay-external view change to registration impl ( reduce the complexity in * ClientImpl ). The V2 implementation did not have this logic and was following a * more intuitive structure of preserving the hierarchy. */ if ((null != regMap) && (null != topLevelRegs)) { for (RegInfo reg : topLevelRegs) { DatabusV3Registration r = regMap.get(reg.getRegId()); if (r.getState().isRunning()) { if (r.getState() != RegistrationState.PAUSED) r.pause(); } } } writeJsonObjectToResponse(getAllTopLevelRegStates(), request); } /** * Resume all registrations paused or suspended (both V2 and V3 in this client instance) * * @param request * DatabusRequest corresponding to the REST call. * @throws IOException * when unable to write the output. */ private void resumeAllRegistrations(DatabusRequest request) throws IOException { LOG.info("REST call to resume all registrations"); /** * Get the top-level V2 registrations and pause them. The child-level registrations by * the top-level registrations that aggregates them. */ Collection<DatabusRegistration> regs = _client.getAllRegistrations(); if (null != regs) { for (DatabusRegistration r : regs) { if (r.getState().isRunning()) { if ((r.getState() == DatabusRegistration.RegistrationState.PAUSED) || (r.getState() == DatabusRegistration.RegistrationState.SUSPENDED_ON_ERROR)) r.resume(); } } } /** * Get the top-level V3 registrations and pause them. The child-level registrations by * the top-level registrations that aggregates them. */ Map<RegistrationId, DatabusV3Registration> regMap = _client.getRegistrationIdMap(); Collection<RegInfo> topLevelRegs = getAllTopLevelV3Registrations(); /** * Important Note: There is an important implementation difference on which * registrations are stored in the global registration data-structure maintained by * the client (DatabusHttp[V3]ClientImpls) between V2 and V3. * * 1. In the case of V2, only top-level registrations are stored in the global * data-structure (DatabusHttpClientImpl.regList 2. In the case of V3, all * registrations are stored in the global data-structure. * * In the case of V3, this is needed so that all registrations can act on the relay * external view change. This can be refactored in the future by moving the * relay-external view change to registration impl ( reduce the complexity in * ClientImpl ). The V2 implementation did not have this logic and was following a * more intuitive structure of preserving the hierarchy. */ if ((null != regMap) && (null != topLevelRegs)) { for (RegInfo reg : topLevelRegs) { DatabusV3Registration r = regMap.get(reg.getRegId()); if (r.getState().isRunning()) { if ((r.getState() == RegistrationState.PAUSED) || (r.getState() == RegistrationState.SUSPENDED_ON_ERROR)) r.resume(); } } } writeJsonObjectToResponse(getAllTopLevelRegStates(), request); } /** * Generate regStatePair for all the top-level registrations (both V2 and V3). * * @return */ private Collection<RegStatePair> getAllTopLevelRegStates() { List<RegStatePair> regList = new ArrayList<RegStatePair>(); Collection<RegInfo> regs = getAllTopLevelRegistrations(); for (RegInfo reg : regs) { regList.add(new RegStatePair(reg.getState(), reg.getRegId())); } return regList; } /** * Returns all the top-level registrations (both V2 and V3). Top-level registrations are * those that were created as a result of one of "registerXXX()" calls on * databus-client. In the case of multi-partition registrations (like MPRegistration, * V2/V3 CLB), only the parent registration is considered the top-level registration. * Per-partition (child) registrations which were created as part of partition migration * are NOT top-level registrations. * * @return collection of top-level registrations (V2/V3) */ private Collection<RegInfo> getAllTopLevelRegistrations() { List<RegInfo> regList = new ArrayList<RegInfo>(); regList.addAll(getAllTopLevelV2Registrations()); regList.addAll(getAllTopLevelV3Registrations()); return regList; } /** * Returns all the top-level V3 registrations. Top-level registrations are those that * were created as a result of one of "registerXXX()" calls on databus-client. In the * case of multi-partition registrations (like MPRegistration, V3 CLB), only the parent * registration is considered the top-level registration. Per-partition (child) * registrations which were created as part of partition migration are NOT top-level * registrations. * * @return collection of top-level registrations (V3) */ private Collection<RegInfo> getAllTopLevelV3Registrations() { /** * Important Note: There is an important implementation difference on which * registrations are stored in the global registration data-structure maintained by * the client (DatabusHttp[V3]ClientImpls) between V2 and V3. * * 1. In the case of V2, only top-level registrations are stored in the global * data-structure (DatabusHttpClientImpl.regList 2. In the case of V3, all * registrations are stored in the global data-structure. * * In the case of V3, this is needed so that all registrations can act on the relay * external view change. This can be refactored in the future by moving the * relay-external view change to registration impl ( reduce the complexity in * ClientImpl ). The V2 implementation did not have this logic and was following a * more intuitive structure of preserving the hierarchy. */ Map<RegistrationId, RegInfo> regListMap = new HashMap<RegistrationId, RegInfo>(); /** * The _client.getRegistrationIdMap() has all registrations in one place. Top-Level * Registrations = Only those registrations whose getParent() == null. */ Map<RegistrationId, DatabusV3Registration> regMap = _client.getRegistrationIdMap(); for (Entry<RegistrationId, DatabusV3Registration> e : regMap.entrySet()) { RegInfo regInfo = null; DatabusV3Registration r = e.getValue(); // If not top-level, skip if (null != r.getParentRegistration()) { continue; } Map<DbusPartitionInfo, RegInfo> childR = null; if (r instanceof DatabusV3MultiPartitionRegistration) { // ass the children regs to parent. Map<PhysicalPartition, DatabusV3Registration> childRegs = ((DatabusV3MultiPartitionRegistration) r).getPartionRegs(); childR = new HashMap<DbusPartitionInfo, RegInfo>(); for (Entry<PhysicalPartition, DatabusV3Registration> e2 : childRegs.entrySet()) { childR.put(new DbusPartitionInfoImpl(e2.getKey().getId()), new RegInfo(e.getValue().getState().name(), e.getValue().getRegistrationId(), e.getValue().getStatus(), null, e.getValue().getSubscriptions())); } } regInfo = new RegInfo(r.getState().name(), r.getRegistrationId(), r.getStatus(), null, r.getSubscriptions(), true, childR); regListMap.put(e.getKey(), regInfo); } return regListMap.values(); } /** * Returns all the top-level V2 registrations. Top-level registrations are those that * were created as a result of one of "registerXXX()" calls on databus-client. In the * case of multi-partition registrations (like V2 CLB), only the parent registration is * considered the top-level registration. Per-partition (child) registrations which were * created as part of partition migration are NOT top-level registrations. * * @return collection of top-level registrations (V2) */ private Collection<RegInfo> getAllTopLevelV2Registrations() { List<RegInfo> regList = new ArrayList<RegInfo>(); Collection<DatabusRegistration> regs = _client.getAllRegistrations(); for (DatabusRegistration r : regs) { RegInfo regInfo = null; if (r instanceof DatabusMultiPartitionRegistration) { Map<DbusPartitionInfo, DatabusRegistration> childRegs = ((DatabusMultiPartitionRegistration) r).getPartitionRegs(); Map<DbusPartitionInfo, RegInfo> childR = new HashMap<DbusPartitionInfo, RegInfo>(); for (Entry<DbusPartitionInfo, DatabusRegistration> e : childRegs.entrySet()) { childR.put(e.getKey(), new RegInfo(e.getValue().getState().name(), e.getValue().getRegistrationId(), e.getValue().getStatus(), e.getValue().getFilterConfig(), e.getValue().getSubscriptions())); } regInfo = new RegInfo(r.getState().name(), r.getRegistrationId(), r.getStatus(), r.getFilterConfig(), r.getSubscriptions(), true, childR); } else { regInfo = new RegInfo(r.getState().name(), r.getRegistrationId(), r.getStatus(), r.getFilterConfig(), r.getSubscriptions()); } regList.add(regInfo); } return regList; } /** * Get the list of partitions hosted by this client for the V2 cluster. * * @param cluster * V2 CLuster for which we need to find out the partitions. * @return * @throws RequestProcessingException * when unable to find the cluster. */ private Collection<PartitionInfo> getV2ClusterPartitions(String cluster) throws RequestProcessingException { DatabusV2ClusterRegistrationImpl reg = getV2ClusterRegistration(cluster); List<PartitionInfo> partitions = new ArrayList<PartitionInfo>(); Map<DbusPartitionInfo, DatabusRegistration> regMap = reg.getPartitionRegs(); for (Entry<DbusPartitionInfo, DatabusRegistration> e : regMap.entrySet()) { PartitionInfo p = new PartitionInfo(e.getKey().getPartitionId(), e.getValue().getRegistrationId()); partitions.add(p); } return partitions; } /** * Get the list of partitions hosted by this client for the V3 cluster. * * @param cluster * V3 CLuster for which we need to find out the partitions. * @return * @throws RequestProcessingException * when unable to find the cluster. */ private Collection<PartitionInfo> getV3ClusterPartitions(String cluster) throws RequestProcessingException { DatabusV3MultiPartitionRegistration reg = getV3ClusterRegistration(cluster); List<PartitionInfo> partitions = new ArrayList<PartitionInfo>(); Map<PhysicalPartition, DatabusV3Registration> regMap = reg.getPartionRegs(); for (Entry<PhysicalPartition, DatabusV3Registration> e : regMap.entrySet()) { PartitionInfo p = new PartitionInfo(e.getKey().getId(), e.getValue().getRegistrationId()); partitions.add(p); } return partitions; } /** * Helper method to get partition registration information for a given V2 Cluster * partition * * @param cluster * V2 Cluster * @param partition * Partition in the cluster. * @return * @throws RequestProcessingException * When cluster or partition is not hosted in this instance. */ private RegInfo getV2PartitionRegistration(String cluster, long partition) throws RequestProcessingException { DatabusV2ClusterRegistrationImpl reg = getV2ClusterRegistration(cluster); DbusPartitionInfo p = new DbusPartitionInfoImpl(partition); DatabusRegistration r = reg.getPartitionRegs().get(p); if (null == r) throw new RequestProcessingException("Partition(" + partition + ") for cluster (" + cluster + ") not found !!"); return new RegInfo(r.getState().name(), r.getRegistrationId(), r.getStatus(), r.getFilterConfig(), r.getSubscriptions()); } /** * Helper method to get partition registration information for a given V3 Cluster * partition * * @param cluster * V3 Cluster * @param partition * Partition in the cluster. * @return * @throws RequestProcessingException * When cluster or partition is not hosted in this instance. */ private RegInfo getV3PartitionRegistration(String cluster, long partition) throws RequestProcessingException { DatabusV3MultiPartitionRegistration reg = getV3ClusterRegistration(cluster); for (Entry<PhysicalPartition, DatabusV3Registration> e : reg.getPartionRegs() .entrySet()) { if (partition == e.getKey().getId()) { DatabusV3Registration r = e.getValue(); return new RegInfo(r.getState().name(), r.getRegistrationId(), r.getStatus(), null, r.getSubscriptions()); } } throw new RequestProcessingException("Partition(" + partition + ") for cluster (" + cluster + ") not found !!"); } /** * Helper method to locate a databus V2 registration by its registration id. This method * can locate both top-level (registered by one of _dbusClient.registerXXX()) and * individual-partition (child) registration that are aggregated inside a top-level * MultiPartition registration. * * Please note that this can traverse the registration tree which is 1 level deep. In * other words, it will not work when we have MultiPartition registrations aggregated * inside another MultiPartition registrations. * * @param regId * Registration Id to be located * @param request * Databus Request corresponding to the REST call. * @return * @throws RequestProcessingException * when the registration is not found. */ private DatabusRegistration findV2Registration(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(); if (null != regs) { for (DatabusRegistration r : regs) { if (regId.equals(r.getRegistrationId())) { return r; } /** * Important Note: There is an important implementation difference on which * registrations are stored in the global registration data-structure maintained * by the client (DatabusHttp[V3]ClientImpls) between V2 and V3. * * 1. In the case of V2, only top-level registrations are stored in the global * data-structure (DatabusHttpClientImpl.regList 2. In the case of V3, all * registrations are stored in the global data-structure. * * In the case of V3, this is needed so that all registrations can act on the * relay external view change. This can be refactored in the future by moving the * relay-external view change to registration impl ( reduce the complexity in * ClientImpl ). The V2 implementation did not have this logic and was following a * more intuitive structure of preserving the hierarchy. The below code handles * the discrepancy for V2. */ 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 + ") "); } /** * Helper method to locate a databus V3 registration by its registration id. This method * can locate both top-level (registered by one of _dbusClient.registerXXX()) and * individual-partition (child) registration that are aggregated inside a top-level * MultiPartition registration. * * Please note that this can traverse the registration tree which is 1 level deep. In * other words, it will not work when we have MultiPartition registrations aggregated * inside another MultiPartition registrations. * * @param regId * Registration Id to be located * @param request * Databus Request corresponding to the REST call. * @return * @throws RequestProcessingException * when the registration is not found. */ private DatabusV3Registration findV3Registration(RegistrationId regId, DatabusRequest request) throws RequestProcessingException { Map<RegistrationId, DatabusV3Registration> regIdMap = _client.getRegistrationIdMap(); if (null == regIdMap) { throw new InvalidRequestParamValueException(request.getName(), REGISTRATION_KEY_PREFIX, "No registrations available !! "); } /** * Important Note: There is an important implementation difference on which * registrations are stored in the global registration data-structure maintained by * the client (DatabusHttp[V3]ClientImpls) between V2 and V3. * * 1. In the case of V2, only top-level registrations are stored in the global * data-structure (DatabusHttpClientImpl.regList 2. In the case of V3, all * registrations are stored in the global data-structure. * * In the case of V3, this is needed so that all registrations can act on the relay * external view change. This can be refactored in the future by moving the * relay-external view change to registration impl ( reduce the complexity in * ClientImpl ). The V2 implementation did not have this logic and was following a * more intuitive structure of preserving the hierarchy. */ for (DatabusV3Registration r : regIdMap.values()) { if (regId.equals(r.getRegistrationId())) { return r; } } throw new InvalidRequestParamValueException(request.getName(), REGISTRATION_KEY_PREFIX, "Registration with id " + regId + " not present !!"); } private DatabusV3Registration findV3Registration(DatabusRequest request, String prefix) throws RequestProcessingException { String category = request.getParams().getProperty(DatabusRequest.PATH_PARAM_NAME); String regIdStr = category.substring(prefix.length()); RegistrationId regId = new RegistrationId(regIdStr); return findV3Registration(regId, request); } private static class PartitionInfo { private final long partition; private final RegistrationId regId; public long getPartition() { return partition; } public RegistrationId getRegId() { return regId; } public PartitionInfo(long partition, RegistrationId regId) { super(); this.partition = partition; this.regId = regId; } } private static class RegStatePair { private final String _state; private final RegistrationId _regId; public String getState() { return _state; } public RegistrationId getRegId() { return _regId; } public RegStatePair(DatabusRegistration.RegistrationState state, RegistrationId regId) { _regId = regId; _state = state.name(); } public RegStatePair(String state, RegistrationId regId) { _regId = regId; _state = state; } } private static class RegInfo { private final String state; private final RegistrationId regId; private final String status; private final DbusKeyCompositeFilterConfig filter; private final Collection<DatabusSubscription> subs; private final boolean isMultiPartition; private final Map<DbusPartitionInfo, RegInfo> childRegistrations; public String getState() { return state; } public RegistrationId getRegId() { return regId; } public String getStatus() { return status; } public DbusKeyCompositeFilterConfig getFilter() { return filter; } public Collection<DatabusSubscription> getSubs() { return subs; } public boolean isMultiPartition() { return isMultiPartition; } public Map<DbusPartitionInfo, RegInfo> getChildRegistrations() { return childRegistrations; } public RegInfo(String state, RegistrationId regId, DatabusComponentStatus status, DbusKeyCompositeFilterConfig filter, Collection<DatabusSubscription> subs) { this(state, regId, status, filter, subs, false, null); } public RegInfo(String state, RegistrationId regId, DatabusComponentStatus status, DbusKeyCompositeFilterConfig filter, Collection<DatabusSubscription> subs, boolean isMultiPartition, Map<DbusPartitionInfo, RegInfo> childRegistrations) { super(); this.state = state; this.regId = regId; this.status = status.toString(); this.filter = filter; this.subs = subs; this.isMultiPartition = isMultiPartition; this.childRegistrations = childRegistrations; } } }