001    /*
002     * Copyright 2002-2004 the original author or authors.
003     * 
004     * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005     * use this file except in compliance with the License. You may obtain a copy of
006     * 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, WITHOUT
012     * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013     * License for the specific language governing permissions and limitations under
014     * the License.
015     */
016    package org.springframework.richclient.settings;
017    
018    import java.beans.PropertyChangeListener;
019    import java.beans.PropertyChangeSupport;
020    import java.util.Arrays;
021    import java.util.HashMap;
022    import java.util.HashSet;
023    import java.util.Map;
024    import java.util.Set;
025    
026    import org.springframework.core.enums.LabeledEnum;
027    import org.springframework.richclient.util.ClassUtils;
028    import org.springframework.util.Assert;
029    import org.springframework.util.ObjectUtils;
030    import org.springframework.util.StringUtils;
031    
032    /**
033     * Abstract <code>Settings</code> implementation.
034     * 
035     * @author Peter De Bruycker
036     */
037    public abstract class AbstractSettings implements Settings {
038    
039        private PropertyChangeSupport listeners = new PropertyChangeSupport( this );
040    
041        private Map defaults = new HashMap();
042    
043        private Map children = new HashMap();
044    
045        private String name;
046    
047        private Settings parent;
048    
049        public AbstractSettings( Settings parent, String name ) {
050            this.name = name;
051            this.parent = parent;
052        }
053    
054        public boolean contains( String key ) {
055            return internalContains( key ) || defaults.containsKey( key );
056        }
057    
058        protected abstract boolean internalContains( String key );
059    
060        /**
061         * Should return the names of the child settings initially in this settings instance,
062         * i.e. the children that were stored in the backend.
063         * 
064         * @return the names of the child settings
065         */
066        protected abstract String[] internalGetChildSettings();
067    
068        /*
069         * (non-Javadoc)
070         * 
071         * @see org.springframework.richclient.settings.Settings#setString(java.lang.String,
072         *      java.lang.String)
073         */
074        public void setString( String key, String value ) {
075            Assert.notNull( key, "Key cannot be null" );
076    
077            String old = getString( key );
078            internalSet( key, value );
079            afterSet( key, old, value );
080    
081        }
082    
083        protected abstract Settings internalCreateChild( String key );
084    
085        public String[] getChildSettings() {
086            if( !childSettingsLoaded ) {
087                childSettingsLoaded = true;
088                childSettingNames.addAll( Arrays.asList( internalGetChildSettings() ) );
089            }
090            return (String[]) childSettingNames.toArray( new String[childSettingNames.size()] );
091        }
092    
093        private boolean childSettingsLoaded = false;
094    
095        private Set childSettingNames = new HashSet();
096    
097        public Settings getSettings( String name ) {
098            if( !children.containsKey( name ) ) {
099                children.put( name, internalCreateChild( name ) );
100                childSettingNames.add( name );
101            }
102            return (Settings) children.get( name );
103        }
104    
105        protected abstract void internalSet( String key, String value );
106    
107        /**
108         * Return null if no value found for key
109         */
110        protected abstract String internalGet( String key );
111    
112        /*
113         * (non-Javadoc)
114         * 
115         * @see org.springframework.richclient.settings.Settings#getString(java.lang.String)
116         */
117        public String getString( String key ) {
118            Assert.notNull( key, "Key cannot be null" );
119    
120            String value = internalGet( key );
121            if( !StringUtils.hasText( value ) ) {
122                return getDefaultString( key );
123            }
124            return value;
125        }
126    
127        /*
128         * (non-Javadoc)
129         * 
130         * @see org.springframework.richclient.settings.Settings#setDefaultString(java.lang.String,
131         *      java.lang.String)
132         */
133        public void setDefaultString( String key, String value ) {
134            Assert.notNull( key, "Key cannot be null" );
135    
136            defaults.put( key, value );
137        }
138    
139        /*
140         * (non-Javadoc)
141         * 
142         * @see org.springframework.richclient.settings.Settings#getDefaultString(java.lang.String)
143         */
144        public String getDefaultString( String key ) {
145            Assert.notNull( key, "Key cannot be null" );
146    
147            if( !defaults.containsKey( key ) ) {
148                return "";
149            }
150            return (String) defaults.get( key );
151    
152        }
153    
154        /*
155         * (non-Javadoc)
156         * 
157         * @see org.springframework.richclient.settings.Settings#setInt(java.lang.String, int)
158         */
159        public void setInt( String key, int value ) {
160            Assert.notNull( key, "Key cannot be null" );
161    
162            int old = getInt( key );
163            internalSet( key, String.valueOf( value ) );
164            afterSet( key, new Integer( old ), new Integer( value ) );
165        }
166    
167        /*
168         * (non-Javadoc)
169         * 
170         * @see org.springframework.richclient.settings.Settings#getInt(java.lang.String)
171         */
172        public int getInt( String key ) {
173            Assert.notNull( key, "Key cannot be null" );
174    
175            String value = internalGet( key );
176            if( !StringUtils.hasText( value ) ) {
177                return getDefaultInt( key );
178            }
179            return Integer.parseInt( value );
180        }
181    
182        /*
183         * (non-Javadoc)
184         * 
185         * @see org.springframework.richclient.settings.Settings#setDefaultInt(java.lang.String,
186         *      int)
187         */
188        public void setDefaultInt( String key, int value ) {
189            Assert.notNull( key, "Key cannot be null" );
190    
191            defaults.put( key, String.valueOf( value ) );
192        }
193    
194        /*
195         * (non-Javadoc)
196         * 
197         * @see org.springframework.richclient.settings.Settings#getDefaultInt(java.lang.String)
198         */
199        public int getDefaultInt( String key ) {
200            Assert.notNull( key, "Key cannot be null" );
201    
202            if( !defaults.containsKey( key ) ) {
203                return 0;
204            }
205            return Integer.parseInt( (String) defaults.get( key ) );
206    
207        }
208    
209        /*
210         * (non-Javadoc)
211         * 
212         * @see org.springframework.richclient.settings.Settings#setDefaultLong(java.lang.String,
213         *      long)
214         */
215        public void setDefaultLong( String key, long value ) {
216            Assert.notNull( key, "Key cannot be null" );
217    
218            defaults.put( key, String.valueOf( value ) );
219        }
220    
221        /*
222         * (non-Javadoc)
223         * 
224         * @see org.springframework.richclient.settings.Settings#getDefaultLong(java.lang.String)
225         */
226        public long getDefaultLong( String key ) {
227            Assert.notNull( key, "Key cannot be null" );
228    
229            if( !defaults.containsKey( key ) ) {
230                return 0L;
231            }
232            return Long.parseLong( (String) defaults.get( key ) );
233    
234        }
235    
236        /*
237         * (non-Javadoc)
238         * 
239         * @see org.springframework.richclient.settings.Settings#setFloat(java.lang.String,
240         *      float)
241         */
242        public void setFloat( String key, float value ) {
243            Assert.notNull( key, "Key cannot be null" );
244    
245            float old = getFloat( key );
246            internalSet( key, String.valueOf( value ) );
247            afterSet( key, new Float( old ), new Float( value ) );
248        }
249    
250        /*
251         * (non-Javadoc)
252         * 
253         * @see org.springframework.richclient.settings.Settings#getFloat(java.lang.String)
254         */
255        public float getFloat( String key ) {
256            Assert.notNull( key, "Key cannot be null" );
257    
258            String value = internalGet( key );
259            if( !StringUtils.hasText( value ) ) {
260                return getDefaultFloat( key );
261            }
262            return Float.parseFloat( value );
263        }
264    
265        /*
266         * (non-Javadoc)
267         * 
268         * @see org.springframework.richclient.settings.Settings#setDefaultFloat(java.lang.String,
269         *      float)
270         */
271        public void setDefaultFloat( String key, float value ) {
272            Assert.notNull( key, "Key cannot be null" );
273    
274            defaults.put( key, String.valueOf( value ) );
275        }
276    
277        /*
278         * (non-Javadoc)
279         * 
280         * @see org.springframework.richclient.settings.Settings#getDefaultFloat(java.lang.String)
281         */
282        public float getDefaultFloat( String key ) {
283            Assert.notNull( key, "Key cannot be null" );
284    
285            if( !defaults.containsKey( key ) ) {
286                return 0.0f;
287            }
288            return Float.parseFloat( (String) defaults.get( key ) );
289    
290        }
291    
292        /*
293         * (non-Javadoc)
294         * 
295         * @see org.springframework.richclient.settings.Settings#setDouble(java.lang.String,
296         *      double)
297         */
298        public void setDouble( String key, double value ) {
299            Assert.notNull( key, "Key cannot be null" );
300    
301            double old = getDouble( key );
302            internalSet( key, String.valueOf( value ) );
303            afterSet( key, new Double( old ), new Double( value ) );
304        }
305    
306        /*
307         * (non-Javadoc)
308         * 
309         * @see org.springframework.richclient.settings.Settings#getDouble(java.lang.String)
310         */
311        public double getDouble( String key ) {
312            Assert.notNull( key, "Key cannot be null" );
313    
314            String value = internalGet( key );
315            if( !StringUtils.hasText( value ) ) {
316                return getDefaultDouble( key );
317            }
318            return Double.parseDouble( value );
319        }
320    
321        /*
322         * (non-Javadoc)
323         * 
324         * @see org.springframework.richclient.settings.Settings#setDefaultDouble(java.lang.String,
325         *      double)
326         */
327        public void setDefaultDouble( String key, double value ) {
328            Assert.notNull( key, "Key cannot be null" );
329    
330            defaults.put( key, String.valueOf( value ) );
331        }
332    
333        /*
334         * (non-Javadoc)
335         * 
336         * @see org.springframework.richclient.settings.Settings#getDefaultDouble(java.lang.String)
337         */
338        public double getDefaultDouble( String key ) {
339            Assert.notNull( key, "Key cannot be null" );
340    
341            if( !defaults.containsKey( key ) ) {
342                return 0.0;
343            }
344            return Double.parseDouble( (String) defaults.get( key ) );
345    
346        }
347    
348        /*
349         * (non-Javadoc)
350         * 
351         * @see org.springframework.richclient.settings.Settings#setBoolean(java.lang.String,
352         *      boolean)
353         */
354        public void setBoolean( String key, boolean value ) {
355            Assert.notNull( key, "Key cannot be null" );
356    
357            boolean old = getBoolean( key );
358            internalSet( key, String.valueOf( value ) );
359            afterSet( key, Boolean.valueOf( old ), Boolean.valueOf( value ) );
360        }
361    
362        /*
363         * (non-Javadoc)
364         * 
365         * @see org.springframework.richclient.settings.Settings#getBoolean(java.lang.String)
366         */
367        public boolean getBoolean( String key ) {
368            Assert.notNull( key, "Key cannot be null" );
369    
370            String value = internalGet( key );
371            if( !StringUtils.hasText( value ) ) {
372                return getDefaultBoolean( key );
373            }
374            return Boolean.valueOf( value ).booleanValue();
375        }
376    
377        /*
378         * (non-Javadoc)
379         * 
380         * @see org.springframework.richclient.settings.Settings#setDefaultBoolean(java.lang.String,
381         *      boolean)
382         */
383        public void setDefaultBoolean( String key, boolean value ) {
384            Assert.notNull( key, "Key cannot be null" );
385    
386            if( value ) {
387                defaults.put( key, String.valueOf( value ) );
388            } else {
389                defaults.remove( key );
390            }
391            removeIfDefault( key );
392        }
393    
394        /*
395         * (non-Javadoc)
396         * 
397         * @see org.springframework.richclient.settings.Settings#getDefaultBoolean(java.lang.String)
398         */
399        public boolean getDefaultBoolean( String key ) {
400            Assert.notNull( key, "Key cannot be null" );
401    
402            if( !defaults.containsKey( key ) ) {
403                return false;
404            }
405            return Boolean.valueOf( (String) defaults.get( key ) ).booleanValue();
406        }
407    
408        /*
409         * (non-Javadoc)
410         * 
411         * @see org.springframework.richclient.settings.Settings#setLabeledEnum(java.lang.String,
412         *      org.springframework.enums.LabeledEnum)
413         */
414        public void setLabeledEnum( String key, LabeledEnum value ) {
415            Assert.notNull( key, "Key cannot be null" );
416    
417            LabeledEnum old = getLabeledEnum( key );
418            internalSet( key, enumToString( value ) );
419            afterSet( key, old, value );
420        }
421    
422        private LabeledEnum stringToEnum( String s ) {
423            if( s == null || s.trim().equals( "" ) ) {
424                return null;
425            }
426            return (LabeledEnum) ClassUtils.getFieldValue( s );
427        }
428    
429        private String enumToString( LabeledEnum e ) {
430            return e == null ? "" : ClassUtils.getClassFieldNameWithValue( e.getClass(), e );
431        }
432    
433        /*
434         * (non-Javadoc)
435         * 
436         * @see org.springframework.richclient.settings.Settings#getLabeledEnum(java.lang.String)
437         */
438        public LabeledEnum getLabeledEnum( String key ) {
439            Assert.notNull( key, "Key cannot be null" );
440    
441            String value = internalGet( key );
442            if( !StringUtils.hasText( value ) ) {
443                return getDefaultLabeledEnum( key );
444            }
445            return stringToEnum( value );
446        }
447    
448        /*
449         * (non-Javadoc)
450         * 
451         * @see org.springframework.richclient.settings.Settings#setDefaultLabeledEnum(java.lang.String,
452         *      org.springframework.enums.LabeledEnum)
453         */
454        public void setDefaultLabeledEnum( String key, LabeledEnum value ) {
455            Assert.notNull( key, "Key cannot be null" );
456    
457            defaults.put( key, enumToString( value ) );
458        }
459    
460        /*
461         * (non-Javadoc)
462         * 
463         * @see org.springframework.richclient.settings.Settings#getDefaultLabeledEnum(java.lang.String)
464         */
465        public LabeledEnum getDefaultLabeledEnum( String key ) {
466            Assert.notNull( key, "Key cannot be null" );
467            return stringToEnum( (String) defaults.get( key ) );
468        }
469    
470        public boolean isDefault( String key ) {
471            Assert.notNull( key, "Key cannot be null" );
472    
473            return internalGet( key ) == null || ObjectUtils.nullSafeEquals( internalGet( key ), defaults.get( key ) );
474        }
475    
476        /*
477         * (non-Javadoc)
478         * 
479         * @see org.springframework.richclient.settings.Settings#getDefaultKeys()
480         */
481        public String[] getDefaultKeys() {
482            return (String[]) defaults.keySet().toArray( new String[0] );
483        }
484    
485        /*
486         * (non-Javadoc)
487         * 
488         * @see org.springframework.richclient.settings.Settings#getAllKeys()
489         */
490        public String[] getAllKeys() {
491            Set keys = new HashSet();
492            keys.addAll( Arrays.asList( getKeys() ) );
493            keys.addAll( defaults.keySet() );
494    
495            return (String[]) keys.toArray( new String[0] );
496        }
497    
498        /*
499         * (non-Javadoc)
500         * 
501         * @see org.springframework.richclient.settings.Settings#getName()
502         */
503        public String getName() {
504            return name;
505        }
506    
507        /*
508         * (non-Javadoc)
509         * 
510         * @see org.springframework.richclient.settings.Settings#getParent()
511         */
512        public Settings getParent() {
513            return parent;
514        }
515    
516        /*
517         * (non-Javadoc)
518         * 
519         * @see org.springframework.richclient.settings.Settings#addPropertyChangeListener(java.beans.PropertyChangeListener)
520         */
521        public void addPropertyChangeListener( PropertyChangeListener l ) {
522            listeners.addPropertyChangeListener( l );
523        }
524    
525        /*
526         * (non-Javadoc)
527         * 
528         * @see org.springframework.richclient.settings.Settings#addPropertyChangeListener(java.lang.String,
529         *      java.beans.PropertyChangeListener)
530         */
531        public void addPropertyChangeListener( String key, PropertyChangeListener l ) {
532            listeners.addPropertyChangeListener( key, l );
533        }
534    
535        /*
536         * (non-Javadoc)
537         * 
538         * @see org.springframework.richclient.settings.Settings#removePropertyChangeListener(java.beans.PropertyChangeListener)
539         */
540        public void removePropertyChangeListener( PropertyChangeListener l ) {
541            listeners.removePropertyChangeListener( l );
542        }
543    
544        /*
545         * (non-Javadoc)
546         * 
547         * @see org.springframework.richclient.settings.Settings#removePropertyChangeListener(java.lang.String,
548         *      java.beans.PropertyChangeListener)
549         */
550        public void removePropertyChangeListener( String key, PropertyChangeListener l ) {
551            listeners.removePropertyChangeListener( key, l );
552        }
553    
554        private void afterSet( String key, Object oldValue, Object newValue ) {
555            removeIfDefault( key );
556            firePropertyChange( key, oldValue, newValue );
557        }
558    
559        private void firePropertyChange( String key, Object oldValue, Object newValue ) {
560            listeners.firePropertyChange( key, oldValue, newValue );
561        }
562    
563        protected abstract void internalRemove( String key );
564    
565        private void removeIfDefault( String key ) {
566            if( isDefault( key ) ) {
567                internalRemove( key );
568            }
569        }
570    
571        public void remove( String key ) {
572            if( contains( key ) ) {
573                internalRemove( key );
574            }
575        }
576    
577        /*
578         * (non-Javadoc)
579         * 
580         * @see org.springframework.richclient.settings.Settings#setLong(java.lang.String,
581         *      long)
582         */
583        public void setLong( String key, long value ) {
584            Assert.notNull( key, "Key cannot be null" );
585    
586            long old = getLong( key );
587            internalSet( key, String.valueOf( value ) );
588            afterSet( key, new Long( old ), new Long( value ) );
589        }
590    
591        /*
592         * (non-Javadoc)
593         * 
594         * @see org.springframework.richclient.settings.Settings#getLong(java.lang.String)
595         */
596        public long getLong( String key ) {
597            Assert.notNull( key, "Key cannot be null" );
598    
599            String value = internalGet( key );
600            if( !StringUtils.hasText( value ) ) {
601                return getDefaultLong( key );
602            }
603            return Long.parseLong( value );
604        }
605    
606        public boolean isRoot() {
607            return getParent() == null;
608        }
609    
610        public void removeSettings() {
611            internalRemoveSettings();
612            if( getParent() instanceof AbstractSettings ) {
613                ((AbstractSettings) getParent()).childSettingNames.remove( getName() );
614            }
615        }
616    
617        protected abstract void internalRemoveSettings();
618    }