001    /*
002     * Copyright 2005 Stephen J. McConnell
003     *
004     * Licensed  under the  Apache License,  Version 2.0  (the "License");
005     * you may not use  this file  except in  compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     *   http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed  under the  License is distributed on an "AS IS" BASIS,
012     * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
013     * implied.
014     *
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    
019    package net.dpml.library.impl;
020    
021    import java.util.ArrayList;
022    import java.util.Enumeration;
023    import java.util.Properties;
024    
025    import net.dpml.library.Dictionary;
026    import net.dpml.library.info.AbstractDirective;
027    
028    import net.dpml.util.PropertyResolver;
029    
030    /**
031     * Utility class used for construction of a module model from an XML source.
032     *
033     * @author <a href="http://www.dpml.net">Digital Product Meta Library</a>
034     * @version 1.2.0
035     */
036    public class DefaultDictionary implements Dictionary
037    {
038        private final DefaultDictionary m_parent;
039        private final AbstractDirective m_directive;
040        private final Properties m_properties;
041        
042       /**
043        * Creation of a new dictionary.  The dictionary provides support
044        * for property inheritance within the hierachy of of modules based
045        * an a single root virtual module.  When handling a propety request
046        * the dictionary will attempt to resolve the property value using 
047        * local property values.  If the value is unresolved, the implemenetation
048        * will attempt to delegate the request to a parent dictionary if available.
049        *
050        * @param parent the parent dictionary (possibly null)
051        * @param directive an abstract directive containing local properties
052        */
053        public DefaultDictionary( DefaultDictionary parent, AbstractDirective directive )
054        {
055            if( null == directive )
056            {
057                throw new NullPointerException( "directive" );
058            }
059            m_parent = parent;
060            m_directive = directive;
061            
062            Properties properties = getParentProperties();
063            m_properties = new Properties( properties );
064            Properties local = directive.getProperties();
065            String[] keys = getLocalPropertyNames( local );
066            for( int i=0; i<keys.length; i++ )
067            {
068                String key = keys[i];
069                String value = local.getProperty( key );
070                m_properties.setProperty( key, value );
071            }
072        }
073        
074        //----------------------------------------------------------------------------
075        // Dictionary
076        //----------------------------------------------------------------------------
077        
078       /**
079        * Return the property names associated with the dictionary.
080        * @return the array of property names
081        */
082        public String[] getPropertyNames()
083        {
084            return getLocalPropertyNames( m_properties );
085        }
086        
087       /**
088        * Return the local property names associated with the dictionary.
089        * @return the array of local property names
090        */
091        public String[] getLocalPropertyNames()
092        {
093            return getLocalPropertyNames( m_directive.getProperties() );
094        }
095        
096       /**
097        * Return a property value.
098        * @param key the property key
099        * @return the property value
100        */
101        public String getProperty( String key )
102        {
103            return getProperty( key, null );
104        }
105        
106       /**
107        * Return a property value.
108        * @param key the property key
109        * @param value the default value
110        * @return the property value
111        */
112        public String getProperty( String key, String value )
113        {
114            String result = m_properties.getProperty( key, value );
115            return resolve( result );
116        }
117        
118       /**
119        * Return an integer property value.
120        * @param key the property key
121        * @param value the default value
122        * @return the property value as an integer
123        */
124        public int getIntegerProperty( String key, int value )
125        {
126            String result = m_properties.getProperty( key );
127            if( null == result )
128            {
129                return value;
130            }
131            else
132            {
133                String literal = resolve( result );
134                return Integer.parseInt( literal );
135            }
136        }
137        
138       /**
139        * Return an boolean property value.
140        * @param key the property key
141        * @param value the default value
142        * @return the property value as an boolean
143        */
144        public boolean getBooleanProperty( String key, boolean value )
145        {
146            String result = m_properties.getProperty( key );
147            if( null != result )
148            {
149                return Boolean.valueOf( result ).booleanValue();
150            }
151            else
152            {
153                return value;
154            }
155        }
156        
157       /**
158        * Evaluate and expand any symbolic references in the supplied value.
159        * @param value the value to resolve
160        * @return the resolved value
161        */
162        public String resolve( String value )
163        {
164            return PropertyResolver.resolve( m_properties, value );
165        }
166        
167        //----------------------------------------------------------------------------
168        // internal
169        //----------------------------------------------------------------------------
170        
171        void setProperty( String name, String value )
172        {
173            m_properties.setProperty( name, value );
174        }
175        
176        AbstractDirective getAbstractDirective()
177        {
178            return m_directive;
179        }
180        
181        Properties getProperties()
182        {
183            return m_properties;
184        }
185        
186        private Properties getParentProperties()
187        {
188            if( null == m_parent )
189            {
190                return new Properties();
191            }
192            else
193            {
194                return m_parent.getProperties();
195            }
196        }
197        
198        private String[] getLocalPropertyNames( Properties properties )
199        {
200            ArrayList list = new ArrayList();
201            Enumeration names = properties.propertyNames();
202            while( names.hasMoreElements() )
203            {
204                list.add( (String) names.nextElement() );
205            }
206            return (String[]) list.toArray( new String[0] );
207        }
208    
209        Properties getExportProperties()
210        {
211            String[] keys = getLocalPropertyNames();
212            Properties properties = new Properties();
213            for( int i=0; i<keys.length; i++ )
214            {
215                String key = keys[i];
216                String value = getProperty( key );
217                properties.setProperty( key, value );
218            }
219            return properties;
220        }
221    }