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