/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ package org.apache.kafka.common.requests; import org.apache.kafka.common.protocol.ApiKeys; import org.apache.kafka.common.protocol.Errors; import org.apache.kafka.common.protocol.types.Struct; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; public class DescribeGroupsResponse extends AbstractResponse { private static final String THROTTLE_TIME_KEY_NAME = "throttle_time_ms"; private static final String GROUPS_KEY_NAME = "groups"; private static final String ERROR_CODE_KEY_NAME = "error_code"; private static final String GROUP_ID_KEY_NAME = "group_id"; private static final String GROUP_STATE_KEY_NAME = "state"; private static final String PROTOCOL_TYPE_KEY_NAME = "protocol_type"; private static final String PROTOCOL_KEY_NAME = "protocol"; private static final String MEMBERS_KEY_NAME = "members"; private static final String MEMBER_ID_KEY_NAME = "member_id"; private static final String CLIENT_ID_KEY_NAME = "client_id"; private static final String CLIENT_HOST_KEY_NAME = "client_host"; private static final String MEMBER_METADATA_KEY_NAME = "member_metadata"; private static final String MEMBER_ASSIGNMENT_KEY_NAME = "member_assignment"; public static final String UNKNOWN_STATE = ""; public static final String UNKNOWN_PROTOCOL_TYPE = ""; public static final String UNKNOWN_PROTOCOL = ""; /** * Possible per-group error codes: * * COORDINATOR_LOAD_IN_PROGRESS (14) * COORDINATOR_NOT_AVAILABLE (15) * NOT_COORDINATOR (16) * AUTHORIZATION_FAILED (29) */ private final Map<String, GroupMetadata> groups; private final int throttleTimeMs; public DescribeGroupsResponse(Map<String, GroupMetadata> groups) { this(DEFAULT_THROTTLE_TIME, groups); } public DescribeGroupsResponse(int throttleTimeMs, Map<String, GroupMetadata> groups) { this.throttleTimeMs = throttleTimeMs; this.groups = groups; } public DescribeGroupsResponse(Struct struct) { this.throttleTimeMs = struct.hasField(THROTTLE_TIME_KEY_NAME) ? struct.getInt(THROTTLE_TIME_KEY_NAME) : DEFAULT_THROTTLE_TIME; this.groups = new HashMap<>(); for (Object groupObj : struct.getArray(GROUPS_KEY_NAME)) { Struct groupStruct = (Struct) groupObj; String groupId = groupStruct.getString(GROUP_ID_KEY_NAME); Errors error = Errors.forCode(groupStruct.getShort(ERROR_CODE_KEY_NAME)); String state = groupStruct.getString(GROUP_STATE_KEY_NAME); String protocolType = groupStruct.getString(PROTOCOL_TYPE_KEY_NAME); String protocol = groupStruct.getString(PROTOCOL_KEY_NAME); List<GroupMember> members = new ArrayList<>(); for (Object memberObj : groupStruct.getArray(MEMBERS_KEY_NAME)) { Struct memberStruct = (Struct) memberObj; String memberId = memberStruct.getString(MEMBER_ID_KEY_NAME); String clientId = memberStruct.getString(CLIENT_ID_KEY_NAME); String clientHost = memberStruct.getString(CLIENT_HOST_KEY_NAME); ByteBuffer memberMetadata = memberStruct.getBytes(MEMBER_METADATA_KEY_NAME); ByteBuffer memberAssignment = memberStruct.getBytes(MEMBER_ASSIGNMENT_KEY_NAME); members.add(new GroupMember(memberId, clientId, clientHost, memberMetadata, memberAssignment)); } this.groups.put(groupId, new GroupMetadata(error, state, protocolType, protocol, members)); } } public int throttleTimeMs() { return throttleTimeMs; } public Map<String, GroupMetadata> groups() { return groups; } public static class GroupMetadata { private final Errors error; private final String state; private final String protocolType; private final String protocol; private final List<GroupMember> members; public GroupMetadata(Errors error, String state, String protocolType, String protocol, List<GroupMember> members) { this.error = error; this.state = state; this.protocolType = protocolType; this.protocol = protocol; this.members = members; } public Errors error() { return error; } public String state() { return state; } public String protocolType() { return protocolType; } public String protocol() { return protocol; } public List<GroupMember> members() { return members; } public static GroupMetadata forError(Errors error) { return new DescribeGroupsResponse.GroupMetadata( error, DescribeGroupsResponse.UNKNOWN_STATE, DescribeGroupsResponse.UNKNOWN_PROTOCOL_TYPE, DescribeGroupsResponse.UNKNOWN_PROTOCOL, Collections.<DescribeGroupsResponse.GroupMember>emptyList()); } } public static class GroupMember { private final String memberId; private final String clientId; private final String clientHost; private final ByteBuffer memberMetadata; private final ByteBuffer memberAssignment; public GroupMember(String memberId, String clientId, String clientHost, ByteBuffer memberMetadata, ByteBuffer memberAssignment) { this.memberId = memberId; this.clientId = clientId; this.clientHost = clientHost; this.memberMetadata = memberMetadata; this.memberAssignment = memberAssignment; } public String memberId() { return memberId; } public String clientId() { return clientId; } public String clientHost() { return clientHost; } public ByteBuffer memberMetadata() { return memberMetadata; } public ByteBuffer memberAssignment() { return memberAssignment; } } public static DescribeGroupsResponse fromError(Errors error, List<String> groupIds) { return fromError(DEFAULT_THROTTLE_TIME, error, groupIds); } public static DescribeGroupsResponse fromError(int throttleTimeMs, Errors error, List<String> groupIds) { GroupMetadata errorMetadata = GroupMetadata.forError(error); Map<String, GroupMetadata> groups = new HashMap<>(); for (String groupId : groupIds) groups.put(groupId, errorMetadata); return new DescribeGroupsResponse(throttleTimeMs, groups); } @Override protected Struct toStruct(short version) { Struct struct = new Struct(ApiKeys.DESCRIBE_GROUPS.responseSchema(version)); if (struct.hasField(THROTTLE_TIME_KEY_NAME)) struct.set(THROTTLE_TIME_KEY_NAME, throttleTimeMs); List<Struct> groupStructs = new ArrayList<>(); for (Map.Entry<String, GroupMetadata> groupEntry : groups.entrySet()) { Struct groupStruct = struct.instance(GROUPS_KEY_NAME); GroupMetadata group = groupEntry.getValue(); groupStruct.set(GROUP_ID_KEY_NAME, groupEntry.getKey()); groupStruct.set(ERROR_CODE_KEY_NAME, group.error.code()); groupStruct.set(GROUP_STATE_KEY_NAME, group.state); groupStruct.set(PROTOCOL_TYPE_KEY_NAME, group.protocolType); groupStruct.set(PROTOCOL_KEY_NAME, group.protocol); List<Struct> membersList = new ArrayList<>(); for (GroupMember member : group.members) { Struct memberStruct = groupStruct.instance(MEMBERS_KEY_NAME); memberStruct.set(MEMBER_ID_KEY_NAME, member.memberId); memberStruct.set(CLIENT_ID_KEY_NAME, member.clientId); memberStruct.set(CLIENT_HOST_KEY_NAME, member.clientHost); memberStruct.set(MEMBER_METADATA_KEY_NAME, member.memberMetadata); memberStruct.set(MEMBER_ASSIGNMENT_KEY_NAME, member.memberAssignment); membersList.add(memberStruct); } groupStruct.set(MEMBERS_KEY_NAME, membersList.toArray()); groupStructs.add(groupStruct); } struct.set(GROUPS_KEY_NAME, groupStructs.toArray()); return struct; } public static DescribeGroupsResponse parse(ByteBuffer buffer, short version) { return new DescribeGroupsResponse(ApiKeys.DESCRIBE_GROUPS.parseResponse(version, buffer)); } }