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.consistency;
019    
020    import java.util.*;
021    import org.aopalliance.intercept.ConstructorInvocation;
022    import org.aopalliance.intercept.MethodInvocation;
023    import org.apache.log4j.Logger;
024    import org.objectweb.jac.core.*;
025    import org.objectweb.jac.core.dist.*;
026    import org.objectweb.jac.core.rtti.ClassRepository;
027    import org.objectweb.jac.util.Log;
028    
029    /**
030     * This wrapper class is the base class for all the consistency
031     * wrappers that implement a consistency protocol.
032     *
033     * <p>By default it does nothing and provides no consistency at all
034     * between the replicas. A consistency programmer should define the
035     * wrapping and role method to implement a specific consistency
036     * protocol.<p>
037     *
038     * @author <a href="http://cedric.cnam.fr/~pawlak/index-english.html">Renaud Pawlak</a>
039     */
040    
041    public class ConsistencyWrapper extends Wrapper {
042        static Logger logger = Logger.getLogger("consistency");
043    
044            /** Storage for known replicas. */
045            protected Vector knownReplicas = new Vector();
046    
047            /** The replicas type. */
048            Class type = null;
049    
050            /** The read method names. */
051            String[] readMethods = null;
052    
053            /** The write method names. */
054            String[] writeMethods = null;
055    
056            /** The call method names. */
057            String[] callMethods = null;
058    
059            String hosts = null;
060    
061            /** Visited sites global attribute name. */
062            static protected String visitedReplicas = "visitedReplicas";
063    
064            static {
065                    Collaboration.setGlobal(visitedReplicas);
066            }
067    
068            /** Use to indicate that you need all the methods. */
069            public static String ALL_METHODS = "ALL";
070            /** Use to indicate that you need all the modifiers. */
071            public static String ALL_MODIFIERS = "ALL_MODIFIERS";
072            /** Use to indicate that you need all the getters. */
073            public static String ALL_GETTERS = "ALL_GETTERS";
074    
075            /**
076             * Default constructor. */
077    
078            public ConsistencyWrapper(AspectComponent ac) {
079                    super(ac);
080                    this.knownReplicas = null;
081            }
082    
083            /**
084             * Contructor for initialization.
085             *
086             * @param type the type of the wrappee
087             * @param readMethods the methods that read the wrappee's state
088             * @param writeMethods the methods that write the wrappee's state
089             * @param callMethods the stateless methods */
090    
091            public ConsistencyWrapper(
092                    AspectComponent ac,
093                    Class type,
094                    String[] readMethods,
095                    String[] writeMethods,
096                    String[] callMethods,
097                    String hosts) {
098                    super(ac);
099                    this.type = type;
100                    setReadMethods(readMethods);
101                    setWriteMethods(writeMethods);
102                    setCallMethods(callMethods);
103                    this.hosts = hosts;
104            }
105    
106            /**
107             * Wraps a wrappee with a consistency wrapper. */
108    
109            public static void wrap(
110                    Wrappee wrappee,
111                    Class wrapperClass,
112                    String[] readMethods,
113                    String[] writeMethods,
114                    String[] callMethods,
115                    String hosts) {
116                    ConsistencyWrapper wrapper = null;
117                    try {
118                            wrapper =
119                                    (ConsistencyWrapper) wrapperClass
120                                            .getConstructor(new Class[] { AspectComponent.class })
121                                            .newInstance(new Object[] { null });
122                    } catch (Exception e) {
123                            e.printStackTrace();
124                            return;
125                    }
126                    wrapper.type = wrappee.getClass();
127                    wrapper.setReadMethods(readMethods);
128                    wrapper.setWriteMethods(writeMethods);
129                    wrapper.setCallMethods(callMethods);
130                    wrapper.hosts = hosts;
131                    // TODO: consitency reengineering.
132                    //Wrapping.wrap(wrappee, wrapper, "whenRead", readMethods);
133                    //Wrapping.wrap(wrappee, wrapper, "whenWrite", writeMethods);
134                    //Wrapping.wrap(wrappee, wrapper, "whenCall", callMethods);
135            }
136    
137            /**
138             * Add a replica to the knowledge graph.<p>
139             *
140             * The way the member is added
141             * to the knowledge graph depends on the knowledge graph.
142             *
143             * @param newReplica the reference on the replica to add
144             */
145    
146            public void addMember(RemoteRef newReplica) {
147    
148                    String[][] wrapped_methods =
149                            new String[][] { readMethods, writeMethods, callMethods };
150                    String[] wrapping_methods =
151                            new String[] { "whenRead", "whenWrite", "whenCall" };
152                    Class wrapper_type = getClass();
153                    ConsistencyWrapper wrapper = null;
154    
155                    try {
156    
157                            wrapper = (ConsistencyWrapper) wrapper_type.newInstance();
158    
159                            if (wrapper == null) {
160                                    throw new InstantiationException();
161                            }
162    
163                            wrapper.setReadMethods(readMethods);
164                            wrapper.setWriteMethods(writeMethods);
165                            wrapper.setCallMethods(callMethods);
166    
167                    } catch (Exception e) {
168                            e.printStackTrace();
169                    }
170    
171                    wrapper.addKnownReplica(newReplica);
172    
173                    newReplica.invoke(
174                            "wrap",
175                            new Object[] { wrapper, wrapping_methods, wrapped_methods });
176    
177                    whenBindingNewReplica(newReplica);
178    
179                    /*      newReplica.invoke(
180                       "invokeRoleMethod",
181                       new Object[] {
182                          "whenNewReplicaBounded",
183                          new Object[] {
184                             null,
185                          }
186                       }
187                       );*/
188    
189            }
190    
191            /**
192             * Invalidates the topology.
193             *
194             * <p>When this method is called, the next consistency protocol run
195             * will recalculate the known replica with the new topology. */
196    
197            public void invalidateTopology() {
198                    knownReplicas = null;
199            }
200    
201            /**
202             * Calculates the known replicas with the topology and the host
203             * expression. */
204    
205            void calculateKnownReplicas(Wrappee wrappee) {
206                    logger.debug("calculing known replicas for " + wrappee);
207                    knownReplicas = Topology.getPartialTopology(hosts).getReplicas(wrappee);
208                    logger.debug("result for known replicas="+ knownReplicas
209                                    + "(on topology " + Topology.getPartialTopology(hosts) + ")");
210            }
211    
212            /**
213             * This method is called when new member is bounded to the
214             * replication group.
215             *
216             * <p>It is typically used to initialize (in a push manner) the new
217             * member state with the data that need to be replicated. By
218             * default, this method does nothing.
219             *
220             * @param newReplica the replica that is beeing added */
221    
222            public void whenBindingNewReplica(RemoteRef newReplica) {
223            }
224    
225            /**
226             * This method is called on the new member when the binding is
227             * finished.
228             *
229             * <p>It is typically used to initialize (in a pull manner)
230             * the new member state with the data that need to be
231             * replicated. By default, this method does nothing.
232             *
233             * @param remoteReplica the replica that has just been bounded
234             */
235    
236            public void whenNewReplicaBounded(RemoteRef remoteReplica) {
237            }
238    
239            /**
240             * Returns the visited replicas global attribute of the
241             * collaboration.
242             * 
243             * @return the name of the attribute
244             */
245    
246            public String getVisitedReplicas() {
247                    return visitedReplicas;
248            }
249    
250            /**
251             * Returns a string representation of the wrapper.
252             *
253             * @return a string representation of the wrapper
254             */
255    
256            public String toString() {
257                    if (knownReplicas == null)
258                            return "Consistency wrapper, no known replicas";
259                    else
260                            return "Consistency wrapper, known replicas = " + knownReplicas;
261            }
262    
263            /**
264             * Set the read method names (methods that read the replica
265             * state).
266             *
267             * @param readMethods the names of the read methods */
268    
269            public void setReadMethods(String[] readMethods) {
270                    this.readMethods = expandMethods(readMethods);
271            }
272    
273            /** 
274             * Set the write method names (methods that change the replica
275             * state).
276             * 
277             * @param writeMethods the names of the write methods
278             */
279    
280            public void setWriteMethods(String[] writeMethods) {
281                    this.writeMethods = expandMethods(writeMethods);
282            }
283    
284            /** 
285             * Set the call method names (methods that neither write or read
286             * the replica state).
287             * 
288             * @param callMethods the names of the call methods
289             */
290    
291            public void setCallMethods(String[] callMethods) {
292                    this.callMethods = expandMethods(callMethods);
293            }
294    
295            /**
296             * The getter method for the known replicas.
297             *
298             * <p>The known replicas of a consistency wrapper are remote
299             * references on other member of the replication group. With this
300             * information, the consistency wrapper can implement consistency
301             * protocols. The most usual schemes are to be aware of all the
302             * replicas of the group (see for instance
303             * <code>StrongPushConsistencyWrapper</code>) or to be aware of ony
304             * one replica (see for instance
305             * <code>ClientServerConsistencyWrapper</code>.
306             *
307             * @return a set of references on the known replicas */
308    
309            public Vector getKnownReplicas() {
310                    return knownReplicas;
311            }
312    
313            /**
314             * Adds a known replica.
315             * 
316             * @param newReplica the known replica to add
317             */
318            public void addKnownReplica(RemoteRef newReplica) {
319                    knownReplicas.add(newReplica);
320            }
321    
322            /**
323             * The get method for the consistency wrapper actual type.<p>
324             *
325             * @return the class of the wrapper */
326    
327            public Class getConsistencyWrapperType() {
328                    return getClass();
329            }
330    
331            /**
332             * The setter method for the known replicas.<p>
333             *
334             * The known replicas of a consistency wrapper are remote
335             * references on other member of the replication group. With this
336             * information, the consistency wrapper can implement consistency
337             * protocols. The most usual schemes are to be aware of all the
338             * replicas of the group (see for instance
339             * <code>StrongPushConsistencyWrapper</code>) or to be aware of ony
340             * one replica (see for instance
341             * <code>ClientServerConsistencyWrapper</code>.<p>
342             *
343             * @param knownReplicas the new known replicas */
344    
345            public void setKnownReplicas(Vector knownReplicas) {
346                    this.knownReplicas = knownReplicas;
347            }
348    
349            /**
350             * This wrapping method must be defined to implement a given
351             * builtin consistency protocol and must wrap the replica methods
352             * that need to be consistent with the other replicas.<p>
353             *
354             * It should not wrap a method that is allready wrapped by a
355             * <code>WhenWrite</code> or <code>WhenRead</code> method.<p>
356             *
357             * Default: do nothing and call the replica.<p>
358             *
359             * @return by default the wrapped method return value
360             * @see #acceptRemoteCall(RemoteRef,Object[]) */
361    
362            public Object whenCall(Interaction interaction) {
363                    return proceed(interaction);
364            }
365    
366            /**
367             * This wrapping method must be defined to implement a given
368             * builtin consistency protocol and must wrap all the replicas
369             * methods that provoque a change in this replica state.<p>
370             *
371             * Default: do nothing and call the replica.<p>
372             *
373             * @return by default the wrapped method return value
374             * @see #acceptRemoteWrite(Wrappee,RemoteRef,Object[]) */
375    
376            public Object whenWrite(Interaction interaction) {
377                    return proceed(interaction);
378            }
379    
380            /**
381             * This wrapping method must be defined to implement a given
382             * builtin consistency protocol and must wrap all the replica
383             * methods that read the replica state.<p>
384             *
385             * Default: do nothing and call the replica.<p>
386             *
387             * @return by default the wrapped method return value
388             * @see #acceptRemoteRead(Wrappee,RemoteRef,Object[]) */
389    
390            public Object whenRead(Interaction interaction) {
391                    return proceed(interaction);
392            }
393    
394            /**
395             * This role method can called by the <code>whenCall</code>
396             * wrapping method of a remote replica.<p>
397             *
398             * By overloading this method, the programmer can implement
399             * specific consistency protocols.<p>
400             *
401             * Default: do nothing.<p>
402             *
403             * @param remoteReplica expected to be a reference on the remote
404             * replica that recieved the call event
405             * @param data the data transmittedd by <code>whenCall</code>
406             * @return null by default
407             * @see #whenCall(Interaction) */
408    
409            public Object acceptRemoteCall(RemoteRef remoteReplica, Object[] data) {
410                    return null;
411            }
412    
413            /**
414             * This role method can called by the <code>whenWrite</code>
415             * wrapping method of a remote replica.<p>
416             *
417             * By overloading this method, the programmer can implement
418             * specific consistency protocols.<p>
419             *
420             * Default: do nothing.<p>
421             *
422             * @param remoteReplica expected to be a reference on the remote
423             * replica that recieved the write event
424             * @param data the data transmittedd by <code>whenWrite</code>
425             * @return null by default
426             * @see #whenWrite(Interaction) */
427    
428            public Object acceptRemoteWrite(
429                    Wrappee wrappee,
430                    RemoteRef remoteReplica,
431                    Object[] data) {
432                    return null;
433            }
434    
435            /**
436             * This role method can called by the <code>whenRead</code>
437             * wrapping method of a remote replica.<p>
438             *
439             * By overloading this method, the programmer can implement
440             * specific consistency protocols.<p>
441             *
442             * Default: do nothing.<p>
443             *
444             * @param remoteReplica expected to be a reference on the remote
445             * replica that recieved the read event
446             * @param data the data transmittedd by <code>whenRead</code>
447             * @return null by default
448             * @see #whenRead(Interaction) */
449    
450            public Object acceptRemoteRead(
451                    Wrappee wrappee,
452                    RemoteRef remoteReplica,
453                    Object[] data) {
454                    return null;
455            }
456    
457            /**
458             * Construct a real methods array with an array that can contain
459             * consistency specific strings (like the one that indicates that
460             * we need all the modifiers).
461             *
462             * @param methods a set of methods to expand (can contain
463             * ALL_METHODS, ALL_MODIFIERS, and ALL_GETTERS keywords)
464             * @return a set of methods where the keywords have been expanded
465             * with the corresponding method of the type 
466             */
467            protected String[] expandMethods(String[] methods) {
468                    if (methods == null)
469                            return null;
470                    Vector newVM = new Vector();
471                    for (int i = 0; i < methods.length; i++) {
472                            if (methods[i].equals(ALL_METHODS)) {
473                                    newVM.addAll(
474                                            Arrays.asList(ClassRepository.getMethodsName(type)));
475                            } else if (methods[i].equals(ALL_MODIFIERS)) {
476                                    newVM.addAll(
477                                            Arrays.asList(ClassRepository.getModifiersNames(type)));
478                            } else if (methods[i].equals(ALL_GETTERS)) {
479                                    newVM.addAll(
480                                            Arrays.asList(ClassRepository.getGettersNames(type)));
481                            } else {
482                                    newVM.add(methods[i]);
483                            }
484                    }
485                    String[] newMethods = new String[newVM.size()];
486                    for (int i = 0; i < newMethods.length; i++) {
487                            newMethods[i] = (String) newVM.get(i);
488                    }
489                    return newMethods;
490            }
491    
492            /* (non-Javadoc)
493             * @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation)
494             */
495            public Object invoke(MethodInvocation invocation) throws Throwable {
496                    // TODO Auto-generated method stub
497                    return null;
498            }
499    
500            /* (non-Javadoc)
501             * @see org.aopalliance.intercept.ConstructorInterceptor#construct(org.aopalliance.intercept.ConstructorInvocation)
502             */
503            public Object construct(ConstructorInvocation invocation)
504                    throws Throwable {
505                    // TODO Auto-generated method stub
506                    return null;
507            }
508    
509    }