001    /*
002    @license.text@
003     */
004    package biz.hammurapi.util;
005    
006    import java.util.ArrayList;
007    import java.util.Collections;
008    import java.util.Iterator;
009    import java.util.List;
010    
011    /**
012     * Load balancer distributes work to other workers
013     * according to weights. The less the weight the more
014     * job worker is getting.
015     * @author Pavel Vlasov
016     * @revision $Revision$
017     */
018    public class LoadBalancer implements Worker {
019    
020            private List workers=new ArrayList();
021            
022            private void descore() {
023                    synchronized (workers) {
024                            Iterator it=workers.iterator();
025                            while (it.hasNext()) {
026                                    ((WorkerEntry) it.next()).score-=Integer.MAX_VALUE;
027                            }
028                    }
029            }
030            
031            private class WorkerEntry implements Comparable {
032                    Worker worker;
033                    int weight;
034                    int score;
035                    
036                    /**
037                     * @param worker
038                     * @param weight Must be >0
039                     */
040                    WorkerEntry(Worker worker, int weight) {
041                            super();
042                            if (weight<1) {
043                                    throw new IllegalArgumentException("Worker weight must be >0");
044                            }
045                            this.worker = worker;
046                            this.weight = weight;
047                    }
048    
049                    public int compareTo(Object o) {
050                            if (o instanceof WorkerEntry) {
051                                    return score-((WorkerEntry) o).score;
052                            }
053                                    
054                            return hashCode()-o.hashCode();
055                    }
056                    
057                    boolean post(Runnable job) {
058                            if (worker.post(job)) {
059                                    // reduce all scores to avoid overflow.
060                                    if (score>Integer.MAX_VALUE-weight) {
061                                            descore();
062                                    }
063                                    
064                                    score+=weight;
065                                    return true;
066                            }
067                            return false;
068                    }
069            }
070            
071            public boolean post(Runnable job) {
072                    synchronized (workers) {
073                            Collections.sort(workers);
074                            Iterator it=workers.iterator();
075                            while (it.hasNext()) {
076                                    WorkerEntry we=(WorkerEntry) it.next();
077                                    if (we.post(job)) {
078                                            return true;
079                                    }
080                            }
081                    }
082                    
083                    return false;
084            }
085    
086            public void addWorker(Worker worker, int weight) {
087                    synchronized (workers) {
088                            workers.add(new WorkerEntry(worker, weight));
089                    }
090            }
091    }