1 16 package com.google.gwt.dev.cfg; 17 18 import com.google.gwt.core.ext.Generator; 19 import com.google.gwt.core.ext.TreeLogger; 20 import com.google.gwt.core.ext.UnableToCompleteException; 21 import com.google.gwt.dev.js.JsParser; 22 import com.google.gwt.dev.js.JsParserException; 23 import com.google.gwt.dev.js.JsParserException.SourceDetail; 24 import com.google.gwt.dev.js.ast.JsExprStmt; 25 import com.google.gwt.dev.js.ast.JsFunction; 26 import com.google.gwt.dev.js.ast.JsProgram; 27 import com.google.gwt.dev.js.ast.JsStatements; 28 import com.google.gwt.dev.util.Empty; 29 import com.google.gwt.dev.util.Util; 30 import com.google.gwt.dev.util.xml.AttributeConverter; 31 import com.google.gwt.dev.util.xml.Schema; 32 33 import java.io.IOException ; 34 import java.io.StringReader ; 35 import java.net.URL ; 36 import java.util.HashMap ; 37 import java.util.HashSet ; 38 import java.util.Map ; 39 import java.util.Set ; 40 41 45 public class ModuleDefSchema extends Schema { 46 private final class BodySchema extends Schema { 47 48 protected final String __define_property_1_name = null; 49 50 protected final String __define_property_2_values = null; 51 52 protected final String __entry_point_1_class = null; 53 54 protected final String __extend_property_1_name = null; 55 56 protected final String __extend_property_2_values = null; 57 58 protected final String __generate_with_1_class = null; 59 60 protected final String __inherits_1_name = null; 61 62 protected final String __property_provider_1_name = null; 63 64 protected final String __public_1_path = null; 65 66 protected final String __public_2_includes = ""; 67 68 protected final String __public_3_excludes = ""; 69 70 protected final String __public_4_defaultexcludes = "yes"; 71 72 protected final String __public_5_casesensitive = "true"; 73 74 protected final String __replace_with_1_class = null; 75 76 protected final String __script_1_src = null; 77 78 protected final String __servlet_1_path = null; 79 80 protected final String __servlet_2_class = null; 81 82 protected final String __set_property_1_name = null; 83 84 protected final String __set_property_2_value = null; 85 86 protected final String __source_1_path = ""; 87 88 protected final String __stylesheet_1_src = null; 89 90 protected final String __super_source_1_path = ""; 91 92 private Schema fChild; 93 94 protected Schema __define_property_begin(PropertyName name, 95 PropertyValue[] values) throws UnableToCompleteException { 96 if (moduleDef.getProperties().find(name.token) != null) { 97 String msg = "Attempt to redefine property '" + name.token + "'"; 99 logger.log(TreeLogger.ERROR, msg, null); 100 throw new UnableToCompleteException(); 101 } 102 103 Property prop = moduleDef.getProperties().create(name.token); 104 for (int i = 0; i < values.length; i++) { 105 prop.addKnownValue(values[i].token); 106 } 107 108 return null; 110 } 111 112 protected Schema __entry_point_begin(String className) { 113 moduleDef.addEntryPointTypeName(className); 114 return null; 115 } 116 117 protected Schema __extend_property_begin(Property property, 118 PropertyValue[] values) { 119 for (int i = 0; i < values.length; i++) { 120 property.addKnownValue(values[i].token); 121 } 122 123 return null; 125 } 126 127 protected Schema __fail_begin() { 128 RuleFail rule = new RuleFail(); 129 moduleDef.getRules().prepend(rule); 130 return new ConditionSchema(rule.getRootCondition()); 131 } 132 133 protected Schema __generate_with_begin(Generator gen) { 134 RuleGenerateWith rule = new RuleGenerateWith(gen); 135 moduleDef.getRules().prepend(rule); 136 return new ConditionSchema(rule.getRootCondition()); 137 } 138 139 protected Schema __inherits_begin(String name) 140 throws UnableToCompleteException { 141 TreeLogger branch = logger.branch(TreeLogger.TRACE, 142 "Loading inherited module '" + name + "'", null); 143 loader.nestedLoad(branch, name, moduleDef); 144 return null; 145 } 146 147 protected Schema __property_provider_begin(Property property) { 148 property.setProvider(new PropertyProvider(moduleDef, property)); 149 return fChild = new PropertyProviderBodySchema(); 150 } 151 152 protected void __property_provider_end(Property property) 153 throws UnableToCompleteException { 154 PropertyProviderBodySchema childSchema = ((PropertyProviderBodySchema) fChild); 155 String script = childSchema.getScript(); 156 if (script == null) { 157 logger.log(TreeLogger.ERROR, 160 "Property providers must specify a JavaScript body", null); 161 throw new UnableToCompleteException(); 162 } 163 164 int lineNumber = childSchema.getStartLineNumber(); 165 JsFunction fn = parseJsBlock(lineNumber, script); 166 167 property.getProvider().setBody(fn.getBody()); 168 } 169 170 protected Schema __public_begin(String path, String includes, 171 String excludes, String defaultExcludes, String caseSensitive) { 172 return fChild = new IncludeExcludeSchema(); 173 } 174 175 protected void __public_end(String path, String includes, String excludes, 176 String defaultExcludes, String caseSensitive) { 177 IncludeExcludeSchema childSchema = ((IncludeExcludeSchema) fChild); 178 foundAnyPublic = true; 179 180 Set includeSet = childSchema.getIncludes(); 181 addDelimitedStringToSet(includes, "[ ,]", includeSet); 182 String [] includeList = (String []) includeSet.toArray(new String [includeSet.size()]); 183 184 Set excludeSet = childSchema.getExcludes(); 185 addDelimitedStringToSet(excludes, "[ ,]", excludeSet); 186 String [] excludeList = (String []) excludeSet.toArray(new String [excludeSet.size()]); 187 188 boolean doDefaultExcludes = "yes".equalsIgnoreCase(defaultExcludes) 189 || "true".equalsIgnoreCase(defaultExcludes); 190 boolean doCaseSensitive = "yes".equalsIgnoreCase(caseSensitive) 191 || "true".equalsIgnoreCase(caseSensitive); 192 193 addPublicPackage(modulePackageAsPath, path, includeList, excludeList, 194 doDefaultExcludes, doCaseSensitive); 195 } 196 197 protected Schema __replace_with_begin(String className) { 198 RuleReplaceWith rule = new RuleReplaceWith(className); 199 moduleDef.getRules().prepend(rule); 200 return new ConditionSchema(rule.getRootCondition()); 201 } 202 203 207 protected Schema __script_begin(String src) { 208 return fChild = new ScriptReadyBodySchema(); 209 } 210 211 protected void __script_end(String src) throws UnableToCompleteException { 212 ScriptReadyBodySchema childSchema = (ScriptReadyBodySchema) fChild; 213 String js = childSchema.getScriptReadyBlock(); 214 if (js != null) { 215 logger.log( 216 TreeLogger.WARN, 217 "Injected scripts no longer require an associated JavaScript block.", 218 null); 219 } 220 221 js = "var $wnd = window; " + js; 226 227 int lineNumber = childSchema.getStartLineNumber(); 228 JsFunction fn = parseJsBlock(lineNumber, js); 229 Script script = new Script(src, fn); 230 moduleDef.getScripts().append(script); 231 } 232 233 protected Schema __servlet_begin(String path, String servletClass) 234 throws UnableToCompleteException { 235 236 if (!path.startsWith("/")) { 238 logger.log(TreeLogger.ERROR, "Servlet path '" + path 239 + "' must begin with forward slash (e.g. '/foo')", null); 240 throw new UnableToCompleteException(); 241 } 242 243 moduleDef.mapServlet(path, servletClass); 245 246 return null; 247 } 248 249 protected Schema __set_property_begin(Property prop, PropertyValue value) { 250 prop.setActiveValue(value.token); 251 252 return null; 254 } 255 256 260 protected Schema __source_begin(String path) { 261 foundExplicitSourceOrSuperSource = true; 262 263 addSourcePackage(modulePackageAsPath, path, false); 266 return null; 267 } 268 269 273 protected Schema __stylesheet_begin(String src) { 274 moduleDef.getStyles().append(src); 275 return null; 276 } 277 278 282 protected Schema __super_source_begin(String path) { 283 foundExplicitSourceOrSuperSource = true; 284 285 addSourcePackage(modulePackageAsPath, path, true); 288 return null; 289 } 290 291 private void addDelimitedStringToSet(String delimited, String delimiter, 292 Set toSet) { 293 if (delimited.length() > 0) { 294 String [] split = delimited.split(delimiter); 295 for (int i = 0; i < split.length; ++i) { 296 if (split[i].length() > 0) { 297 toSet.add(split[i]); 298 } 299 } 300 } 301 } 302 303 private void addPublicPackage(String parentDir, String relDir, 304 String [] includeList, String [] excludeList, boolean defaultExcludes, 305 boolean caseSensitive) { 306 String normChildDir = normalizePathEntry(relDir); 307 if (normChildDir.startsWith("/")) { 308 logger.log(TreeLogger.WARN, "Non-relative public package: " 309 + normChildDir, null); 310 return; 311 } 312 if (normChildDir.startsWith("./") || normChildDir.indexOf("/./") >= 0) { 313 logger.log(TreeLogger.WARN, "Non-canonical public package: " 314 + normChildDir, null); 315 return; 316 } 317 if (normChildDir.startsWith("../") || normChildDir.indexOf("/../") >= 0) { 318 logger.log(TreeLogger.WARN, "Non-canonical public package: " 319 + normChildDir, null); 320 return; 321 } 322 String fullDir = parentDir + normChildDir; 323 moduleDef.addPublicPackage(fullDir, includeList, excludeList, 324 defaultExcludes, caseSensitive); 325 } 326 327 private void addSourcePackage(String parentDir, String relDir, 328 boolean isSuperSource) { 329 String normChildDir = normalizePathEntry(relDir); 330 if (normChildDir.startsWith("/")) { 331 logger.log(TreeLogger.WARN, "Non-relative source package: " 332 + normChildDir, null); 333 return; 334 } 335 if (normChildDir.startsWith("./") || normChildDir.indexOf("/./") >= 0) { 336 logger.log(TreeLogger.WARN, "Non-canonical source package: " 337 + normChildDir, null); 338 return; 339 } 340 if (normChildDir.startsWith("../") || normChildDir.indexOf("/../") >= 0) { 341 logger.log(TreeLogger.WARN, "Non-canonical source package: " 342 + normChildDir, null); 343 return; 344 } 345 346 String fullDir = parentDir + normChildDir; 347 if (isSuperSource) { 348 moduleDef.addSuperSourcePackage(fullDir); 349 } else { 350 moduleDef.addSourcePackage(fullDir); 351 } 352 } 353 354 358 private String normalizePathEntry(String path) { 359 path = path.trim(); 360 361 if (path.length() == 0) { 362 return ""; 363 } 364 365 path = path.replace('\\', '/'); 366 367 if (!path.endsWith("/")) { 368 path += "/"; 369 } 370 371 return path; 372 } 373 } 374 375 private final class ConditionSchema extends Schema { 376 377 protected final String __when_property_is_1_name = null; 378 379 protected final String __when_property_is_2_value = null; 380 381 protected final String __when_type_assignable_1_class = null; 382 383 protected final String __when_type_is_1_class = null; 384 385 private final CompoundCondition parentCondition; 386 387 public ConditionSchema(CompoundCondition parentCondition) { 388 this.parentCondition = parentCondition; 389 } 390 391 protected Schema __all_begin() { 392 CompoundCondition cond = new ConditionAll(); 393 parentCondition.getConditions().add(cond); 394 return new ConditionSchema(cond); 395 } 396 397 protected Schema __any_begin() { 398 CompoundCondition cond = new ConditionAny(); 399 parentCondition.getConditions().add(cond); 400 return new ConditionSchema(cond); 401 } 402 403 protected Schema __none_begin() { 404 CompoundCondition cond = new ConditionNone(); 405 parentCondition.getConditions().add(cond); 406 return new ConditionSchema(cond); 407 } 408 409 protected Schema __when_property_is_begin(Property prop, PropertyValue value) { 414 Condition cond = new ConditionWhenPropertyIs(prop.getName(), value.token); 415 parentCondition.getConditions().add(cond); 416 417 return null; 419 } 420 421 protected Schema __when_type_assignable_begin(String className) { 422 Condition cond = new ConditionWhenTypeAssignableTo(className); 423 parentCondition.getConditions().add(cond); 424 425 return null; 427 } 428 429 protected Schema __when_type_is_begin(String className) { 430 Condition cond = new ConditionWhenTypeIs(className); 431 parentCondition.getConditions().add(cond); 432 433 return null; 435 } 436 } 437 438 private final class IncludeExcludeSchema extends Schema { 439 440 protected final String __exclude_1_name = null; 441 442 protected final String __include_1_name = null; 443 444 private final Set excludes = new HashSet (); 445 446 private final Set includes = new HashSet (); 447 448 public Set getExcludes() { 449 return excludes; 450 } 451 452 public Set getIncludes() { 453 return includes; 454 } 455 456 protected Schema __exclude_begin(String name) { 457 excludes.add(name); 458 return null; 459 } 460 461 protected Schema __include_begin(String name) { 462 includes.add(name); 463 return null; 464 } 465 } 466 467 471 private final class ObjAttrCvt extends AttributeConverter { 472 473 private final Class fReqdSuperclass; 474 475 public ObjAttrCvt(Class reqdSuperclass) { 476 fReqdSuperclass = reqdSuperclass; 477 } 478 479 public Object convertToArg(Schema schema, int lineNumber, String elemName, 480 String attrName, String attrValue) throws UnableToCompleteException { 481 482 Object found = singletonsByName.get(attrValue); 483 if (found != null) { 484 return found; 487 } 488 489 try { 490 ClassLoader cl = Thread.currentThread().getContextClassLoader(); 493 Class clazz = cl.loadClass(attrValue); 494 495 if (!fReqdSuperclass.isAssignableFrom(clazz)) { 498 Messages.INVALID_CLASS_DERIVATION.log(logger, clazz, fReqdSuperclass, 499 null); 500 throw new UnableToCompleteException(); 501 } 502 503 Object object = clazz.newInstance(); 504 singletonsByName.put(attrValue, object); 505 return object; 506 } catch (ClassNotFoundException e) { 507 Messages.UNABLE_TO_LOAD_CLASS.log(logger, attrValue, e); 508 throw new UnableToCompleteException(); 509 } catch (InstantiationException e) { 510 Messages.UNABLE_TO_CREATE_OBJECT.log(logger, attrValue, e); 511 throw new UnableToCompleteException(); 512 } catch (IllegalAccessException e) { 513 Messages.UNABLE_TO_CREATE_OBJECT.log(logger, attrValue, e); 514 throw new UnableToCompleteException(); 515 } 516 } 517 } 518 519 522 private final class PropertyAttrCvt extends AttributeConverter { 523 public Object convertToArg(Schema schema, int line, String elem, 524 String attr, String value) throws UnableToCompleteException { 525 Property prop = moduleDef.getProperties().find(value); 528 529 if (prop != null) { 530 return prop; 533 } else { 534 Messages.PROPERTY_NOT_FOUND.log(logger, value, null); 537 throw new UnableToCompleteException(); 538 } 539 } 540 } 541 542 private static class PropertyName { 543 public final String token; 544 545 public PropertyName(String token) { 546 this.token = token; 547 } 548 } 549 550 553 private final class PropertyNameAttrCvt extends AttributeConverter { 554 555 public Object convertToArg(Schema schema, int line, String elem, 556 String attr, String value) throws UnableToCompleteException { 557 String [] tokens = (value + ". ").split("\\."); 560 for (int i = 0; i < tokens.length - 1; i++) { 561 String token = tokens[i]; 562 if (!Util.isValidJavaIdent(token)) { 563 Messages.PROPERTY_NAME_INVALID.log(logger, value, null); 564 throw new UnableToCompleteException(); 565 } 566 } 567 568 return new PropertyName(value); 571 } 572 } 573 574 private class PropertyProviderBodySchema extends Schema { 575 576 private StringBuffer script; 577 578 private int startLineNumber = -1; 579 580 public PropertyProviderBodySchema() { 581 } 582 583 public void __text(String text) { 584 if (script == null) { 585 script = new StringBuffer (); 586 startLineNumber = getLineNumber(); 587 } 588 script.append(text); 589 } 590 591 public String getScript() { 592 return script != null ? script.toString() : null; 593 } 594 595 public int getStartLineNumber() { 596 return startLineNumber; 597 } 598 } 599 600 private static class PropertyValue { 601 public final String token; 602 603 public PropertyValue(String token) { 604 this.token = token; 605 } 606 } 607 608 611 private final class PropertyValueArrayAttrCvt extends AttributeConverter { 612 public Object convertToArg(Schema schema, int line, String elem, 613 String attr, String value) throws UnableToCompleteException { 614 String [] tokens = value.split(","); 615 PropertyValue[] values = new PropertyValue[tokens.length]; 616 617 for (int i = 0; i < tokens.length; i++) { 620 values[i] = (PropertyValue) propValueAttrCvt.convertToArg(schema, line, 621 elem, attr, tokens[i]); 622 } 623 624 return values; 625 } 626 } 627 628 631 private final class PropertyValueAttrCvt extends AttributeConverter { 632 public Object convertToArg(Schema schema, int line, String elem, 633 String attr, String value) throws UnableToCompleteException { 634 635 String token = value.trim(); 636 if (Util.isValidJavaIdent(token)) { 637 return new PropertyValue(token); 638 } else { 639 Messages.PROPERTY_VALUE_INVALID.log(logger, token, null); 640 throw new UnableToCompleteException(); 641 } 642 } 643 } 644 645 private class ScriptReadyBodySchema extends Schema { 646 647 private StringBuffer script; 648 649 private int startLineNumber = -1; 650 651 public ScriptReadyBodySchema() { 652 } 653 654 public void __text(String text) { 655 if (script == null) { 656 script = new StringBuffer (); 657 startLineNumber = getLineNumber(); 658 } 659 script.append(text); 660 } 661 662 public String getScriptReadyBlock() { 663 return script != null ? script.toString() : null; 664 } 665 666 public int getStartLineNumber() { 667 return startLineNumber; 668 } 669 } 670 671 private static final Map singletonsByName = new HashMap (); 672 673 private final BodySchema bodySchema; 674 675 private boolean foundAnyPublic; 676 677 private boolean foundExplicitSourceOrSuperSource; 678 679 private final ObjAttrCvt genAttrCvt = new ObjAttrCvt(Generator.class); 680 681 private final JsParser jsParser = new JsParser(); 682 private final JsProgram jsPgm = new JsProgram(); 683 private final ModuleDefLoader loader; 684 private final TreeLogger logger; 685 private final ModuleDef moduleDef; 686 private final String modulePackageAsPath; 687 private final URL moduleURL; 688 private final PropertyAttrCvt propAttrCvt = new PropertyAttrCvt(); 689 private final PropertyNameAttrCvt propNameAttrCvt = new PropertyNameAttrCvt(); 690 private final PropertyValueArrayAttrCvt propValueArrayAttrCvt = new PropertyValueArrayAttrCvt(); 691 private final PropertyValueAttrCvt propValueAttrCvt = new PropertyValueAttrCvt(); 692 693 public ModuleDefSchema(TreeLogger logger, ModuleDefLoader loader, 694 URL moduleURL, String modulePackageAsPath, ModuleDef toConfigure) { 695 this.logger = logger; 696 this.loader = loader; 697 this.moduleURL = moduleURL; 698 this.modulePackageAsPath = modulePackageAsPath; 699 assert (modulePackageAsPath.endsWith("/") || modulePackageAsPath.equals("")); 700 this.moduleDef = toConfigure; 701 this.bodySchema = new BodySchema(); 702 703 registerAttributeConverter(PropertyName.class, propNameAttrCvt); 704 registerAttributeConverter(Property.class, propAttrCvt); 705 registerAttributeConverter(PropertyValue.class, propValueAttrCvt); 706 registerAttributeConverter(PropertyValue[].class, propValueArrayAttrCvt); 707 registerAttributeConverter(Generator.class, genAttrCvt); 708 } 709 710 protected Schema __module_begin() { 711 return bodySchema; 712 } 713 714 protected void __module_end() { 715 if (!foundExplicitSourceOrSuperSource) { 718 bodySchema.addSourcePackage(modulePackageAsPath, "client", false); 719 } 720 721 if (!foundAnyPublic) { 722 bodySchema.addPublicPackage(modulePackageAsPath, "public", Empty.STRINGS, 723 Empty.STRINGS, true, true); 724 } 725 } 726 727 737 private JsFunction parseJsBlock(int startLineNumber, String script) 738 throws UnableToCompleteException { 739 script = "function() { " + script + "}"; 740 StringReader r = new StringReader (script); 741 JsStatements stmts; 742 try { 743 stmts = jsParser.parse(jsPgm.getScope(), r, startLineNumber); 744 } catch (IOException e) { 745 logger.log(TreeLogger.ERROR, "Error reading script source", e); 746 throw new UnableToCompleteException(); 747 } catch (JsParserException e) { 748 SourceDetail dtl = e.getSourceDetail(); 749 if (dtl != null) { 750 StringBuffer sb = new StringBuffer (); 751 sb.append(moduleURL.toExternalForm()); 752 sb.append("("); 753 sb.append(dtl.getLine()); 754 sb.append(", "); 755 sb.append(dtl.getLineOffset()); 756 sb.append("): "); 757 sb.append(e.getMessage()); 758 logger.log(TreeLogger.ERROR, sb.toString(), e); 759 } else { 760 logger.log(TreeLogger.ERROR, "Error parsing JavaScript source", e); 761 } 762 throw new UnableToCompleteException(); 763 } 764 765 JsFunction fn = (JsFunction) ((JsExprStmt) stmts.get(0)).getExpression(); 769 return fn; 770 } 771 772 } 773 | Popular Tags |