Clover coverage report - Code Coverage for tapestry release 4.0-beta-6
Coverage timestamp: Wed Sep 7 2005 18:41:34 EDT
file stats: LOC: 1,792   Methods: 76
NCLOC: 1,112   Classes: 1
 
 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  6713 protected void begin(String elementName, Map attributes)
 380    {
 381  6713 _elementName = elementName;
 382  6713 _attributes = attributes;
 383   
 384  6713 switch (getState())
 385    {
 386  337 case STATE_COMPONENT_SPECIFICATION_INITIAL:
 387   
 388  337 beginComponentSpecificationInitial();
 389  336 break;
 390   
 391  105 case STATE_PAGE_SPECIFICATION_INITIAL:
 392   
 393  105 beginPageSpecificationInitial();
 394  105 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  2194 case STATE_COMPONENT_SPECIFICATION:
 407   
 408  2194 beginComponentSpecification();
 409  2188 break;
 410   
 411  186 case STATE_PAGE_SPECIFICATION:
 412   
 413  186 beginPageSpecification();
 414  186 break;
 415   
 416  771 case STATE_ALLOW_DESCRIPTION:
 417   
 418  771 beginAllowDescription();
 419  771 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  771 private void beginAllowDescription()
 458    {
 459  771 if (_elementName.equals("description"))
 460    {
 461  771 enterDescription();
 462  771 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  2194 private void beginComponentSpecification()
 578    {
 579  2194 if (_elementName.equals("reserved-parameter"))
 580    {
 581  112 enterReservedParameter();
 582  112 return;
 583    }
 584   
 585  2082 if (_elementName.equals("parameter"))
 586    {
 587  1107 enterParameter();
 588  1106 return;
 589    }
 590   
 591    // The remainder are common to both <component-specification> and
 592    // <page-specification>
 593   
 594  975 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  1161 private void beginPageSpecification()
 685    {
 686  1161 if (_elementName.equals("component"))
 687    {
 688  276 enterComponent();
 689  272 return;
 690    }
 691   
 692  885 if (_elementName.equals("bean"))
 693    {
 694  34 enterBean();
 695  34 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  851 if (_elementName.equals("property-specification")
 702    || (_DTD_4_0 && _elementName.equals("property")))
 703    {
 704  126 enterProperty();
 705  126 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  105 private void beginPageSpecificationInitial()
 755    {
 756  105 expectElement("page-specification");
 757   
 758  105 IComponentSpecification cs = _factory.createComponentSpecification();
 759   
 760  105 String className = getAttribute("class");
 761   
 762  105 if (className != null)
 763  74 cs.setComponentClassName(className);
 764   
 765  105 cs.setSpecificationLocation(getResource());
 766  105 cs.setPageSpecification(true);
 767   
 768  105 _rootObject = cs;
 769   
 770  105 push(_elementName, cs, STATE_PAGE_SPECIFICATION);
 771    }
 772   
 773    /**
 774    * Close a stream (if not null), ignoring any errors.
 775    */
 776  550 private void close(InputStream stream)
 777    {
 778  550 try
 779    {
 780  550 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());
 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  6686 protected void end(String elementName)
 809    {
 810  6686 _elementName = elementName;
 811   
 812  6686 switch (getState())
 813    {
 814  1056 case STATE_DESCRIPTION:
 815   
 816  1056 endDescription();
 817  1056 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  126 case STATE_PROPERTY:
 850   
 851  126 endPropertySpecification();
 852  126 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  4951 default:
 865  4951 break;
 866    }
 867   
 868    // Pop the top element of the stack and continue processing from there.
 869   
 870  6684 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  1056 private void endDescription()
 897    {
 898  1056 DescriptionSetter setter = (DescriptionSetter) peekObject();
 899   
 900  1056 String description = peekContent();
 901   
 902  1056 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  126 private void endPropertySpecification()
 940    {
 941  126 IPropertySpecification ps = (IPropertySpecification) peekObject();
 942   
 943  126 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  126 if (initialValue != null && !_DTD_4_0)
 949  5 initialValue = BindingConstants.OGNL_PREFIX + ":" + initialValue;
 950   
 951  126 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  34 private void enterBean()
 999    {
 1000  34 String name = getValidatedAttribute("name", BEAN_NAME_PATTERN, "invalid-bean-name");
 1001   
 1002  34 String classAttribute = getAttribute("class");
 1003   
 1004    // Look for the lightweight initialization
 1005   
 1006  34 int commax = classAttribute.indexOf(',');
 1007   
 1008  34 String className = commax < 0 ? classAttribute : classAttribute.substring(0, commax);
 1009   
 1010  34 BeanLifecycle lifecycle = (BeanLifecycle) getConvertedAttribute(
 1011    "lifecycle",
 1012    BeanLifecycle.REQUEST);
 1013  34 String propertyName = getValidatedAttribute(
 1014    "property",
 1015    PROPERTY_NAME_PATTERN,
 1016    "invalid-property-name");
 1017   
 1018  34 IBeanSpecification bs = _factory.createBeanSpecification();
 1019   
 1020  34 bs.setClassName(className);
 1021  34 bs.setLifecycle(lifecycle);
 1022  34 bs.setPropertyName(propertyName);
 1023   
 1024  34 if (commax > 0)
 1025    {
 1026  1 String initializer = classAttribute.substring(commax + 1);
 1027  1 bs.addInitializer(new LightweightBeanInitializer(initializer));
 1028    }
 1029   
 1030  34 IComponentSpecification cs = (IComponentSpecification) peekObject();
 1031   
 1032  34 cs.addBeanSpecification(name, bs);
 1033   
 1034  34 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), getLocation());
 1113    }
 1114    else
 1115    {
 1116  271 if (HiveMind.isBlank(type))
 1117  1 throw new DocumentParseException(ParseMessages.missingTypeOrCopyOf(id),
 1118    getLocation());
 1119    }
 1120   
 1121  273 IContainedComponent cc = _factory.createContainedComponent();
 1122  273 cc.setType(type);
 1123  273 cc.setCopyOf(copyOf);
 1124  273 cc.setInheritInformalParameters(inherit);
 1125  273 cc.setPropertyName(propertyName);
 1126   
 1127  273 IComponentSpecification cs = (IComponentSpecification) peekObject();
 1128   
 1129  273 cs.addComponent(id, cc);
 1130   
 1131  273 if (hasCopyOf)
 1132  3 copyBindings(copyOf, cs, cc);
 1133   
 1134  272 push(_elementName, cc, STATE_COMPONENT);
 1135    }
 1136   
 1137  2040 private void enterComponentType()
 1138    {
 1139  2040 String type = getValidatedAttribute(
 1140    "type",
 1141    COMPONENT_ALIAS_PATTERN,
 1142    "invalid-component-type");
 1143  2039 String path = getAttribute("specification-path");
 1144   
 1145  2039 ILibrarySpecification ls = (ILibrarySpecification) peekObject();
 1146   
 1147  2039 ls.setComponentSpecificationPath(type, path);
 1148   
 1149  2039 push(_elementName, null, STATE_NO_CONTENT);
 1150    }
 1151   
 1152  30 private void enterConfigure()
 1153    {
 1154  30 String attributeName = _DTD_4_0 ? "property" : "property-name";
 1155   
 1156  30 String propertyName = getValidatedAttribute(
 1157    attributeName,
 1158    PROPERTY_NAME_PATTERN,
 1159    "invalid-property-name");
 1160   
 1161  30 String value = getAttribute("value");
 1162   
 1163  30 IExtensionSpecification es = (IExtensionSpecification) peekObject();
 1164   
 1165  30 ExtensionConfigurationSetter setter = new ExtensionConfigurationSetter(es, propertyName,
 1166    value);
 1167   
 1168  30 push(_elementName, setter, STATE_CONFIGURE, false);
 1169    }
 1170   
 1171  7 private void enterContextAsset_3_0()
 1172    {
 1173  7 enterAsset("path", "context:");
 1174    }
 1175   
 1176    /**
 1177    * New in the 4.0 DTD. When using the 4.0 DTD, you must explicitly specify prefix if the asset
 1178    * is not stored in the same domain as the specification file.
 1179    *
 1180    * @since 4.0
 1181    */
 1182   
 1183  27 private void enterAsset()
 1184    {
 1185  27 enterAsset("path", null);
 1186    }
 1187   
 1188  1056 private void enterDescription()
 1189    {
 1190  1056 push(_elementName, new DescriptionSetter(peekObject()), STATE_DESCRIPTION, false);
 1191    }
 1192   
 1193  11 private void enterExtension()
 1194    {
 1195  11 String name = getValidatedAttribute(
 1196    "name",
 1197    EXTENSION_NAME_PATTERN,
 1198    "invalid-extension-name");
 1199   
 1200  10 boolean immediate = getBooleanAttribute("immediate", false);
 1201  10 String className = getAttribute("class");
 1202   
 1203  10 IExtensionSpecification es = _factory.createExtensionSpecification(
 1204    _resolver,
 1205    _valueConverter);
 1206   
 1207  10 es.setClassName(className);
 1208  10 es.setImmediate(immediate);
 1209   
 1210  10 ILibrarySpecification ls = (ILibrarySpecification) peekObject();
 1211   
 1212  10 ls.addExtensionSpecification(name, es);
 1213   
 1214  10 push(_elementName, es, STATE_EXTENSION);
 1215    }
 1216   
 1217  3 private void enterExternalAsset_3_0()
 1218    {
 1219    // External URLs get no prefix, but will have a scheme (i.e., "http:") that
 1220    // fulfils much the same purpose.
 1221   
 1222  3 enterAsset("URL", null);
 1223    }
 1224   
 1225    /** A throwback to the 3.0 DTD */
 1226   
 1227  2 private void enterInheritedBinding_3_0()
 1228    {
 1229  2 String name = getAttribute("name");
 1230  2 String parameterName = getAttribute("parameter-name");
 1231   
 1232  2 IBindingSpecification bs = _factory.createBindingSpecification();
 1233  2 bs.setType(BindingType.INHERITED);
 1234  2 bs.setValue(parameterName);
 1235   
 1236  2 IContainedComponent cc = (IContainedComponent) peekObject();
 1237   
 1238  2 cc.setBinding(name, bs);
 1239   
 1240  2 push(_elementName, null, STATE_NO_CONTENT);
 1241    }
 1242   
 1243  23 private void enterLibrary()
 1244    {
 1245  23 String libraryId = getValidatedAttribute("id", LIBRARY_ID_PATTERN, "invalid-library-id");
 1246  22 String path = getAttribute("specification-path");
 1247   
 1248  22 if (libraryId.equals(INamespace.FRAMEWORK_NAMESPACE)
 1249    || libraryId.equals(INamespace.APPLICATION_NAMESPACE))
 1250  1 throw new DocumentParseException(ParseMessages
 1251    .frameworkLibraryIdIsReserved(INamespace.FRAMEWORK_NAMESPACE), getLocation());
 1252   
 1253  21 ILibrarySpecification ls = (ILibrarySpecification) peekObject();
 1254   
 1255  21 ls.setLibrarySpecificationPath(libraryId, path);
 1256   
 1257  21 push(_elementName, null, STATE_NO_CONTENT);
 1258    }
 1259   
 1260  4 private void enterListenerBinding()
 1261    {
 1262  4 String name = getAttribute("name");
 1263  4 String language = getAttribute("language");
 1264   
 1265  4 IContainedComponent cc = (IContainedComponent) peekObject();
 1266  4 BindingSetter bs = new BindingSetter(cc, name, language);
 1267   
 1268  4 push(_elementName, bs, STATE_LISTENER_BINDING, false);
 1269    }
 1270   
 1271  4 private void enterMessageBinding_3_0()
 1272    {
 1273  4 String name = getAttribute("name");
 1274  4 String key = getAttribute("key");
 1275   
 1276  4 IBindingSpecification bs = _factory.createBindingSpecification();
 1277  4 bs.setType(BindingType.PREFIXED);
 1278  4 bs.setValue(BindingConstants.MESSAGE_PREFIX + ":" + key);
 1279  4 bs.setLocation(getLocation());
 1280   
 1281  4 IContainedComponent cc = (IContainedComponent) peekObject();
 1282   
 1283  4 cc.setBinding(name, bs);
 1284   
 1285  4 push(_elementName, null, STATE_NO_CONTENT);
 1286    }
 1287   
 1288  501 private void enterPage()
 1289    {
 1290  501 String name = getValidatedAttribute("name", PAGE_NAME_PATTERN, "invalid-page-name");
 1291  500 String path = getAttribute("specification-path");
 1292   
 1293  500 ILibrarySpecification ls = (ILibrarySpecification) peekObject();
 1294   
 1295  500 ls.setPageSpecificationPath(name, path);
 1296   
 1297  500 push(_elementName, null, STATE_NO_CONTENT);
 1298    }
 1299   
 1300  1107 private void enterParameter()
 1301    {
 1302  1107 IParameterSpecification ps = _factory.createParameterSpecification();
 1303   
 1304  1107 String name = getValidatedAttribute(
 1305    "name",
 1306    PARAMETER_NAME_PATTERN,
 1307    "invalid-parameter-name");
 1308   
 1309  1106 String attributeName = _DTD_4_0 ? "property" : "property-name";
 1310   
 1311  1106 String propertyName = getValidatedAttribute(
 1312    attributeName,
 1313    PROPERTY_NAME_PATTERN,
 1314    "invalid-property-name");
 1315   
 1316  1106 if (propertyName == null)
 1317  1010 propertyName = name;
 1318   
 1319  1106 ps.setParameterName(name);
 1320  1106 ps.setPropertyName(propertyName);
 1321   
 1322  1106 ps.setRequired(getBooleanAttribute("required", false));
 1323   
 1324    // In the 3.0 DTD, default-value was always an OGNL expression.
 1325    // Starting with 4.0, it's like a binding (prefixed). For a 3.0
 1326    // DTD, we supply the "ognl:" prefix.
 1327   
 1328  1106 String defaultValue = getAttribute("default-value");
 1329   
 1330  1106 if (defaultValue != null && !_DTD_4_0)
 1331  7 defaultValue = BindingConstants.OGNL_PREFIX + ":" + defaultValue;
 1332   
 1333  1106 ps.setDefaultValue(defaultValue);
 1334   
 1335  1106 if (!_DTD_4_0)
 1336    {
 1337    // When direction=auto (in a 3.0 DTD), turn caching off
 1338   
 1339  44 String direction = getAttribute("direction");
 1340  44 ps.setCache(!"auto".equals(direction));
 1341    }
 1342    else
 1343    {
 1344  1062 boolean cache = getBooleanAttribute("cache", true);
 1345  1062 ps.setCache(cache);
 1346    }
 1347   
 1348    // type will only be specified in a 3.0 DTD.
 1349   
 1350  1106 String type = getAttribute("type");
 1351   
 1352  1106 if (type != null)
 1353  38 ps.setType(type);
 1354   
 1355    // aliases is new in the 4.0 DTD
 1356   
 1357  1106 String aliases = getAttribute("aliases");
 1358   
 1359  1106 ps.setAliases(aliases);
 1360  1106 ps.setDeprecated(getBooleanAttribute("deprecated", false));
 1361   
 1362  1106 IComponentSpecification cs = (IComponentSpecification) peekObject();
 1363   
 1364  1106 cs.addParameter(ps);
 1365   
 1366  1106 push(_elementName, ps, STATE_ALLOW_DESCRIPTION);
 1367    }
 1368   
 1369  8 private void enterPrivateAsset_3_0()
 1370    {
 1371  8 enterAsset("resource-path", "classpath:");
 1372    }
 1373   
 1374    /** @since 4.0 */
 1375  11 private void enterMeta()
 1376    {
 1377  11 String key = getAttribute("key");
 1378  11 String value = getAttribute("value");
 1379   
 1380    // Value may be null, in which case the value is set from the element content
 1381   
 1382  11 IPropertyHolder ph = (IPropertyHolder) peekObject();
 1383   
 1384  11 push(_elementName, new PropertyValueSetter(ph, key, value), STATE_META, false);
 1385    }
 1386   
 1387  47 private void enterProperty_3_0()
 1388    {
 1389  47 String name = getAttribute("name");
 1390  47 String value = getAttribute("value");
 1391   
 1392    // Value may be null, in which case the value is set from the element content
 1393   
 1394  47 IPropertyHolder ph = (IPropertyHolder) peekObject();
 1395   
 1396  47 push(_elementName, new PropertyValueSetter(ph, name, value), STATE_META, false);
 1397    }
 1398   
 1399    /**
 1400    * &tl;property&gt; in 4.0, or &lt;property-specification&gt; in 3.0
 1401    */
 1402   
 1403  126 private void enterProperty()
 1404    {
 1405  126 String name = getValidatedAttribute("name", PROPERTY_NAME_PATTERN, "invalid-property-name");
 1406  126 String type = getAttribute("type");
 1407   
 1408  126 String persistence = null;
 1409   
 1410  126 if (_DTD_4_0)
 1411  73 persistence = getAttribute("persist");
 1412    else
 1413  53 persistence = getBooleanAttribute("persistent", false) ? "session" : null;
 1414   
 1415  126 String initialValue = getAttribute("initial-value");
 1416   
 1417  126 IPropertySpecification ps = _factory.createPropertySpecification();
 1418  126 ps.setName(name);
 1419   
 1420  126 if (HiveMind.isNonBlank(type))
 1421  50 ps.setType(type);
 1422   
 1423  126 ps.setPersistence(persistence);
 1424  126 ps.setInitialValue(initialValue);
 1425   
 1426  126 IComponentSpecification cs = (IComponentSpecification) peekObject();
 1427  126 cs.addPropertySpecification(ps);
 1428   
 1429  126 push(_elementName, ps, STATE_PROPERTY, false);
 1430    }
 1431   
 1432    /**
 1433    * @since 4.0
 1434    */
 1435   
 1436  374 private void enterInject()
 1437    {
 1438  374 String property = getValidatedAttribute(
 1439    "property",
 1440    PROPERTY_NAME_PATTERN,
 1441    "invalid-property-name");
 1442  374 String type = getAttribute("type");
 1443  374 String objectReference = getAttribute("object");
 1444   
 1445  374 InjectSpecification spec = _factory.createInjectSpecification();
 1446   
 1447  374 spec.setProperty(property);
 1448  374 spec.setType(type);
 1449  374 spec.setObject(objectReference);
 1450  374 IComponentSpecification cs = (IComponentSpecification) peekObject();
 1451   
 1452  374 cs.addInjectSpecification(spec);
 1453   
 1454  374 push(_elementName, spec, STATE_NO_CONTENT);
 1455    }
 1456   
 1457  112 private void enterReservedParameter()
 1458    {
 1459  112 String name = getAttribute("name");
 1460  112 IComponentSpecification cs = (IComponentSpecification) peekObject();
 1461   
 1462  112 cs.addReservedParameterName(name);
 1463   
 1464  112 push(_elementName, null, STATE_NO_CONTENT);
 1465    }
 1466   
 1467  1 private void enterService_3_0()
 1468    {
 1469  1 _errorHandler.error(_log, ParseMessages.serviceElementNotSupported(), getLocation(), null);
 1470   
 1471  1 push(_elementName, null, STATE_NO_CONTENT);
 1472    }
 1473   
 1474  1 private void enterSetMessage_3_0()
 1475    {
 1476  1 String name = getAttribute("name");
 1477  1 String key = getAttribute("key");
 1478   
 1479  1 BindingBeanInitializer bi = _factory.createBindingBeanInitializer(_bindingSource);
 1480   
 1481  1 bi.setPropertyName(name);
 1482  1 bi.setBindingReference(BindingConstants.MESSAGE_PREFIX + ":" + key);
 1483  1 bi.setLocation(getLocation());
 1484   
 1485  1 IBeanSpecification bs = (IBeanSpecification) peekObject();
 1486   
 1487  1 bs.addInitializer(bi);
 1488   
 1489  1 push(_elementName, null, STATE_NO_CONTENT);
 1490    }
 1491   
 1492  3 private void enterSet()
 1493    {
 1494  3 String name = getAttribute("name");
 1495  3 String reference = getAttribute("value");
 1496   
 1497  3 BindingBeanInitializer bi = _factory.createBindingBeanInitializer(_bindingSource);
 1498   
 1499  3 bi.setPropertyName(name);
 1500   
 1501  3 IBeanSpecification bs = (IBeanSpecification) peekObject();
 1502   
 1503  3 push(_elementName, new BeanSetPropertySetter(bs, bi, null, reference), STATE_SET, false);
 1504    }
 1505   
 1506  5 private void enterSetProperty_3_0()
 1507    {
 1508  5 String name = getAttribute("name");
 1509  5 String expression = getAttribute("expression");
 1510   
 1511  5 BindingBeanInitializer bi = _factory.createBindingBeanInitializer(_bindingSource);
 1512   
 1513  5 bi.setPropertyName(name);
 1514   
 1515  5 IBeanSpecification bs = (IBeanSpecification) peekObject();
 1516   
 1517  5 push(_elementName, new BeanSetPropertySetter(bs, bi, BindingConstants.OGNL_PREFIX + ":",
 1518    expression), STATE_SET, false);
 1519    }
 1520   
 1521  31 private void enterStaticBinding_3_0()
 1522    {
 1523  31 String name = getAttribute("name");
 1524  31 String expression = getAttribute("value");
 1525   
 1526  31 IContainedComponent cc = (IContainedComponent) peekObject();
 1527   
 1528  31 BindingSetter bs = new BindingSetter(cc, name, expression);
 1529   
 1530  31 push(_elementName, bs, STATE_STATIC_BINDING, false);
 1531    }
 1532   
 1533  548 private void expectElement(String elementName)
 1534    {
 1535  548 if (_elementName.equals(elementName))
 1536  547 return;
 1537   
 1538  1 throw new DocumentParseException(ParseMessages.incorrectDocumentType(
 1539    _elementName,
 1540    elementName), getLocation(), null);
 1541   
 1542    }
 1543   
 1544  19837 private String getAttribute(String name)
 1545    {
 1546  19837 return (String) _attributes.get(name);
 1547    }
 1548   
 1549  4620 private boolean getBooleanAttribute(String name, boolean defaultValue)
 1550    {
 1551  4620 String value = getAttribute(name);
 1552   
 1553  4620 if (value == null)
 1554  85 return defaultValue;
 1555   
 1556  4535 Boolean b = (Boolean) CONVERSION_MAP.get(value);
 1557   
 1558  4535 return b.booleanValue();
 1559    }
 1560   
 1561  34 private Object getConvertedAttribute(String name, Object defaultValue)
 1562    {
 1563  34 String key = getAttribute(name);
 1564   
 1565  34 if (key == null)
 1566  0 return defaultValue;
 1567   
 1568  34 return CONVERSION_MAP.get(key);
 1569    }
 1570   
 1571  548 private InputSource getDTDInputSource(String name)
 1572    {
 1573  548 InputStream stream = getClass().getResourceAsStream(name);
 1574   
 1575  548 return new InputSource(stream);
 1576    }
 1577   
 1578  574 private String getExtendedValue(String attributeValue, String attributeName, boolean required)
 1579    {
 1580  574 String contentValue = peekContent();
 1581   
 1582  574 boolean asAttribute = HiveMind.isNonBlank(attributeValue);
 1583  574 boolean asContent = HiveMind.isNonBlank(contentValue);
 1584   
 1585  574 if (asAttribute && asContent)
 1586    {
 1587  1 throw new DocumentParseException(ParseMessages.noAttributeAndBody(
 1588    attributeName,
 1589    _elementName), getLocation(), null);
 1590    }
 1591   
 1592  573 if (required && !(asAttribute || asContent))
 1593    {
 1594  1 throw new DocumentParseException(ParseMessages.requiredExtendedAttribute(
 1595    _elementName,
 1596    attributeName), getLocation(), null);
 1597    }
 1598   
 1599  572 if (asAttribute)
 1600  396 return attributeValue;
 1601   
 1602  176 return contentValue;
 1603    }
 1604   
 1605  6593 private String getValidatedAttribute(String name, String pattern, String errorKey)
 1606    {
 1607  6593 String value = getAttribute(name);
 1608   
 1609  6593 if (value == null)
 1610  1360 return null;
 1611   
 1612  5233 if (_matcher.matches(pattern, value))
 1613  5226 return value;
 1614   
 1615  7 throw new InvalidStringException(ParseMessages.invalidAttribute(errorKey, value), value,
 1616    getLocation());
 1617    }
 1618   
 1619  550 protected void initializeParser(Resource resource, int startState)
 1620    {
 1621  550 super.initializeParser(resource, startState);
 1622   
 1623  550 _rootObject = null;
 1624  550 _attributes = new HashMap();
 1625    }
 1626   
 1627  43 public IApplicationSpecification parseApplicationSpecification(Resource resource)
 1628    {
 1629  43 initializeParser(resource, STATE_APPLICATION_SPECIFICATION_INITIAL);
 1630   
 1631  43 try
 1632    {
 1633  43 parseDocument();
 1634   
 1635  38 return (IApplicationSpecification) _rootObject;
 1636    }
 1637    finally
 1638    {
 1639  43 resetParser();
 1640    }
 1641    }
 1642   
 1643  337 public IComponentSpecification parseComponentSpecification(Resource resource)
 1644    {
 1645  337 initializeParser(resource, STATE_COMPONENT_SPECIFICATION_INITIAL);
 1646   
 1647  337 try
 1648    {
 1649  337 parseDocument();
 1650   
 1651  330 return (IComponentSpecification) _rootObject;
 1652    }
 1653    finally
 1654    {
 1655  337 resetParser();
 1656    }
 1657    }
 1658   
 1659  550 private void parseDocument()
 1660    {
 1661  550 InputStream stream = null;
 1662   
 1663  550 Resource resource = getResource();
 1664   
 1665  550 boolean success = false;
 1666   
 1667  550 try
 1668    {
 1669  550 if (_parser == null)
 1670  103 _parser = _parserFactory.newSAXParser();
 1671   
 1672  550 URL resourceURL = resource.getResourceURL();
 1673   
 1674  550 if (resourceURL == null)
 1675  0 throw new DocumentParseException(ParseMessages.missingResource(resource), resource);
 1676   
 1677  550 InputStream rawStream = resourceURL.openStream();
 1678  550 stream = new BufferedInputStream(rawStream);
 1679   
 1680  550 _parser.parse(stream, this, resourceURL.toExternalForm());
 1681   
 1682  534 stream.close();
 1683  534 stream = null;
 1684   
 1685  534 success = true;
 1686    }
 1687    catch (SAXParseException ex)
 1688    {
 1689  1 _parser = null;
 1690   
 1691  1 Location location = new LocationImpl(resource, ex.getLineNumber(), ex.getColumnNumber());
 1692   
 1693  1 throw new DocumentParseException(ParseMessages.errorReadingResource(resource, ex),
 1694    location, ex);
 1695    }
 1696    catch (Exception ex)
 1697    {
 1698  15 _parser = null;
 1699   
 1700  15 throw new DocumentParseException(ParseMessages.errorReadingResource(resource, ex),
 1701    resource, ex);
 1702    }
 1703    finally
 1704    {
 1705  550 if (!success)
 1706  16 _parser = null;
 1707   
 1708  550 close(stream);
 1709    }
 1710    }
 1711   
 1712  65 public ILibrarySpecification parseLibrarySpecification(Resource resource)
 1713    {
 1714  65 initializeParser(resource, STATE_LIBRARY_SPECIFICATION_INITIAL);
 1715   
 1716  65 try
 1717    {
 1718  65 parseDocument();
 1719   
 1720  63 return (ILibrarySpecification) _rootObject;
 1721    }
 1722    finally
 1723    {
 1724  65 resetParser();
 1725    }
 1726    }
 1727   
 1728  105 public IComponentSpecification parsePageSpecification(Resource resource)
 1729    {
 1730  105 initializeParser(resource, STATE_PAGE_SPECIFICATION_INITIAL);
 1731   
 1732  105 try
 1733    {
 1734  105 parseDocument();
 1735   
 1736  103 return (IComponentSpecification) _rootObject;
 1737    }
 1738    finally
 1739    {
 1740  105 resetParser();
 1741    }
 1742    }
 1743   
 1744  1634 protected String peekContent()
 1745    {
 1746  1634 String content = super.peekContent();
 1747   
 1748  1634 if (content == null)
 1749  513 return null;
 1750   
 1751  1121 return content.trim();
 1752    }
 1753   
 1754  550 protected void resetParser()
 1755    {
 1756  550 _rootObject = null;
 1757  550 _DTD_4_0 = false;
 1758   
 1759  550 _attributes.clear();
 1760    }
 1761   
 1762    /**
 1763    * Resolved an external entity, which is assumed to be the doctype. Might need a check to ensure
 1764    * that specs without a doctype fail.
 1765    */
 1766  549 public InputSource resolveEntity(String publicId, String systemId) throws SAXException
 1767    {
 1768  549 if (TAPESTRY_DTD_4_0_PUBLIC_ID.equals(publicId))
 1769    {
 1770  329 _DTD_4_0 = true;
 1771  329 return getDTDInputSource("Tapestry_4_0.dtd");
 1772    }
 1773   
 1774  220 if (TAPESTRY_DTD_3_0_PUBLIC_ID.equals(publicId))
 1775  219 return getDTDInputSource("Tapestry_3_0.dtd");
 1776   
 1777  1 throw new DocumentParseException(ParseMessages.unknownPublicId(getResource(), publicId),
 1778    new LocationImpl(getResource()), null);
 1779    }
 1780   
 1781    /** @since 4.0 */
 1782  56 public void setBindingSource(BindingSource bindingSource)
 1783    {
 1784  56 _bindingSource = bindingSource;
 1785    }
 1786   
 1787    /** @since 4.0 */
 1788  64 public void setValueConverter(ValueConverter valueConverter)
 1789    {
 1790  64 _valueConverter = valueConverter;
 1791    }
 1792    }