Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
   // Copyright 2004, 2005 The Apache Software Foundation
   //
   // Licensed under the Apache License, Version 2.0 (the "License");
   // you may not use this file except in compliance with the License.
   // You may obtain a copy of the License at
   //
   //     http://www.apache.org/licenses/LICENSE-2.0
   //
   // Unless required by applicable law or agreed to in writing, software
  // distributed under the License is distributed on an "AS IS" BASIS,
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  // See the License for the specific language governing permissions and
  // limitations under the License.
  
  package org.apache.tapestry.parse;
  
  import  org.apache.hivemind.*;
  import  org.apache.hivemind.impl.DefaultErrorHandler;
  import  org.apache.hivemind.impl.LocationImpl;
  import  org.apache.hivemind.parse.AbstractParser;
  
  import java.net.URL;
  import java.util.HashMap;
  import java.util.Map;

Parses the different types of Tapestry specifications.

Not threadsafe; it is the callers responsibility to ensure thread safety.

Author(s):
Howard Lewis Ship
  
  public class SpecificationParser extends AbstractParser implements ISpecificationParser
  {
    
Perl5 pattern for asset names. Letter, followed by letter, number or underscore. Also allows the special "$template" value.

Since:
2.2
  
  
      public static final String ASSET_NAME_PATTERN = "(\\$template)|(" + . + ")";

    
Perl5 pattern for helper bean names. Letter, followed by letter, number or underscore.

Since:
2.2
  
  
      public static final String BEAN_NAME_PATTERN = .;
  
      public static final String IDENTIFIER_PATTERN = "_?[a-zA-Z]\\w*";
      
      public static final String EXTENDED_IDENTIFIER_PATTERN = "_?[a-zA-Z](\\w|-)*";
    
    
Perl5 pattern for component type (which was known as an "alias" in earlier versions of Tapestry). This is either a simple property name, or a series of property names seperated by slashes (the latter being new in Tapestry 4.0). This defines a literal that can appear in a library or application specification.

Since:
2.2
  
  
      public static final String COMPONENT_ALIAS_PATTERN = "^(" +  + "/)*"
              +  + "$";

    
Perl5 pattern for component ids. Letter, followed by letter, number or underscore.

Since:
2.2
  
  
      public static final String COMPONENT_ID_PATTERN = .;

    
Perl5 pattern for component types (i.e., the type attribute of the <component> element). Component types are an optional namespace prefix followed by a component type (within the library defined by the namespace). Starting in 4.0, the type portion is actually a series of identifiers seperated by slashes.

Since:
2.2
 
 
     public static final String COMPONENT_TYPE_PATTERN = "^(" +  + ":)?" + "("
             +  + "/)*" +  + "$";

    
Extended version of Tapestry.SIMPLE_PROPERTY_NAME_PATTERN, but allows a series of individual property names, seperated by periods. In addition, each name within the dotted sequence is allowed to contain dashes.

Since:
2.2
 
 
     public static final String EXTENDED_PROPERTY_NAME_PATTERN = "^" + 
             + "(\\." +  + ")*$";

    
Per5 pattern for extension names. Letter followed by letter, number, dash, period or underscore.

Since:
2.2
 
 
     public static final String EXTENSION_NAME_PATTERN = ;

    
Perl5 pattern for library ids. Letter followed by letter, number or underscore.

Since:
2.2
 
 
     public static final String LIBRARY_ID_PATTERN = .;
    
    
Perl5 pattern for page names. Page names appear in library and application specifications, in the <page> element. Starting with 4.0, the page name may look more like a path name, consisting of a number of ids seperated by slashes. This is used to determine the folder which contains the page specification or the page's template.

Since:
2.2
 
 
     public static final String PAGE_NAME_PATTERN = "^" +  + "(/" +  + ")*$";

    
Perl5 pattern that parameter names must conform to. Letter, followed by letter, number or underscore.

Since:
2.2
 
 
     public static final String PARAMETER_NAME_PATTERN = .;

    
Perl5 pattern that property names (that can be connected to parameters) must conform to. Letter, followed by letter, number or underscore.

Since:
2.2
 
 
     public static final String PROPERTY_NAME_PATTERN = .;

    
Perl5 pattern for service names. Letter followed by letter, number, dash, underscore or period.

Deprecated:
As of release 4.0, the <service> element (in 3.0 DTDs) is no longer supported.
Since:
2.2
 
 
     public static final String SERVICE_NAME_PATTERN = ;
    
    

Since:
3.0
 
 
     public static final String TAPESTRY_DTD_3_0_PUBLIC_ID = "-//Apache Software Foundation//Tapestry Specification 3.0//EN";

    

Since:
4.0
 
 
     public static final String TAPESTRY_DTD_4_0_PUBLIC_ID = "-//Apache Software Foundation//Tapestry Specification 4.0//EN";

    

Since:
4.1
 
     
     public static final String TAPESTRY_DTD_4_1_PUBLIC_ID = "-//Apache Software Foundation//Tapestry Specification 4.1//EN";
     
     private static final int STATE_ALLOW_DESCRIPTION = 2000;
 
     private static final int STATE_ALLOW_PROPERTY = 2001;
 
     private static final int STATE_APPLICATION_SPECIFICATION_INITIAL = 1002;
 
     private static final int STATE_BEAN = 4;

    
Very different between 3.0 and 4.0 DTD.
 
 
     private static final int STATE_BINDING_3_0 = 7;

    

Since:
4.0
 
 
     private static final int STATE_BINDING = 100;
 
     private static final int STATE_COMPONENT = 6;
 
     private static final int STATE_COMPONENT_SPECIFICATION = 1;
 
     private static final int STATE_COMPONENT_SPECIFICATION_INITIAL = 1000;
 
     private static final int STATE_CONFIGURE = 14;
 
     private static final int STATE_DESCRIPTION = 2;
 
     private static final int STATE_EXTENSION = 13;
 
     private static final int STATE_LIBRARY_SPECIFICATION = 12;
 
     private static final int STATE_LIBRARY_SPECIFICATION_INITIAL = 1003;
 
     private static final int STATE_LISTENER_BINDING = 8;
 
     private static final int STATE_NO_CONTENT = 3000;
 
     private static final int STATE_PAGE_SPECIFICATION = 11;
 
     private static final int STATE_PAGE_SPECIFICATION_INITIAL = 1001;
 
     private static final int STATE_META = 3;
 
     private static final int STATE_PROPERTY = 10;
 
     private static final int STATE_SET = 5;

    
3.0 DTD only.
 
     private static final int STATE_STATIC_BINDING = 9;
    
    
We can share a single map for all the XML attribute to object conversions, since the keys are unique.
 
 
     private final Map _conversionMap = new HashMap();

    

Since:
4.0
 
     private final Log _log;

    

Since:
4.0
 
     private final ErrorHandler _errorHandler;

    
Set to true if parsing the 4.0 DTD.

Since:
4.0
 
 
     private boolean _dtd40;

    
The attributes of the current element, as a map (string keyed on string).
 
 
     private Map _attributes;

    
The name of the current element.
 
 
     private String _elementName;

    

Since:
1.0.9
 
 
     private final SpecFactory _factory;
 
     private RegexpMatcher _matcher = new RegexpMatcher();
 
     private SAXParser _parser;
 
     private SAXParserFactory _parserFactory = SAXParserFactory.newInstance();

    

Since:
3.0
 
 
     private final ClassResolver _resolver;

    

Since:
4.0
 
 
     private BindingSource _bindingSource;

    
The root object parsed: a component or page specification, a library specification, or an application specification.
 
     private Object _rootObject;

    

Since:
4.0
 
 
     private ValueConverter _valueConverter;
 
     // Identify all the different acceptible values.
     // We continue to sneak by with a single map because
     // there aren't conflicts; when we have 'foo' meaning
     // different things in different places in the DTD, we'll
     // need multiple maps.
 
     {
 
         .put("true".);
         .put("t".);
         .put("1".);
         .put("y".);
         .put("yes".);
         .put("on".);
         .put("aye".);
 
         .put("false".);
         .put("f".);
         .put("0".);
         .put("off".);
         .put("no".);
         .put("n".);
         .put("nay".);
 
         .put("none".);
         .put("request".);
         .put("page".);
         .put("render".);
 
         .setNamespaceAware(false);
         .setValidating(true);
     }

    
This constructor is a convienience used by some tests.
 
     public SpecificationParser(ClassResolver resolver)
     {
         this(new DefaultErrorHandler(), LogFactory.getLog(SpecificationParser.class), 
                 resolvernew SpecFactory());
     }

    
The full constructor, used within Tapestry.
 
     public SpecificationParser(ErrorHandler errorHandlerLog log, ClassResolver resolver,
             SpecFactory factory)
     {
          = errorHandler;
          = log;
          = resolver;
          = factory;
     }
 
     protected void begin(String elementNameMap attributes)
     {
          = elementName;
          = attributes;
 
         switch (getState())
         {
             case :
 
                 beginComponentSpecificationInitial();
                 break;
 
             case :
 
                 beginPageSpecificationInitial();
                 break;
 
             case :
 
                 beginApplicationSpecificationInitial();
                 break;
 
             case :
 
                 beginLibrarySpecificationInitial();
                 break;
 
             case :
 
                 beginComponentSpecification();
                 break;
 
             case :
 
                 beginPageSpecification();
                 break;
 
             case :
 
                 beginAllowDescription();
                 break;
 
             case :
 
                 allowMetaData();
                 break;
 
             case :
 
                 beginBean();
                 break;
 
             case :
 
                 beginComponent();
                 break;
 
             case :
 
                 beginLibrarySpecification();
                 break;
 
             case :
 
                 beginExtension();
                 break;
 
             default:
 
                 unexpectedElement();
         }
     }

    
Special state for a number of specification types that can support the <description> element.
 
 
     private void beginAllowDescription()
     {
         if (.equals("description"))
         {
             enterDescription();
             return;
         }
 
     }

    
Special state for a number of elements that can support the nested <meta> meta data element (<property> in 3.0 DTD).
 
 
     private void allowMetaData()
     {
         if ()
         {
             if (.equals("meta"))
             {
                 enterMeta();
                 return;
             }
         }
         else if (.equals("property"))
         {
             enterProperty30();
             return;
         }
 
     }
 
     private void beginApplicationSpecificationInitial()
     {
         expectElement("application");
 
         String name = getAttribute("name");
         String engineClassName = getAttribute("engine-class");
 
 
         as.setName(name);
 
         if (HiveMind.isNonBlank(engineClassName))
             as.setEngineClassName(engineClassName);
 
          = as;
 
     }
 
     private void beginBean()
     {
         if (.equals("set"))
         {
             enterSet();
             return;
         }
 
         if (.equals("set-property"))
         {
             enterSetProperty30();
             return;
         }
 
         if (.equals("set-message-property"))
         {
             enterSetMessage30();
             return;
         }
 
         if (.equals("description"))
         {
             enterDescription();
             return;
         }
 
         allowMetaData();
     }
 
     private void beginComponent()
     {
         // <binding> has changed between 3.0 and 4.0
 
         if (.equals("binding"))
         {
             enterBinding();
             return;
         }
 
         if (.equals("static-binding"))
         {
             enterStaticBinding30();
             return;
         }
 
         if (.equals("message-binding"))
         {
             enterMessageBinding30();
             return;
         }
 
         if (.equals("inherited-binding"))
         {
             enterInheritedBinding30();
             return;
         }
 
         if (.equals("listener-binding"))
         {
             enterListenerBinding();
             return;
         }
 
         allowMetaData();
     }
 
     private void beginComponentSpecification()
     {
         if (.equals("reserved-parameter"))
         {
             enterReservedParameter();
             return;
         }
 
         if (.equals("parameter"))
         {
             enterParameter();
             return;
         }
 
         // The remainder are common to both <component-specification> and
         // <page-specification>
 
         beginPageSpecification();
     }
 
     private void beginComponentSpecificationInitial()
     {
         expectElement("component-specification");
 
 
         cs.setAllowBody(getBooleanAttribute("allow-body"true));
         cs.setAllowInformalParameters(getBooleanAttribute("allow-informal-parameters"true));
         cs.setDeprecated(getBooleanAttribute("deprecated"false));
 
         String className = getAttribute("class");
 
         if (className != null)
             cs.setComponentClassName(className);
 
         cs.setSpecificationLocation(getResource());
 
          = cs;
 
     }
 
     private void beginExtension()
     {
         if (.equals("configure"))
         {
             enterConfigure();
             return;
         }
 
         allowMetaData();
     }
 
     private void beginLibrarySpecification()
     {
         if (.equals("description"))
         {
             enterDescription();
             return;
         }
 
         if (.equals("page"))
         {
             enterPage();
             return;
         }
 
         if (.equals("component-type"))
         {
             enterComponentType();
             return;
         }
 
         // Holdover from the 3.0 DTD, now ignored.
 
         if (.equals("service"))
         {
             enterService30();
             return;
         }
 
         if (.equals("library"))
         {
             enterLibrary();
             return;
         }
 
         if (.equals("extension"))
         {
             enterExtension();
             return;
         }
 
         allowMetaData();
     }
 
     private void beginLibrarySpecificationInitial()
     {
         expectElement("library-specification");
 
 
          = ls;
 
     }
 
     private void beginPageSpecification()
     {
         if (.equals("component"))
         {
             enterComponent();
             return;
         }
 
         if (.equals("bean"))
         {
             enterBean();
             return;
         }
 
         // <property-specification> in 3.0, <property> in 4.0
         // Have to be careful, because <meta> in 4.0 was <property> in 3.0
 
         if (.equals("property-specification")
                 || ( && .equals("property")))
         {
             enterProperty();
             return;
         }
 
         if (.equals("inject"))
         {
             enterInject();
             return;
         }
 
         // <asset> is new in 4.0
 
         if (.equals("asset"))
         {
             enterAsset();
             return;
         }
 
         // <context-asset>, <external-asset>, and <private-asset>
         // are all throwbacks to the 3.0 DTD and don't exist
         // in the 4.0 DTD.
 
         if (.equals("context-asset"))
         {
             enterContextAsset30();
             return;
         }
 
         if (.equals("private-asset"))
         {
             enterPrivateAsset30();
             return;
         }
 
         if (.equals("external-asset"))
         {
             enterExternalAsset30();
             return;
 
         }
 
         if (.equals("description"))
         {
             enterDescription();
             return;
         }
 
         allowMetaData();
     }
 
     private void beginPageSpecificationInitial()
     {
         expectElement("page-specification");
 
 
         String className = getAttribute("class");
 
         if (className != null)
             cs.setComponentClassName(className);
 
         cs.setSpecificationLocation(getResource());
         cs.setPageSpecification(true);
 
          = cs;
 
         push(cs);
     }

    
Close a stream (if not null), ignoring any errors.
 
     private void close(InputStream stream)
     {
         try
         {
             if (stream != null)
                 stream.close();
         }
         catch (IOException ex)
         {
             // ignore
         }
     }
 
     private void copyBindings(String sourceComponentIdIComponentSpecification cs,
             IContainedComponent target)
     {
         IContainedComponent source = cs.getComponent(sourceComponentId);
         if (source == null)
             throw new DocumentParseException(ParseMessages.unableToCopy(sourceComponentId),
                     getLocation());
 
         Iterator i = source.getBindingNames().iterator();
         while (i.hasNext())
         {
             String bindingName = (Stringi.next();
             IBindingSpecification binding = source.getBinding(bindingName);
             target.setBinding(bindingNamebinding);
         }
 
         target.setType(source.getType());
     }
 
     protected void end(String elementName)
     {
          = elementName;
 
         switch (getState())
         {
             case :
 
                 endDescription();
                 break;
 
             case :
 
                 endProperty();
                 break;
 
             case :
 
                 endSetProperty();
                 break;
 
             case :
 
                 endBinding30();
                 break;
 
             case :
 
                 endBinding();
                 break;
 
             case :
 
                 endStaticBinding();
                 break;
 
             case :
 
                 endPropertySpecification();
                 break;
 
             case :
 
                 endLibrarySpecification();
                 break;
 
             case :
 
                 endConfigure();
                 break;
 
             default:
                 break;
         }
 
         // Pop the top element of the stack and continue processing from there.
 
         pop();
     }
 
     private void endBinding30()
     {
         BindingSetter bs = (BindingSetterpeekObject();
 
         String expression = getExtendedValue(bs.getValue(), "expression"true);
 
 
         spec.setType(.);
         spec.setValue(. + ":" + expression);
 
         bs.apply(spec);
     }
 
     private void endConfigure()
     {
 
         String finalValue = getExtendedValue(setter.getValue(), "value"true);
 
         setter.apply(finalValue);
     }
 
     private void endDescription()
     {
         DescriptionSetter setter = (DescriptionSetterpeekObject();
 
         String description = peekContent();
 
         setter.apply(description);
     }
 
     private void endLibrarySpecification()
     {
 
         spec.setSpecificationLocation(getResource());
 
         spec.instantiateImmediateExtensions();
     }
 
     private void endProperty()
     {
         PropertyValueSetter pvs = (PropertyValueSetterpeekObject();
 
         String finalValue = getExtendedValue(pvs.getPropertyValue(), "value"true);
 
         pvs.applyValue(finalValue);
     }
 
     private void endPropertySpecification()
     {
 
         String initialValue = getExtendedValue(ps.getInitialValue(), "initial-value"false);
 
         // In the 3.0 DTD, the initial value was always an OGNL expression.
         // In the 4.0 DTD, it is a binding reference, qualified with a prefix.
 
         if (initialValue != null && !)
             initialValue = . + ":" + initialValue;
 
         ps.setInitialValue(initialValue);
     }
 
     private void endSetProperty()
     {
 
         String finalValue = getExtendedValue(bs.getBindingReference(), "expression"true);
 
         bs.applyBindingReference(finalValue);
     }
 
     private void endStaticBinding()
     {
         BindingSetter bs = (BindingSetterpeekObject();
 
         String literalValue = getExtendedValue(bs.getValue(), "value"true);
 
 
         spec.setType(.);
         spec.setValue(. + ":" + literalValue);
 
         bs.apply(spec);
     }
 
     private void enterAsset(String pathAttributeNameString prefix)
     {
         String name = getValidatedAttribute("name""invalid-asset-name");
         String path = getAttribute(pathAttributeName);
         String propertyName = getValidatedAttribute(
                 "property",
                 ,
                 "invalid-property-name");
 
 
         ia.setPath(prefix == null ? path : prefix + path);
         ia.setPropertyName(propertyName);
 
 
         cs.addAsset(nameia);
 
         push(ia);
     }
 
     private void enterBean()
     {
         String name = getValidatedAttribute("name""invalid-bean-name");
 
         String classAttribute = getAttribute("class");
 
         // Look for the lightweight initialization
 
         int commax = classAttribute.indexOf(',');
 
         String className = commax < 0 ? classAttribute : classAttribute.substring(0, commax);
 
         BeanLifecycle lifecycle = (BeanLifecyclegetConvertedAttribute(
                 "lifecycle",
                 .);
         String propertyName = getValidatedAttribute(
                 "property",
                 ,
                 "invalid-property-name");
 
 
         bs.setClassName(className);
         bs.setLifecycle(lifecycle);
         bs.setPropertyName(propertyName);
 
         if (commax > 0)
         {
             String initializer = classAttribute.substring(commax + 1);
             bs.addInitializer(new LightweightBeanInitializer(initializer));
         }
 
 
         cs.addBeanSpecification(namebs);
 
         push(bs);
     }
 
     private void enterBinding()
     {
         if (!)
         {
             enterBinding30();
             return;
        }
        // 4.0 stuff
        String name = getValidatedAttribute(
                "name",
                ,
                "invalid-parameter-name");
        String value = getAttribute("value");
        BindingSetter bs = new BindingSetter(ccnamevalue);
        push(bsfalse);
    }
    private void endBinding()
    {
        BindingSetter bs = (BindingSetterpeekObject();
        String value = getExtendedValue(bs.getValue(), "value"true);
        spec.setType(.);
        spec.setValue(value);
        bs.apply(spec);
    }

    
Handles a binding in a 3.0 DTD.
    private void enterBinding30()
    {
        String name = getAttribute("name");
        String expression = getAttribute("expression");
        BindingSetter bs = new BindingSetter(ccnameexpression);
        push(bsfalse);
    }
    private void enterComponent()
    {
        String id = getValidatedAttribute("id""invalid-component-id");
        String type = getValidatedAttribute(
                "type",
                ,
                "invalid-component-type");
        String copyOf = getAttribute("copy-of");
        boolean inherit = getBooleanAttribute("inherit-informal-parameters"false);
        String propertyName = getValidatedAttribute(
                "property",
                ,
                "invalid-property-name");
        // Check that either copy-of or type, but not both
        boolean hasCopyOf = HiveMind.isNonBlank(copyOf);
        if (hasCopyOf)
        {
            if (HiveMind.isNonBlank(type))
                throw new DocumentParseException(ParseMessages.bothTypeAndCopyOf(id), getLocation());
        }
        else
        {
            if (HiveMind.isBlank(type))
                throw new DocumentParseException(ParseMessages.missingTypeOrCopyOf(id),
                        getLocation());
        }
        cc.setType(type);
        cc.setCopyOf(copyOf);
        cc.setInheritInformalParameters(inherit);
        cc.setPropertyName(propertyName);
        cs.addComponent(idcc);
        if (hasCopyOf)
            copyBindings(copyOfcscc);
        push(cc);
    }
    private void enterComponentType()
    {
        String type = getValidatedAttribute(
                "type",
                ,
                "invalid-component-type");
        String path = getAttribute("specification-path");
        ls.setComponentSpecificationPath(typepath);
        push(null);
    }
    private void enterConfigure()
    {
        String attributeName =  ? "property" : "property-name";
        String propertyName = getValidatedAttribute(
                attributeName,
                ,
                "invalid-property-name");
        String value = getAttribute("value");
        ExtensionConfigurationSetter setter = new ExtensionConfigurationSetter(espropertyName,
                value);
        push(setterfalse);
    }
    private void enterContextAsset30()
    {
        enterAsset("path""context:");
    }

    
New in the 4.0 DTD. When using the 4.0 DTD, you must explicitly specify prefix if the asset is not stored in the same domain as the specification file.

Since:
4.0
    private void enterAsset()
    {
        enterAsset("path"null);
    }
    private void enterDescription()
    {
    }
    private void enterExtension()
    {
        String name = getValidatedAttribute(
                "name",
                ,
                "invalid-extension-name");
        boolean immediate = getBooleanAttribute("immediate"false);
        String className = getAttribute("class");
                ,
                );
        es.setClassName(className);
        es.setImmediate(immediate);
        ls.addExtensionSpecification(namees);
        push(es);
    }
    private void enterExternalAsset30()
    {
        // External URLs get no prefix, but will have a scheme (i.e., "http:") that
        // fulfils much the same purpose.
        enterAsset("URL"null);
    }

    
A throwback to the 3.0 DTD.
    private void enterInheritedBinding30()
    {
        String name = getAttribute("name");
        String parameterName = getAttribute("parameter-name");
        bs.setType(.);
        bs.setValue(parameterName);
        cc.setBinding(namebs);
        push(null);
    }
    private void enterLibrary()
    {
        String libraryId = getValidatedAttribute("id""invalid-library-id");
        String path = getAttribute("specification-path");
        if (libraryId.equals(.)
                || libraryId.equals(.))
            throw new DocumentParseException(ParseMessages
                    .frameworkLibraryIdIsReserved(.), getLocation());
        ls.setLibrarySpecificationPath(libraryIdpath);
        push(null);
    }
    private void enterListenerBinding()
    {
        .warn(ParseMessages.listenerBindingUnsupported(getLocation()));
        push(nullfalse);
    }
    private void enterMessageBinding30()
    {
        String name = getAttribute("name");
        String key = getAttribute("key");
        bs.setType(.);
        bs.setValue(. + ":" + key);
        bs.setLocation(getLocation());
        cc.setBinding(namebs);
        push(null);
    }
    private void enterPage()
    {
        String name = getValidatedAttribute("name""invalid-page-name");
        String path = getAttribute("specification-path");
        ls.setPageSpecificationPath(namepath);
        push(null);
    }
    private void enterParameter()
    {
        String name =