blob: e46108505812fa9eef561d5a9e293dd1428514b1 [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
21{{ .AccessModifier }} final class {{ .ServiceName }}ServerWrapper {
22
23 private final {{ .FullServiceName }}Server server;
24
25{{/* Define fields to hold each of the embedded server wrappers*/}}
26{{ range $embed := .Embeds }}
27 {{/* e.g. private final com.somepackage.gen_impl.ArithStub stubArith; */}}
28 private final {{ $embed.WrapperClassName }} {{ $embed.LocalWrapperVarName }};
29 {{ end }}
30
31 public {{ .ServiceName }}ServerWrapper(final {{ .FullServiceName }}Server server) {
32 this.server = server;
33 {{/* Initialize the embeded server wrappers */}}
34 {{ range $embed := .Embeds }}
35 this.{{ $embed.LocalWrapperVarName }} = new {{ $embed.WrapperClassName }}(server);
36 {{ end }}
37 }
38
39 /**
40 * Returns a description of this server.
41 */
James Ringe3d19222015-03-18 08:02:04 -070042 public io.v.v23.vdlroot.signature.Interface signature() throws io.v.v23.verror.VException {
Suharsh Sivakumarb4123262015-03-26 18:45:11 -070043 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 -070044 java.util.List<io.v.v23.vdlroot.signature.Method> methods = new java.util.ArrayList<io.v.v23.vdlroot.signature.Method>();
45 {{ range $method := .Methods }}
46 {
47 java.util.List<io.v.v23.vdlroot.signature.Arg> inArgs = new java.util.ArrayList<io.v.v23.vdlroot.signature.Arg>();
48 {{ range $arg := $method.CallingArgTypes }}
49 inArgs.add(new io.v.v23.vdlroot.signature.Arg("", "", new io.v.v23.vdl.VdlTypeObject({{ $arg }})));
50 {{ end }}
51 java.util.List<io.v.v23.vdlroot.signature.Arg> outArgs = new java.util.ArrayList<io.v.v23.vdlroot.signature.Arg>();
52 {{ range $arg := $method.RetJavaTypes }}
53 outArgs.add(new io.v.v23.vdlroot.signature.Arg("", "", new io.v.v23.vdl.VdlTypeObject({{ $arg }})));
54 {{ end }}
55 java.util.List<io.v.v23.vdl.VdlAny> tags = new java.util.ArrayList<io.v.v23.vdl.VdlAny>();
56 {{ range $tag := .Tags }}
57 tags.add(new io.v.v23.vdl.VdlAny(io.v.v23.vdl.VdlValue.valueOf({{ $tag.Value }}, {{ $tag.Type }})));
58 {{ end }}
59 methods.add(new io.v.v23.vdlroot.signature.Method(
60 "{{ $method.Name }}",
61 "{{ $method.Doc }}",
62 inArgs,
63 outArgs,
64 null,
65 null,
66 tags));
67 }
68 {{ end }}
69
70 return new io.v.v23.vdlroot.signature.Interface("{{ .ServiceName }}", "{{ .PackagePath }}", "{{ .Doc }}", embeds, methods);
71 }
Todd Wang232d6492015-02-25 18:04:54 -080072
73 /**
74 * Returns all tags associated with the provided method or null if the method isn't implemented
75 * by this server.
76 */
77 @SuppressWarnings("unused")
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070078 public io.v.v23.vdl.VdlValue[] getMethodTags(final io.v.v23.rpc.StreamServerCall call, final java.lang.String method) throws io.v.v23.verror.VException {
Todd Wang232d6492015-02-25 18:04:54 -080079 {{ range $methodName, $tags := .MethodTags }}
80 if ("{{ $methodName }}".equals(method)) {
81 try {
82 return new io.v.v23.vdl.VdlValue[] {
83 {{ range $tag := $tags }} io.v.v23.vdl.VdlValue.valueOf({{ $tag.Value }}, {{ $tag.Type }}), {{ end }}
84 };
85 } catch (IllegalArgumentException e) {
86 throw new io.v.v23.verror.VException(String.format("Couldn't get tags for method \"{{ $methodName }}\": %s", e.getMessage()));
87 }
88 }
89 {{ end }}
90 {{ range $embed := .Embeds }}
91 {
92 final io.v.v23.vdl.VdlValue[] tags = this.{{ $embed.LocalWrapperVarName }}.getMethodTags(call, method);
93 if (tags != null) {
94 return tags;
95 }
96 }
97 {{ end }}
98 return null; // method not found
99 }
100
101 {{/* Iterate over methods defined directly in the body of this server */}}
102 {{ range $method := .Methods }}
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700103 {{ $method.AccessModifier }} {{ $method.RetType }} {{ $method.Name }}(final io.v.v23.rpc.StreamServerCall call{{ $method.DeclarationArgs }}) throws io.v.v23.verror.VException {
Todd Wang232d6492015-02-25 18:04:54 -0800104 {{ if $method.IsStreaming }}
105 final io.v.v23.vdl.Stream<{{ $method.SendType }}, {{ $method.RecvType }}> _stream = new io.v.v23.vdl.Stream<{{ $method.SendType }}, {{ $method.RecvType }}>() {
106 @Override
107 public void send({{ $method.SendType }} item) throws io.v.v23.verror.VException {
108 final java.lang.reflect.Type type = new com.google.common.reflect.TypeToken< {{ $method.SendType }} >() {}.getType();
109 call.send(item, type);
110 }
111 @Override
112 public {{ $method.RecvType }} recv() throws java.io.EOFException, io.v.v23.verror.VException {
113 final java.lang.reflect.Type type = new com.google.common.reflect.TypeToken< {{ $method.RecvType }} >() {}.getType();
114 final java.lang.Object result = call.recv(type);
115 try {
116 return ({{ $method.RecvType }})result;
117 } catch (java.lang.ClassCastException e) {
118 throw new io.v.v23.verror.VException("Unexpected result type: " + result.getClass().getCanonicalName());
119 }
120 }
121 };
122 {{ end }} {{/* end if $method.IsStreaming */}}
123 {{ if $method.Returns }} return {{ end }} this.server.{{ $method.Name }}( call {{ $method.CallingArgs }} {{ if $method.IsStreaming }} ,_stream {{ end }} );
124 }
125{{end}}
126
127{{/* Iterate over methods from embeded servers and generate code to delegate the work */}}
128{{ range $eMethod := .EmbedMethods }}
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700129 {{ $eMethod.AccessModifier }} {{ $eMethod.RetType }} {{ $eMethod.Name }}(final io.v.v23.rpc.StreamServerCall call{{ $eMethod.DeclarationArgs }}) throws io.v.v23.verror.VException {
Todd Wang232d6492015-02-25 18:04:54 -0800130 {{/* e.g. return this.stubArith.cosine(call, [args], options) */}}
131 {{ if $eMethod.Returns }}return{{ end }} this.{{ $eMethod.LocalWrapperVarName }}.{{ $eMethod.Name }}(call{{ $eMethod.CallingArgs }});
132 }
133{{ end }} {{/* end range .EmbedMethods */}}
134
135}
136`
137
138type serverWrapperMethod struct {
139 AccessModifier string
140 CallingArgs string
James Ringe3d19222015-03-18 08:02:04 -0700141 CallingArgTypes []string
Todd Wang232d6492015-02-25 18:04:54 -0800142 DeclarationArgs string
143 IsStreaming bool
144 Name string
145 RecvType string
146 RetType string
James Ringe3d19222015-03-18 08:02:04 -0700147 RetJavaTypes []string
Todd Wang232d6492015-02-25 18:04:54 -0800148 Returns bool
149 SendType string
James Ringe3d19222015-03-18 08:02:04 -0700150 Doc string
151 Tags []methodTag
Todd Wang232d6492015-02-25 18:04:54 -0800152}
153
154type serverWrapperEmbedMethod struct {
155 AccessModifier string
156 CallingArgs string
157 DeclarationArgs string
158 LocalWrapperVarName string
159 Name string
160 RetType string
161 Returns bool
162}
163
164type serverWrapperEmbed struct {
165 LocalWrapperVarName string
166 WrapperClassName string
167}
168
169type methodTag struct {
170 Value string
171 Type string
172}
173
James Ringe3d19222015-03-18 08:02:04 -0700174// TODO(sjr): move this to somewhere in util_*.
175func toJavaString(goString string) string {
176 result := strings.Replace(goString, "\"", "\\\"", -1)
177 result = strings.Replace(result, "\n", "\" + \n\"", -1)
178 return result
179}
180
181func processServerWrapperMethod(iface *compile.Interface, method *compile.Method, env *compile.Env, tags []methodTag) serverWrapperMethod {
182 callArgTypes := make([]string, len(method.InArgs))
183 for i, arg := range method.InArgs {
184 callArgTypes[i] = javaReflectType(arg.Type, env)
185 }
186 retArgTypes := make([]string, len(method.OutArgs))
187 for i, arg := range method.OutArgs {
188 retArgTypes[i] = javaReflectType(arg.Type, env)
189 }
Todd Wang232d6492015-02-25 18:04:54 -0800190 return serverWrapperMethod{
191 AccessModifier: accessModifierForName(method.Name),
192 CallingArgs: javaCallingArgStr(method.InArgs, true),
James Ringe3d19222015-03-18 08:02:04 -0700193 CallingArgTypes: callArgTypes,
Todd Wang232d6492015-02-25 18:04:54 -0800194 DeclarationArgs: javaDeclarationArgStr(method.InArgs, env, true),
195 IsStreaming: isStreamingMethod(method),
Todd Wang53a4e2e2015-03-18 10:54:54 -0700196 Name: vdlutil.FirstRuneToLower(method.Name),
Todd Wang232d6492015-02-25 18:04:54 -0800197 RecvType: javaType(method.InStream, true, env),
198 RetType: clientInterfaceOutArg(iface, method, true, env),
James Ringe3d19222015-03-18 08:02:04 -0700199 RetJavaTypes: retArgTypes,
Todd Wang232d6492015-02-25 18:04:54 -0800200 Returns: len(method.OutArgs) >= 1,
201 SendType: javaType(method.OutStream, true, env),
James Ringe3d19222015-03-18 08:02:04 -0700202 Doc: toJavaString(method.NamePos.Doc),
203 Tags: tags,
Todd Wang232d6492015-02-25 18:04:54 -0800204 }
205}
206
207func processServerWrapperEmbedMethod(iface *compile.Interface, embedMethod *compile.Method, env *compile.Env) serverWrapperEmbedMethod {
208 return serverWrapperEmbedMethod{
209 AccessModifier: accessModifierForName(embedMethod.Name),
210 CallingArgs: javaCallingArgStr(embedMethod.InArgs, true),
211 DeclarationArgs: javaDeclarationArgStr(embedMethod.InArgs, env, true),
Todd Wang53a4e2e2015-03-18 10:54:54 -0700212 LocalWrapperVarName: vdlutil.FirstRuneToLower(iface.Name) + "Wrapper",
213 Name: vdlutil.FirstRuneToLower(embedMethod.Name),
Todd Wang232d6492015-02-25 18:04:54 -0800214 RetType: clientInterfaceOutArg(iface, embedMethod, true, env),
215 Returns: len(embedMethod.OutArgs) >= 1,
216 }
217}
218
219// genJavaServerWrapperFile generates a java file containing a server wrapper for the specified
220// interface.
221func genJavaServerWrapperFile(iface *compile.Interface, env *compile.Env) JavaFileInfo {
222 embeds := []serverWrapperEmbed{}
223 for _, embed := range allEmbeddedIfaces(iface) {
224 embeds = append(embeds, serverWrapperEmbed{
Todd Wang53a4e2e2015-03-18 10:54:54 -0700225 WrapperClassName: javaPath(javaGenPkgPath(path.Join(embed.File.Package.GenPath, vdlutil.FirstRuneToUpper(embed.Name+"ServerWrapper")))),
226 LocalWrapperVarName: vdlutil.FirstRuneToLower(embed.Name) + "Wrapper",
Todd Wang232d6492015-02-25 18:04:54 -0800227 })
228 }
229 methodTags := make(map[string][]methodTag)
230 // Add generated methods to the tag map:
231 methodTags["signature"] = []methodTag{}
232 methodTags["getMethodTags"] = []methodTag{}
233 // Copy method tags off of the interface.
James Ringe3d19222015-03-18 08:02:04 -0700234 methods := make([]serverWrapperMethod, len(iface.Methods))
235 for i, method := range iface.Methods {
Todd Wang232d6492015-02-25 18:04:54 -0800236 tags := make([]methodTag, len(method.Tags))
James Ringe3d19222015-03-18 08:02:04 -0700237 for j, tag := range method.Tags {
238 tags[j].Value = javaConstVal(tag, env)
239 tags[j].Type = javaReflectType(tag.Type(), env)
Todd Wang232d6492015-02-25 18:04:54 -0800240 }
Todd Wang53a4e2e2015-03-18 10:54:54 -0700241 methodTags[vdlutil.FirstRuneToLower(method.Name)] = tags
James Ringe3d19222015-03-18 08:02:04 -0700242 methods[i] = processServerWrapperMethod(iface, method, env, tags)
Todd Wang232d6492015-02-25 18:04:54 -0800243 }
244 embedMethods := []serverWrapperEmbedMethod{}
245 for _, embedMao := range dedupedEmbeddedMethodAndOrigins(iface) {
246 embedMethods = append(embedMethods, processServerWrapperEmbedMethod(embedMao.Origin, embedMao.Method, env))
247 }
Todd Wang53a4e2e2015-03-18 10:54:54 -0700248 javaServiceName := vdlutil.FirstRuneToUpper(iface.Name)
Todd Wang232d6492015-02-25 18:04:54 -0800249 data := struct {
250 AccessModifier string
251 EmbedMethods []serverWrapperEmbedMethod
252 Embeds []serverWrapperEmbed
253 FullServiceName string
254 Methods []serverWrapperMethod
255 MethodTags map[string][]methodTag
256 PackagePath string
257 ServiceName string
258 Source string
James Ringe3d19222015-03-18 08:02:04 -0700259 Doc string
Todd Wang232d6492015-02-25 18:04:54 -0800260 }{
261 AccessModifier: accessModifierForName(iface.Name),
262 EmbedMethods: embedMethods,
263 Embeds: embeds,
264 FullServiceName: javaPath(interfaceFullyQualifiedName(iface)),
265 Methods: methods,
266 MethodTags: methodTags,
267 PackagePath: javaPath(javaGenPkgPath(iface.File.Package.GenPath)),
268 ServiceName: javaServiceName,
269 Source: iface.File.BaseName,
James Ringe3d19222015-03-18 08:02:04 -0700270 Doc: toJavaString(iface.NamePos.Doc),
Todd Wang232d6492015-02-25 18:04:54 -0800271 }
272 var buf bytes.Buffer
273 err := parseTmpl("server wrapper", serverWrapperTmpl).Execute(&buf, data)
274 if err != nil {
275 log.Fatalf("vdl: couldn't execute server wrapper template: %v", err)
276 }
277 return JavaFileInfo{
278 Name: javaServiceName + "ServerWrapper.java",
279 Data: buf.Bytes(),
280 }
281}