001    package org.apache.commons.digester3.plugins;
002    
003    /*
004     * Licensed to the Apache Software Foundation (ASF) under one
005     * or more contributor license agreements.  See the NOTICE file
006     * distributed with this work for additional information
007     * regarding copyright ownership.  The ASF licenses this file
008     * to you under the Apache License, Version 2.0 (the
009     * "License"); you may not use this file except in compliance
010     * with the License.  You may obtain a copy of the License at
011     *
012     *   http://www.apache.org/licenses/LICENSE-2.0
013     *
014     * Unless required by applicable law or agreed to in writing,
015     * software distributed under the License is distributed on an
016     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017     * KIND, either express or implied.  See the License for the
018     * specific language governing permissions and limitations
019     * under the License.
020     */
021    
022    import java.util.Properties;
023    
024    import org.apache.commons.digester3.Digester;
025    import org.apache.commons.digester3.Rule;
026    import org.xml.sax.Attributes;
027    
028    /**
029     * A Digester rule which allows the user to pre-declare a class which is to be referenced later at a plugin point by a
030     * PluginCreateRule.
031     * <p>
032     * Normally, a PluginDeclarationRule is added to a Digester instance with the pattern "{root}/plugin" or "* /plugin"
033     * where {root} is the name of the root tag in the input document.
034     * 
035     * @since 1.6
036     */
037    public class PluginDeclarationRule
038        extends Rule
039    {
040    
041        // ------------------- constructors ---------------------------------------
042    
043        /** constructor */
044        public PluginDeclarationRule()
045        {
046            super();
047        }
048    
049        // ------------------- methods --------------------------------------------
050    
051        /**
052         * Invoked upon reading a tag defining a plugin declaration. The tag must have the following mandatory attributes:
053         * <ul>
054         * <li>id</li>
055         * <li>class</li>
056         * </ul>
057         * 
058         * @param namespace The xml namespace in which the xml element which triggered this rule resides.
059         * @param name The name of the xml element which triggered this rule.
060         * @param attributes The set of attributes on the xml element which triggered this rule.
061         * @exception Exception if any error occurs
062         */
063        @Override
064        public void begin( String namespace, String name, Attributes attributes )
065            throws Exception
066        {
067            int nAttrs = attributes.getLength();
068            Properties props = new Properties();
069            for ( int i = 0; i < nAttrs; ++i )
070            {
071                String key = attributes.getLocalName( i );
072                if ( ( key == null ) || ( key.length() == 0 ) )
073                {
074                    key = attributes.getQName( i );
075                }
076                String value = attributes.getValue( i );
077                props.setProperty( key, value );
078            }
079    
080            try
081            {
082                declarePlugin( getDigester(), props );
083            }
084            catch ( PluginInvalidInputException ex )
085            {
086                throw new PluginInvalidInputException( "Error on element [" + getDigester().getMatch() + "]: "
087                    + ex.getMessage() );
088            }
089        }
090    
091        /**
092         * Helper method to declare a plugin inside the given Digester.
093         *
094         * @param digester The Digester instance to declare plugin
095         * @param props the properties where extracting plugin attributes
096         * @throws PluginException if any error occurs while declaring the plugin
097         */
098        public static void declarePlugin( Digester digester, Properties props )
099            throws PluginException
100        {
101            String id = props.getProperty( "id" );
102            String pluginClassName = props.getProperty( "class" );
103    
104            if ( id == null )
105            {
106                throw new PluginInvalidInputException( "mandatory attribute id not present on plugin declaration" );
107            }
108    
109            if ( pluginClassName == null )
110            {
111                throw new PluginInvalidInputException( "mandatory attribute class not present on plugin declaration" );
112            }
113    
114            Declaration newDecl = new Declaration( pluginClassName );
115            newDecl.setId( id );
116            newDecl.setProperties( props );
117    
118            PluginRules rc = (PluginRules) digester.getRules();
119            PluginManager pm = rc.getPluginManager();
120    
121            newDecl.init( digester, pm );
122            pm.addDeclaration( newDecl );
123    
124            // Note that it is perfectly safe to redeclare a plugin, because
125            // the declaration doesn't add any rules to digester; all it does
126            // is create a RuleLoader instance whch is *capable* of adding the
127            // rules to the digester.
128        }
129    
130    }