blob: d732495cff45f9dde7314d7fd96fafa56cd87d56 [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package io.v.impl.google.rpc;
import com.google.common.base.Preconditions;
import io.v.v23.OptionDefs;
import io.v.v23.Options;
import io.v.v23.context.VContext;
import io.v.v23.rpc.Callback;
import io.v.v23.rpc.Client;
import io.v.v23.rpc.ClientCall;
import io.v.v23.verror.VException;
import io.v.v23.vom.VomUtil;
import java.lang.reflect.Type;
/**
* An implementation of the {@link Client} interface that calls to native code for most of its
* functionalities.
*/
public class ClientImpl implements Client {
private final long nativePtr;
private native ClientCall nativeStartCall(long nativePtr, VContext context,
String name, String method, byte[][] vomArgs,
boolean skipServerAuth)
throws VException;
private native void nativeStartCallAsync(long nativePtr, VContext context,
String name, String method, byte[][] vomArgs,
boolean skipServerAuth,
Callback<ClientCall> callback)
throws VException;
private native void nativeClose(long nativePtr);
private native void nativeFinalize(long nativePtr);
private ClientImpl(long nativePtr) {
this.nativePtr = nativePtr;
}
// Implement io.v.v23.rpc.Client.
@Override
public ClientCall startCall(VContext context, String name,
String method, Object[] args, Type[] argTypes) throws VException {
return startCall(context, name, method, args, argTypes, (Options) null);
}
@Override
public ClientCall startCall(VContext context, String name,
String method, Object[] args, Type[] argTypes, Options opts)
throws VException {
if (opts == null) {
opts = new Options();
}
checkStartCallArgs(name, method, args, argTypes);
return nativeStartCall(this.nativePtr, context, name, getMethodName(method),
getEncodedVomArgs(args, argTypes), shouldSkipServerAuth(opts));
}
private boolean shouldSkipServerAuth(Options opts) {
return !opts.has(OptionDefs.SKIP_SERVER_ENDPOINT_AUTHORIZATION)
? false
: opts.get(OptionDefs.SKIP_SERVER_ENDPOINT_AUTHORIZATION, Boolean.class);
}
@Override
public void startCall(VContext context, String name, String method, Object[] args, Type[]
argTypes, Callback<ClientCall> callback) throws VException {
startCall(context, name, method, args, argTypes, null, callback);
}
@Override
public void startCall(VContext context, String name, String method, Object[] args, Type[]
argTypes, Options opts, Callback<ClientCall> callback) throws VException {
Preconditions.checkNotNull(callback);
if (opts == null) {
opts = new Options();
}
checkStartCallArgs(name, method, args, argTypes);
nativeStartCallAsync(this.nativePtr, context, name, getMethodName(method),
getEncodedVomArgs(args, argTypes), shouldSkipServerAuth(opts), callback);
}
private String getMethodName(String method) {
return Character.toUpperCase(method.charAt(0)) + method.substring(1);
}
/**
* Asserts that the given parameters are valid for {@code startCall} and throws {@link
* VException} if they are not.
*/
private void checkStartCallArgs(String name, String method, Object[] args, Type[] argTypes)
throws VException {
if ("".equals(method)) {
throw new VException(String.format("Empty method name invoked on object %s", name));
}
if (args.length != argTypes.length) {
throw new VException(String.format(
"Argument count (%d) doesn't match type count (%d) for method %s of object %s",
args.length, argTypes.length, name, method));
}
}
private byte[][] getEncodedVomArgs(Object[] args, Type[] argTypes) throws VException {
// VOM-encode all input arguments, individually.
byte[][] vomArgs = new byte[args.length][];
for (int i = 0; i < args.length; ++i) {
vomArgs[i] = VomUtil.encode(args[i], argTypes[i]);
}
return vomArgs;
}
@Override
public void close() {
nativeClose(this.nativePtr);
}
// Implement java.lang.Object.
@Override
public boolean equals(Object other) {
if (this == other) return true;
if (other == null) return false;
if (this.getClass() != other.getClass()) return false;
return this.nativePtr == ((ClientImpl) other).nativePtr;
}
@Override
public int hashCode() {
return Long.valueOf(this.nativePtr).hashCode();
}
@Override
protected void finalize() {
nativeFinalize(this.nativePtr);
}
}