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