1 | // |
2 | // (c) Copyright, Moebius Solutions, 2002 |
3 | // |
4 | // All Rights Reserved |
5 | // |
6 | // This material may be reproduced by or for the U. S. Government |
7 | // pursuant to the copyright license under the clause at |
8 | // DFARS 252.227-7013 (OCT 1988). |
9 | // |
10 | /* |
11 | * $Id: JniClassGeneratorVisitor.java,v 1.1.1.5 2004/05/25 20:23:29 hastings Exp $ |
12 | */ |
13 | package com.moesol.generator; |
14 | |
15 | import java.io.*; |
16 | import java.lang.reflect.*; |
17 | import java.util.*; |
18 | import com.moesol.generator.core.*; |
19 | import com.moesol.generator.printer.*; |
20 | |
21 | public class JniClassGeneratorVisitor extends ClassGeneratorVisitor { |
22 | JniClassGeneratorVisitor(Writer out, TranslationContext ctx) { |
23 | super(out, ctx); |
24 | } |
25 | protected void extendFieldProperties(Field field, Properties p) { |
26 | if (Modifier.isStatic(field.getModifiers())) { |
27 | p.setProperty("comment", "//"); |
28 | } else { |
29 | p.setProperty("comment", "#error"); // make non-statics fail compile. |
30 | } |
31 | } |
32 | protected String getFieldTemplateName(Field field) { |
33 | return "jni.field.tmpl"; |
34 | } |
35 | protected boolean shouldGenerateMethod(Method method) { |
36 | try { |
37 | return Modifier.isNative(method.getModifiers()) |
38 | && !getC2pcCoclass(method.getDeclaringClass()).equals("Unknown"); |
39 | } catch (ApplyException e) { |
40 | return false; |
41 | } |
42 | } |
43 | protected Callable createCallable(Class a_class, Method method) throws ApplyException { |
44 | return new JniMethodCallable(method, getNumMeParameters(new MethodCallable(a_class, method))); |
45 | } |
46 | protected void extendMethodProperties(Method method, Properties p) throws ApplyException { |
47 | p.setProperty("do_return", getDoReturn(method, false)); |
48 | p.setProperty("ret_type", getDoReturn(method, true)); |
49 | p.setProperty("=", getEqual(method)); |
50 | p.setProperty("ret_translation", getReturnTranslation(method)); |
51 | p.setProperty("ret", getResult(method)); |
52 | p.setProperty("jni_return", getJniReturn(method)); |
53 | p.setProperty("jni_return_error", getJniReturnError(method)); |
54 | p.setProperty("jni_name", getJniName(new MethodCallable(method))); |
55 | p.setProperty("me_parameters", getMeParameters(current_callable)); |
56 | p.setProperty("me_arguments", getMeArguments(current_callable)); |
57 | p.setProperty("me_recover", getMeRecover(current_callable)); |
58 | p.setProperty("c2pc_ifname", getC2pcIfname(method.getDeclaringClass())); |
59 | p.setProperty("coclass", getC2pcCoclass(current_callable.getDeclaringClass())); |
60 | p.setProperty("translation", getTranslation()); |
61 | } |
62 | private String getDoReturn(Method method, boolean hide_void) throws ApplyException { |
63 | if (hide_void && method.getReturnType() == Void.TYPE) { |
64 | return ""; |
65 | } |
66 | try { |
67 | // TODO refactor below method, it's strange to create an |
68 | // instance with null for the writer to call a single method |
69 | // then dump the whole instance... |
70 | return new JniDoParamsVisitor(null, getTranslationContext()) |
71 | .getTranslatedParam(method.getReturnType()); |
72 | } catch (IOException e) { |
73 | throw new ApplyException(e); |
74 | } |
75 | } |
76 | private String getJniReturn(Method method) throws ApplyException { |
77 | try { |
78 | StringWriter out = new StringWriter(); |
79 | JniTypePrinter.getInstance().print(method.getReturnType(), out); |
80 | return out.toString(); |
81 | } catch (IOException e) { |
82 | throw new ApplyException(e); |
83 | } |
84 | } |
85 | private String getResult(Method method) { |
86 | return method.getReturnType() == Void.TYPE ? "" : "result"; |
87 | } |
88 | private String getEqual(Method method) { |
89 | return method.getReturnType() == Void.TYPE ? "" : "="; |
90 | } |
91 | private String getReturnTranslation(Method method) throws ApplyException { |
92 | if (method.getReturnType() == Void.TYPE) { |
93 | return ""; |
94 | } |
95 | return "return " + findParameterTranslation("jni", "do.ret", method.getReturnType()) + ";"; |
96 | } |
97 | private String getJniReturnError(Method method) { |
98 | // TODO might need a method by method way to return an error. |
99 | if (method.getReturnType() == Void.TYPE) { |
100 | return ""; |
101 | } |
102 | return "return 0;"; |
103 | } |
104 | private String getMeParameters(Callable callable) throws ApplyException { |
105 | if (!Modifier.isStatic(callable.getModifiers())) { |
106 | return findMeParams(callable); |
107 | } else { |
108 | return ""; |
109 | } |
110 | } |
111 | private String findMeParams(Callable callable) throws ApplyException { |
112 | if (Modifier.isStatic(callable.getModifiers())) { |
113 | return ""; |
114 | } |
115 | return ", " + findMeTranslation("jni", "me_parameters", callable); |
116 | } |
117 | private String getMeArguments(Callable callable) throws ApplyException { |
118 | if (Modifier.isStatic(callable.getModifiers())) { |
119 | return ""; |
120 | } |
121 | return ", " + findMeTranslation("jni", "me_arguments", callable); |
122 | } |
123 | private String getMeRecover(Callable callable) throws ApplyException { |
124 | if (Modifier.isStatic(callable.getModifiers())) { |
125 | return ""; |
126 | } |
127 | return findMeTranslation("jni", "me_recover", callable); |
128 | } |
129 | private String getC2pcIfname(Class cls) throws ApplyException { |
130 | String iface = getTransProperty("interface." + cls.getName()); |
131 | if (iface != null) { |
132 | return iface; |
133 | } |
134 | |
135 | // Mangle the coclass to get the interface name |
136 | String coclass = getC2pcCoclass(cls); |
137 | int rdx = coclass.lastIndexOf("::"); |
138 | |
139 | if (rdx == -1) { |
140 | return "I" + coclass; |
141 | } else { |
142 | StringBuffer result = new StringBuffer(); |
143 | rdx += 1; |
144 | for (int i = 0; i < coclass.length(); i++) { |
145 | result.append(coclass.charAt(i)); |
146 | if (i == rdx) { |
147 | result.append('I'); |
148 | } |
149 | } |
150 | return result.toString(); |
151 | } |
152 | } |
153 | private String getTranslation() throws ApplyException { |
154 | if (isJniConstructor()) { |
155 | return findConstructorTranslation("jni", "translation", null, current_callable); |
156 | } |
157 | return findMethodTranslation("jni", "translation", "*", current_callable); |
158 | } |
159 | protected String getTemplateName(Method method) throws ApplyException { |
160 | String suffix; |
161 | |
162 | if (isJniConstructor()) { |
163 | return findMethodTranslation("jni", "constructor", "*", current_callable); |
164 | } |
165 | |
166 | if (Modifier.isStatic(current_callable.getModifiers())) { |
167 | suffix = "static"; |
168 | } else { |
169 | suffix = "instance"; |
170 | } |
171 | return findMethodTranslation("jni", "method", suffix, current_callable); |
172 | } |
173 | protected boolean shouldGenerateConstructor(Constructor ctor) { |
174 | return false; |
175 | } |
176 | private boolean isJniConstructor() { |
177 | String class_name = ClassGenerator.stripPackageName(current_callable.getDeclaringClass().getName()); |
178 | return current_callable.getName().equals(class_name); |
179 | } |
180 | |
181 | // TODO remove |
182 | protected String getTemplateName(Constructor ctor) throws ApplyException { |
183 | String prefix = "jni.constructor"; |
184 | String suffixes[] = { |
185 | ctor.getName(), |
186 | "*", |
187 | }; |
188 | |
189 | String translation; |
190 | for (int i = 0; i < suffixes.length; i++) { |
191 | translation = getTransProperty(prefix + "." + suffixes[i]); |
192 | if (translation != null) { |
193 | return translation; |
194 | } |
195 | } |
196 | throw new ApplyException("No "+ prefix +" template for " + ctor.getName()); |
197 | } |
198 | |
199 | /** |
200 | * callback from *.tmpl |
201 | */ |
202 | public void parameters(Writer out) |
203 | throws IOException, ApplyException |
204 | { |
205 | JniParamsVisitor v = new JniParamsVisitor(out); |
206 | VisitClass.visitParamTypes(current_callable.getParameterTypes(), v); |
207 | } |
208 | /** |
209 | * callback from *.tmpl |
210 | */ |
211 | public void do_parameters(Writer out) |
212 | throws IOException, ApplyException |
213 | { |
214 | JniDoParamsVisitor v = new JniDoParamsVisitor(out, getTranslationContext()); |
215 | VisitClass.visitParamTypes(current_callable.getParameterTypes(), v); |
216 | } |
217 | /** |
218 | * callback from *.tmpl |
219 | */ |
220 | public void arguments(Writer out) |
221 | throws IOException, ApplyException |
222 | { |
223 | Class params[] = current_callable.getParameterTypes(); |
224 | Properties p = new Properties(); |
225 | for (int i = 0; i < params.length; i++) { |
226 | out.write(", "); |
227 | String arg_trans = findParameterTranslation("jni", "do.arg", params[i]); |
228 | Template t = new Template(new StringReader(arg_trans)); |
229 | p.setProperty("arg", "p" + Integer.toString(i)); |
230 | t.apply(p, out); |
231 | } |
232 | } |
233 | |
234 | private int getNumMeParameters(Callable callable) throws ApplyException { |
235 | if (Modifier.isStatic(callable.getModifiers())) { |
236 | return 0; |
237 | } |
238 | String me_parameters = findMeParams(callable); |
239 | int num_me_parameters = 0; |
240 | for (int i = 0; i < me_parameters.length(); i++) { |
241 | if (me_parameters.charAt(i) == ',') { |
242 | num_me_parameters++; |
243 | } |
244 | } |
245 | return num_me_parameters; |
246 | } |
247 | protected String getC2pcCoclass(Class cls) throws ApplyException { |
248 | String mapped = getTransProperty("coclass." + cls.getName()); |
249 | if (mapped == null) { |
250 | return getTransProperty("coclass.*"); |
251 | } else { |
252 | return mapped; |
253 | } |
254 | } |
255 | } |