Clover coverage report - Code Coverage for tapestry release 4.0-beta-2
Coverage timestamp: Sat Jul 9 2005 22:02:17 EDT
file stats: LOC: 1,794   Methods: 76
NCLOC: 1,115   Classes: 1
30 day Evaluation License registered to hlship@comcast.net Your 30 day evaluation period has expired. Please visit http://www.cenqua.com to obtain a licensed version of Clover
 
 Source file Conditionals Statements Methods TOTAL
SpecificationParser.java 95.7% 99% 100% 98.5%
coverage coverage
 1    // Copyright 2004, 2005 The Apache Software Foundation
 2    //
 3    // Licensed under the Apache License, Version 2.0 (the "License");
 4    // you may not use this file except in compliance with the License.
 5    // You may obtain a copy of the License at
 6    //
 7    // http://www.apache.org/licenses/LICENSE-2.0
 8    //
 9    // Unless required by applicable law or agreed to in writing, software
 10    // distributed under the License is distributed on an "AS IS" BASIS,
 11    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12    // See the License for the specific language governing permissions and
 13    // limitations under the License.
 14   
 15    package org.apache.tapestry.parse;
 16   
 17    import java.io.BufferedInputStream;
 18    import java.io.IOException;
 19    import java.io.InputStream;
 20    import java.net.URL;
 21    import java.util.HashMap;
 22    import java.util.Iterator;
 23    import java.util.Map;
 24   
 25    import javax.xml.parsers.SAXParser;
 26    import javax.xml.parsers.SAXParserFactory;
 27   
 28    import org.apache.commons.logging.Log;
 29    import org.apache.commons.logging.LogFactory;
 30    import org.apache.hivemind.ClassResolver;
 31    import org.apache.hivemind.ErrorHandler;
 32    import org.apache.hivemind.HiveMind;
 33    import org.apache.hivemind.Location;
 34    import org.apache.hivemind.Resource;
 35    import org.apache.hivemind.impl.DefaultErrorHandler;
 36    import org.apache.hivemind.impl.LocationImpl;
 37    import org.apache.hivemind.parse.AbstractParser;
 38    import org.apache.tapestry.INamespace;
 39    import org.apache.tapestry.Tapestry;
 40    import org.apache.tapestry.bean.BindingBeanInitializer;
 41    import org.apache.tapestry.bean.LightweightBeanInitializer;
 42    import org.apache.tapestry.binding.BindingConstants;
 43    import org.apache.tapestry.binding.BindingSource;
 44    import org.apache.tapestry.coerce.ValueConverter;
 45    import org.apache.tapestry.spec.BeanLifecycle;
 46    import org.apache.tapestry.spec.BindingType;
 47    import org.apache.tapestry.spec.IApplicationSpecification;
 48    import org.apache.tapestry.spec.IAssetSpecification;
 49    import org.apache.tapestry.spec.IBeanSpecification;
 50    import org.apache.tapestry.spec.IBindingSpecification;
 51    import org.apache.tapestry.spec.IComponentSpecification;
 52    import org.apache.tapestry.spec.IContainedComponent;
 53    import org.apache.tapestry.spec.IExtensionSpecification;
 54    import org.apache.tapestry.spec.ILibrarySpecification;
 55    import org.apache.tapestry.spec.IListenerBindingSpecification;
 56    import org.apache.tapestry.spec.IParameterSpecification;
 57    import org.apache.tapestry.spec.IPropertySpecification;
 58    import org.apache.tapestry.spec.InjectSpecification;
 59    import org.apache.tapestry.spec.SpecFactory;
 60    import org.apache.tapestry.util.IPropertyHolder;
 61    import org.apache.tapestry.util.RegexpMatcher;
 62    import org.apache.tapestry.util.xml.DocumentParseException;
 63    import org.apache.tapestry.util.xml.InvalidStringException;
 64    import org.xml.sax.InputSource;
 65    import org.xml.sax.SAXException;
 66    import org.xml.sax.SAXParseException;
 67   
 68    /**
 69    * Parses the different types of Tapestry specifications.
 70    * <p>
 71    * Not threadsafe; it is the callers responsibility to ensure thread safety.
 72    *
 73    * @author Howard Lewis Ship
 74    */
 75    public class SpecificationParser extends AbstractParser implements ISpecificationParser
 76    {
 77    private static final String IDENTIFIER_PATTERN = "_?[a-zA-Z]\\w*";
 78   
 79    private static final String EXTENDED_IDENTIFIER_PATTERN = "_?[a-zA-Z](\\w|-)*";
 80   
 81    /**
 82    * Perl5 pattern for asset names. Letter, followed by letter, number or underscore. Also allows
 83    * the special "$template" value.
 84    *
 85    * @since 2.2
 86    */
 87   
 88    public static final String ASSET_NAME_PATTERN = "(\\$template)|("
 89    + Tapestry.SIMPLE_PROPERTY_NAME_PATTERN + ")";
 90   
 91    /**
 92    * Perl5 pattern for helper bean names. Letter, followed by letter, number or underscore.
 93    *
 94    * @since 2.2
 95    */
 96   
 97    public static final String BEAN_NAME_PATTERN = Tapestry.SIMPLE_PROPERTY_NAME_PATTERN;
 98   
 99    /**
 100    * Perl5 pattern for component alias. Letter, followed by letter, number, or underscore. This is
 101    * used to validate component types registered in the application or library specifications.
 102    *
 103    * @since 2.2
 104    */
 105   
 106    public static final String COMPONENT_ALIAS_PATTERN = Tapestry.SIMPLE_PROPERTY_NAME_PATTERN;
 107   
 108    /**
 109    * Perl5 pattern for component ids. Letter, followed by letter, number or underscore.
 110    *
 111    * @since 2.2
 112    */
 113   
 114    public static final String COMPONENT_ID_PATTERN = Tapestry.SIMPLE_PROPERTY_NAME_PATTERN;
 115   
 116    /**
 117    * Perl5 pattern for component types. Component types are an optional namespace prefix followed
 118    * by a normal identifier.
 119    *
 120    * @since 2.2
 121    */
 122   
 123    public static final String COMPONENT_TYPE_PATTERN = "^(" + IDENTIFIER_PATTERN + ":)?"
 124    + IDENTIFIER_PATTERN + "$";
 125   
 126    /**
 127    * We can share a single map for all the XML attribute to object conversions, since the keys are
 128    * unique.
 129    */
 130   
 131    private final Map CONVERSION_MAP = new HashMap();
 132   
 133    /**
 134    * Extended version of {@link Tapestry.SIMPLE_PROPERTY_NAME_PATTERN}, but allows a series of
 135    * individual property names, seperated by periods. In addition, each name within the dotted
 136    * sequence is allowed to contain dashes.
 137    *
 138    * @since 2.2
 139    */
 140   
 141    public static final String EXTENDED_PROPERTY_NAME_PATTERN = "^" + EXTENDED_IDENTIFIER_PATTERN
 142    + "(\\." + EXTENDED_IDENTIFIER_PATTERN + ")*$";
 143   
 144    /**
 145    * Per5 pattern for extension names. Letter followed by letter, number, dash, period or
 146    * underscore.
 147    *
 148    * @since 2.2
 149    */
 150   
 151    public static final String EXTENSION_NAME_PATTERN = EXTENDED_PROPERTY_NAME_PATTERN;
 152   
 153    /**
 154    * Perl5 pattern for library ids. Letter followed by letter, number or underscore.
 155    *
 156    * @since 2.2
 157    */
 158   
 159    public static final String LIBRARY_ID_PATTERN = Tapestry.SIMPLE_PROPERTY_NAME_PATTERN;
 160   
 161    /** @since 4.0 */
 162    private final Log _log;
 163   
 164    /** @since 4.0 */
 165    private final ErrorHandler _errorHandler;
 166   
 167    /**
 168    * Set to true if parsing the 4.0 DTD.
 169    *
 170    * @since 4.0
 171    */
 172   
 173    private boolean _DTD_4_0;
 174   
 175    /**
 176    * Perl5 pattern for page names. Page names appear in library and application specifications, in
 177    * the &lt;page&gt; element. Starting with 4.0, the page name may look more like a path name,
 178    * consisting of a number of ids seperated by slashes. This is used to determine the folder
 179    * which contains the page specification or the page's template.
 180    *
 181    * @since 2.2
 182    */
 183   
 184    public static final String PAGE_NAME_PATTERN = "^" + IDENTIFIER_PATTERN + "(/"
 185    + IDENTIFIER_PATTERN + ")*$";
 186   
 187    /**
 188    * Perl5 pattern that parameter names must conform to. Letter, followed by letter, number or
 189    * underscore.
 190    *
 191    * @since 2.2
 192    */
 193   
 194    public static final String PARAMETER_NAME_PATTERN = Tapestry.SIMPLE_PROPERTY_NAME_PATTERN;
 195   
 196    /**
 197    * Perl5 pattern that property names (that can be connected to parameters) must conform to.
 198    * Letter, followed by letter, number or underscore.
 199    *
 200    * @since 2.2
 201    */
 202   
 203    public static final String PROPERTY_NAME_PATTERN = Tapestry.SIMPLE_PROPERTY_NAME_PATTERN;
 204   
 205    /**
 206    * Perl5 pattern for service names. Letter followed by letter, number, dash, underscore or
 207    * period.
 208    *
 209    * @since 2.2
 210    * @deprecated As of release 4.0, the &lt;service&gt; element (in 3.0 DTDs) is no longer
 211    * supported.
 212    */
 213   
 214    public static final String SERVICE_NAME_PATTERN = EXTENDED_PROPERTY_NAME_PATTERN;
 215   
 216    private static final int STATE_ALLOW_DESCRIPTION = 2000;
 217   
 218    private static final int STATE_ALLOW_PROPERTY = 2001;
 219   
 220    private static final int STATE_APPLICATION_SPECIFICATION_INITIAL = 1002;
 221   
 222    private static final int STATE_BEAN = 4;
 223   
 224    /** Very different between 3.0 and 4.0 DTD */
 225   
 226    private static final int STATE_BINDING_3_0 = 7;
 227   
 228    /** @since 4.0 */
 229   
 230    private static final int STATE_BINDING = 100;
 231   
 232    private static final int STATE_COMPONENT = 6;
 233   
 234    private static final int STATE_COMPONENT_SPECIFICATION = 1;
 235   
 236    private static final int STATE_COMPONENT_SPECIFICATION_INITIAL = 1000;
 237   
 238    private static final int STATE_CONFIGURE = 14;
 239   
 240    private static final int STATE_DESCRIPTION = 2;
 241   
 242    private static final int STATE_EXTENSION = 13;
 243   
 244    private static final int STATE_LIBRARY_SPECIFICATION = 12;
 245   
 246    private static final int STATE_LIBRARY_SPECIFICATION_INITIAL = 1003;
 247   
 248    private static final int STATE_LISTENER_BINDING = 8;
 249   
 250    private static final int STATE_NO_CONTENT = 3000;
 251   
 252    private static final int STATE_PAGE_SPECIFICATION = 11;
 253   
 254    private static final int STATE_PAGE_SPECIFICATION_INITIAL = 1001;
 255   
 256    private static final int STATE_META = 3;
 257   
 258    private static final int STATE_PROPERTY = 10;
 259   
 260    private static final int STATE_SET = 5;
 261   
 262    /** 3.0 DTD only */
 263    private static final int STATE_STATIC_BINDING = 9;
 264   
 265    /** @since 3.0 */
 266   
 267    public static final String TAPESTRY_DTD_3_0_PUBLIC_ID = "-//Apache Software Foundation//Tapestry Specification 3.0//EN";
 268   
 269    /** @since 4.0 */
 270   
 271    public static final String TAPESTRY_DTD_4_0_PUBLIC_ID = "-//Apache Software Foundation//Tapestry Specification 4.0//EN";
 272   
 273    /**
 274    * The attributes of the current element, as a map (string keyed on string).
 275    */
 276   
 277    private Map _attributes;
 278   
 279    /**
 280    * The name of the current element.
 281    */
 282   
 283    private String _elementName;
 284   
 285    /** @since 1.0.9 */
 286   
 287    private final SpecFactory _factory;
 288   
 289    private RegexpMatcher _matcher = new RegexpMatcher();
 290   
 291    private SAXParser _parser;
 292   
 293    private SAXParserFactory _parserFactory = SAXParserFactory.newInstance();
 294   
 295    /**
 296    * @since 3.0
 297    */
 298   
 299    private final ClassResolver _resolver;
 300   
 301    /** @since 4.0 */
 302   
 303    private BindingSource _bindingSource;
 304   
 305    /**
 306    * The root object parsed: a component or page specification, a library specification, or an
 307    * application specification.
 308    */
 309    private Object _rootObject;
 310   
 311    /** @since 4.0 */
 312   
 313    private ValueConverter _valueConverter;
 314   
 315    // Identify all the different acceptible values.
 316    // We continue to sneak by with a single map because
 317    // there aren't conflicts; when we have 'foo' meaning
 318    // different things in different places in the DTD, we'll
 319    // need multiple maps.
 320   
 321    {
 322   
 323  103 CONVERSION_MAP.put("true", Boolean.TRUE);
 324  103 CONVERSION_MAP.put("t", Boolean.TRUE);
 325  103 CONVERSION_MAP.put("1", Boolean.TRUE);
 326  103 CONVERSION_MAP.put("y", Boolean.TRUE);
 327  103 CONVERSION_MAP.put("yes", Boolean.TRUE);
 328  103 CONVERSION_MAP.put("on", Boolean.TRUE);
 329  103 CONVERSION_MAP.put("aye", Boolean.TRUE);
 330   
 331  103 CONVERSION_MAP.put("false", Boolean.FALSE);
 332  103 CONVERSION_MAP.put("f", Boolean.FALSE);
 333  103 CONVERSION_MAP.put("0", Boolean.FALSE);
 334  103 CONVERSION_MAP.put("off", Boolean.FALSE);
 335  103 CONVERSION_MAP.put("no", Boolean.FALSE);
 336  103 CONVERSION_MAP.put("n", Boolean.FALSE);
 337  103 CONVERSION_MAP.put("nay", Boolean.FALSE);
 338   
 339  103 CONVERSION_MAP.put("none", BeanLifecycle.NONE);
 340  103 CONVERSION_MAP.put("request", BeanLifecycle.REQUEST);
 341  103 CONVERSION_MAP.put("page", BeanLifecycle.PAGE);
 342  103 CONVERSION_MAP.put("render", BeanLifecycle.RENDER);
 343   
 344  103 _parserFactory.setNamespaceAware(false);
 345  103 _parserFactory.setValidating(true);
 346    }
 347   
 348    /**
 349    * This constructor is a convienience used by some tests.
 350    */
 351  61 public SpecificationParser(ClassResolver resolver)
 352    {
 353  61 this(resolver, new SpecFactory());
 354    }
 355   
 356    /**
 357    * Create a new instance with resolver and a provided SpecFactory (used by Spindle).
 358    *
 359    * @deprecated to be removed in release 4.1
 360    */
 361  61 public SpecificationParser(ClassResolver resolver, SpecFactory factory)
 362    {
 363  61 this(new DefaultErrorHandler(), LogFactory.getLog(SpecificationParser.class), resolver,
 364    factory);
 365    }
 366   
 367    /**
 368    * The full constructor, used within Tapestry.
 369    */
 370  103 public SpecificationParser(ErrorHandler errorHandler, Log log, ClassResolver resolver,
 371    SpecFactory factory)
 372    {
 373  103 _errorHandler = errorHandler;
 374  103 _log = log;
 375  103 _resolver = resolver;
 376  103 _factory = factory;
 377    }
 378   
 379  6686 protected void begin(String elementName, Map attributes)
 380    {
 381  6686 _elementName = elementName;
 382  6686 _attributes = attributes;
 383   
 384  6686 switch (getState())
 385    {
 386  337 case STATE_COMPONENT_SPECIFICATION_INITIAL:
 387   
 388  337 beginComponentSpecificationInitial();
 389  336 break;
 390   
 391  104 case STATE_PAGE_SPECIFICATION_INITIAL:
 392   
 393  104 beginPageSpecificationInitial();
 394  104 break;
 395   
 396  41 case STATE_APPLICATION_SPECIFICATION_INITIAL:
 397   
 398  41 beginApplicationSpecificationInitial();
 399  41 break;
 400   
 401  65 case STATE_LIBRARY_SPECIFICATION_INITIAL:
 402   
 403  65 beginLibrarySpecificationInitial();
 404  65 break;
 405   
 406  2181 case STATE_COMPONENT_SPECIFICATION:
 407   
 408  2181 beginComponentSpecification();
 409  2175 break;
 410   
 411  185 case STATE_PAGE_SPECIFICATION:
 412   
 413  185 beginPageSpecification();
 414  185 break;
 415   
 416  759 case STATE_ALLOW_DESCRIPTION:
 417   
 418  759 beginAllowDescription();
 419  759 break;
 420   
 421  3 case STATE_ALLOW_PROPERTY:
 422   
 423  3 allowMetaData();
 424  3 break;
 425   
 426  16 case STATE_BEAN:
 427   
 428  16 beginBean();
 429  16 break;
 430   
 431  366 case STATE_COMPONENT:
 432   
 433  366 beginComponent();
 434  366 break;
 435   
 436  2596 case STATE_LIBRARY_SPECIFICATION:
 437   
 438  2596 beginLibrarySpecification();
 439  2591 break;
 440   
 441  33 case STATE_EXTENSION:
 442   
 443  33 beginExtension();
 444  33 break;
 445   
 446  0 default:
 447   
 448  0 unexpectedElement(_elementName);
 449    }
 450    }
 451   
 452    /**
 453    * Special state for a number of specification types that can support the &lt;description&gt;
 454    * element.
 455    */
 456   
 457  759 private void beginAllowDescription()
 458    {
 459  759 if (_elementName.equals("description"))
 460    {
 461  759 enterDescription();
 462  759 return;
 463    }
 464   
 465  0 unexpectedElement(_elementName);
 466    }
 467   
 468    /**
 469    * Special state for a number of elements that can support the nested &lt;meta&gt; meta data
 470    * element (&lt;property&gt; in 3.0 DTD).
 471    */
 472   
 473  58 private void allowMetaData()
 474    {
 475  58 if (_DTD_4_0)
 476    {
 477  11 if (_elementName.equals("meta"))
 478    {
 479  11 enterMeta();
 480  11 return;
 481    }
 482    }
 483  47 else if (_elementName.equals("property"))
 484    {
 485  47 enterProperty_3_0();
 486  47 return;
 487    }
 488   
 489  0 unexpectedElement(_elementName);
 490    }
 491   
 492  41 private void beginApplicationSpecificationInitial()
 493    {
 494  41 expectElement("application");
 495   
 496  41 String name = getAttribute("name");
 497  41 String engineClassName = getAttribute("engine-class");
 498   
 499  41 IApplicationSpecification as = _factory.createApplicationSpecification();
 500   
 501  41 as.setName(name);
 502   
 503  41 if (HiveMind.isNonBlank(engineClassName))
 504  5 as.setEngineClassName(engineClassName);
 505   
 506  41 _rootObject = as;
 507   
 508  41 push(_elementName, as, STATE_LIBRARY_SPECIFICATION);
 509    }
 510   
 511  16 private void beginBean()
 512    {
 513  16 if (_elementName.equals("set"))
 514    {
 515  3 enterSet();
 516  3 return;
 517    }
 518   
 519  13 if (_elementName.equals("set-property"))
 520    {
 521  5 enterSetProperty_3_0();
 522  5 return;
 523    }
 524   
 525  8 if (_elementName.equals("set-message-property"))
 526    {
 527  1 enterSetMessage_3_0();
 528  1 return;
 529    }
 530   
 531  7 if (_elementName.equals("description"))
 532    {
 533  2 enterDescription();
 534  2 return;
 535    }
 536   
 537  5 allowMetaData();
 538    }
 539   
 540  366 private void beginComponent()
 541    {
 542    // <binding> has changed between 3.0 and 4.0
 543   
 544  366 if (_elementName.equals("binding"))
 545    {
 546  321 enterBinding();
 547  321 return;
 548    }
 549   
 550  45 if (_elementName.equals("static-binding"))
 551    {
 552  31 enterStaticBinding_3_0();
 553  31 return;
 554    }
 555   
 556  14 if (_elementName.equals("message-binding"))
 557    {
 558  4 enterMessageBinding_3_0();
 559  4 return;
 560    }
 561   
 562  10 if (_elementName.equals("inherited-binding"))
 563    {
 564  2 enterInheritedBinding_3_0();
 565  2 return;
 566    }
 567   
 568  8 if (_elementName.equals("listener-binding"))
 569    {
 570  4 enterListenerBinding();
 571  4 return;
 572    }
 573   
 574  4 allowMetaData();
 575    }
 576   
 577  2181 private void beginComponentSpecification()
 578    {
 579  2181 if (_elementName.equals("reserved-parameter"))
 580    {
 581  106 enterReservedParameter();
 582  106 return;
 583    }
 584   
 585  2075 if (_elementName.equals("parameter"))
 586    {
 587  1101 enterParameter();
 588  1100 return;
 589    }
 590   
 591    // The remainder are common to both <component-specification> and
 592    // <page-specification>
 593   
 594  974 beginPageSpecification();
 595    }
 596   
 597  337 private void beginComponentSpecificationInitial()
 598    {
 599  337 expectElement("component-specification");
 600   
 601  336 IComponentSpecification cs = _factory.createComponentSpecification();
 602   
 603  336 cs.setAllowBody(getBooleanAttribute("allow-body", true));
 604  336 cs.setAllowInformalParameters(getBooleanAttribute("allow-informal-parameters", true));
 605  336 cs.setDeprecated(getBooleanAttribute("deprecated", false));
 606   
 607  336 String className = getAttribute("class");
 608   
 609  336 if (className != null)
 610  303 cs.setComponentClassName(className);
 611   
 612  336 cs.setSpecificationLocation(getResource());
 613   
 614  336 _rootObject = cs;
 615   
 616  336 push(_elementName, cs, STATE_COMPONENT_SPECIFICATION);
 617    }
 618   
 619  33 private void beginExtension()
 620    {
 621  33 if (_elementName.equals("configure"))
 622    {
 623  30 enterConfigure();
 624  30 return;
 625    }
 626   
 627  3 allowMetaData();
 628    }
 629   
 630  2596 private void beginLibrarySpecification()
 631    {
 632  2596 if (_elementName.equals("description"))
 633    {
 634  1 enterDescription();
 635  1 return;
 636    }
 637   
 638  2595 if (_elementName.equals("page"))
 639    {
 640  501 enterPage();
 641  500 return;
 642    }
 643   
 644  2094 if (_elementName.equals("component-type"))
 645    {
 646  2040 enterComponentType();
 647  2039 return;
 648    }
 649   
 650    // Holdover from the 3.0 DTD, now ignored.
 651   
 652  54 if (_elementName.equals("service"))
 653    {
 654  1 enterService_3_0();
 655  1 return;
 656    }
 657   
 658  53 if (_elementName.equals("library"))
 659    {
 660  23 enterLibrary();
 661  21 return;
 662    }
 663   
 664  30 if (_elementName.equals("extension"))
 665    {
 666  11 enterExtension();
 667  10 return;
 668    }
 669   
 670  19 allowMetaData();
 671    }
 672   
 673  65 private void beginLibrarySpecificationInitial()
 674    {
 675  65 expectElement("library-specification");
 676   
 677  65 ILibrarySpecification ls = _factory.createLibrarySpecification();
 678   
 679  65 _rootObject = ls;
 680   
 681  65 push(_elementName, ls, STATE_LIBRARY_SPECIFICATION);
 682    }
 683   
 684  1159 private void beginPageSpecification()
 685    {
 686  1159 if (_elementName.equals("component"))
 687    {
 688  276 enterComponent();
 689  272 return;
 690    }
 691   
 692  883 if (_elementName.equals("bean"))
 693    {
 694  35 enterBean();
 695  35 return;
 696    }
 697   
 698    // <property-specification> in 3.0, <property> in 4.0
 699    // Have to be careful, because <meta> in 4.0 was <property> in 3.0
 700   
 701  848 if (_elementName.equals("property-specification")
 702    || (_DTD_4_0 && _elementName.equals("property")))
 703    {
 704  123 enterProperty();
 705  123 return;
 706    }
 707   
 708  725 if (_elementName.equals("inject"))
 709    {
 710  374 enterInject();
 711  374 return;
 712    }
 713   
 714    // <asset> is new in 4.0
 715   
 716  351 if (_elementName.equals("asset"))
 717    {
 718  27 enterAsset();
 719  27 return;
 720    }
 721   
 722    // <context-asset>, <external-asset>, and <private-asset>
 723    // are all throwbacks to the 3.0 DTD and don't exist
 724    // in the 4.0 DTD.
 725   
 726  324 if (_elementName.equals("context-asset"))
 727    {
 728  7 enterContextAsset_3_0();
 729  7 return;
 730    }
 731   
 732  317 if (_elementName.equals("private-asset"))
 733    {
 734  8 enterPrivateAsset_3_0();
 735  7 return;
 736    }
 737   
 738  309 if (_elementName.equals("external-asset"))
 739    {
 740  3 enterExternalAsset_3_0();
 741  3 return;
 742   
 743    }
 744   
 745  306 if (_elementName.equals("description"))
 746    {
 747  282 enterDescription();
 748  282 return;
 749    }
 750   
 751  24 allowMetaData();
 752    }
 753   
 754  104 private void beginPageSpecificationInitial()
 755    {
 756  104 expectElement("page-specification");
 757   
 758  104 IComponentSpecification cs = _factory.createComponentSpecification();
 759   
 760  104 String className = getAttribute("class");
 761   
 762  104 if (className != null)
 763  73 cs.setComponentClassName(className);
 764   
 765  104 cs.setSpecificationLocation(getResource());
 766  104 cs.setPageSpecification(true);
 767   
 768  104 _rootObject = cs;
 769   
 770  104 push(_elementName, cs, STATE_PAGE_SPECIFICATION);
 771    }
 772   
 773    /**
 774    * Close a stream (if not null), ignoring any errors.
 775    */
 776  549 private void close(InputStream stream)
 777    {
 778  549 try
 779    {
 780  549 if (stream != null)
 781  16 stream.close();
 782    }
 783    catch (IOException ex)
 784    {
 785    // ignore
 786    }
 787    }
 788   
 789  3 private void copyBindings(String sourceComponentId, IComponentSpecification cs,
 790    IContainedComponent target)
 791    {
 792  3 IContainedComponent source = cs.getComponent(sourceComponentId);
 793  3 if (source == null)
 794  1 throw new DocumentParseException(ParseMessages.unableToCopy(sourceComponentId),
 795    getLocation(), null);
 796   
 797  2 Iterator i = source.getBindingNames().iterator();
 798  2 while (i.hasNext())
 799    {
 800  4 String bindingName = (String) i.next();
 801  4 IBindingSpecification binding = source.getBinding(bindingName);
 802  4 target.setBinding(bindingName, binding);
 803    }
 804   
 805  2 target.setType(source.getType());
 806    }
 807   
 808  6659 protected void end(String elementName)
 809    {
 810  6659 _elementName = elementName;
 811   
 812  6659 switch (getState())
 813    {
 814  1044 case STATE_DESCRIPTION:
 815   
 816  1044 endDescription();
 817  1044 break;
 818   
 819  58 case STATE_META:
 820   
 821  58 endProperty();
 822  58 break;
 823   
 824  8 case STATE_SET:
 825   
 826  8 endSetProperty();
 827  8 break;
 828   
 829  29 case STATE_BINDING_3_0:
 830   
 831  29 endBinding_3_0();
 832  28 break;
 833   
 834  292 case STATE_BINDING:
 835   
 836  292 endBinding();
 837  292 break;
 838   
 839  4 case STATE_LISTENER_BINDING:
 840   
 841  4 endListenerBinding();
 842  4 break;
 843   
 844  31 case STATE_STATIC_BINDING:
 845   
 846  31 endStaticBinding();
 847  30 break;
 848   
 849  123 case STATE_PROPERTY:
 850   
 851  123 endPropertySpecification();
 852  123 break;
 853   
 854  101 case STATE_LIBRARY_SPECIFICATION:
 855   
 856  101 endLibrarySpecification();
 857  101 break;
 858   
 859  30 case STATE_CONFIGURE:
 860   
 861  30 endConfigure();
 862  30 break;
 863   
 864  4939 default:
 865  4939 break;
 866    }
 867   
 868    // Pop the top element of the stack and continue processing from there.
 869   
 870  6657 pop();
 871    }
 872   
 873  29 private void endBinding_3_0()
 874    {
 875  29 BindingSetter bs = (BindingSetter) peekObject();
 876   
 877  29 String expression = getExtendedValue(bs.getValue(), "expression", true);
 878   
 879  28 IBindingSpecification spec = _factory.createBindingSpecification();
 880   
 881  28 spec.setType(BindingType.PREFIXED);
 882  28 spec.setValue(BindingConstants.OGNL_PREFIX + ":" + expression);
 883   
 884  28 bs.apply(spec);
 885    }
 886   
 887  30 private void endConfigure()
 888    {
 889  30 ExtensionConfigurationSetter setter = (ExtensionConfigurationSetter) peekObject();
 890   
 891  30 String finalValue = getExtendedValue(setter.getValue(), "value", true);
 892   
 893  30 setter.apply(finalValue);
 894    }
 895   
 896  1044 private void endDescription()
 897    {
 898  1044 DescriptionSetter setter = (DescriptionSetter) peekObject();
 899   
 900  1044 String description = peekContent();
 901   
 902  1044 setter.apply(description);
 903    }
 904   
 905  101 private void endLibrarySpecification()
 906    {
 907  101 ILibrarySpecification spec = (ILibrarySpecification) peekObject();
 908   
 909  101 spec.setSpecificationLocation(getResource());
 910   
 911  101 spec.instantiateImmediateExtensions();
 912    }
 913   
 914  4 private void endListenerBinding()
 915    {
 916  4 BindingSetter bs = (BindingSetter) peekObject();
 917   
 918  4 IListenerBindingSpecification lbs = _factory.createListenerBindingSpecification();
 919   
 920  4 lbs.setLanguage(bs.getValue());
 921   
 922    // Do we need a check for no body content?
 923   
 924  4 lbs.setValue(peekContent());
 925  4 lbs.setLocation(getLocation());
 926   
 927  4 bs.apply(lbs);
 928    }
 929   
 930  58 private void endProperty()
 931    {
 932  58 PropertyValueSetter pvs = (PropertyValueSetter) peekObject();
 933   
 934  58 String finalValue = getExtendedValue(pvs.getPropertyValue(), "value", true);
 935   
 936  58 pvs.applyValue(finalValue);
 937    }
 938   
 939  123 private void endPropertySpecification()
 940    {
 941  123 IPropertySpecification ps = (IPropertySpecification) peekObject();
 942   
 943  123 String initialValue = getExtendedValue(ps.getInitialValue(), "initial-value", false);
 944   
 945    // In the 3.0 DTD, the initial value was always an OGNL expression.
 946    // In the 4.0 DTD, it is a binding reference, qualified with a prefix.
 947   
 948  123 if (initialValue != null && !_DTD_4_0)
 949  5 initialValue = BindingConstants.OGNL_PREFIX + ":" + initialValue;
 950   
 951  123 ps.setInitialValue(initialValue);
 952    }
 953   
 954  8 private void endSetProperty()
 955    {
 956  8 BeanSetPropertySetter bs = (BeanSetPropertySetter) peekObject();
 957   
 958  8 String finalValue = getExtendedValue(bs.getBindingReference(), "expression", true);
 959   
 960  8 bs.applyBindingReference(finalValue);
 961    }
 962   
 963  31 private void endStaticBinding()
 964    {
 965  31 BindingSetter bs = (BindingSetter) peekObject();
 966   
 967  31 String literalValue = getExtendedValue(bs.getValue(), "value", true);
 968   
 969  30 IBindingSpecification spec = _factory.createBindingSpecification();
 970   
 971  30 spec.setType(BindingType.PREFIXED);
 972  30 spec.setValue(BindingConstants.LITERAL_PREFIX + ":" + literalValue);
 973   
 974  30 bs.apply(spec);
 975    }
 976   
 977  45 private void enterAsset(String pathAttributeName, String prefix)
 978    {
 979  45 String name = getValidatedAttribute("name", ASSET_NAME_PATTERN, "invalid-asset-name");
 980  44 String path = getAttribute(pathAttributeName);
 981  44 String propertyName = getValidatedAttribute(
 982    "property",
 983    PROPERTY_NAME_PATTERN,
 984    "invalid-property-name");
 985   
 986  44 IAssetSpecification ia = _factory.createAssetSpecification();
 987   
 988  44 ia.setPath(prefix == null ? path : prefix + path);
 989  44 ia.setPropertyName(propertyName);
 990   
 991  44 IComponentSpecification cs = (IComponentSpecification) peekObject();
 992   
 993  44 cs.addAsset(name, ia);
 994   
 995  44 push(_elementName, ia, STATE_ALLOW_PROPERTY);
 996    }
 997   
 998  35 private void enterBean()
 999    {
 1000  35 String name = getValidatedAttribute("name", BEAN_NAME_PATTERN, "invalid-bean-name");
 1001   
 1002  35 String classAttribute = getAttribute("class");
 1003   
 1004    // Look for the lightweight initialization
 1005   
 1006  35 int commax = classAttribute.indexOf(',');
 1007   
 1008  35 String className = commax < 0 ? classAttribute : classAttribute.substring(0, commax);
 1009   
 1010  35 BeanLifecycle lifecycle = (BeanLifecycle) getConvertedAttribute(
 1011    "lifecycle",
 1012    BeanLifecycle.REQUEST);
 1013  35 String propertyName = getValidatedAttribute(
 1014    "property",
 1015    PROPERTY_NAME_PATTERN,
 1016    "invalid-property-name");
 1017   
 1018  35 IBeanSpecification bs = _factory.createBeanSpecification();
 1019   
 1020  35 bs.setClassName(className);
 1021  35 bs.setLifecycle(lifecycle);
 1022  35 bs.setPropertyName(propertyName);
 1023   
 1024  35 if (commax > 0)
 1025    {
 1026  1 String initializer = classAttribute.substring(commax + 1);
 1027  1 bs.addInitializer(new LightweightBeanInitializer(initializer));
 1028    }
 1029   
 1030  35 IComponentSpecification cs = (IComponentSpecification) peekObject();
 1031   
 1032  35 cs.addBeanSpecification(name, bs);
 1033   
 1034  35 push(_elementName, bs, STATE_BEAN);
 1035    }
 1036   
 1037  321 private void enterBinding()
 1038    {
 1039  321 if (!_DTD_4_0)
 1040    {
 1041  29 enterBinding_3_0();
 1042  29 return;
 1043    }
 1044   
 1045    // 4.0 stuff
 1046   
 1047  292 String name = getValidatedAttribute(
 1048    "name",
 1049    PARAMETER_NAME_PATTERN,
 1050    "invalid-parameter-name");
 1051  292 String value = getAttribute("value");
 1052   
 1053  292 IContainedComponent cc = (IContainedComponent) peekObject();
 1054   
 1055  292 BindingSetter bs = new BindingSetter(cc, name, value);
 1056   
 1057  292 push(_elementName, bs, STATE_BINDING, false);
 1058    }
 1059   
 1060  292 private void endBinding()
 1061    {
 1062  292 BindingSetter bs = (BindingSetter) peekObject();
 1063   
 1064  292 String value = getExtendedValue(bs.getValue(), "value", true);
 1065   
 1066  292 IBindingSpecification spec = _factory.createBindingSpecification();
 1067   
 1068  292 spec.setType(BindingType.PREFIXED);
 1069  292 spec.setValue(value);
 1070   
 1071  292 bs.apply(spec);
 1072    }
 1073   
 1074    /**
 1075    * Handles a binding in a 3.0 DTD.
 1076    */
 1077   
 1078  29 private void enterBinding_3_0()
 1079    {
 1080  29 String name = getAttribute("name");
 1081  29 String expression = getAttribute("expression");
 1082   
 1083  29 IContainedComponent cc = (IContainedComponent) peekObject();
 1084   
 1085  29 BindingSetter bs = new BindingSetter(cc, name, expression);
 1086   
 1087  29 push(_elementName, bs, STATE_BINDING_3_0, false);
 1088    }
 1089   
 1090  276 private void enterComponent()
 1091    {
 1092  276 String id = getValidatedAttribute("id", COMPONENT_ID_PATTERN, "invalid-component-id");
 1093   
 1094  275 String type = getValidatedAttribute(
 1095    "type",
 1096    COMPONENT_TYPE_PATTERN,
 1097    "invalid-component-type");
 1098  275 String copyOf = getAttribute("copy-of");
 1099  275 boolean inherit = getBooleanAttribute("inherit-informal-parameters", false);
 1100  275 String propertyName = getValidatedAttribute(
 1101    "property",
 1102    PROPERTY_NAME_PATTERN,
 1103    "invalid-property-name");
 1104   
 1105    // Check that either copy-of or type, but not both
 1106   
 1107  275 boolean hasCopyOf = HiveMind.isNonBlank(copyOf);
 1108   
 1109  275 if (hasCopyOf)
 1110    {
 1111  4 if (HiveMind.isNonBlank(type))
 1112  1 throw new DocumentParseException(ParseMessages.bothTypeAndCopyOf(id),
 1113    getLocation(), null);
 1114    }
 1115    else
 1116    {
 1117  271 if (HiveMind.isBlank(type))
 1118  1 throw new DocumentParseException(ParseMessages.missingTypeOrCopyOf(id),
 1119    getLocation(), null);
 1120    }
 1121   
 1122  273 IContainedComponent cc = _factory.createContainedComponent();
 1123  273 cc.setType(type);
 1124  273 cc.setCopyOf(copyOf);
 1125  273 cc.setInheritInformalParameters(inherit);
 1126  273 cc.setPropertyName(propertyName);
 1127   
 1128  273 IComponentSpecification cs = (IComponentSpecification) peekObject();
 1129   
 1130  273 cs.addComponent(id, cc);
 1131   
 1132  273 if (hasCopyOf)
 1133  3 copyBindings(copyOf, cs, cc);
 1134   
 1135  272 push(_elementName, cc, STATE_COMPONENT);
 1136    }
 1137   
 1138  2040 private void enterComponentType()
 1139    {
 1140  2040 String type = getValidatedAttribute(
 1141    "type",
 1142    COMPONENT_ALIAS_PATTERN,
 1143    "invalid-component-type");
 1144  2039 String path = getAttribute("specification-path");
 1145   
 1146  2039 ILibrarySpecification ls = (ILibrarySpecification) peekObject();
 1147   
 1148  2039 ls.setComponentSpecificationPath(type, path);
 1149   
 1150  2039 push(_elementName, null, STATE_NO_CONTENT);
 1151    }
 1152   
 1153  30 private void enterConfigure()
 1154    {
 1155  30 String attributeName = _DTD_4_0 ? "property" : "property-name";
 1156   
 1157  30 String propertyName = getValidatedAttribute(
 1158    attributeName,
 1159    PROPERTY_NAME_PATTERN,
 1160    "invalid-property-name");
 1161   
 1162  30 String value = getAttribute("value");
 1163   
 1164  30 IExtensionSpecification es = (IExtensionSpecification) peekObject();
 1165   
 1166  30 ExtensionConfigurationSetter setter = new ExtensionConfigurationSetter(es, propertyName,
 1167    value);
 1168   
 1169  30 push(_elementName, setter, STATE_CONFIGURE, false);
 1170    }
 1171   
 1172  7 private void enterContextAsset_3_0()
 1173    {
 1174  7 enterAsset("path", "context:");
 1175    }
 1176   
 1177    /**
 1178    * New in the 4.0 DTD. When using the 4.0 DTD, you must explicitly specify prefix if the asset
 1179    * is not stored in the same domain as the specification file.
 1180    *
 1181    * @since 4.0
 1182    */
 1183   
 1184  27 private void enterAsset()
 1185    {
 1186  27 enterAsset("path", null);
 1187    }
 1188   
 1189  1044 private void enterDescription()
 1190    {
 1191  1044 push(_elementName, new DescriptionSetter(peekObject()), STATE_DESCRIPTION, false);
 1192    }
 1193   
 1194  11 private void enterExtension()
 1195    {
 1196  11 String name = getValidatedAttribute(
 1197    "name",
 1198    EXTENSION_NAME_PATTERN,
 1199    "invalid-extension-name");
 1200   
 1201  10 boolean immediate = getBooleanAttribute("immediate", false);
 1202  10 String className = getAttribute("class");
 1203   
 1204  10 IExtensionSpecification es = _factory.createExtensionSpecification(
 1205    _resolver,
 1206    _valueConverter);
 1207   
 1208  10 es.setClassName(className);
 1209  10 es.setImmediate(immediate);
 1210   
 1211  10 ILibrarySpecification ls = (ILibrarySpecification) peekObject();
 1212   
 1213  10 ls.addExtensionSpecification(name, es);
 1214   
 1215  10 push(_elementName, es, STATE_EXTENSION);
 1216    }
 1217   
 1218  3 private void enterExternalAsset_3_0()
 1219    {
 1220    // External URLs get no prefix, but will have a scheme (i.e., "http:") that
 1221    // fulfils much the same purpose.
 1222   
 1223  3 enterAsset("URL", null);
 1224    }
 1225   
 1226    /** A throwback to the 3.0 DTD */
 1227   
 1228  2 private void enterInheritedBinding_3_0()
 1229    {
 1230  2 String name = getAttribute("name");
 1231  2 String parameterName = getAttribute("parameter-name");
 1232   
 1233  2 IBindingSpecification bs = _factory.createBindingSpecification();
 1234  2 bs.setType(BindingType.INHERITED);
 1235  2 bs.setValue(parameterName);
 1236   
 1237  2 IContainedComponent cc = (IContainedComponent) peekObject();
 1238   
 1239  2 cc.setBinding(name, bs);
 1240   
 1241  2 push(_elementName, null, STATE_NO_CONTENT);
 1242    }
 1243   
 1244  23 private void enterLibrary()
 1245    {
 1246  23 String libraryId = getValidatedAttribute("id", LIBRARY_ID_PATTERN, "invalid-library-id");
 1247  22 String path = getAttribute("specification-path");
 1248   
 1249  22 if (libraryId.equals(INamespace.FRAMEWORK_NAMESPACE))
 1250  1 throw new DocumentParseException(ParseMessages
 1251    .frameworkLibraryIdIsReserved(INamespace.FRAMEWORK_NAMESPACE), getLocation(),
 1252    null);
 1253   
 1254  21 ILibrarySpecification ls = (ILibrarySpecification) peekObject();
 1255   
 1256  21 ls.setLibrarySpecificationPath(libraryId, path);
 1257   
 1258  21 push(_elementName, null, STATE_NO_CONTENT);
 1259    }
 1260   
 1261  4 private void enterListenerBinding()
 1262    {
 1263  4 String name = getAttribute("name");
 1264  4 String language = getAttribute("language");
 1265   
 1266  4 IContainedComponent cc = (IContainedComponent) peekObject();
 1267  4 BindingSetter bs = new BindingSetter(cc, name, language);
 1268   
 1269  4 push(_elementName, bs, STATE_LISTENER_BINDING, false);
 1270    }
 1271   
 1272  4 private void enterMessageBinding_3_0()
 1273    {
 1274  4 String name = getAttribute("name");
 1275  4 String key = getAttribute("key");
 1276   
 1277  4 IBindingSpecification bs = _factory.createBindingSpecification();
 1278  4 bs.setType(BindingType.PREFIXED);
 1279  4 bs.setValue(BindingConstants.MESSAGE_PREFIX + ":" + key);
 1280  4 bs.setLocation(getLocation());
 1281   
 1282  4 IContainedComponent cc = (IContainedComponent) peekObject();
 1283   
 1284  4 cc.setBinding(name, bs);
 1285   
 1286  4 push(_elementName, null, STATE_NO_CONTENT);
 1287    }
 1288   
 1289  501 private void enterPage()
 1290    {
 1291  501 String name = getValidatedAttribute("name", PAGE_NAME_PATTERN, "invalid-page-name");
 1292  500 String path = getAttribute("specification-path");
 1293   
 1294  500 ILibrarySpecification ls = (ILibrarySpecification) peekObject();
 1295   
 1296  500 ls.setPageSpecificationPath(name, path);
 1297   
 1298  500 push(_elementName, null, STATE_NO_CONTENT);
 1299    }
 1300   
 1301  1101 private void enterParameter()
 1302    {
 1303  1101 IParameterSpecification ps = _factory.createParameterSpecification();
 1304   
 1305  1101 String name = getValidatedAttribute(
 1306    "name",
 1307    PARAMETER_NAME_PATTERN,
 1308    "invalid-parameter-name");
 1309   
 1310  1100 String attributeName = _DTD_4_0 ? "property" : "property-name";
 1311   
 1312  1100 String propertyName = getValidatedAttribute(
 1313    attributeName,
 1314    PROPERTY_NAME_PATTERN,
 1315    "invalid-property-name");
 1316   
 1317  1100 if (propertyName == null)
 1318  1004 propertyName = name;
 1319   
 1320  1100 ps.setParameterName(name);
 1321  1100 ps.setPropertyName(propertyName);
 1322   
 1323  1100 ps.setRequired(getBooleanAttribute("required", false));
 1324   
 1325    // In the 3.0 DTD, default-value was always an OGNL expression.
 1326    // Starting with 4.0, it's like a binding (prefixed). For a 3.0
 1327    // DTD, we supply the "ognl:" prefix.
 1328   
 1329  1100 String defaultValue = getAttribute("default-value");
 1330   
 1331  1100 if (defaultValue != null && !_DTD_4_0)
 1332  7 defaultValue = BindingConstants.OGNL_PREFIX + ":" + defaultValue;
 1333   
 1334  1100 ps.setDefaultValue(defaultValue);
 1335   
 1336  1100 ps.setDefaultBindingType(getAttribute("default-binding"));
 1337   
 1338  1100 if (!_DTD_4_0)
 1339    {
 1340  44 String direction = getAttribute("direction");
 1341  44 ps.setCache(!"auto".equals(direction));
 1342    }
 1343    else
 1344    {
 1345  1056 boolean cache = getBooleanAttribute("cache", true);
 1346  1056 ps.setCache(cache);
 1347    }
 1348   
 1349    // type will only be specified in a 3.0 DTD.
 1350   
 1351  1100 String type = getAttribute("type");
 1352   
 1353  1100 if (type != null)
 1354  38 ps.setType(type);
 1355   
 1356    // aliases is new in the 4.0 DTD
 1357   
 1358  1100 String aliases = getAttribute("aliases");
 1359   
 1360  1100 ps.setAliases(aliases);
 1361  1100 ps.setDeprecated(getBooleanAttribute("deprecated", false));
 1362   
 1363  1100 IComponentSpecification cs = (IComponentSpecification) peekObject();
 1364   
 1365  1100 cs.addParameter(ps);
 1366   
 1367  1100 push(_elementName, ps, STATE_ALLOW_DESCRIPTION);
 1368    }
 1369   
 1370  8 private void enterPrivateAsset_3_0()
 1371    {
 1372  8 enterAsset("resource-path", "classpath:");
 1373    }
 1374   
 1375    /** @since 4.0 */
 1376  11 private void enterMeta()
 1377    {
 1378  11 String key = getAttribute("key");
 1379  11 String value = getAttribute("value");
 1380   
 1381    // Value may be null, in which case the value is set from the element content
 1382   
 1383  11 IPropertyHolder ph = (IPropertyHolder) peekObject();
 1384   
 1385  11 push(_elementName, new PropertyValueSetter(ph, key, value), STATE_META, false);
 1386    }
 1387   
 1388  47 private void enterProperty_3_0()
 1389    {
 1390  47 String name = getAttribute("name");
 1391  47 String value = getAttribute("value");
 1392   
 1393    // Value may be null, in which case the value is set from the element content
 1394   
 1395  47 IPropertyHolder ph = (IPropertyHolder) peekObject();
 1396   
 1397  47 push(_elementName, new PropertyValueSetter(ph, name, value), STATE_META, false);
 1398    }
 1399   
 1400    /**
 1401    * &tl;property&gt; in 4.0, or &lt;property-specification&gt; in 3.0
 1402    */
 1403   
 1404  123 private void enterProperty()
 1405    {
 1406  123 String name = getValidatedAttribute("name", PROPERTY_NAME_PATTERN, "invalid-property-name");
 1407  123 String type = getAttribute("type");
 1408   
 1409  123 String persistence = null;
 1410   
 1411  123 if (_DTD_4_0)
 1412  70 persistence = getAttribute("persist");
 1413    else
 1414  53 persistence = getBooleanAttribute("persistent", false) ? "session" : null;
 1415   
 1416  123 String initialValue = getAttribute("initial-value");
 1417   
 1418  123 IPropertySpecification ps = _factory.createPropertySpecification();
 1419  123 ps.setName(name);
 1420   
 1421  123 if (HiveMind.isNonBlank(type))
 1422  50 ps.setType(type);
 1423   
 1424  123 ps.setPersistence(persistence);
 1425  123 ps.setInitialValue(initialValue);
 1426   
 1427  123 IComponentSpecification cs = (IComponentSpecification) peekObject();
 1428  123 cs.addPropertySpecification(ps);
 1429   
 1430  123 push(_elementName, ps, STATE_PROPERTY, false);
 1431    }
 1432   
 1433    /**
 1434    * @since 4.0
 1435    */
 1436   
 1437  374 private void enterInject()
 1438    {
 1439  374 String property = getValidatedAttribute(
 1440    "property",
 1441    PROPERTY_NAME_PATTERN,
 1442    "invalid-property-name");
 1443  374 String type = getAttribute("type");
 1444  374 String objectReference = getAttribute("object");
 1445   
 1446  374 InjectSpecification spec = _factory.createInjectSpecification();
 1447   
 1448  374 spec.setProperty(property);
 1449  374 spec.setType(type);
 1450  374 spec.setObject(objectReference);
 1451  374 IComponentSpecification cs = (IComponentSpecification) peekObject();
 1452   
 1453  374 cs.addInjectSpecification(spec);
 1454   
 1455  374 push(_elementName, spec, STATE_NO_CONTENT);
 1456    }
 1457   
 1458  106 private void enterReservedParameter()
 1459    {
 1460  106 String name = getAttribute("name");
 1461  106 IComponentSpecification cs = (IComponentSpecification) peekObject();
 1462   
 1463  106 cs.addReservedParameterName(name);
 1464   
 1465  106 push(_elementName, null, STATE_NO_CONTENT);
 1466    }
 1467   
 1468  1 private void enterService_3_0()
 1469    {
 1470  1 _errorHandler.error(_log, ParseMessages.serviceElementNotSupported(), getLocation(), null);
 1471   
 1472  1 push(_elementName, null, STATE_NO_CONTENT);
 1473    }
 1474   
 1475  1 private void enterSetMessage_3_0()
 1476    {
 1477  1 String name = getAttribute("name");
 1478  1 String key = getAttribute("key");
 1479   
 1480  1 BindingBeanInitializer bi = _factory.createBindingBeanInitializer(_bindingSource);
 1481   
 1482  1 bi.setPropertyName(name);
 1483  1 bi.setBindingReference(BindingConstants.MESSAGE_PREFIX + ":" + key);
 1484  1 bi.setLocation(getLocation());
 1485   
 1486  1 IBeanSpecification bs = (IBeanSpecification) peekObject();
 1487   
 1488  1 bs.addInitializer(bi);
 1489   
 1490  1 push(_elementName, null, STATE_NO_CONTENT);
 1491    }
 1492   
 1493  3 private void enterSet()
 1494    {
 1495  3 String name = getAttribute("name");
 1496  3 String reference = getAttribute("value");
 1497   
 1498  3 BindingBeanInitializer bi = _factory.createBindingBeanInitializer(_bindingSource);
 1499   
 1500  3 bi.setPropertyName(name);
 1501   
 1502  3 IBeanSpecification bs = (IBeanSpecification) peekObject();
 1503   
 1504  3 push(_elementName, new BeanSetPropertySetter(bs, bi, null, reference), STATE_SET, false);
 1505    }
 1506   
 1507  5 private void enterSetProperty_3_0()
 1508    {
 1509  5 String name = getAttribute("name");
 1510  5 String expression = getAttribute("expression");
 1511   
 1512  5 BindingBeanInitializer bi = _factory.createBindingBeanInitializer(_bindingSource);
 1513   
 1514  5 bi.setPropertyName(name);
 1515   
 1516  5 IBeanSpecification bs = (IBeanSpecification) peekObject();
 1517   
 1518  5 push(_elementName, new BeanSetPropertySetter(bs, bi, BindingConstants.OGNL_PREFIX + ":",
 1519    expression), STATE_SET, false);
 1520    }
 1521   
 1522  31 private void enterStaticBinding_3_0()
 1523    {
 1524  31 String name = getAttribute("name");
 1525  31 String expression = getAttribute("value");
 1526   
 1527  31 IContainedComponent cc = (IContainedComponent) peekObject();
 1528   
 1529  31 BindingSetter bs = new BindingSetter(cc, name, expression);
 1530   
 1531  31 push(_elementName, bs, STATE_STATIC_BINDING, false);
 1532    }
 1533   
 1534  547 private void expectElement(String elementName)
 1535    {
 1536  547 if (_elementName.equals(elementName))
 1537  546 return;
 1538   
 1539  1 throw new DocumentParseException(ParseMessages.incorrectDocumentType(
 1540    _elementName,
 1541    elementName), getLocation(), null);
 1542   
 1543    }
 1544   
 1545  20874 private String getAttribute(String name)
 1546    {
 1547  20874 return (String) _attributes.get(name);
 1548    }
 1549   
 1550  4602 private boolean getBooleanAttribute(String name, boolean defaultValue)
 1551    {
 1552  4602 String value = getAttribute(name);
 1553   
 1554  4602 if (value == null)
 1555  85 return defaultValue;
 1556   
 1557  4517 Boolean b = (Boolean) CONVERSION_MAP.get(value);
 1558   
 1559  4517 return b.booleanValue();
 1560    }
 1561   
 1562  35 private Object getConvertedAttribute(String name, Object defaultValue)
 1563    {
 1564  35 String key = getAttribute(name);
 1565   
 1566  35 if (key == null)
 1567  0 return defaultValue;
 1568   
 1569  35 return CONVERSION_MAP.get(key);
 1570    }
 1571   
 1572  547 private InputSource getDTDInputSource(String name)
 1573    {
 1574  547 InputStream stream = getClass().getResourceAsStream(name);
 1575   
 1576  547 return new InputSource(stream);
 1577    }
 1578   
 1579  571 private String getExtendedValue(String attributeValue, String attributeName, boolean required)
 1580    {
 1581  571 String contentValue = peekContent();
 1582   
 1583  571 boolean asAttribute = HiveMind.isNonBlank(attributeValue);
 1584  571 boolean asContent = HiveMind.isNonBlank(contentValue);
 1585   
 1586  571 if (asAttribute && asContent)
 1587    {
 1588  1 throw new DocumentParseException(ParseMessages.noAttributeAndBody(
 1589    attributeName,
 1590    _elementName), getLocation(), null);
 1591    }
 1592   
 1593  570 if (required && !(asAttribute || asContent))
 1594    {
 1595  1 throw new DocumentParseException(ParseMessages.requiredExtendedAttribute(
 1596    _elementName,
 1597    attributeName), getLocation(), null);
 1598    }
 1599   
 1600  569 if (asAttribute)
 1601  393 return attributeValue;
 1602   
 1603  176 return contentValue;
 1604    }
 1605   
 1606  6580 private String getValidatedAttribute(String name, String pattern, String errorKey)
 1607    {
 1608  6580 String value = getAttribute(name);
 1609   
 1610  6580 if (value == null)
 1611  1355 return null;
 1612   
 1613  5225 if (_matcher.matches(pattern, value))
 1614  5218 return value;
 1615   
 1616  7 throw new InvalidStringException(ParseMessages.invalidAttribute(errorKey, value), value,
 1617    getLocation());
 1618    }
 1619   
 1620  549 protected void initializeParser(Resource resource, int startState)
 1621    {
 1622  549 super.initializeParser(resource, startState);
 1623   
 1624  549 _rootObject = null;
 1625  549 _attributes = new HashMap();
 1626    }
 1627   
 1628  43 public IApplicationSpecification parseApplicationSpecification(Resource resource)
 1629    {
 1630  43 initializeParser(resource, STATE_APPLICATION_SPECIFICATION_INITIAL);
 1631   
 1632  43 try
 1633    {
 1634  43 parseDocument();
 1635   
 1636  38 return (IApplicationSpecification) _rootObject;
 1637    }
 1638    finally
 1639    {
 1640  43 resetParser();
 1641    }
 1642    }
 1643   
 1644  337 public IComponentSpecification parseComponentSpecification(Resource resource)
 1645    {
 1646  337 initializeParser(resource, STATE_COMPONENT_SPECIFICATION_INITIAL);
 1647   
 1648  337 try
 1649    {
 1650  337 parseDocument();
 1651   
 1652  330 return (IComponentSpecification) _rootObject;
 1653    }
 1654    finally
 1655    {
 1656  337 resetParser();
 1657    }
 1658    }
 1659   
 1660  549 private void parseDocument()
 1661    {
 1662  549 InputStream stream = null;
 1663   
 1664  549 Resource resource = getResource();
 1665   
 1666  549 boolean success = false;
 1667   
 1668  549 try
 1669    {
 1670  549 if (_parser == null)
 1671  103 _parser = _parserFactory.newSAXParser();
 1672   
 1673  549 URL resourceURL = resource.getResourceURL();
 1674   
 1675  549 if (resourceURL == null)
 1676  0 throw new DocumentParseException(ParseMessages.missingResource(resource), resource,
 1677    null);
 1678   
 1679  549 InputStream rawStream = resourceURL.openStream();
 1680  549 stream = new BufferedInputStream(rawStream);
 1681   
 1682  549 _parser.parse(stream, this, resourceURL.toExternalForm());
 1683   
 1684  533 stream.close();
 1685  533 stream = null;
 1686   
 1687  533 success = true;
 1688    }
 1689    catch (SAXParseException ex)
 1690    {
 1691  1 _parser = null;
 1692   
 1693  1 Location location = new LocationImpl(resource, ex.getLineNumber(), ex.getColumnNumber());
 1694   
 1695  1 throw new DocumentParseException(ParseMessages.errorReadingResource(resource, ex),
 1696    location, ex);
 1697    }
 1698    catch (Exception ex)
 1699    {
 1700  15 _parser = null;
 1701   
 1702  15 throw new DocumentParseException(ParseMessages.errorReadingResource(resource, ex),
 1703    resource, ex);
 1704    }
 1705    finally
 1706    {
 1707  549 if (!success)
 1708  16 _parser = null;
 1709   
 1710  549 close(stream);
 1711    }
 1712    }
 1713   
 1714  65 public ILibrarySpecification parseLibrarySpecification(Resource resource)
 1715    {
 1716  65 initializeParser(resource, STATE_LIBRARY_SPECIFICATION_INITIAL);
 1717   
 1718  65 try
 1719    {
 1720  65 parseDocument();
 1721   
 1722  63 return (ILibrarySpecification) _rootObject;
 1723    }
 1724    finally
 1725    {
 1726  65 resetParser();
 1727    }
 1728    }
 1729   
 1730  104 public IComponentSpecification parsePageSpecification(Resource resource)
 1731    {
 1732  104 initializeParser(resource, STATE_PAGE_SPECIFICATION_INITIAL);
 1733   
 1734  104 try
 1735    {
 1736  104 parseDocument();
 1737   
 1738  102 return (IComponentSpecification) _rootObject;
 1739    }
 1740    finally
 1741    {
 1742  104 resetParser();
 1743    }
 1744    }
 1745   
 1746  1619 protected String peekContent()
 1747    {
 1748  1619 String content = super.peekContent();
 1749   
 1750  1619 if (content == null)
 1751  510 return null;
 1752   
 1753  1109 return content.trim();
 1754    }
 1755   
 1756  549 protected void resetParser()
 1757    {
 1758  549 _rootObject = null;
 1759  549 _DTD_4_0 = false;
 1760   
 1761  549 _attributes.clear();
 1762    }
 1763   
 1764    /**
 1765    * Resolved an external entity, which is assumed to be the doctype. Might need a check to ensure
 1766    * that specs without a doctype fail.
 1767    */
 1768  548 public InputSource resolveEntity(String publicId, String systemId) throws SAXException
 1769    {
 1770  548 if (TAPESTRY_DTD_4_0_PUBLIC_ID.equals(publicId))
 1771    {
 1772  328 _DTD_4_0 = true;
 1773  328 return getDTDInputSource("Tapestry_4_0.dtd");
 1774    }
 1775   
 1776  220 if (TAPESTRY_DTD_3_0_PUBLIC_ID.equals(publicId))
 1777  219 return getDTDInputSource("Tapestry_3_0.dtd");
 1778   
 1779  1 throw new DocumentParseException(ParseMessages.unknownPublicId(getResource(), publicId),
 1780    new LocationImpl(getResource()), null);
 1781    }
 1782   
 1783    /** @since 4.0 */
 1784  56 public void setBindingSource(BindingSource bindingSource)
 1785    {
 1786  56 _bindingSource = bindingSource;
 1787    }
 1788   
 1789    /** @since 4.0 */
 1790  64 public void setValueConverter(ValueConverter valueConverter)
 1791    {
 1792  64 _valueConverter = valueConverter;
 1793    }
 1794    }