001package 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
022import java.util.Properties;
023
024import org.apache.commons.digester3.Digester;
025import org.apache.commons.digester3.Rule;
026import 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 */
037public 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}