blob: da8fadf3d40983f847247693acdb98373f35432b [file] [log] [blame]
/*
* 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
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* 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.hadoop.hdds.scm.ha;
import java.util.ArrayList;
import java.util.List;
import com.google.common.base.Preconditions;
import com.google.protobuf.InvalidProtocolBufferException;
import org.apache.hadoop.hdds.scm.ha.io.CodecFactory;
import org.apache.ratis.protocol.Message;
import org.apache.hadoop.hdds.protocol.proto.SCMRatisProtocol.Method;
import org.apache.hadoop.hdds.protocol.proto.SCMRatisProtocol.MethodArgument;
import org.apache.hadoop.hdds.protocol.proto.SCMRatisProtocol.RequestType;
import org.apache.hadoop.hdds.protocol.proto.SCMRatisProtocol.SCMRatisRequestProto;
/**
* Represents the request that is sent to RatisServer.
*/
public final class SCMRatisRequest {
private final RequestType type;
private final String operation;
private final Object[] arguments;
private final Class<?>[] parameterTypes;
private SCMRatisRequest(final RequestType type, final String operation,
final Class<?>[] parameterTypes, final Object... arguments) {
this.type = type;
this.operation = operation;
this.parameterTypes = parameterTypes;
this.arguments = arguments;
}
public static SCMRatisRequest of(final RequestType type,
final String operation,
final Class<?>[] parameterTypes,
final Object... arguments) {
Preconditions.checkState(parameterTypes.length == arguments.length);
return new SCMRatisRequest(type, operation, parameterTypes, arguments);
}
/**
* Returns the type of request.
*/
public RequestType getType() {
return type;
}
/**
* Returns the operation that this request represents.
*/
public String getOperation() {
return operation;
}
/**
* Returns the arguments encoded in the request.
*/
public Object[] getArguments() {
return arguments.clone();
}
public Class<?>[] getParameterTypes() {
return parameterTypes.clone();
}
/**
* Encodes the request into Ratis Message.
*/
public Message encode() throws InvalidProtocolBufferException {
final SCMRatisRequestProto.Builder requestProtoBuilder =
SCMRatisRequestProto.newBuilder();
requestProtoBuilder.setType(type);
final Method.Builder methodBuilder = Method.newBuilder();
methodBuilder.setName(operation);
final List<MethodArgument> args = new ArrayList<>();
int paramCounter = 0;
for (Object argument : arguments) {
final MethodArgument.Builder argBuilder = MethodArgument.newBuilder();
// Set actual method parameter type, not actual argument type.
// This is done to avoid MethodNotFoundException in case if argument is
// subclass type, where as method is defined with super class type.
argBuilder.setType(parameterTypes[paramCounter++].getName());
argBuilder.setValue(CodecFactory.getCodec(argument.getClass())
.serialize(argument));
args.add(argBuilder.build());
}
methodBuilder.addAllArgs(args);
requestProtoBuilder.setMethod(methodBuilder.build());
return Message.valueOf(
org.apache.ratis.thirdparty.com.google.protobuf.ByteString.copyFrom(
requestProtoBuilder.build().toByteArray()));
}
/**
* Decodes the request from Ratis Message.
*/
public static SCMRatisRequest decode(Message message)
throws InvalidProtocolBufferException {
final SCMRatisRequestProto requestProto =
SCMRatisRequestProto.parseFrom(message.getContent().toByteArray());
final Method method = requestProto.getMethod();
List<Object> args = new ArrayList<>();
Class<?>[] parameterTypes = new Class[method.getArgsCount()];
int paramCounter = 0;
for (MethodArgument argument : method.getArgsList()) {
try {
final Class<?> clazz = ReflectionUtil.getClass(argument.getType());
parameterTypes[paramCounter++] = clazz;
args.add(CodecFactory.getCodec(clazz)
.deserialize(clazz, argument.getValue()));
} catch (ClassNotFoundException ex) {
throw new InvalidProtocolBufferException(argument.getType() +
" cannot be decoded!" + ex.getMessage());
}
}
return new SCMRatisRequest(requestProto.getType(),
method.getName(), parameterTypes, args.toArray());
}
}