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