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: JavaClassGeneratorVisitor.java,v 1.2 2004/05/25 00:25:46 adamp 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 JavaClassGeneratorVisitor extends ClassGeneratorVisitor { |
22 | public JavaClassGeneratorVisitor(Writer out, TranslationContext ctx) { |
23 | super(out, ctx); |
24 | } |
25 | public void visit(Class a_class) throws ApplyException { |
26 | VisitClass.visitReflect(a_class, this); |
27 | |
28 | // TODO move this as a visitor in generator. Custom visit |
29 | // strategy to get at super methods that we need to override. |
30 | Class super_class = a_class.getSuperclass(); |
31 | while (super_class != null) { |
32 | Method[] methods = super_class.getDeclaredMethods(); |
33 | java.util.Arrays.sort(methods, VisitClass.getMethodComparator()); |
34 | for (int i = 0; i < methods.length; i++) { |
35 | String override = findMethodTranslation("java", "override", "*", new MethodCallable(methods[i])); |
36 | if (override != null && !override.equalsIgnoreCase("false")) { |
37 | visitMethod(a_class, methods[i]); |
38 | } |
39 | } |
40 | super_class = super_class.getSuperclass(); |
41 | } |
42 | } |
43 | protected boolean shouldGenerateField(Field field) { |
44 | if (getTranslationContext().genIncludesProtected()) { |
45 | return optShouldGenerateField(field); |
46 | } else { |
47 | return super.shouldGenerateField(field); |
48 | } |
49 | } |
50 | protected boolean optShouldGenerateField(Field field) { |
51 | if (field.getName().indexOf('$') != -1) { |
52 | // Fields with '$' in their name are impl fields |
53 | return false; |
54 | } |
55 | if (Modifier.isPublic(field.getModifiers())) { |
56 | return true; |
57 | } |
58 | if (Modifier.isProtected(field.getModifiers())) { |
59 | return getTranslationContext().genIncludesProtected(); |
60 | } |
61 | if (Modifier.isPrivate(field.getModifiers())) { |
62 | return getTranslationContext().genIncludesPrivate(); |
63 | } |
64 | return getTranslationContext().genIncludesPackage(); |
65 | } |
66 | protected void extendFieldProperties(Field field, Properties p) throws ApplyException { |
67 | p.setProperty("cni_type", getCniType(field.getType())); |
68 | p.setProperty("jni_type", getJniType(field)); |
69 | p.setProperty("jni_signature", getJniSignature(field)); |
70 | p.setProperty("translation", findFieldTranslation("java", "translation", field)); |
71 | if (!getTranslationContext().getNoValues()) { |
72 | addFieldValueProperty(field, p); |
73 | } |
74 | } |
75 | protected void addFieldValueProperty(Field field, Properties p) { |
76 | int modifiers = field.getModifiers(); |
77 | |
78 | if (Modifier.isStatic(modifiers)) { |
79 | try { |
80 | field.setAccessible(true); |
81 | p.setProperty("value", javaForValue(field.get(null))); |
82 | } catch (Exception e) { |
83 | e.printStackTrace(); |
84 | } |
85 | } else { |
86 | p.setProperty("value", "null"); // TODO error: int i = null? |
87 | } |
88 | } |
89 | protected String getFieldTemplateName(Field field) throws ApplyException { |
90 | return findFieldTranslation("java", "field", field); |
91 | } |
92 | |
93 | protected boolean shouldGenerateMethod(Method method) throws ApplyException { |
94 | if (getTranslationContext().genIncludesProtected()) { |
95 | Callable callable = new MethodCallable(method); |
96 | return optShouldGenerateCallable(callable) && !isSkipped(callable); |
97 | } else { |
98 | return origShouldGenerateMethod(method); |
99 | } |
100 | } |
101 | protected boolean origShouldGenerateMethod(Method method) throws ApplyException { |
102 | if (!Modifier.isPublic(method.getModifiers()) && |
103 | !Modifier.isProtected(method.getModifiers()) && |
104 | !method.getName().equals("finalize")) { |
105 | return false; |
106 | } |
107 | return !isSkipped(new MethodCallable(method)); |
108 | } |
109 | protected boolean optShouldGenerateCallable(Callable callable) throws ApplyException { |
110 | //if (callable.getName().indexOf('$') != -1) { |
111 | if (callable.isImpl()) { |
112 | // Methods with '$' in their name are impl methods |
113 | return false; |
114 | } |
115 | if (Modifier.isNative(callable.getModifiers())) { |
116 | if (getTranslationContext().getNoNative()) { |
117 | return false; |
118 | } |
119 | } |
120 | |
121 | if (Modifier.isPublic(callable.getModifiers())) { |
122 | return true; |
123 | } |
124 | if (Modifier.isProtected(callable.getModifiers())) { |
125 | return getTranslationContext().genIncludesProtected(); |
126 | } |
127 | if (Modifier.isPrivate(callable.getModifiers())) { |
128 | return getTranslationContext().genIncludesPrivate(); |
129 | } |
130 | return getTranslationContext().genIncludesPackage(); |
131 | } |
132 | protected void extendMethodProperties(Method method, Properties p) |
133 | throws ApplyException |
134 | { |
135 | // replace modifiers with one which excludes native for all methods. |
136 | int modifiers = method.getModifiers(); |
137 | if (!Modifier.isAbstract(modifiers)) { |
138 | modifiers &= ~Modifier.NATIVE; |
139 | } |
140 | modifiers = filterSynchronized(modifiers); |
141 | p.setProperty("modifiers", Modifier.toString(modifiers)); |
142 | p.setProperty("jni_modifiers", getJniModifiers(method.getModifiers())); |
143 | p.setProperty("jni_return", getJniReturn(method)); |
144 | p.setProperty("jni_signature", getJniSignature(current_callable)); |
145 | p.setProperty("jni_return_error", getJniReturnError(current_callable)); |
146 | p.setProperty("cni_return", getCniReturn(method)); |
147 | p.setProperty("cni_return_cast", getCniReturnCast(method)); |
148 | p.setProperty("cni_class_name", getCniClassName(current_callable)); |
149 | p.setProperty("call_return", getCallReturn(method)); |
150 | p.setProperty("me_arguments", getMeArguments()); |
151 | p.setProperty("me_parameters", getMeParameters()); |
152 | p.setProperty("return_error", getJavaReturnError(method)); |
153 | p.setProperty("null_value", getNullValue(method)); |
154 | p.setProperty("translation", getTranslation()); |
155 | p.setProperty("prop_partial_type", getPropertyPartialType(method)); |
156 | p.setProperty("prop_type", getPropertyType(method)); |
157 | p.setProperty("prop_init", getPropertyInit(current_callable)); |
158 | p.setProperty("catch_return", getCatchReturn(current_callable)); |
159 | p.setProperty("cni_name", getCniName(current_callable)); |
160 | } |
161 | private String getCatchReturn(Callable callable) { |
162 | Class return_type = callable.getReturnType(); |
163 | |
164 | if (return_type == String.class) { |
165 | return "return \"\";"; |
166 | } |
167 | if (return_type == Long.TYPE) { |
168 | return "return -32767;"; |
169 | } |
170 | if (return_type == Integer.TYPE) { |
171 | return "return -32767;"; |
172 | } |
173 | if (return_type == Short.TYPE) { |
174 | return "return -32767;"; |
175 | } |
176 | if (return_type == Double.TYPE) { |
177 | return "return -32767;"; |
178 | } |
179 | if (return_type == Float.TYPE) { |
180 | return "return -32767;"; |
181 | } |
182 | if (return_type == Boolean.TYPE) { |
183 | return "return false;"; |
184 | } |
185 | if (return_type == Character.TYPE) { |
186 | return "return ' ';"; |
187 | } |
188 | return "logger.log(Level.FINE, \"exception\", e);"; |
189 | } |
190 | /** |
191 | * @param current_callable |
192 | * @return |
193 | */ |
194 | private String getCniClassName(Callable current_callable) { |
195 | return CniPointerTypePrinter.getInstance().toString(current_callable.getDeclaringClass()); |
196 | } |
197 | private int filterSynchronized(int modifiers) { |
198 | if (getTranslationContext().getNoSync()) { |
199 | if (Modifier.isSynchronized(modifiers)) { |
200 | modifiers &= ~Modifier.SYNCHRONIZED; |
201 | } |
202 | } |
203 | return modifiers; |
204 | } |
205 | protected boolean shouldGenerateConstructor(Constructor ctor) throws ApplyException { |
206 | if (getTranslationContext().genIncludesProtected()) { |
207 | Callable callable = new ConstructorCallable(ctor); |
208 | return optShouldGenerateCallable(callable) && !isSkipped(callable); |
209 | } else { |
210 | return origShouldGenerateConstructor(ctor); |
211 | } |
212 | } |
213 | protected boolean origShouldGenerateConstructor(Constructor ctor) |
214 | throws ApplyException |
215 | { |
216 | if (!Modifier.isPublic(ctor.getModifiers())) { |
217 | return false; |
218 | } |
219 | return !isSkipped(new ConstructorCallable(ctor)); |
220 | } |
221 | |
222 | protected void extendConstructorProperties(Constructor ctor, Properties p) |
223 | throws ApplyException |
224 | { |
225 | p.setProperty("jni_modifiers", getJniModifiers(ctor.getModifiers())); |
226 | p.setProperty("jni_signature", getJniSignature(current_callable)); |
227 | p.setProperty("translation", getTranslation()); |
228 | p.setProperty("call_return", ""); |
229 | p.setProperty("cni_name", getCniName(current_callable)); |
230 | } |
231 | |
232 | private String getCniName(Callable current_callable) { |
233 | return CniNameTypePrinter.getInstance().toString(current_callable.getDeclaringClass()); |
234 | } |
235 | |
236 | private String getJniModifiers(int modifiers) { |
237 | modifiers &= ~(Modifier.PUBLIC | Modifier.PROTECTED); |
238 | modifiers |= (Modifier.PRIVATE | Modifier.NATIVE); |
239 | modifiers = filterSynchronized(modifiers); |
240 | return Modifier.toString(modifiers); |
241 | } |
242 | private String getJniReturn(Method method) throws ApplyException { |
243 | return _getJniType(method.getReturnType()); |
244 | } |
245 | private String getJniType(Field field) throws ApplyException { |
246 | return _getJniType(field.getType()); |
247 | } |
248 | private String _getJniType(Class type) throws ApplyException { |
249 | try { |
250 | StringWriter out = new StringWriter(); |
251 | JniTypePrinter.getInstance().print(type, out); |
252 | return out.toString(); |
253 | } catch (IOException e) { |
254 | throw new ApplyException(e); |
255 | } |
256 | } |
257 | private String getJniSignature(Callable callable) throws ApplyException { |
258 | try { |
259 | StringWriter out = new StringWriter(); |
260 | TypePrinter printer = JniSignatureTypePrinter.getInstance(); |
261 | out.write("("); |
262 | SimpleParamsVisitor v = new SimpleParamsVisitor(out, printer); |
263 | v.setPrintParamNumber(false); |
264 | v.setSeparatorString(""); |
265 | VisitClass.visitParamTypes(callable.getParameterTypes(), v); |
266 | out.write(")"); |
267 | // ctor's have null return type. |
268 | if (null != callable.getReturnType()) { |
269 | printer.print(callable.getReturnType(), out); |
270 | } else { |
271 | out.write("V"); |
272 | } |
273 | return out.toString(); |
274 | } catch (IOException e) { |
275 | throw new ApplyException(e); |
276 | } |
277 | } |
278 | private String getJniSignature(Field field) throws ApplyException { |
279 | try { |
280 | StringWriter out = new StringWriter(); |
281 | TypePrinter printer = JniSignatureTypePrinter.getInstance(); |
282 | printer.print(field.getType(), out); |
283 | return out.toString(); |
284 | } catch (IOException e) { |
285 | throw new ApplyException(e); |
286 | } |
287 | } |
288 | private String getCniReturn(Method method) throws ApplyException { |
289 | return getCniType(method.getReturnType()); |
290 | } |
291 | private String getCniReturnCast(Method method) throws ApplyException { |
292 | if (Void.TYPE == method.getReturnType()) { |
293 | return ""; |
294 | } else { |
295 | return "(" + getCniReturn(method) + ")"; |
296 | } |
297 | } |
298 | private String getCallReturn(Method method) { |
299 | if (Void.TYPE == method.getReturnType()) { |
300 | return ""; |
301 | } else { |
302 | return "return "; |
303 | } |
304 | } |
305 | private String getMeArguments() |
306 | throws ApplyException |
307 | { |
308 | if (!Modifier.isStatic(current_callable.getModifiers())) { |
309 | return findMeTranslation("java", "me_arguments", current_callable) |
310 | + getSeparator(current_callable); |
311 | } else { |
312 | return ""; |
313 | } |
314 | } |
315 | private String getMeParameters() |
316 | throws ApplyException |
317 | { |
318 | if (!Modifier.isStatic(current_callable.getModifiers())) { |
319 | return findMeTranslation("java", "me_parameters", current_callable) |
320 | + getSeparator(current_callable); |
321 | } else { |
322 | return ""; |
323 | } |
324 | } |
325 | private String getJavaReturnError(Method method) { |
326 | return "return " + getNullValue(method) + ";"; |
327 | } |
328 | private String getNullValue(Method method) { |
329 | if (method.getReturnType() == Void.TYPE) { |
330 | return ""; |
331 | } |
332 | if (method.getReturnType().isPrimitive()) { |
333 | return "0"; |
334 | } |
335 | return "null"; |
336 | } |
337 | private String getTranslation() throws ApplyException { |
338 | return findMethodTranslation("java", "translation", "*", current_callable); |
339 | } |
340 | private String getPropertyPartialType(Method method) { |
341 | return ClassGenerator.stripPackageName(getPropertyType(method)); |
342 | } |
343 | private String getPropertyType(Method method) { |
344 | // If setter use type of last p otherwise use return type |
345 | if (isSetter(method)) { |
346 | if (hasParameters(method)) { |
347 | return lastParameterTypeName(method); |
348 | } |
349 | } |
350 | return JavaTypePrinter.getInstance().toString(method.getReturnType()); |
351 | } |
352 | private boolean isSetter(Method method) { |
353 | return method.getName().startsWith("set"); |
354 | } |
355 | private boolean hasParameters(Method method) { |
356 | return method.getParameterTypes().length > 0; |
357 | } |
358 | private String lastParameterTypeName(Method method) { |
359 | Class[] ptypes = method.getParameterTypes(); |
360 | return JavaTypePrinter.getInstance().toString(ptypes[ptypes.length - 1]); |
361 | } |
362 | protected String getPropertyInit(Callable callable) throws ApplyException { |
363 | String init = findPropInitTranslation("java", "prop_init", callable); |
364 | return (init.length() == 0) ? "" : " = " + init; |
365 | } |
366 | |
367 | protected String getTemplateName(Method method) throws ApplyException { |
368 | String type = Modifier.isAbstract(method.getModifiers()) ? "method.abstract" : "method"; |
369 | return findMethodTranslation("java", type, "*", current_callable); |
370 | } |
371 | protected String getTemplateName(Constructor ctor) throws ApplyException { |
372 | return findConstructorTranslation("java", "constructor", null, current_callable); |
373 | } |
374 | |
375 | private boolean isSkipped(Callable callable) throws ApplyException { |
376 | if (getTranslationContext().getSkipOnMissingTranslation()) { |
377 | String old_pass = getPassAppend(); |
378 | setPassAppend(null); // TODO hack to get pass number set to zero for this one call |
379 | String translation = queryMethodTranslation("java", "translation", "*", callable); |
380 | setPassAppend(old_pass); |
381 | if (translation == null) { |
382 | return true; |
383 | } |
384 | } |
385 | return false; |
386 | } |
387 | |
388 | static String javaForValue(Object v) { |
389 | return JavaValuePrinter.getInstance().toString(v); |
390 | } |
391 | private String getCniType(Class type) throws ApplyException { |
392 | try { |
393 | StringWriter out = new StringWriter(); |
394 | CniPointerTypePrinter.getInstance().print(type, out); |
395 | return out.toString(); |
396 | } catch (IOException e) { |
397 | throw new ApplyException(e); |
398 | } |
399 | } |
400 | /** |
401 | * callback from method.tmpl |
402 | * TODO refactor into base class and just get TypePrinter...! |
403 | */ |
404 | public void parameters(Writer out) |
405 | throws IOException, ApplyException |
406 | { |
407 | JavaParamsVisitor v = new JavaParamsVisitor(out); |
408 | VisitClass.visitParamTypes(current_callable.getParameterTypes(), v); |
409 | } |
410 | /** |
411 | * callback from method.tmpl |
412 | */ |
413 | public void arguments(Writer out) throws IOException { |
414 | Class[] params = current_callable.getParameterTypes(); |
415 | for (int i = 0; i < params.length; i++) { |
416 | if (i > 0) { out.write(", "); } |
417 | out.write('p'); |
418 | out.write(Integer.toString(i)); |
419 | } |
420 | } |
421 | /** |
422 | * callback from method.tmpl |
423 | */ |
424 | public void throws_clause(Writer out) throws IOException { |
425 | Class[] exceptions = current_callable.getExceptionTypes(); |
426 | for (int i = 0; i < exceptions.length; i++) { |
427 | if (i == 0) { out.write(" throws "); } |
428 | if (i > 0) { out.write(", "); } |
429 | JavaTypePrinter.getInstance().print(exceptions[i], out); |
430 | } |
431 | } |
432 | /** |
433 | * callback from method.tmpl |
434 | */ |
435 | public void jni_parameters(Writer out) |
436 | throws IOException, ApplyException |
437 | { |
438 | JavaJniParamsVisitor v = new JavaJniParamsVisitor(out, getTranslationContext()); |
439 | VisitClass.visitParamTypes(current_callable.getParameterTypes(), v); |
440 | } |
441 | /** |
442 | * callback from method.tmpl |
443 | */ |
444 | public void cni_parameters(Writer out) |
445 | throws IOException, ApplyException |
446 | { |
447 | SimpleParamsVisitor v = new SimpleParamsVisitor(out, CniPointerTypePrinter.getInstance()); |
448 | VisitClass.visitParamTypes(current_callable.getParameterTypes(), v); |
449 | } |
450 | /** |
451 | * callback from method.tmpl |
452 | */ |
453 | public void jni_arguments(Writer out) throws IOException { |
454 | Class[] params = current_callable.getParameterTypes(); |
455 | for (int i = 0; i < params.length; i++) { |
456 | if (i > 0) { out.write(", "); } |
457 | out.write('p'); |
458 | out.write(Integer.toString(i)); |
459 | out.write(getParamExtra(params[i])); |
460 | } |
461 | } |
462 | /** |
463 | * callback from method.tmpl |
464 | */ |
465 | public void final_parameters(Writer out) throws ApplyException { |
466 | JavaFinalParamsVisitor v = new JavaFinalParamsVisitor(out); |
467 | VisitClass.visitParamTypes(current_callable.getParameterTypes(), v); |
468 | } |
469 | |
470 | private String getParamExtra(Class param_type) throws IOException { |
471 | StringWriter sw = new StringWriter(); |
472 | JavaTypePrinter.getInstance().print(param_type, sw); |
473 | try { |
474 | String r = getTransProperty("java.param." + sw.toString()); |
475 | return r == null ? "" : r; |
476 | } catch (ApplyException e) { |
477 | throw new IOException("getTransProperty failed"); |
478 | } |
479 | } |
480 | } |