001/*
002 * HA-JDBC: High-Availability JDBC
003 * Copyright (c) 2004-2007 Paul Ferraro
004 * 
005 * This library is free software; you can redistribute it and/or modify it 
006 * under the terms of the GNU Lesser General Public License as published by the 
007 * Free Software Foundation; either version 2.1 of the License, or (at your 
008 * option) any later version.
009 * 
010 * This library is distributed in the hope that it will be useful, but WITHOUT
011 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
012 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 
013 * for more details.
014 * 
015 * You should have received a copy of the GNU Lesser General Public License
016 * along with this library; if not, write to the Free Software Foundation, 
017 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018 * 
019 * Contact: ferraro@users.sourceforge.net
020 */
021package net.sf.hajdbc.local;
022
023import java.util.ArrayList;
024import java.util.Arrays;
025import java.util.Collections;
026import java.util.List;
027import java.util.Set;
028import java.util.TreeSet;
029import java.util.prefs.BackingStoreException;
030import java.util.prefs.Preferences;
031
032import net.sf.hajdbc.Database;
033import net.sf.hajdbc.DatabaseCluster;
034import net.sf.hajdbc.DatabaseEvent;
035import net.sf.hajdbc.Messages;
036import net.sf.hajdbc.StateManager;
037import net.sf.hajdbc.util.Strings;
038
039import org.slf4j.Logger;
040import org.slf4j.LoggerFactory;
041
042/**
043 * @author Paul Ferraro
044 */
045public class LocalStateManager implements StateManager
046{
047        private static Preferences preferences = Preferences.userNodeForPackage(LocalStateManager.class);
048        private static Logger logger = LoggerFactory.getLogger(LocalStateManager.class);
049        
050        private DatabaseCluster<?> databaseCluster;
051        
052        /**
053         * @param databaseCluster
054         */
055        public LocalStateManager(DatabaseCluster<?> databaseCluster)
056        {
057                this.databaseCluster = databaseCluster;
058        }
059
060        /**
061         * @see net.sf.hajdbc.StateManager#getInitialState()
062         */
063        @Override
064        public Set<String> getInitialState()
065        {
066                String state = preferences.get(this.statePreferenceKey(), null);
067                
068                if (state == null)
069                {
070                        logger.info(Messages.getMessage(Messages.INITIAL_CLUSTER_STATE_NONE));
071                        
072                        return null;
073                }
074                
075                Set<String> databaseSet = Collections.emptySet();
076                
077                if (state.length() > 0)
078                {
079                        databaseSet = new TreeSet<String>(Arrays.asList(state.split(Strings.COMMA)));
080                }
081                
082                logger.info(Messages.getMessage(Messages.INITIAL_CLUSTER_STATE_LOCAL, databaseSet));
083
084                return databaseSet;
085        }
086
087        /**
088         * @see net.sf.hajdbc.Lifecycle#start()
089         */
090        @Override
091        public void start() throws Exception
092        {
093                preferences.sync();
094        }
095
096        /**
097         * @see net.sf.hajdbc.Lifecycle#stop()
098         */
099        @Override
100        public void stop()
101        {
102                // Nothing to do
103        }
104        
105        private String statePreferenceKey()
106        {
107                return this.databaseCluster.getId();
108        }
109
110        /**
111         * @see net.sf.hajdbc.StateManager#isMembershipEmpty()
112         */
113        @Override
114        public boolean isMembershipEmpty()
115        {
116                return false;
117        }
118
119        /**
120         * @see net.sf.hajdbc.DatabaseActivationListener#activated(net.sf.hajdbc.DatabaseEvent)
121         */
122        @Override
123        public void activated(DatabaseEvent event)
124        {
125                this.storeState();
126        }
127
128        /**
129         * @see net.sf.hajdbc.DatabaseDeactivationListener#deactivated(net.sf.hajdbc.DatabaseEvent)
130         */
131        @Override
132        public void deactivated(DatabaseEvent event)
133        {
134                this.storeState();
135        }
136        
137        private void storeState()
138        {
139                List<String> databaseList = new ArrayList<String>();
140
141                for (Database<?> database: this.databaseCluster.getBalancer().all())
142                {
143                        databaseList.add(database.getId());
144                }
145                
146                preferences.put(this.statePreferenceKey(), Strings.join(databaseList, Strings.COMMA));
147                
148                try
149                {
150                        preferences.flush();
151                }
152                catch (BackingStoreException e)
153                {
154                        throw new RuntimeException(Messages.getMessage(Messages.CLUSTER_STATE_STORE_FAILED, this.databaseCluster), e);
155                }
156        }
157}