001    package org.apache.commons.digester3.substitution;
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 org.xml.sax.Attributes;
023    
024    import java.util.ArrayList;
025    
026    /**
027     * Wrapper for an {@link Attributes} object which expands any "variables" referenced in the attribute value via
028     * ${foo} or similar. This is only done when something actually asks for the attribute value, thereby imposing no
029     * performance penalty if the attribute is not used.
030     * 
031     * @since 1.6
032     */
033    public class VariableAttributes
034        implements Attributes
035    {
036    
037        // list of mapped attributes.
038        private ArrayList<String> values = new ArrayList<String>( 10 );
039    
040        private Attributes attrs;
041    
042        private VariableExpander expander;
043    
044        // ------------------- Public Methods
045    
046        /**
047         * Specify which attributes class this object is a proxy for.
048         *
049         * @param attrs The attributes where variables have to be expanded.
050         * @param expander The variables expander instance.
051         */
052        public void init( Attributes attrs, VariableExpander expander )
053        {
054            this.attrs = attrs;
055            this.expander = expander;
056    
057            // I hope this doesn't release the memory for this array; for
058            // efficiency, this should just mark the array as being size 0.
059            values.clear();
060        }
061    
062        /**
063         * {@inheritDoc}
064         */
065        public String getValue( int index )
066        {
067            if ( index >= values.size() )
068            {
069                // Expand the values array with null elements, so the later
070                // call to set(index, s) works ok.
071                //
072                // Unfortunately, there is no easy way to set the size of
073                // an arraylist; we must repeatedly add null elements to it..
074                values.ensureCapacity( index + 1 );
075                for ( int i = values.size(); i <= index; ++i )
076                {
077                    values.add( null );
078                }
079            }
080    
081            String s = values.get( index );
082    
083            if ( s == null )
084            {
085                // we have never been asked for this value before.
086                // get the real attribute value and perform substitution
087                // on it.
088                s = attrs.getValue( index );
089                if ( s != null )
090                {
091                    s = expander.expand( s );
092                    values.set( index, s );
093                }
094            }
095    
096            return s;
097        }
098    
099        /**
100         * {@inheritDoc}
101         */
102        public String getValue( String qname )
103        {
104            int index = attrs.getIndex( qname );
105            if ( index == -1 )
106            {
107                return null;
108            }
109            return getValue( index );
110        }
111    
112        /**
113         * {@inheritDoc}
114         */
115        public String getValue( String uri, String localname )
116        {
117            int index = attrs.getIndex( uri, localname );
118            if ( index == -1 )
119            {
120                return null;
121            }
122            return getValue( index );
123        }
124    
125        // plain proxy methods follow : nothing interesting :-)
126        /**
127         * {@inheritDoc}
128         */
129        public int getIndex( String qname )
130        {
131            return attrs.getIndex( qname );
132        }
133    
134        /**
135         * {@inheritDoc}
136         */
137        public int getIndex( String uri, String localpart )
138        {
139            return attrs.getIndex( uri, localpart );
140        }
141    
142        /**
143         * {@inheritDoc}
144         */
145        public int getLength()
146        {
147            return attrs.getLength();
148        }
149    
150        /**
151         * {@inheritDoc}
152         */
153        public String getLocalName( int index )
154        {
155            return attrs.getLocalName( index );
156        }
157    
158        /**
159         * {@inheritDoc}
160         */
161        public String getQName( int index )
162        {
163            return attrs.getQName( index );
164        }
165    
166        /**
167         * {@inheritDoc}
168         */
169        public String getType( int index )
170        {
171            return attrs.getType( index );
172        }
173    
174        /**
175         * {@inheritDoc}
176         */
177        public String getType( String qname )
178        {
179            return attrs.getType( qname );
180        }
181    
182        /**
183         * {@inheritDoc}
184         */
185        public String getType( String uri, String localname )
186        {
187            return attrs.getType( uri, localname );
188        }
189    
190        /**
191         * {@inheritDoc}
192         */
193        public String getURI( int index )
194        {
195            return attrs.getURI( index );
196        }
197    
198    }