首页 > 解决方案 > Can I call an xml-rpc service with gRPC and basic auth?

问题描述

I have the requirement to do a Java call to a xml-rpc service provided by an external editor.
It's an old protocol, but since it's external I don't have a choice over it.

I have the url, a login and a password for authentication.

I have a working prototype, using java 11 and the library apache xml-rpc.
Here is my working code :

XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
config.setBasicUserName("some-usr");
config.setBasicPassword("some-pwd");
config.setServerURL(URL url = new URL("https://my-editor/my-service/rpc/"));

XmlRpcClient client = new XmlRpcClient();
client.setConfig(config);

Map<String, Object> requestMap = ...;
Map<String, Object> responseMap = (Map<String, Object>) client.execute("my-rpc-method", new Object[]{requestMap});

Note that I don't have the port.
This works with java.util.Map as input/output, and I use jackson to convert plain model objects to/from Map.

This is all well and good, however I have two main gripes with apache xml-rpc :

So I searched for alternatives implementations, and am actually looking at gRPC. I have to define some king of contract definition file (.protobuff) which I use for client code generation; no problem with that.

However I can't make the call work for two reasons :

Here is my first attempt (mots of the classes are generated by some .protobuff facilities) :

public class MyCred extends CallCredentials {
    @Override
    public void applyRequestMetadata(RequestInfo requestInfo, Executor appExecutor, MetadataApplier applier) {
        System.out.println("should see this");
    }

    @Override
    public void thisUsesUnstableApi() {}
}
ManagedChannelBuilder<?> forTarget = ManagedChannelBuilder.forAddress("https://my-editor/my-service/rpc/", 443);
MyServiceBlockingStub blockingStub = MyServiceGrpc
    .newBlockingStub(forTarget.build())
    .withCallCredentials(new MyCred());
MyRpcRequest request = MyRpcRequest.newBuilder()
    .setFirstname("dummy-firstname")
    .setLastname("dummy-lastname").build();

MyRpcResponse response = blockingStub.myRpcMethod(request);

It requires a port, and since I don't know what it is, I tried what seems to be the default one (but that may be wrong).
This gives me the following error on the ChannelBuilder initialization :

java.lang.IllegalArgumentException: Invalid host or port: https://my-editor/my-service/rpc/ 443
    at io.grpc.internal.GrpcUtil.authorityFromHostAndPort(GrpcUtil.java:520)
    at io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder.forAddress(NettyChannelBuilder.java:135)
    at io.grpc.netty.shaded.io.grpc.netty.NettyChannelProvider.builderForAddress(NettyChannelProvider.java:38)
    at io.grpc.netty.shaded.io.grpc.netty.NettyChannelProvider.builderForAddress(NettyChannelProvider.java:24)
    at io.grpc.ManagedChannelBuilder.forAddress(ManagedChannelBuilder.java:39)
...
Caused by: java.net.URISyntaxException: Expected closing bracket for IPv6 address at index 9: //[https://my-editor/my-service/rpc/]:443
    at java.base/java.net.URI$Parser.fail(URI.java:2915)
    at java.base/java.net.URI$Parser.failExpecting(URI.java:2921)
    at java.base/java.net.URI$Parser.parseServer(URI.java:3294)
    at java.base/java.net.URI$Parser.parseAuthority(URI.java:3218)
    at java.base/java.net.URI$Parser.parseHierarchical(URI.java:3160)
    at java.base/java.net.URI$Parser.parse(URI.java:3127)
    at java.base/java.net.URI.<init>(URI.java:685)
    at io.grpc.internal.GrpcUtil.authorityFromHostAndPort(GrpcUtil.java:518)

I tried replacing the first line with :

ManagedChannelBuilder<?> forTarget = ManagedChannelBuilder.forTarget("https://my-editor/my-service/rpc/");

I also get an error, on building the Channel :

java.lang.IllegalArgumentException: cannot find a NameResolver for https://my-editor/my-service/rpc/
    at io.grpc.internal.ManagedChannelImpl.getNameResolver(ManagedChannelImpl.java:763)
    at io.grpc.internal.ManagedChannelImpl.getNameResolver(ManagedChannelImpl.java:772)
    at io.grpc.internal.ManagedChannelImpl.<init>(ManagedChannelImpl.java:652)
    at io.grpc.internal.ManagedChannelImplBuilder.build(ManagedChannelImplBuilder.java:615)
    at io.grpc.internal.AbstractManagedChannelImplBuilder.build(AbstractManagedChannelImplBuilder.java:261)

What am I doing wrong? Is it even possible to migrate my old code to gRPC ?

I found two more recent librairies and made them work, but they have similar flaws :

These are :

As a final note, I'm also interested in any code example using alternative libraries, providing they are maintained and have decent logging. Maybe CXF or Jakarte EE ? I had a look but the APIs are quite confusing; and seem to require a wsdl (which would mean SOAP only).
Or maybe some facilities in Spring (my app will be Spring-based) ?

Any thoughts ?

标签: javaspringxml-rpc

解决方案


推荐阅读