| // 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 java |
| |
| import ( |
| "bytes" |
| "log" |
| "path" |
| |
| "v.io/x/ref/lib/vdl/compile" |
| "v.io/x/ref/lib/vdl/vdlutil" |
| ) |
| |
| const clientStubTmpl = header + ` |
| // Source(s): {{ .Source }} |
| package {{ .PackagePath }}; |
| |
| /* Client stub for interface: {{ .ServiceName }}Client. */ |
| {{ .AccessModifier }} final class {{ .ServiceName }}ClientStub implements {{ .FullServiceName }}Client { |
| private final io.v.v23.rpc.Client client; |
| private final java.lang.String veyronName; |
| |
| {{/* Define fields to hold each of the embedded object stubs*/}} |
| {{ range $embed := .Embeds }} |
| {{/* e.g. private final com.somepackage.gen_impl.ArithStub stubArith; */}} |
| private final {{ $embed.StubClassName }} {{ $embed.LocalStubVarName }}; |
| {{ end }} |
| |
| public {{ .ServiceName }}ClientStub(final io.v.v23.rpc.Client client, final java.lang.String veyronName) { |
| this.client = client; |
| this.veyronName = veyronName; |
| {{/* Initialize the embeded stubs */}} |
| {{ range $embed := .Embeds }} |
| this.{{ $embed.LocalStubVarName }} = new {{ $embed.StubClassName }}(client, veyronName); |
| {{ end }} |
| } |
| |
| private io.v.v23.rpc.Client getClient(io.v.v23.context.VContext context) { |
| return this.client != null ? client : io.v.v23.V.getClient(context); |
| |
| } |
| |
| // Methods from interface UniversalServiceMethods. |
| // TODO(spetrovic): Re-enable once we can import the new Signature classes. |
| //@Override |
| //public io.v.v23.rpc.ServiceSignature getSignature(io.v.v23.context.VContext context) throws io.v.v23.verror.VException { |
| // return getSignature(context, null); |
| //} |
| //@Override |
| //public io.v.v23.rpc.ServiceSignature getSignature(io.v.v23.context.VContext context, io.v.v23.Options veyronOpts) throws io.v.v23.verror.VException { |
| // // Start the call. |
| // final io.v.v23.rpc.Client.Call _call = getClient(context).startCall(context, this.veyronName, "signature", new java.lang.Object[0], new java.lang.reflect.Type[0], veyronOpts); |
| |
| // // Finish the call. |
| // final java.lang.reflect.Type[] _resultTypes = new java.lang.reflect.Type[]{ |
| // new com.google.common.reflect.TypeToken<io.v.v23.rpc.ServiceSignature>() {}.getType(), |
| // }; |
| // final java.lang.Object[] _results = _call.finish(_resultTypes); |
| // return (io.v.v23.rpc.ServiceSignature)_results[0]; |
| //} |
| |
| // Methods from interface {{ .ServiceName }}Client. |
| {{/* Iterate over methods defined directly in the body of this service */}} |
| {{ range $method := .Methods }} |
| {{/* The optionless overload simply calls the overload with options */}} |
| @Override |
| {{ $method.AccessModifier }} {{ $method.RetType }} {{ $method.Name }}(final io.v.v23.context.VContext context{{ $method.DeclarationArgs }}) throws io.v.v23.verror.VException { |
| {{if $method.Returns }}return{{ end }} {{ $method.Name }}(context{{ $method.CallingArgsLeadingComma }}, null); |
| } |
| {{/* The main client stub method body */}} |
| @Override |
| {{ $method.AccessModifier }} {{ $method.RetType }} {{ $method.Name }}(final io.v.v23.context.VContext context{{ $method.DeclarationArgs }}, io.v.v23.Options veyronOpts) throws io.v.v23.verror.VException { |
| {{/* Start the veyron call */}} |
| // Start the call. |
| final java.lang.Object[] _args = new java.lang.Object[]{ {{ $method.CallingArgs }} }; |
| final java.lang.reflect.Type[] _argTypes = new java.lang.reflect.Type[]{ {{ $method.CallingArgTypes }} }; |
| final io.v.v23.rpc.Client.Call _call = getClient(context).startCall(context, this.veyronName, "{{ $method.Name }}", _args, _argTypes, veyronOpts); |
| |
| // Finish the call. |
| {{/* Now handle returning from the function. */}} |
| {{ if $method.NotStreaming }} |
| |
| {{ if $method.IsVoid }} |
| final java.lang.reflect.Type[] _resultTypes = new java.lang.reflect.Type[]{}; |
| _call.finish(_resultTypes); |
| {{ else }} {{/* else $method.IsVoid */}} |
| final java.lang.reflect.Type[] _resultTypes = new java.lang.reflect.Type[]{ |
| {{ range $outArg := $method.OutArgs }} |
| new com.google.common.reflect.TypeToken<{{ $outArg.Type }}>() {}.getType(), |
| {{ end }} |
| }; |
| final java.lang.Object[] _results = _call.finish(_resultTypes); |
| {{ if $method.MultipleReturn }} |
| final {{ $method.DeclaredObjectRetType }} _ret = new {{ $method.DeclaredObjectRetType }}(); |
| {{ range $i, $outArg := $method.OutArgs }} |
| _ret.{{ $outArg.FieldName }} = ({{ $outArg.Type }})_results[{{ $i }}]; |
| {{ end }} {{/* end range over outargs */}} |
| return _ret; |
| {{ else }} {{/* end if $method.MultipleReturn */}} |
| return ({{ $method.DeclaredObjectRetType }})_results[0]; |
| {{ end }} {{/* end if $method.MultipleReturn */}} |
| |
| {{ end }} {{/* end if $method.IsVoid */}} |
| |
| {{else }} {{/* else $method.NotStreaming */}} |
| return new io.v.v23.vdl.ClientStream<{{ $method.SendType }}, {{ $method.RecvType }}, {{ $method.DeclaredObjectRetType }}>() { |
| @Override |
| public void send(final {{ $method.SendType }} item) throws io.v.v23.verror.VException { |
| final java.lang.reflect.Type type = new com.google.common.reflect.TypeToken<{{ $method.SendType }}>() {}.getType(); |
| _call.send(item, type); |
| } |
| @Override |
| public {{ $method.RecvType }} recv() throws java.io.EOFException, io.v.v23.verror.VException { |
| final java.lang.reflect.Type type = new com.google.common.reflect.TypeToken<{{ $method.RecvType }}>() {}.getType(); |
| final java.lang.Object result = _call.recv(type); |
| try { |
| return ({{ $method.RecvType }})result; |
| } catch (java.lang.ClassCastException e) { |
| throw new io.v.v23.verror.VException("Unexpected result type: " + result.getClass().getCanonicalName()); |
| } |
| } |
| @Override |
| public {{ $method.DeclaredObjectRetType }} finish() throws io.v.v23.verror.VException { |
| {{ if $method.IsVoid }} |
| final java.lang.reflect.Type[] resultTypes = new java.lang.reflect.Type[]{}; |
| _call.finish(resultTypes); |
| return null; |
| {{ else }} {{/* else $method.IsVoid */}} |
| final java.lang.reflect.Type[] resultTypes = new java.lang.reflect.Type[]{ |
| new com.google.common.reflect.TypeToken<{{ $method.DeclaredObjectRetType }}>() {}.getType() |
| }; |
| return ({{ $method.DeclaredObjectRetType }})_call.finish(resultTypes)[0]; |
| {{ end }} {{/* end if $method.IsVoid */}} |
| } |
| }; |
| {{ end }}{{/* end if $method.NotStreaming */}} |
| } |
| {{ end }}{{/* end range over methods */}} |
| |
| {{/* Iterate over methods from embeded services and generate code to delegate the work */}} |
| {{ range $eMethod := .EmbedMethods }} |
| @Override |
| {{ $eMethod.AccessModifier }} {{ $eMethod.RetType }} {{ $eMethod.Name }}(final io.v.v23.context.VContext context{{ $eMethod.DeclarationArgs }}) throws io.v.v23.verror.VException { |
| {{/* e.g. return this.stubArith.cosine(context, [args]) */}} |
| {{ if $eMethod.Returns }}return{{ end }} this.{{ $eMethod.LocalStubVarName }}.{{ $eMethod.Name }}(context{{ $eMethod.CallingArgsLeadingComma }}); |
| } |
| @Override |
| {{ $eMethod.AccessModifier }} {{ $eMethod.RetType }} {{ $eMethod.Name }}(final io.v.v23.context.VContext context{{ $eMethod.DeclarationArgs }}, io.v.v23.Options veyronOpts) throws io.v.v23.verror.VException { |
| {{/* e.g. return this.stubArith.cosine(context, [args], options) */}} |
| {{ if $eMethod.Returns }}return{{ end }} this.{{ $eMethod.LocalStubVarName }}.{{ $eMethod.Name }}(context{{ $eMethod.CallingArgsLeadingComma }}, veyronOpts); |
| } |
| {{ end }} |
| |
| } |
| ` |
| |
| type clientStubMethodOutArg struct { |
| FieldName string |
| Type string |
| } |
| |
| type clientStubMethod struct { |
| AccessModifier string |
| CallingArgs string |
| CallingArgTypes string |
| CallingArgsLeadingComma string |
| DeclarationArgs string |
| DeclaredObjectRetType string |
| IsVoid bool |
| MultipleReturn bool |
| Name string |
| NotStreaming bool |
| OutArgs []clientStubMethodOutArg |
| RecvType string |
| RetType string |
| Returns bool |
| SendType string |
| ServiceName string |
| } |
| |
| type clientStubEmbedMethod struct { |
| AccessModifier string |
| CallingArgsLeadingComma string |
| DeclarationArgs string |
| LocalStubVarName string |
| Name string |
| RetType string |
| Returns bool |
| } |
| |
| type clientStubEmbed struct { |
| StubClassName string |
| LocalStubVarName string |
| } |
| |
| func processClientStubMethod(iface *compile.Interface, method *compile.Method, env *compile.Env) clientStubMethod { |
| outArgs := make([]clientStubMethodOutArg, len(method.OutArgs)) |
| for i := 0; i < len(method.OutArgs); i++ { |
| outArgs[i].FieldName = vdlutil.FirstRuneToLower(method.OutArgs[i].Name) |
| outArgs[i].Type = javaType(method.OutArgs[i].Type, true, env) |
| } |
| return clientStubMethod{ |
| AccessModifier: accessModifierForName(method.Name), |
| CallingArgs: javaCallingArgStr(method.InArgs, false), |
| CallingArgTypes: javaCallingArgTypeStr(method.InArgs, env), |
| CallingArgsLeadingComma: javaCallingArgStr(method.InArgs, true), |
| DeclarationArgs: javaDeclarationArgStr(method.InArgs, env, true), |
| DeclaredObjectRetType: clientInterfaceNonStreamingOutArg(iface, method, true, env), |
| IsVoid: len(method.OutArgs) < 1, |
| MultipleReturn: len(method.OutArgs) > 1, |
| Name: vdlutil.FirstRuneToLower(method.Name), |
| NotStreaming: !isStreamingMethod(method), |
| OutArgs: outArgs, |
| RecvType: javaType(method.OutStream, true, env), |
| RetType: clientInterfaceOutArg(iface, method, false, env), |
| Returns: len(method.OutArgs) >= 1 || isStreamingMethod(method), |
| SendType: javaType(method.InStream, true, env), |
| ServiceName: vdlutil.FirstRuneToUpper(iface.Name), |
| } |
| } |
| |
| func processClientStubEmbedMethod(iface *compile.Interface, embedMethod *compile.Method, env *compile.Env) clientStubEmbedMethod { |
| return clientStubEmbedMethod{ |
| AccessModifier: accessModifierForName(embedMethod.Name), |
| CallingArgsLeadingComma: javaCallingArgStr(embedMethod.InArgs, true), |
| DeclarationArgs: javaDeclarationArgStr(embedMethod.InArgs, env, true), |
| LocalStubVarName: vdlutil.FirstRuneToLower(iface.Name) + "ClientStub", |
| Name: vdlutil.FirstRuneToLower(embedMethod.Name), |
| RetType: clientInterfaceOutArg(iface, embedMethod, false, env), |
| Returns: len(embedMethod.OutArgs) >= 1 || isStreamingMethod(embedMethod), |
| } |
| } |
| |
| // genJavaClientStubFile generates a client stub for the specified interface. |
| func genJavaClientStubFile(iface *compile.Interface, env *compile.Env) JavaFileInfo { |
| embeds := []clientStubEmbed{} |
| for _, embed := range allEmbeddedIfaces(iface) { |
| embeds = append(embeds, clientStubEmbed{ |
| LocalStubVarName: vdlutil.FirstRuneToLower(embed.Name) + "ClientStub", |
| StubClassName: javaPath(javaGenPkgPath(path.Join(embed.File.Package.GenPath, vdlutil.FirstRuneToUpper(embed.Name)+"ClientStub"))), |
| }) |
| } |
| embedMethods := []clientStubEmbedMethod{} |
| for _, embedMao := range dedupedEmbeddedMethodAndOrigins(iface) { |
| embedMethods = append(embedMethods, processClientStubEmbedMethod(embedMao.Origin, embedMao.Method, env)) |
| } |
| methods := make([]clientStubMethod, len(iface.Methods)) |
| for i, method := range iface.Methods { |
| methods[i] = processClientStubMethod(iface, method, env) |
| } |
| javaServiceName := vdlutil.FirstRuneToUpper(iface.Name) |
| data := struct { |
| AccessModifier string |
| EmbedMethods []clientStubEmbedMethod |
| Embeds []clientStubEmbed |
| FullServiceName string |
| Methods []clientStubMethod |
| PackagePath string |
| ServiceName string |
| Source string |
| VDLIfacePathName string |
| }{ |
| AccessModifier: accessModifierForName(iface.Name), |
| EmbedMethods: embedMethods, |
| Embeds: embeds, |
| FullServiceName: javaPath(interfaceFullyQualifiedName(iface)), |
| Methods: methods, |
| PackagePath: javaPath(javaGenPkgPath(iface.File.Package.GenPath)), |
| ServiceName: javaServiceName, |
| Source: iface.File.BaseName, |
| VDLIfacePathName: path.Join(iface.File.Package.GenPath, iface.Name+"ClientMethods"), |
| } |
| var buf bytes.Buffer |
| err := parseTmpl("client stub", clientStubTmpl).Execute(&buf, data) |
| if err != nil { |
| log.Fatalf("vdl: couldn't execute client stub template: %v", err) |
| } |
| return JavaFileInfo{ |
| Name: javaServiceName + "ClientStub.java", |
| Data: buf.Bytes(), |
| } |
| } |