/*
* 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.clients.admin.AccessControlEntry;
import org.apache.kafka.clients.admin.AclBinding;
import org.apache.kafka.clients.admin.Resource;
import org.apache.kafka.common.errors.ApiException;
import org.apache.kafka.common.protocol.ApiKeys;
import org.apache.kafka.common.protocol.Errors;
import org.apache.kafka.common.protocol.types.Struct;
import org.apache.kafka.common.utils.Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
public class DeleteAclsResponse extends AbstractResponse {
public static final Logger log = LoggerFactory.getLogger(DeleteAclsResponse.class);
private final static String THROTTLE_TIME_MS = "throttle_time_ms";
private final static String FILTER_RESPONSES = "filter_responses";
private final static String ERROR_CODE = "error_code";
private final static String ERROR_MESSAGE = "error_message";
private final static String MATCHING_ACLS = "matching_acls";
public static class AclDeletionResult {
private final ApiException exception;
private final AclBinding acl;
public AclDeletionResult(ApiException exception, AclBinding acl) {
this.exception = exception;
this.acl = acl;
}
public ApiException exception() {
return exception;
}
public AclBinding acl() {
return acl;
}
@Override
public String toString() {
return "(apiException=" + exception + ", acl=" + acl + ")";
}
}
public static class AclFilterResponse {
private final Throwable throwable;
private final Collection<AclDeletionResult> deletions;
public AclFilterResponse(Throwable throwable, Collection<AclDeletionResult> deletions) {
this.throwable = throwable;
this.deletions = deletions;
}
public Throwable throwable() {
return throwable;
}
public Collection<AclDeletionResult> deletions() {
return deletions;
}
@Override
public String toString() {
return "(throwable=" + throwable + ", deletions=" + Utils.join(deletions, ",") + ")";
}
}
private final int throttleTimeMs;
private final List<AclFilterResponse> responses;
public DeleteAclsResponse(int throttleTimeMs, List<AclFilterResponse> responses) {
this.throttleTimeMs = throttleTimeMs;
this.responses = responses;
}
public DeleteAclsResponse(Struct struct) {
this.throttleTimeMs = struct.getInt(THROTTLE_TIME_MS);
this.responses = new ArrayList<>();
for (Object responseStructObj : struct.getArray(FILTER_RESPONSES)) {
Struct responseStruct = (Struct) responseStructObj;
short responseErrorCode = responseStruct.getShort(ERROR_CODE);
String responseErrorMessage = responseStruct.getString(ERROR_MESSAGE);
if (responseErrorCode != 0) {
this.responses.add(new AclFilterResponse(
Errors.forCode(responseErrorCode).exception(responseErrorMessage),
Collections.<AclDeletionResult>emptySet()));
} else {
List<AclDeletionResult> deletions = new ArrayList<>();
for (Object matchingAclStructObj : responseStruct.getArray(MATCHING_ACLS)) {
Struct matchingAclStruct = (Struct) matchingAclStructObj;
short matchErrorCode = matchingAclStruct.getShort(ERROR_CODE);
ApiException exception = null;
if (matchErrorCode != 0) {
Errors errors = Errors.forCode(matchErrorCode);
String matchErrorMessage = matchingAclStruct.getString(ERROR_MESSAGE);
exception = errors.exception(matchErrorMessage);
}
AccessControlEntry entry = RequestUtils.aceFromStructFields(matchingAclStruct);
Resource resource = RequestUtils.resourceFromStructFields(matchingAclStruct);
deletions.add(new AclDeletionResult(exception, new AclBinding(resource, entry)));
}
this.responses.add(new AclFilterResponse(null, deletions));
}
}
}
@Override
protected Struct toStruct(short version) {
Struct struct = new Struct(ApiKeys.DELETE_ACLS.responseSchema(version));
struct.set(THROTTLE_TIME_MS, throttleTimeMs);
List<Struct> responseStructs = new ArrayList<>();
for (AclFilterResponse response : responses) {
Struct responseStruct = struct.instance(FILTER_RESPONSES);
if (response.throwable() != null) {
Errors error = Errors.forException(response.throwable());
responseStruct.set(ERROR_CODE, error.code());
responseStruct.set(ERROR_MESSAGE, response.throwable().getMessage());
responseStruct.set(MATCHING_ACLS, new Struct[0]);
} else {
responseStruct.set(ERROR_CODE, (short) 0);
List<Struct> deletionStructs = new ArrayList<>();
for (AclDeletionResult deletion : response.deletions()) {
Struct deletionStruct = responseStruct.instance(MATCHING_ACLS);
if (deletion.exception() != null) {
Errors error = Errors.forException(deletion.exception);
deletionStruct.set(ERROR_CODE, error.code());
deletionStruct.set(ERROR_MESSAGE, deletion.exception.getMessage());
} else {
deletionStruct.set(ERROR_CODE, (short) 0);
}
RequestUtils.resourceSetStructFields(deletion.acl().resource(), deletionStruct);
RequestUtils.aceSetStructFields(deletion.acl().entry(), deletionStruct);
deletionStructs.add(deletionStruct);
}
responseStruct.set(MATCHING_ACLS, deletionStructs.toArray(new Struct[0]));
}
responseStructs.add(responseStruct);
}
struct.set(FILTER_RESPONSES, responseStructs.toArray());
return struct;
}
public int throttleTimeMs() {
return throttleTimeMs;
}
public List<AclFilterResponse> responses() {
return responses;
}
public static DeleteAclsResponse parse(ByteBuffer buffer, short version) {
return new DeleteAclsResponse(ApiKeys.DELETE_ACLS.responseSchema(version).read(buffer));
}
public String toString() {
return "(responses=" + Utils.join(responses, ",") + ")";
}
}