001    /*
002     * Copyright (C) 2006-2007 the original author or authors.
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 implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package org.codehaus.gmaven.feature;
018    
019    import java.io.File;
020    import java.net.MalformedURLException;
021    import java.net.URI;
022    import java.net.URISyntaxException;
023    import java.net.URL;
024    import java.util.Collections;
025    import java.util.HashMap;
026    import java.util.HashSet;
027    import java.util.Iterator;
028    import java.util.Map;
029    import java.util.Set;
030    
031    /**
032     * Container for configuration information as name-value pairs.
033     *
034     * @version $Id: Configuration.java 9 2009-07-16 09:22:08Z user57 $
035     * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
036     */
037    public final class Configuration
038        implements Cloneable
039    {
040        private Map store;
041    
042        private String prefix;
043    
044        private Configuration parent;
045    
046        private Configuration(final Map store, final String prefix) {
047            assert store != null;
048            // prefix can be null
049            
050            this.store = store;
051            this.prefix = prefix;
052        }
053    
054        public Configuration() {
055            this(new HashMap(), null);
056        }
057    
058        public Configuration(final Configuration config) {
059            this(config.store, config.prefix);
060        }
061    
062        /** @noinspection CloneDoesntDeclareCloneNotSupportedException */
063        public Object clone() {
064            try {
065                return super.clone();
066            }
067            catch (CloneNotSupportedException e) {
068                throw new InternalError();
069            }
070        }
071        public String getPrefix() {
072            return prefix;
073        }
074    
075        public String key(final String name) {
076            assert name != null;
077    
078            if (prefix != null) {
079                return prefix + "." + name;
080            }
081    
082            return name;
083        }
084    
085        public boolean contains(final String name) {
086            assert name != null;
087    
088            return store.containsKey(key(name));
089        }
090    
091        public Object set(final String name, final Object value) {
092            assert name != null;
093            assert value != null;
094    
095            return store.put(key(name), value);
096        }
097    
098        public Object get(final String name, final Object defaultValue) {
099            assert name != null;
100            // defaultValue can be null
101    
102            Object value = store.get(key(name));
103    
104            if (value == null) {
105                value =  defaultValue;
106            }
107    
108            return value;
109        }
110    
111        public Object get(final String name) {
112            return get(name, (Object)null);
113        }
114    
115        public Object remove(final String name) {
116            assert name != null;
117    
118            return store.remove(key(name));
119        }
120    
121        //
122        // TODO: Really need to have some methods to merge and overwrite, or
123        //       only update if the exiting values are not set etc...
124        //
125    
126        public void merge(final Configuration config) {
127            assert config != null;
128    
129            store.putAll(config.store);
130        }
131    
132        public void clear() {
133            store.clear();
134        }
135    
136        public int size() {
137            if (prefix == null) {
138                return store.size();
139            }
140    
141            int c = 0;
142    
143            for (Iterator iter=store.keySet().iterator(); iter.hasNext();) {
144                String key = (String) iter.next();
145                if (key.startsWith(prefix)) {
146                    c++;
147                }
148            }
149    
150            return c;
151        }
152    
153        public boolean isEmpty() {
154            return size() == 0;
155        }
156    
157        public Set names() {
158            if (prefix == null) {
159                return Collections.unmodifiableSet(store.keySet());
160            }
161    
162            Set matching = new HashSet();
163            int l = prefix.length();
164    
165            for (Iterator iter=store.keySet().iterator(); iter.hasNext();) {
166                String key = (String) iter.next();
167    
168                if (key.startsWith(prefix + ".")) {
169                    // Strip off the prefix
170                    key = key.substring(l + 1, key.length());
171    
172                    matching.add(key);
173                }
174            }
175    
176            return Collections.unmodifiableSet(matching);
177        }
178    
179        //
180        // Children
181        //
182    
183        public Configuration parent() {
184            if (parent == null) {
185                throw new IllegalStateException("Parent is not bound");
186            }
187    
188            return parent;
189        }
190    
191        public Configuration child(final String prefix) {
192            assert prefix != null;
193    
194            Configuration child = (Configuration) clone();
195    
196            child.parent = this;
197    
198            if (child.prefix != null) {
199                child.prefix += prefix;
200            }
201            else {
202                child.prefix = prefix;
203            }
204    
205            return child;
206        }
207    
208        public Configuration child(final Feature feature) {
209            assert feature != null;
210    
211            return child(feature.key());
212        }
213    
214        //
215        // Typed Access
216        //
217    
218        public Object set(final String name, final boolean value) {
219            return set(name, Boolean.valueOf(value));
220        }
221    
222        public boolean get(final String name, final boolean defaultValue) {
223            Object value = get(name);
224    
225            if (value == null) {
226                return defaultValue;
227            }
228    
229            if (value instanceof Boolean) {
230                return ((Boolean)value).booleanValue();
231            }
232    
233            return Boolean.valueOf(String.valueOf(value)).booleanValue();
234        }
235    
236        public Object set(final String name, final int value) {
237            return set(name, new Integer(value));
238        }
239        
240        public int get(final String name, final int defaultValue) {
241            Object value = get(name);
242    
243            if (value == null) {
244                return defaultValue;
245            }
246    
247            if (value instanceof Number) {
248                return ((Number)value).intValue();
249            }
250    
251            return Integer.valueOf(String.valueOf(value)).intValue();
252        }
253    
254        public String get(final String name, final String defaultValue) {
255            Object value = get(name);
256    
257            if (value == null) {
258                return defaultValue;
259            }
260    
261            if (value instanceof String) {
262                return ((String)value);
263            }
264    
265            return String.valueOf(value);
266        }
267    
268        public File get(final String name, final File defaultValue) {
269            Object value = get(name);
270    
271            if (value == null) {
272                return defaultValue;
273            }
274    
275            if (value instanceof File) {
276                return ((File)value);
277            }
278    
279            return new File(String.valueOf(value));
280        }
281    
282        public URL get(final String name, final URL defaultValue) {
283            Object value = get(name);
284    
285            if (value == null) {
286                return defaultValue;
287            }
288    
289            if (value instanceof URL) {
290                return ((URL)value);
291            }
292    
293            try {
294                return new URL(String.valueOf(value));
295            }
296            catch (MalformedURLException e) {
297                throw new ConfigurationException("Unable to decode URL; name=" + name + ", value=" + value, e);
298            }
299        }
300    
301        public URI get(final String name, final URI defaultValue) {
302            Object value = get(name);
303    
304            if (value == null) {
305                return defaultValue;
306            }
307    
308            if (value instanceof URI) {
309                return ((URI)value);
310            }
311    
312            try {
313                return new URI(String.valueOf(value));
314            }
315            catch (URISyntaxException e) {
316                throw new ConfigurationException("Unable to decode URI; name=" + name + ", value=" + value, e);
317            }
318        }
319    }