| 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 | } |