001    /*
002      Copyright (C) 2001-2002 Renaud Pawlak <renaud@aopsys.com>
003    
004      This program is free software; you can redistribute it and/or modify
005      it under the terms of the GNU Lesser General Public License as
006      published by the Free Software Foundation; either version 2 of the
007      License, or (at your option) any later version.
008    
009      This program is distributed in the hope that it will be useful,
010      but WITHOUT ANY WARRANTY; without even the implied warranty of
011      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
012      GNU Lesser General Public License for more details.
013    
014      You should have received a copy of the GNU Lesser General Public License
015      along with this program; if not, write to the Free Software
016      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
017    
018    package org.objectweb.jac.aspects.distribution;
019    
020    
021    import java.util.*;
022    import org.aopalliance.intercept.ConstructorInvocation;
023    import org.aopalliance.intercept.MethodInvocation;
024    import org.apache.log4j.Logger;
025    import org.objectweb.jac.core.*;
026    import org.objectweb.jac.core.dist.*;
027    import org.objectweb.jac.util.Log;
028    
029    /**
030     * This Aspect Component allows the programmer to easily implement
031     * load-balancing features for its application when JAC is running in
032     * distributed mode.
033     *
034     * @see LoadBalancingConf
035     * @author Renaud Pawlak
036     */
037    
038    public class LoadBalancingAC
039            extends AspectComponent
040            implements LoadBalancingConf 
041    {
042        static Logger logger = Logger.getLogger("loadbalancing");
043    
044            public void addRoundTripLoadBalancer(
045                    String wrappeeName,
046                    String methods,
047                    String hostName,
048                    String replicaExpr) {
049    
050                    pointcut(
051                            wrappeeName,
052                            ".*",
053                            methods + " && !CONSTRUCTORS && !STATICS",
054                            new LoadBalancingWrapper(this, replicaExpr),
055                            hostName,
056                            null);
057            }
058    
059            public void addRandomLoadBalancer(
060                    String wrappeeName,
061                    String methods,
062                    String hostName,
063                    String replicaExpr) {
064    
065                    pointcut(
066                            wrappeeName,
067                            ".*",
068                            methods + " && !CONSTRUCTORS && !STATICS",
069                            new LoadBalancingWrapper(this, replicaExpr),
070                            hostName,
071                            null);
072            }
073    
074            /**
075             * This inner-wrapper handles the load-balancing wrapping methods that
076             * actually implement the load-balancing algorithms. */
077    
078            public class LoadBalancingWrapper extends Wrapper {
079    
080                    int count = 0;
081                    Vector replicas = null;
082                    Random random = new Random();
083                    String hostExpr;
084                    boolean doFill = true;
085    
086                    public LoadBalancingWrapper(AspectComponent ac, String hostExpr) {
087                            super(ac);
088                            this.hostExpr = hostExpr;
089                    }
090    
091                    public void invalidate() {
092                            doFill = true;
093                    }
094    
095                    public Object invoke(MethodInvocation invocation) throws Throwable {
096                            return roundTripBalance((Interaction) invocation);
097                    }
098    
099                    public Object construct(ConstructorInvocation invocation)
100                            throws Throwable {
101                            throw new Exception("This wrapper does not support constructor wrapping");
102                    }
103    
104                    /**
105                     * Performs a round-trip load-balancing. */
106    
107                    public Object roundTripBalance(Interaction interaction) {
108                            if (doFill) {
109                                    replicas =
110                                            Topology.getPartialTopology(hostExpr).getReplicas(
111                                                    interaction.wrappee);
112                                    logger.debug("filled partial topo with "+ hostExpr
113                                 + " on "+ Topology.get() + ": " + replicas);
114                                    doFill = false;
115                            }
116                            if (replicas.size() == 0) {
117                                    // none replicas where found, we perform a local call and 
118                                    // will try to get them again on the next call
119                                    doFill = true;
120                                    logger.warn(
121                                            "load-balancing: no replica found, on "
122                                                    + interaction.wrappee + ": local call performed");
123                                    return proceed(interaction);
124                            }
125                            if (count >= replicas.size()) {
126                                    count = 0;
127                            }
128                            return ((RemoteRef) replicas.get(count++)).invoke(
129                                    interaction.method.getName(),
130                                    interaction.args);
131                    }
132    
133                    /**
134                     * Performs a random load-balancing. */
135    
136                    public Object randomBalance(Interaction interaction) {
137                            if (doFill) {
138                                    replicas =
139                                            Topology.getPartialTopology(hostExpr).getReplicas(
140                                                    interaction.wrappee);
141                                    doFill = false;
142                            }
143                            if (replicas.size() == 0) {
144                                    // none replicas where found, we perform a local call and 
145                                    // will try to get them again on the next call
146                                    doFill = true;
147                                    logger.warn("load-balancing: no replica found, local call performed");
148                                    return proceed(interaction);
149                            }
150                            return (
151                                    (RemoteRef) replicas.get(
152                                            random.nextInt(replicas.size()))).invoke(
153                                    interaction.method.getName(),
154                                    interaction.args);
155                    }
156            }
157    
158    }