blob: 7b845f9026b94b75f59f0eb402a672fc54a31785 [file] [log] [blame]
Jiri Simsad7616c92015-03-24 23:44:30 -07001// Copyright 2015 The Vanadium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
Todd Wang232d6492015-02-25 18:04:54 -08005package java
6
7import (
8 "bytes"
James Ring0c739da2015-04-01 13:12:24 -07009 "fmt"
Todd Wang232d6492015-02-25 18:04:54 -080010 "log"
11 "path"
12
Jiri Simsaffceefa2015-02-28 11:03:34 -080013 "v.io/x/ref/lib/vdl/compile"
14 "v.io/x/ref/lib/vdl/vdlutil"
Todd Wang232d6492015-02-25 18:04:54 -080015)
16
Srdjan Petroviceee415c2015-05-18 15:50:04 -070017const clientImplTmpl = header + `
Todd Wang232d6492015-02-25 18:04:54 -080018// Source(s): {{ .Source }}
19package {{ .PackagePath }};
20
Srdjan Petroviceee415c2015-05-18 15:50:04 -070021/**
22 * Implementation of the {@link {{ .ServiceName }}Client} interface.
23 */
24final class {{ .ServiceName }}ClientImpl implements {{ .FullServiceName }}Client {
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070025 private final io.v.v23.rpc.Client client;
Suharsh Sivakumarb4123262015-03-26 18:45:11 -070026 private final java.lang.String vName;
Todd Wang232d6492015-02-25 18:04:54 -080027
Srdjan Petroviceee415c2015-05-18 15:50:04 -070028 {{/* Define fields to hold each of the embedded object impls*/}}
Todd Wang232d6492015-02-25 18:04:54 -080029 {{ range $embed := .Embeds }}
Srdjan Petroviceee415c2015-05-18 15:50:04 -070030 {{/* e.g. private final com.somepackage.ArithClient implArith; */}}
31 private final {{ $embed.FullName }}Client impl{{ $embed.Name }};
Todd Wang232d6492015-02-25 18:04:54 -080032 {{ end }}
33
Srdjan Petroviceee415c2015-05-18 15:50:04 -070034 /**
35 * Creates a new instance of {@link {{ .ServiceName }}ClientImpl}.
36 *
37 * @param client Vanadium client
38 * @param vName remote server name
39 */
40 public {{ .ServiceName }}ClientImpl(final io.v.v23.rpc.Client client, final java.lang.String vName) {
Todd Wang232d6492015-02-25 18:04:54 -080041 this.client = client;
Suharsh Sivakumarb4123262015-03-26 18:45:11 -070042 this.vName = vName;
Srdjan Petroviceee415c2015-05-18 15:50:04 -070043 {{/* Initialize the embeded impls */}}
Todd Wang232d6492015-02-25 18:04:54 -080044 {{ range $embed := .Embeds }}
Srdjan Petroviceee415c2015-05-18 15:50:04 -070045 {
46 io.v.v23.Options opts = new io.v.v23.Options();
47 opts.set(io.v.v23.OptionDefs.CLIENT, client);
48 this.impl{{ $embed.Name }} = {{ $embed.FullName }}ClientFactory.get{{ $embed.Name }}Client(vName, opts);
49 }
50 {{ end }}
Todd Wang232d6492015-02-25 18:04:54 -080051 }
52
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070053 private io.v.v23.rpc.Client getClient(io.v.v23.context.VContext context) {
Todd Wang232d6492015-02-25 18:04:54 -080054 return this.client != null ? client : io.v.v23.V.getClient(context);
55
56 }
57
Todd Wang232d6492015-02-25 18:04:54 -080058 // Methods from interface {{ .ServiceName }}Client.
59{{/* Iterate over methods defined directly in the body of this service */}}
60{{ range $method := .Methods }}
61 {{/* The optionless overload simply calls the overload with options */}}
62 @Override
Srdjan Petroviceee415c2015-05-18 15:50:04 -070063 public {{ $method.RetType }} {{ $method.Name }}(final io.v.v23.context.VContext context{{ $method.DeclarationArgs }}) throws io.v.v23.verror.VException {
Todd Wang232d6492015-02-25 18:04:54 -080064 {{if $method.Returns }}return{{ end }} {{ $method.Name }}(context{{ $method.CallingArgsLeadingComma }}, null);
65 }
Srdjan Petroviceee415c2015-05-18 15:50:04 -070066 {{/* The main client impl method body */}}
Todd Wang232d6492015-02-25 18:04:54 -080067 @Override
Srdjan Petroviceee415c2015-05-18 15:50:04 -070068 public {{ $method.RetType }} {{ $method.Name }}(final io.v.v23.context.VContext context{{ $method.DeclarationArgs }}, io.v.v23.Options vOpts) throws io.v.v23.verror.VException {
Suharsh Sivakumarb4123262015-03-26 18:45:11 -070069 {{/* Start the vanadium call */}}
Todd Wang232d6492015-02-25 18:04:54 -080070 // Start the call.
71 final java.lang.Object[] _args = new java.lang.Object[]{ {{ $method.CallingArgs }} };
72 final java.lang.reflect.Type[] _argTypes = new java.lang.reflect.Type[]{ {{ $method.CallingArgTypes }} };
Suharsh Sivakumarb4123262015-03-26 18:45:11 -070073 final io.v.v23.rpc.Client.Call _call = getClient(context).startCall(context, this.vName, "{{ $method.Name }}", _args, _argTypes, vOpts);
Todd Wang232d6492015-02-25 18:04:54 -080074
75 // Finish the call.
76 {{/* Now handle returning from the function. */}}
77 {{ if $method.NotStreaming }}
78
79 {{ if $method.IsVoid }}
80 final java.lang.reflect.Type[] _resultTypes = new java.lang.reflect.Type[]{};
81 _call.finish(_resultTypes);
82 {{ else }} {{/* else $method.IsVoid */}}
83 final java.lang.reflect.Type[] _resultTypes = new java.lang.reflect.Type[]{
84 {{ range $outArg := $method.OutArgs }}
85 new com.google.common.reflect.TypeToken<{{ $outArg.Type }}>() {}.getType(),
86 {{ end }}
87 };
88 final java.lang.Object[] _results = _call.finish(_resultTypes);
89 {{ if $method.MultipleReturn }}
90 final {{ $method.DeclaredObjectRetType }} _ret = new {{ $method.DeclaredObjectRetType }}();
91 {{ range $i, $outArg := $method.OutArgs }}
92 _ret.{{ $outArg.FieldName }} = ({{ $outArg.Type }})_results[{{ $i }}];
93 {{ end }} {{/* end range over outargs */}}
94 return _ret;
95 {{ else }} {{/* end if $method.MultipleReturn */}}
96 return ({{ $method.DeclaredObjectRetType }})_results[0];
97 {{ end }} {{/* end if $method.MultipleReturn */}}
98
99 {{ end }} {{/* end if $method.IsVoid */}}
100
101 {{else }} {{/* else $method.NotStreaming */}}
102 return new io.v.v23.vdl.ClientStream<{{ $method.SendType }}, {{ $method.RecvType }}, {{ $method.DeclaredObjectRetType }}>() {
103 @Override
104 public void send(final {{ $method.SendType }} item) throws io.v.v23.verror.VException {
105 final java.lang.reflect.Type type = new com.google.common.reflect.TypeToken<{{ $method.SendType }}>() {}.getType();
106 _call.send(item, type);
107 }
108 @Override
109 public {{ $method.RecvType }} recv() throws java.io.EOFException, io.v.v23.verror.VException {
110 final java.lang.reflect.Type type = new com.google.common.reflect.TypeToken<{{ $method.RecvType }}>() {}.getType();
111 final java.lang.Object result = _call.recv(type);
112 try {
113 return ({{ $method.RecvType }})result;
114 } catch (java.lang.ClassCastException e) {
115 throw new io.v.v23.verror.VException("Unexpected result type: " + result.getClass().getCanonicalName());
116 }
117 }
118 @Override
119 public {{ $method.DeclaredObjectRetType }} finish() throws io.v.v23.verror.VException {
120 {{ if $method.IsVoid }}
121 final java.lang.reflect.Type[] resultTypes = new java.lang.reflect.Type[]{};
122 _call.finish(resultTypes);
123 return null;
124 {{ else }} {{/* else $method.IsVoid */}}
125 final java.lang.reflect.Type[] resultTypes = new java.lang.reflect.Type[]{
126 new com.google.common.reflect.TypeToken<{{ $method.DeclaredObjectRetType }}>() {}.getType()
127 };
128 return ({{ $method.DeclaredObjectRetType }})_call.finish(resultTypes)[0];
129 {{ end }} {{/* end if $method.IsVoid */}}
130 }
131 };
132 {{ end }}{{/* end if $method.NotStreaming */}}
133 }
134{{ end }}{{/* end range over methods */}}
135
136{{/* Iterate over methods from embeded services and generate code to delegate the work */}}
137{{ range $eMethod := .EmbedMethods }}
138 @Override
Srdjan Petroviceee415c2015-05-18 15:50:04 -0700139 public {{ $eMethod.RetType }} {{ $eMethod.Name }}(final io.v.v23.context.VContext context{{ $eMethod.DeclarationArgs }}) throws io.v.v23.verror.VException {
140 {{/* e.g. return this.implArith.cosine(context, [args]) */}}
141 {{ if $eMethod.Returns }}return{{ end }} this.impl{{ $eMethod.IfaceName }}.{{ $eMethod.Name }}(context{{ $eMethod.CallingArgsLeadingComma }});
Todd Wang232d6492015-02-25 18:04:54 -0800142 }
143 @Override
Srdjan Petroviceee415c2015-05-18 15:50:04 -0700144 public {{ $eMethod.RetType }} {{ $eMethod.Name }}(final io.v.v23.context.VContext context{{ $eMethod.DeclarationArgs }}, io.v.v23.Options vOpts) throws io.v.v23.verror.VException {
145 {{/* e.g. return this.implArith.cosine(context, [args], options) */}}
146 {{ if $eMethod.Returns }}return{{ end }} this.impl{{ $eMethod.IfaceName }}.{{ $eMethod.Name }}(context{{ $eMethod.CallingArgsLeadingComma }}, vOpts);
Todd Wang232d6492015-02-25 18:04:54 -0800147 }
148{{ end }}
149
150}
151`
152
Srdjan Petroviceee415c2015-05-18 15:50:04 -0700153type clientImplMethodOutArg struct {
Todd Wang232d6492015-02-25 18:04:54 -0800154 FieldName string
155 Type string
156}
157
Srdjan Petroviceee415c2015-05-18 15:50:04 -0700158type clientImplMethod struct {
Todd Wang232d6492015-02-25 18:04:54 -0800159 CallingArgs string
160 CallingArgTypes string
161 CallingArgsLeadingComma string
162 DeclarationArgs string
163 DeclaredObjectRetType string
164 IsVoid bool
165 MultipleReturn bool
166 Name string
167 NotStreaming bool
Srdjan Petroviceee415c2015-05-18 15:50:04 -0700168 OutArgs []clientImplMethodOutArg
Todd Wang232d6492015-02-25 18:04:54 -0800169 RecvType string
170 RetType string
171 Returns bool
172 SendType string
173 ServiceName string
174}
175
Srdjan Petroviceee415c2015-05-18 15:50:04 -0700176type clientImplEmbedMethod struct {
Todd Wang232d6492015-02-25 18:04:54 -0800177 CallingArgsLeadingComma string
178 DeclarationArgs string
Srdjan Petroviceee415c2015-05-18 15:50:04 -0700179 IfaceName string
Todd Wang232d6492015-02-25 18:04:54 -0800180 Name string
181 RetType string
182 Returns bool
183}
184
Srdjan Petroviceee415c2015-05-18 15:50:04 -0700185type clientImplEmbed struct {
186 Name string
187 FullName string
Todd Wang232d6492015-02-25 18:04:54 -0800188}
189
Srdjan Petroviceee415c2015-05-18 15:50:04 -0700190func processClientImplMethod(iface *compile.Interface, method *compile.Method, env *compile.Env) clientImplMethod {
191 outArgs := make([]clientImplMethodOutArg, len(method.OutArgs))
Todd Wang232d6492015-02-25 18:04:54 -0800192 for i := 0; i < len(method.OutArgs); i++ {
James Ring0c739da2015-04-01 13:12:24 -0700193 if method.OutArgs[i].Name != "" {
194 outArgs[i].FieldName = vdlutil.FirstRuneToLower(method.OutArgs[i].Name)
195 } else {
196 outArgs[i].FieldName = fmt.Sprintf("ret%d", i+1)
197 }
Todd Wang232d6492015-02-25 18:04:54 -0800198 outArgs[i].Type = javaType(method.OutArgs[i].Type, true, env)
199 }
Srdjan Petroviceee415c2015-05-18 15:50:04 -0700200 return clientImplMethod{
Todd Wang232d6492015-02-25 18:04:54 -0800201 CallingArgs: javaCallingArgStr(method.InArgs, false),
202 CallingArgTypes: javaCallingArgTypeStr(method.InArgs, env),
203 CallingArgsLeadingComma: javaCallingArgStr(method.InArgs, true),
204 DeclarationArgs: javaDeclarationArgStr(method.InArgs, env, true),
205 DeclaredObjectRetType: clientInterfaceNonStreamingOutArg(iface, method, true, env),
206 IsVoid: len(method.OutArgs) < 1,
207 MultipleReturn: len(method.OutArgs) > 1,
Todd Wang53a4e2e2015-03-18 10:54:54 -0700208 Name: vdlutil.FirstRuneToLower(method.Name),
Todd Wang232d6492015-02-25 18:04:54 -0800209 NotStreaming: !isStreamingMethod(method),
210 OutArgs: outArgs,
211 RecvType: javaType(method.OutStream, true, env),
Srdjan Petrovica7c83032015-05-08 12:08:13 -0700212 RetType: clientInterfaceOutArg(iface, method, env),
Todd Wang232d6492015-02-25 18:04:54 -0800213 Returns: len(method.OutArgs) >= 1 || isStreamingMethod(method),
214 SendType: javaType(method.InStream, true, env),
Todd Wang53a4e2e2015-03-18 10:54:54 -0700215 ServiceName: vdlutil.FirstRuneToUpper(iface.Name),
Todd Wang232d6492015-02-25 18:04:54 -0800216 }
217}
218
Srdjan Petroviceee415c2015-05-18 15:50:04 -0700219func processClientImplEmbedMethod(iface *compile.Interface, embedMethod *compile.Method, env *compile.Env) clientImplEmbedMethod {
220 return clientImplEmbedMethod{
Todd Wang232d6492015-02-25 18:04:54 -0800221 CallingArgsLeadingComma: javaCallingArgStr(embedMethod.InArgs, true),
222 DeclarationArgs: javaDeclarationArgStr(embedMethod.InArgs, env, true),
Srdjan Petroviceee415c2015-05-18 15:50:04 -0700223 IfaceName: vdlutil.FirstRuneToUpper(iface.Name),
Todd Wang53a4e2e2015-03-18 10:54:54 -0700224 Name: vdlutil.FirstRuneToLower(embedMethod.Name),
Srdjan Petrovica7c83032015-05-08 12:08:13 -0700225 RetType: clientInterfaceOutArg(iface, embedMethod, env),
Todd Wang232d6492015-02-25 18:04:54 -0800226 Returns: len(embedMethod.OutArgs) >= 1 || isStreamingMethod(embedMethod),
227 }
228}
229
Srdjan Petroviceee415c2015-05-18 15:50:04 -0700230// genJavaClientImplFile generates a client impl for the specified interface.
231func genJavaClientImplFile(iface *compile.Interface, env *compile.Env) JavaFileInfo {
232 embeds := []clientImplEmbed{}
Todd Wang232d6492015-02-25 18:04:54 -0800233 for _, embed := range allEmbeddedIfaces(iface) {
Srdjan Petroviceee415c2015-05-18 15:50:04 -0700234 embeds = append(embeds, clientImplEmbed{
235 Name: vdlutil.FirstRuneToUpper(embed.Name),
236 FullName: javaPath(javaGenPkgPath(path.Join(embed.File.Package.GenPath, vdlutil.FirstRuneToUpper(embed.Name)))),
Todd Wang232d6492015-02-25 18:04:54 -0800237 })
238 }
Srdjan Petroviceee415c2015-05-18 15:50:04 -0700239 embedMethods := []clientImplEmbedMethod{}
Todd Wang232d6492015-02-25 18:04:54 -0800240 for _, embedMao := range dedupedEmbeddedMethodAndOrigins(iface) {
Srdjan Petroviceee415c2015-05-18 15:50:04 -0700241 embedMethods = append(embedMethods, processClientImplEmbedMethod(embedMao.Origin, embedMao.Method, env))
Todd Wang232d6492015-02-25 18:04:54 -0800242 }
Srdjan Petroviceee415c2015-05-18 15:50:04 -0700243 methods := make([]clientImplMethod, len(iface.Methods))
Todd Wang232d6492015-02-25 18:04:54 -0800244 for i, method := range iface.Methods {
Srdjan Petroviceee415c2015-05-18 15:50:04 -0700245 methods[i] = processClientImplMethod(iface, method, env)
Todd Wang232d6492015-02-25 18:04:54 -0800246 }
Todd Wang53a4e2e2015-03-18 10:54:54 -0700247 javaServiceName := vdlutil.FirstRuneToUpper(iface.Name)
Todd Wang232d6492015-02-25 18:04:54 -0800248 data := struct {
Srdjan Petroviceee415c2015-05-18 15:50:04 -0700249 FileDoc string
250 EmbedMethods []clientImplEmbedMethod
251 Embeds []clientImplEmbed
252 FullServiceName string
253 Methods []clientImplMethod
254 PackagePath string
255 ServiceName string
256 Source string
Todd Wang232d6492015-02-25 18:04:54 -0800257 }{
Srdjan Petroviceee415c2015-05-18 15:50:04 -0700258 FileDoc: iface.File.Package.FileDoc,
259 EmbedMethods: embedMethods,
260 Embeds: embeds,
261 FullServiceName: javaPath(interfaceFullyQualifiedName(iface)),
262 Methods: methods,
263 PackagePath: javaPath(javaGenPkgPath(iface.File.Package.GenPath)),
264 ServiceName: javaServiceName,
265 Source: iface.File.BaseName,
Todd Wang232d6492015-02-25 18:04:54 -0800266 }
267 var buf bytes.Buffer
Srdjan Petroviceee415c2015-05-18 15:50:04 -0700268 err := parseTmpl("client impl", clientImplTmpl).Execute(&buf, data)
Todd Wang232d6492015-02-25 18:04:54 -0800269 if err != nil {
Srdjan Petroviceee415c2015-05-18 15:50:04 -0700270 log.Fatalf("vdl: couldn't execute client impl template: %v", err)
Todd Wang232d6492015-02-25 18:04:54 -0800271 }
272 return JavaFileInfo{
Srdjan Petroviceee415c2015-05-18 15:50:04 -0700273 Name: javaServiceName + "ClientImpl.java",
Todd Wang232d6492015-02-25 18:04:54 -0800274 Data: buf.Bytes(),
275 }
276}