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