1 16 package org.directwebremoting.impl; 17 18 import java.lang.reflect.Method ; 19 import java.util.ArrayList ; 20 import java.util.HashMap ; 21 import java.util.Iterator ; 22 import java.util.List ; 23 import java.util.Map ; 24 import java.util.StringTokenizer ; 25 26 import org.directwebremoting.extend.ConverterManager; 27 import org.directwebremoting.extend.Creator; 28 import org.directwebremoting.extend.CreatorManager; 29 import org.directwebremoting.extend.TypeHintContext; 30 import org.directwebremoting.util.JavascriptUtil; 31 import org.directwebremoting.util.LocalUtil; 32 import org.directwebremoting.util.Logger; 33 34 38 public class SignatureParser 39 { 40 45 public SignatureParser(ConverterManager converterManager, CreatorManager creatorManager) 46 { 47 this.converterManager = converterManager; 48 this.creatorManager = creatorManager; 49 50 packageImports.add("java.lang"); 51 } 52 53 57 public void parse(String sigtext) 58 { 59 try 60 { 61 log.debug("Parsing extra type info: "); 62 63 String reply = JavascriptUtil.stripMultiLineComments(sigtext); 64 reply = JavascriptUtil.stripSingleLineComments(reply); 65 String process = reply; 66 67 process = process.replace('\n', ' '); 68 process = process.replace('\r', ' '); 69 process = process.replace('\t', ' '); 70 71 StringTokenizer st = new StringTokenizer (process, ";"); 72 while (st.hasMoreTokens()) 73 { 74 String line = st.nextToken(); 75 line = line.trim(); 76 if (line.length() == 0) 77 { 78 continue; 79 } 80 81 if (line.startsWith("import ")) 82 { 83 parseImportLine(line); 84 } 85 else 86 { 87 parseDeclarationLine(line); 88 } 89 } 90 } 91 catch (Exception ex) 92 { 93 log.error("Unexpected Error", ex); 94 } 95 } 96 97 101 private void parseImportLine(String line) 102 { 103 String shortcut = line.substring(7, line.length()); 104 shortcut = shortcut.trim(); 105 106 if (line.endsWith(".*")) 107 { 108 shortcut = shortcut.substring(0, shortcut.length() - 2); 109 packageImports.add(shortcut); 110 } 111 else 112 { 113 int lastDot = line.lastIndexOf('.'); 114 if (lastDot == -1) 115 { 116 log.error("Missing . from import statement: " + line); 117 return; 118 } 119 120 String leaf = line.substring(lastDot + 1); 121 classImports.put(leaf, shortcut); 122 } 123 } 124 125 130 private void parseDeclarationLine(String line) 131 { 132 int openBrace = line.indexOf('('); 133 int closeBrace = line.indexOf(')'); 134 135 if (openBrace == -1) 136 { 137 log.error("Missing ( in declaration: " + line); 138 return; 139 } 140 141 if (closeBrace == -1) 142 { 143 log.error("Missing ) in declaration: " + line); 144 return; 145 } 146 147 if (openBrace > closeBrace) 148 { 149 log.error("( Must come before ) in declaration: " + line); 150 return; 151 } 152 153 String classMethod = line.substring(0, openBrace).trim(); 155 156 Method method = findMethod(classMethod); 157 if (method == null) 158 { 159 return; 161 } 162 163 String paramDecl = line.substring(openBrace + 1, closeBrace); 165 String [] paramNames = split(paramDecl); 166 167 if (method.getParameterTypes().length != paramNames.length) 169 { 170 log.error("Parameter mismatch parsing signatures section in dwr.xml on line: " + line); 171 log.info("- Reflected method had: " + method.getParameterTypes().length + " parameters: " + method.toString()); 172 log.info("- Signatures section had: " + paramNames.length + " parameters"); 173 log.info("- This can be caused by method overloading which is not supported by Javascript or DWR"); 174 return; 175 } 176 177 for (int i = 0; i < paramNames.length; i++) 178 { 179 String [] genericList = getGenericParameterTypeList(paramNames[i]); 180 for (int j = 0; j < genericList.length; j++) 181 { 182 String type = genericList[j].trim(); 183 Class clazz = findClass(type); 184 185 if (clazz != null) 186 { 187 TypeHintContext thc = new TypeHintContext(converterManager, method, i).createChildContext(j); 188 converterManager.setExtraTypeInfo(thc, clazz); 189 190 if (log.isDebugEnabled()) 191 { 192 log.debug("- " + thc + " = " + clazz.getName()); 193 } 194 } 195 else 196 { 197 log.warn("Missing class (" + type + ") while parsing signature section on line: " + line); 198 } 199 } 200 } 201 } 202 203 208 private Class findClass(String type) 209 { 210 String itype = type; 211 212 if (itype.indexOf('.') != -1) 214 { 215 log.debug("Inner class detected: " + itype); 216 itype = itype.replace('.', '$'); 217 } 218 219 try 220 { 221 String full = (String ) classImports.get(itype); 222 if (full == null) 223 { 224 full = itype; 225 } 226 227 return LocalUtil.classForName(full); 228 } 229 catch (Exception ex) 230 { 231 } 233 234 for (Iterator it = packageImports.iterator(); it.hasNext();) 235 { 236 String pkg = (String ) it.next(); 237 String lookup = pkg + '.' + itype; 238 239 try 240 { 241 return LocalUtil.classForName(lookup); 242 } 243 catch (Exception ex) 244 { 245 } 247 } 248 249 Creator creator = creatorManager.getCreator(type); 253 if (creator != null) 254 { 255 return creator.getType(); 256 } 257 258 log.error("Failed to find class: '" + itype + "' from <signature> block."); 259 log.info("- Looked in the following class imports:"); 260 for (Iterator it = classImports.entrySet().iterator(); it.hasNext();) 261 { 262 Map.Entry entry = (Map.Entry ) it.next(); 263 log.info(" - " + entry.getKey() + " -> " + entry.getValue()); 264 } 265 log.info("- Looked in the following package imports:"); 266 for (Iterator it = packageImports.iterator(); it.hasNext();) 267 { 268 log.info(" - " + it.next()); 269 } 270 271 return null; 272 } 273 274 280 private String [] getGenericParameterTypeList(String paramName) 281 { 282 int openGeneric = paramName.indexOf('<'); 283 if (openGeneric == -1) 284 { 285 log.debug("No < in paramter declaration: " + paramName); 286 return new String [0]; 287 } 288 289 int closeGeneric = paramName.lastIndexOf('>'); 290 if (closeGeneric == -1) 291 { 292 log.error("Missing > in generic declaration: " + paramName); 293 return new String [0]; 294 } 295 296 String generics = paramName.substring(openGeneric + 1, closeGeneric); 297 StringTokenizer st = new StringTokenizer (generics, ","); 298 String [] types = new String [st.countTokens()]; 299 int i = 0; 300 while (st.hasMoreTokens()) 301 { 302 types[i++] = st.nextToken(); 303 } 304 305 return types; 306 } 307 308 313 private Method findMethod(String classMethod) 314 { 315 String classMethodChop = classMethod; 316 317 int lastSpace = classMethodChop.lastIndexOf(' '); 319 if (lastSpace >= 0) 320 { 321 classMethodChop = classMethodChop.substring(lastSpace); 322 } 323 324 int lastDot = classMethodChop.lastIndexOf('.'); 326 if (lastDot == -1) 327 { 328 log.error("Missing . to separate class name and method: " + classMethodChop); 329 return null; 330 } 331 332 String className = classMethodChop.substring(0, lastDot).trim(); 333 String methodName = classMethodChop.substring(lastDot + 1).trim(); 334 335 Class clazz = findClass(className); 336 if (clazz == null) 337 { 338 return null; 340 } 341 342 Method method = null; 343 Method [] methods = clazz.getMethods(); 344 for (int j = 0; j < methods.length; j++) 345 { 346 Method test = methods[j]; 347 if (test.getName().equals(methodName)) 348 { 349 if (method == null) 350 { 351 method = test; 352 } 353 else 354 { 355 log.warn("Setting extra type info to overloaded methods may fail with <parameter .../>"); 356 } 357 } 358 } 359 360 if (method == null) 361 { 362 log.error("Unable to find method called: " + methodName + " on type: " + clazz.getName()); 363 } 364 365 return method; 366 } 367 368 373 private String [] split(String paramDecl) 374 { 375 List params = new ArrayList (); 376 377 boolean inGeneric = false; 378 int start = 0; 379 for (int i = 0; i < paramDecl.length(); i++) 380 { 381 char c = paramDecl.charAt(i); 382 if (c == '<') 383 { 384 if (inGeneric) 385 { 386 log.error("Found < while parsing generic section: " + paramDecl); 387 break; 388 } 389 390 inGeneric = true; 391 } 392 393 if (c == '>') 394 { 395 if (!inGeneric) 396 { 397 log.error("Found > while not parsing generic section: " + paramDecl); 398 break; 399 } 400 401 inGeneric = false; 402 } 403 404 if (!inGeneric && c == ',') 405 { 406 String param = paramDecl.substring(start, i); 408 params.add(param); 409 start = i + 1; 410 } 411 } 412 413 String param = paramDecl.substring(start, paramDecl.length()); 415 params.add(param); 416 417 return (String []) params.toArray(new String [params.size()]); 418 } 419 420 423 private Map classImports = new HashMap (); 424 425 428 private List packageImports = new ArrayList (); 429 430 433 private ConverterManager converterManager; 434 435 438 private CreatorManager creatorManager; 439 440 443 public static final Logger log = Logger.getLogger(SignatureParser.class); 444 } 445 | Popular Tags |