blob: 55faa595d72f41887f09a4ad959f241a642e46a5 [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"
9 "log"
10 "path"
James Ringe3d19222015-03-18 08:02:04 -070011 "strings"
Todd Wang232d6492015-02-25 18:04:54 -080012
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
Jiri Simsa67b8a262015-03-24 21:14:07 -070017const serverWrapperTmpl = header + `
Todd Wang232d6492015-02-25 18:04:54 -080018// Source(s): {{ .Source }}
19package {{ .PackagePath }};
20
Srdjan Petroviceee415c2015-05-18 15:50:04 -070021/**
22 * Wrapper for {@link {{ .ServiceName }}Server}. This wrapper is used by
23 * {@link io.v.v23.rpc.ReflectInvoker} to indirectly invoke server methods.
24 */
25public final class {{ .ServiceName }}ServerWrapper {
Todd Wang232d6492015-02-25 18:04:54 -080026 private final {{ .FullServiceName }}Server server;
27
28{{/* Define fields to hold each of the embedded server wrappers*/}}
29{{ range $embed := .Embeds }}
30 {{/* e.g. private final com.somepackage.gen_impl.ArithStub stubArith; */}}
Srdjan Petroviceee415c2015-05-18 15:50:04 -070031 private final {{ $embed.FullName }}ServerWrapper wrapper{{ $embed.Name }};
Todd Wang232d6492015-02-25 18:04:54 -080032 {{ end }}
33
Srdjan Petroviceee415c2015-05-18 15:50:04 -070034 /**
35 * Creates a new {@link {{ .ServiceName }}ServerWrapper} to invoke the methods of the
36 * provided server.
37 *
38 * @param server server whose methods are to be invoked
39 */
Todd Wang232d6492015-02-25 18:04:54 -080040 public {{ .ServiceName }}ServerWrapper(final {{ .FullServiceName }}Server server) {
41 this.server = server;
42 {{/* Initialize the embeded server wrappers */}}
43 {{ range $embed := .Embeds }}
Srdjan Petroviceee415c2015-05-18 15:50:04 -070044 this.wrapper{{ $embed.Name }} = new {{ $embed.FullName }}ServerWrapper(server);
Todd Wang232d6492015-02-25 18:04:54 -080045 {{ end }}
46 }
47
48 /**
49 * Returns a description of this server.
50 */
Srdjan Petrovica7c83032015-05-08 12:08:13 -070051 public io.v.v23.vdlroot.signature.Interface signature() {
Suharsh Sivakumarb4123262015-03-26 18:45:11 -070052 java.util.List<io.v.v23.vdlroot.signature.Embed> embeds = new java.util.ArrayList<io.v.v23.vdlroot.signature.Embed>();
James Ringe3d19222015-03-18 08:02:04 -070053 java.util.List<io.v.v23.vdlroot.signature.Method> methods = new java.util.ArrayList<io.v.v23.vdlroot.signature.Method>();
54 {{ range $method := .Methods }}
55 {
56 java.util.List<io.v.v23.vdlroot.signature.Arg> inArgs = new java.util.ArrayList<io.v.v23.vdlroot.signature.Arg>();
57 {{ range $arg := $method.CallingArgTypes }}
58 inArgs.add(new io.v.v23.vdlroot.signature.Arg("", "", new io.v.v23.vdl.VdlTypeObject({{ $arg }})));
59 {{ end }}
60 java.util.List<io.v.v23.vdlroot.signature.Arg> outArgs = new java.util.ArrayList<io.v.v23.vdlroot.signature.Arg>();
61 {{ range $arg := $method.RetJavaTypes }}
62 outArgs.add(new io.v.v23.vdlroot.signature.Arg("", "", new io.v.v23.vdl.VdlTypeObject({{ $arg }})));
63 {{ end }}
64 java.util.List<io.v.v23.vdl.VdlAny> tags = new java.util.ArrayList<io.v.v23.vdl.VdlAny>();
65 {{ range $tag := .Tags }}
66 tags.add(new io.v.v23.vdl.VdlAny(io.v.v23.vdl.VdlValue.valueOf({{ $tag.Value }}, {{ $tag.Type }})));
67 {{ end }}
68 methods.add(new io.v.v23.vdlroot.signature.Method(
69 "{{ $method.Name }}",
70 "{{ $method.Doc }}",
71 inArgs,
72 outArgs,
73 null,
74 null,
75 tags));
76 }
77 {{ end }}
78
79 return new io.v.v23.vdlroot.signature.Interface("{{ .ServiceName }}", "{{ .PackagePath }}", "{{ .Doc }}", embeds, methods);
80 }
Todd Wang232d6492015-02-25 18:04:54 -080081
82 /**
Srdjan Petroviceee415c2015-05-18 15:50:04 -070083 * Returns all tags associated with the provided method or {@code null} if the method isn't
84 * implemented by this server.
85 *
86 * @param method method whose tags are to be returned
Todd Wang232d6492015-02-25 18:04:54 -080087 */
88 @SuppressWarnings("unused")
Srdjan Petrovica7c83032015-05-08 12:08:13 -070089 public io.v.v23.vdl.VdlValue[] getMethodTags(final java.lang.String method) throws io.v.v23.verror.VException {
Todd Wang232d6492015-02-25 18:04:54 -080090 {{ range $methodName, $tags := .MethodTags }}
91 if ("{{ $methodName }}".equals(method)) {
92 try {
93 return new io.v.v23.vdl.VdlValue[] {
94 {{ range $tag := $tags }} io.v.v23.vdl.VdlValue.valueOf({{ $tag.Value }}, {{ $tag.Type }}), {{ end }}
95 };
96 } catch (IllegalArgumentException e) {
97 throw new io.v.v23.verror.VException(String.format("Couldn't get tags for method \"{{ $methodName }}\": %s", e.getMessage()));
98 }
99 }
100 {{ end }}
101 {{ range $embed := .Embeds }}
102 {
Srdjan Petroviceee415c2015-05-18 15:50:04 -0700103 final io.v.v23.vdl.VdlValue[] tags = this.wrapper{{ $embed.Name }}.getMethodTags(method);
Todd Wang232d6492015-02-25 18:04:54 -0800104 if (tags != null) {
105 return tags;
106 }
107 }
108 {{ end }}
109 return null; // method not found
110 }
111
112 {{/* Iterate over methods defined directly in the body of this server */}}
113 {{ range $method := .Methods }}
Srdjan Petroviceee415c2015-05-18 15:50:04 -0700114 {{ $method.JavaDoc }}
115 public {{ $method.RetType }} {{ $method.Name }}(final io.v.v23.context.VContext ctx, final io.v.v23.rpc.StreamServerCall call{{ $method.DeclarationArgs }}) throws io.v.v23.verror.VException {
Todd Wang232d6492015-02-25 18:04:54 -0800116 {{ if $method.IsStreaming }}
117 final io.v.v23.vdl.Stream<{{ $method.SendType }}, {{ $method.RecvType }}> _stream = new io.v.v23.vdl.Stream<{{ $method.SendType }}, {{ $method.RecvType }}>() {
118 @Override
119 public void send({{ $method.SendType }} item) throws io.v.v23.verror.VException {
120 final java.lang.reflect.Type type = new com.google.common.reflect.TypeToken< {{ $method.SendType }} >() {}.getType();
121 call.send(item, type);
122 }
123 @Override
124 public {{ $method.RecvType }} recv() throws java.io.EOFException, io.v.v23.verror.VException {
125 final java.lang.reflect.Type type = new com.google.common.reflect.TypeToken< {{ $method.RecvType }} >() {}.getType();
126 final java.lang.Object result = call.recv(type);
127 try {
128 return ({{ $method.RecvType }})result;
129 } catch (java.lang.ClassCastException e) {
130 throw new io.v.v23.verror.VException("Unexpected result type: " + result.getClass().getCanonicalName());
131 }
132 }
133 };
134 {{ end }} {{/* end if $method.IsStreaming */}}
James Ringa98f67b2015-04-16 20:59:04 -0700135 {{ if $method.Returns }} return {{ end }} this.server.{{ $method.Name }}(ctx, call {{ $method.CallingArgs }} {{ if $method.IsStreaming }} ,_stream {{ end }} );
Todd Wang232d6492015-02-25 18:04:54 -0800136 }
137{{end}}
138
139{{/* Iterate over methods from embeded servers and generate code to delegate the work */}}
140{{ range $eMethod := .EmbedMethods }}
Srdjan Petroviceee415c2015-05-18 15:50:04 -0700141 {{ $eMethod.JavaDoc }}
142 public {{ $eMethod.RetType }} {{ $eMethod.Name }}(final io.v.v23.context.VContext ctx, final io.v.v23.rpc.StreamServerCall call{{ $eMethod.DeclarationArgs }}) throws io.v.v23.verror.VException {
James Ringa98f67b2015-04-16 20:59:04 -0700143 {{/* e.g. return this.stubArith.cosine(ctx, call, [args], options) */}}
Srdjan Petroviceee415c2015-05-18 15:50:04 -0700144 {{ if $eMethod.Returns }}return{{ end }} this.wrapper{{ $eMethod.IfaceName }}.{{ $eMethod.Name }}(ctx, call{{ $eMethod.CallingArgs }});
Todd Wang232d6492015-02-25 18:04:54 -0800145 }
146{{ end }} {{/* end range .EmbedMethods */}}
147
148}
149`
150
151type serverWrapperMethod struct {
Todd Wang232d6492015-02-25 18:04:54 -0800152 CallingArgs string
James Ringe3d19222015-03-18 08:02:04 -0700153 CallingArgTypes []string
Todd Wang232d6492015-02-25 18:04:54 -0800154 DeclarationArgs string
Srdjan Petroviceee415c2015-05-18 15:50:04 -0700155 Doc string
Todd Wang232d6492015-02-25 18:04:54 -0800156 IsStreaming bool
Srdjan Petroviceee415c2015-05-18 15:50:04 -0700157 JavaDoc string
Todd Wang232d6492015-02-25 18:04:54 -0800158 Name string
159 RecvType string
160 RetType string
James Ringe3d19222015-03-18 08:02:04 -0700161 RetJavaTypes []string
Todd Wang232d6492015-02-25 18:04:54 -0800162 Returns bool
163 SendType string
James Ringe3d19222015-03-18 08:02:04 -0700164 Tags []methodTag
Todd Wang232d6492015-02-25 18:04:54 -0800165}
166
167type serverWrapperEmbedMethod struct {
Srdjan Petroviceee415c2015-05-18 15:50:04 -0700168 CallingArgs string
169 DeclarationArgs string
170 Doc string
171 IfaceName string
172 JavaDoc string
173 Name string
174 RetType string
175 Returns bool
Todd Wang232d6492015-02-25 18:04:54 -0800176}
177
178type serverWrapperEmbed struct {
Srdjan Petroviceee415c2015-05-18 15:50:04 -0700179 Name string
180 FullName string
Todd Wang232d6492015-02-25 18:04:54 -0800181}
182
183type methodTag struct {
184 Value string
185 Type string
186}
187
James Ringe3d19222015-03-18 08:02:04 -0700188// TODO(sjr): move this to somewhere in util_*.
189func toJavaString(goString string) string {
190 result := strings.Replace(goString, "\"", "\\\"", -1)
191 result = strings.Replace(result, "\n", "\" + \n\"", -1)
192 return result
193}
194
195func processServerWrapperMethod(iface *compile.Interface, method *compile.Method, env *compile.Env, tags []methodTag) serverWrapperMethod {
196 callArgTypes := make([]string, len(method.InArgs))
197 for i, arg := range method.InArgs {
198 callArgTypes[i] = javaReflectType(arg.Type, env)
199 }
200 retArgTypes := make([]string, len(method.OutArgs))
201 for i, arg := range method.OutArgs {
202 retArgTypes[i] = javaReflectType(arg.Type, env)
203 }
Todd Wang232d6492015-02-25 18:04:54 -0800204 return serverWrapperMethod{
Todd Wang232d6492015-02-25 18:04:54 -0800205 CallingArgs: javaCallingArgStr(method.InArgs, true),
James Ringe3d19222015-03-18 08:02:04 -0700206 CallingArgTypes: callArgTypes,
Todd Wang232d6492015-02-25 18:04:54 -0800207 DeclarationArgs: javaDeclarationArgStr(method.InArgs, env, true),
Srdjan Petroviceee415c2015-05-18 15:50:04 -0700208 Doc: toJavaString(method.Doc),
Todd Wang232d6492015-02-25 18:04:54 -0800209 IsStreaming: isStreamingMethod(method),
Srdjan Petroviceee415c2015-05-18 15:50:04 -0700210 JavaDoc: javaDoc(method.Doc, method.DocSuffix),
Todd Wang53a4e2e2015-03-18 10:54:54 -0700211 Name: vdlutil.FirstRuneToLower(method.Name),
Todd Wang232d6492015-02-25 18:04:54 -0800212 RecvType: javaType(method.InStream, true, env),
Srdjan Petrovica7c83032015-05-08 12:08:13 -0700213 RetType: serverInterfaceOutArg(iface, method, env),
James Ringe3d19222015-03-18 08:02:04 -0700214 RetJavaTypes: retArgTypes,
Todd Wang232d6492015-02-25 18:04:54 -0800215 Returns: len(method.OutArgs) >= 1,
216 SendType: javaType(method.OutStream, true, env),
James Ringe3d19222015-03-18 08:02:04 -0700217 Tags: tags,
Todd Wang232d6492015-02-25 18:04:54 -0800218 }
219}
220
221func processServerWrapperEmbedMethod(iface *compile.Interface, embedMethod *compile.Method, env *compile.Env) serverWrapperEmbedMethod {
222 return serverWrapperEmbedMethod{
Srdjan Petroviceee415c2015-05-18 15:50:04 -0700223 CallingArgs: javaCallingArgStr(embedMethod.InArgs, true),
224 DeclarationArgs: javaDeclarationArgStr(embedMethod.InArgs, env, true),
225 IfaceName: vdlutil.FirstRuneToUpper(iface.Name),
226 JavaDoc: javaDoc(embedMethod.Doc, embedMethod.DocSuffix),
227 Name: vdlutil.FirstRuneToLower(embedMethod.Name),
228 RetType: serverInterfaceOutArg(iface, embedMethod, env),
229 Returns: len(embedMethod.OutArgs) >= 1,
Todd Wang232d6492015-02-25 18:04:54 -0800230 }
231}
232
233// genJavaServerWrapperFile generates a java file containing a server wrapper for the specified
234// interface.
235func genJavaServerWrapperFile(iface *compile.Interface, env *compile.Env) JavaFileInfo {
236 embeds := []serverWrapperEmbed{}
237 for _, embed := range allEmbeddedIfaces(iface) {
238 embeds = append(embeds, serverWrapperEmbed{
Srdjan Petroviceee415c2015-05-18 15:50:04 -0700239 Name: vdlutil.FirstRuneToUpper(embed.Name),
240 FullName: javaPath(javaGenPkgPath(path.Join(embed.File.Package.GenPath, vdlutil.FirstRuneToUpper(embed.Name)))),
Todd Wang232d6492015-02-25 18:04:54 -0800241 })
242 }
243 methodTags := make(map[string][]methodTag)
Todd Wang232d6492015-02-25 18:04:54 -0800244 // Copy method tags off of the interface.
James Ringe3d19222015-03-18 08:02:04 -0700245 methods := make([]serverWrapperMethod, len(iface.Methods))
246 for i, method := range iface.Methods {
Todd Wang232d6492015-02-25 18:04:54 -0800247 tags := make([]methodTag, len(method.Tags))
James Ringe3d19222015-03-18 08:02:04 -0700248 for j, tag := range method.Tags {
249 tags[j].Value = javaConstVal(tag, env)
250 tags[j].Type = javaReflectType(tag.Type(), env)
Todd Wang232d6492015-02-25 18:04:54 -0800251 }
Todd Wang53a4e2e2015-03-18 10:54:54 -0700252 methodTags[vdlutil.FirstRuneToLower(method.Name)] = tags
James Ringe3d19222015-03-18 08:02:04 -0700253 methods[i] = processServerWrapperMethod(iface, method, env, tags)
Todd Wang232d6492015-02-25 18:04:54 -0800254 }
255 embedMethods := []serverWrapperEmbedMethod{}
256 for _, embedMao := range dedupedEmbeddedMethodAndOrigins(iface) {
257 embedMethods = append(embedMethods, processServerWrapperEmbedMethod(embedMao.Origin, embedMao.Method, env))
258 }
Todd Wang53a4e2e2015-03-18 10:54:54 -0700259 javaServiceName := vdlutil.FirstRuneToUpper(iface.Name)
Todd Wang232d6492015-02-25 18:04:54 -0800260 data := struct {
Todd Wangb90b8de2015-03-31 20:04:13 -0700261 FileDoc string
Todd Wang232d6492015-02-25 18:04:54 -0800262 EmbedMethods []serverWrapperEmbedMethod
263 Embeds []serverWrapperEmbed
264 FullServiceName string
265 Methods []serverWrapperMethod
266 MethodTags map[string][]methodTag
267 PackagePath string
268 ServiceName string
269 Source string
James Ringe3d19222015-03-18 08:02:04 -0700270 Doc string
Todd Wang232d6492015-02-25 18:04:54 -0800271 }{
Todd Wangb90b8de2015-03-31 20:04:13 -0700272 FileDoc: iface.File.Package.FileDoc,
Todd Wang232d6492015-02-25 18:04:54 -0800273 EmbedMethods: embedMethods,
274 Embeds: embeds,
275 FullServiceName: javaPath(interfaceFullyQualifiedName(iface)),
276 Methods: methods,
277 MethodTags: methodTags,
278 PackagePath: javaPath(javaGenPkgPath(iface.File.Package.GenPath)),
279 ServiceName: javaServiceName,
280 Source: iface.File.BaseName,
James Ringe3d19222015-03-18 08:02:04 -0700281 Doc: toJavaString(iface.NamePos.Doc),
Todd Wang232d6492015-02-25 18:04:54 -0800282 }
283 var buf bytes.Buffer
284 err := parseTmpl("server wrapper", serverWrapperTmpl).Execute(&buf, data)
285 if err != nil {
286 log.Fatalf("vdl: couldn't execute server wrapper template: %v", err)
287 }
288 return JavaFileInfo{
289 Name: javaServiceName + "ServerWrapper.java",
290 Data: buf.Bytes(),
291 }
292}