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.balancer;
022
023import java.util.ArrayList;
024import java.util.Collections;
025import java.util.List;
026import java.util.Random;
027
028import net.sf.hajdbc.Database;
029
030/**
031 * Balancer implementation whose {@link #next()} implementation returns a random database.
032 * The probability that a given database will be returned is: <em>weight / total-weight</em>.
033 * 
034 * @author  Paul Ferraro
035 * @param <D> either java.sql.Driver or javax.sql.DataSource
036 */
037public class RandomBalancer<D> extends AbstractBalancer<D>
038{
039        private volatile List<Database<D>> databaseList = Collections.emptyList();
040
041        private Random random = new Random();
042
043        /**
044         * @see net.sf.hajdbc.Balancer#next()
045         */
046        @Override
047        public Database<D> next()
048        {
049                List<Database<D>> list = this.databaseList;
050                
051                if (list.isEmpty())
052                {
053                        return this.databaseSet.first();
054                }
055                
056                int index = this.random.nextInt(list.size());
057                
058                return list.get(index);
059        }
060        
061        /**
062         * @see net.sf.hajdbc.balancer.AbstractBalancer#added(net.sf.hajdbc.Database)
063         */
064        @Override
065        protected void added(Database<D> database)
066        {
067                int weight = database.getWeight();
068                
069                if (weight > 0)
070                {
071                        List<Database<D>> list = new ArrayList<Database<D>>(this.databaseList.size() + weight);
072                        
073                        list.addAll(this.databaseList);
074                        
075                        for (int i = 0; i < weight; ++i)
076                        {
077                                list.add(database);
078                        }
079                        
080                        this.databaseList = list;
081                }
082        }
083
084        /**
085         * @see net.sf.hajdbc.balancer.AbstractBalancer#removed(net.sf.hajdbc.Database)
086         */
087        @Override
088        protected void removed(Database<D> database)
089        {
090                int weight = database.getWeight();
091
092                if (weight > 0)
093                {
094                        List<Database<D>> list = new ArrayList<Database<D>>(this.databaseList.size() - weight);
095                        
096                        int index = this.databaseList.indexOf(database);
097                        
098                        list.addAll(this.databaseList.subList(0, index));
099                        list.addAll(this.databaseList.subList(index + weight, this.databaseList.size()));
100                        
101                        this.databaseList = list;
102                }
103        }
104
105        /**
106         * @see net.sf.hajdbc.balancer.AbstractBalancer#cleared()
107         */
108        @Override
109        protected void cleared()
110        {
111                this.databaseList = Collections.emptyList();
112        }
113}