001    /*
002     * Copyright 2002-2006 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.jdbc;
017    
018    import java.io.IOException;
019    import java.util.HashMap;
020    import java.util.HashSet;
021    import java.util.Iterator;
022    import java.util.List;
023    import java.util.Map;
024    import java.util.Set;
025    
026    import javax.sql.DataSource;
027    
028    import org.springframework.jdbc.core.JdbcTemplate;
029    import org.springframework.richclient.settings.AbstractSettings;
030    import org.springframework.richclient.settings.Settings;
031    
032    /**
033     * 
034     * @author Peter De Bruycker
035     */
036    public class JdbcSettings extends AbstractSettings {
037        private DataSource dataSource;
038    
039        private Integer id;
040        private String user;
041    
042        private Map values = new HashMap();
043        private Set remove = new HashSet();
044        private Set add = new HashSet();
045        private Set update = new HashSet();
046    
047        private String[] childKeys;
048    
049        public JdbcSettings( DataSource ds, String user, Integer id, String key ) {
050            this( null, ds, user, id, key );
051        }
052    
053        public JdbcSettings( JdbcSettings parent, DataSource ds, String user, Integer id, String key ) {
054            super( parent, key );
055            this.id = id;
056    
057            // TODO assert dataSource not null
058            dataSource = ds;
059    
060            // TODO assert user not empty
061            this.user = user;
062        }
063    
064        protected boolean internalContains( String key ) {
065            return values.containsKey( key );
066        }
067    
068        protected String[] internalGetChildSettings() {
069            if( childKeys == null ) {
070                loadChildKeys();
071            }
072            return childKeys;
073        }
074    
075        protected Settings internalCreateChild( String key ) {
076            return new JdbcSettings( this, dataSource, user, null, key );
077        }
078    
079        protected void internalSet( String key, String value ) {
080            boolean isNew = !values.containsKey( key ) || add.contains( key );
081    
082            values.put( key, value );
083    
084            if( isNew ) {
085                add.add( key );
086            } else {
087                update.add( key );
088            }
089            remove.remove( key );
090        }
091    
092        protected String internalGet( String key ) {
093            return (String) values.get( key );
094        }
095    
096        protected void internalRemove( String key ) {
097            values.remove( key );
098    
099            if( !add.contains( key ) ) {
100                remove.add( key );
101            }
102    
103            update.remove( key );
104            add.remove( key );
105        }
106    
107        public String[] getKeys() {
108            return (String[]) values.keySet().toArray( new String[0] );
109        }
110    
111        public Integer getId() {
112            return id;
113        }
114    
115        public void save() throws IOException {
116            if( getParent() != null ) {
117                getParent().save();
118            }
119    
120            JdbcTemplate template = new JdbcTemplate( dataSource );
121    
122            // if this is a new node, insert it
123            if( id == null ) {
124                JdbcSettings parent = (JdbcSettings) getParent();
125                template.update( "INSERT INTO SETTINGS (KEY, PARENT, USER) VALUES (?, ?, ?)", new Object[] { getName(),
126                        parent == null ? null : parent.getId(), user } );
127                id = Integer.valueOf( template.queryForInt( "SELECT MAX(ID) FROM SETTINGS" ) );
128            } else {
129                for( Iterator iter = remove.iterator(); iter.hasNext(); ) {
130                    String key = (String) iter.next();
131                    template.update( "REMOVE FROM SETTINGS_VALUES WHERE SETTINGS_ID=? AND KEY=?", new Object[] { id, key } );
132                }
133                for( Iterator iter = update.iterator(); iter.hasNext(); ) {
134                    String key = (String) iter.next();
135                    template.update( "UPDATE SETTINGS_VALUES SET VALUE=? WHERE SETTINGS_ID=? AND KEY=?", new Object[] {
136                            values.get( key ), id, key } );
137                }
138            }
139    
140            for( Iterator iter = add.iterator(); iter.hasNext(); ) {
141                String key = (String) iter.next();
142                template.update( "INSERT INTO SETTINGS_VALUES (SETTINGS_ID, KEY, VALUE) VALUES (?, ?, ?)", new Object[] {
143                        id, key, values.get( key ) } );
144            }
145    
146            remove.clear();
147            update.clear();
148            add.clear();
149        }
150    
151        public void load() throws IOException {
152            if( id == null ) {
153                return;
154            }
155    
156            JdbcTemplate template = new JdbcTemplate( dataSource );
157            List entries = template.queryForList( "SELECT KEY, VALUE FROM SETTINGS_VALUES WHERE SETTINGS_ID=?",
158                    new Object[] { id } );
159            for( Iterator iter = entries.iterator(); iter.hasNext(); ) {
160                Map entry = (Map) iter.next();
161                values.put(entry.get( "KEY" ), entry.get( "VALUE" ));
162            }
163        }
164    
165        private void loadChildKeys() {
166            JdbcTemplate template = new JdbcTemplate( dataSource );
167            List keys = template.queryForList( "SELECT KEY FROM SETTINGS WHERE PARENT=" + id, String.class );
168    
169            childKeys = (String[]) keys.toArray( new String[keys.size()] );
170        }
171    
172        public String getUser() {
173            return user;
174        }
175    
176        public void internalRemoveSettings() {
177            if( id != null ) {
178                // first delete all children
179                for( int i = 0; i < childKeys.length; i++ ) {
180                    getSettings(childKeys[i]).removeSettings();
181                }
182    
183                // now delete all values
184                JdbcTemplate template = new JdbcTemplate( dataSource );
185                template.update( "DELETE FROM SETTINGS_VALUES WHERE SETTINGS_ID=?", new Object[] { id } );
186    
187                // now delete our own record
188                template.update( "DELETE FROM SETTINGS WHERE ID=?", new Object[] { id } );
189    
190                id = null;
191            }
192    
193            values.clear();
194            remove.clear();
195            add.clear();
196            update.clear();
197        }
198    }