001    /*
002      Copyright (C) 2001 Renaud Pawlak
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.consistency;
019    
020    import java.util.*;
021    import org.apache.log4j.Logger;
022    import org.objectweb.jac.core.*;
023    import org.objectweb.jac.core.dist.RemoteRef;
024    import org.objectweb.jac.core.rtti.MethodItem;
025    import org.objectweb.jac.util.Log;
026    
027    /**
028     * This wrapper implements a consistency protocol that forwards all
029     * the writing calls to all the replicas that are known by the
030     * wrapper.
031     *
032     * <p>It is called "push" since the wrapper pushes the data to the
033     * other replicas. Despite this strategy is the most curently used,
034     * other strong or weak consistency strategies can be implemented by
035     * other consistency wrappers.
036     * 
037     * @author <a href="http://cedric.cnam.fr/~pawlak/index-english.html">Renaud Pawlak</a>
038     *
039     * @see #whenWrite(Interaction)
040     * @see StrongPullConsistencyWrapper
041     * @see WeakConsistencyWrapper */
042    
043    public class StrongPushConsistencyWrapper extends ConsistencyWrapper {
044        static Logger logger = Logger.getLogger("consistency");
045    
046        /** a false that is true during notification. */
047        boolean inNotification = false;
048    
049        /**
050         * A friendly constructor for a push consistency wrapper.
051         *
052         * @param hosts a regular expression that defines the host where
053         * the consistency protocol is installed */
054    
055        public StrongPushConsistencyWrapper(AspectComponent ac, String hosts) {
056            super(ac);
057            knownReplicas = null;
058            this.hosts = hosts;
059        } 
060    
061        /** An empty constructor for the Consistency class. */
062        public StrongPushConsistencyWrapper(AspectComponent ac) {
063            super(ac);
064        } 
065    
066        /**
067         * Forwards the call to all the replicas and then call the
068         * replica.<p>
069         *
070         * The pushing mecanism is stopped by using the collaboration
071         * attribute value defined by <code>visitedReplicas</code>.
072         *
073         * @return the value returned by the wrapped method.
074         * @see ConsistencyWrapper#getVisitedReplicas() */
075    
076        public Object whenWrite(Interaction interaction) {
077    
078            Object ret = null;
079    
080            if (knownReplicas == null) {
081                calculateKnownReplicas(interaction.wrappee);
082            } 
083    
084            attrdef("Persistence.disabled", "true");
085    
086            if (knownReplicas != null) {
087                if (inNotification) return proceed(interaction);
088                inNotification = true;
089                Collaboration c = Collaboration.get();
090                Vector notified_replicas = (Vector)c.getAttribute(visitedReplicas);
091                if (notified_replicas == null) {
092                    notified_replicas = (Vector)c.addAttribute( 
093                        visitedReplicas, new Vector());
094                }
095    
096                try {
097                    Vector new_nr = new Vector();
098                    RemoteRef cur_replica = RemoteRef.create( 
099                        NameRepository.get().getName(interaction.wrappee), 
100                        interaction.wrappee);
101                
102                    for (int i = 0; i < knownReplicas.size(); i++) {
103                        if ( (! notified_replicas.contains(knownReplicas.get(i)) ) && 
104                             (! ((RemoteRef)knownReplicas.get(i)).getRemCont().isLocal()) ) {
105                      
106                            Vector kr = new Vector(knownReplicas);
107                            kr.remove(knownReplicas.get(i));
108                            new_nr.clear();
109                            new_nr.addAll(notified_replicas);
110                            new_nr.addAll(kr);
111                            new_nr.add (cur_replica);
112                            c.addAttribute(visitedReplicas, new_nr);
113                      
114                            logger.debug("(strong) write event on " + 
115                                         NameRepository.get().getName(interaction.wrappee)+
116                                         ":" + interaction.method + ":" +
117                                         ((RemoteRef)knownReplicas.get(i)).getRemCont().getName());
118                            try {
119                                ((RemoteRef)knownReplicas.get(i)).invokeRoleMethod(
120                                    "acceptRemoteWrite",
121                                    new Object[] { null, 
122                                                   new Object[] { interaction.method, 
123                                                                  interaction.args } }
124                                );
125                            } catch ( Exception e ) {
126                                logger.error("strong consistency error: "+
127                                             "failed to remotely invoke "+
128                                             "acceptRemoteWrite for "+
129                                             interaction.wrappee+"."+interaction.method);
130                                e.printStackTrace();
131                                break;
132                            }
133                        }
134                    }
135                } finally {
136                    c.addAttribute(visitedReplicas,null);
137                }
138            } else {
139                logger.debug("none replicas are known for "+
140                             NameRepository.get().getName(interaction.wrappee));
141            }
142            ret = proceed(interaction);
143    
144            inNotification = false;
145    
146            return ret;
147        }
148    
149        /**
150         * This method is called by <code>whenWrite</code> to push the
151         * needed data when a state is writen in a remote replica.
152         *
153         * The data is :<p>
154         * <ul><pre>
155         * data[0] = the write method name string
156         * data[1] = an array that contains the arguments of the write method 
157         * </pre></ul>
158         *
159         * @param remoteReplica expected to be a reference on the remote
160         * replica that recieved the write event
161         * @param data the data transmittedd by <code>whenWrite</code>
162         * @return null by default
163         * @see #whenWrite(Interaction) */
164    
165        public Object acceptRemoteWrite(Wrappee wrappee, RemoteRef remoteReplica,
166                                        Object[] data) {
167            logger.debug("(strong) remote write event on " + 
168                         NameRepository.get().getName(wrappee) + 
169                         ":" + data[0]);
170            Object ret=null;
171            try {
172                ret = ((MethodItem)data[0]).invoke(
173                    wrappee, (Object[])data[1]);
174            } catch (Exception e) {
175                e.printStackTrace();
176            }
177            return ret;
178        }
179       
180        /**
181         * Push the current replica state to the binding new replica.
182         *
183         * @param newReplica the replica that is currently binding
184         */
185    
186        public void whenBindingNewReplica(Wrappee wrappee, RemoteRef newReplica) {
187            logger.debug("(strong) initialized " + 
188                         newReplica + " with " + 
189                         NameRepository.get().getName(wrappee));
190            newReplica.remoteCopy(wrappee);
191        }
192          
193    }