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.objectweb.jac.core.*;
022    import org.objectweb.jac.core.rtti.*;
023    import org.objectweb.jac.core.dist.*;
024    
025    /**
026     * This class handles any type of consistency protocol on a
027     * replicaction group.
028     *
029     * <p>A replication group is a set of objects of the same class that
030     * are related through a consistency protocol.<p>
031     *
032     * @author <a href="http://cedric.cnam.fr/~pawlak/index-english.html">Renaud Pawlak</a>
033     */
034    
035    public class Consistency {
036    
037       /** The knowledge style is defined by the user (the whole knowledge
038           graph has to be defined at construction time). */
039       public static int KS_USER = 0;
040       /** With this knowledge style, all the replicas know the same
041           unique replica (to be defined at construction time). */
042       public static int KS_ONE = 1;
043       /** With this knowledge style, all the replicas know all the other
044           replicas (none info is required at construction time). */
045       public static int KS_ALL = 2;
046       /** With this knowledge style, each replica knows only one replica
047           which is its neighbour in the replicas list (and last knows the
048           first) (none info is required at construction time). */
049       public static int KS_NEXT = 3;
050       /** With this knowledge style, each replica knows only one replica
051           which is its father in a binary tree (the top of the tree has
052           to be defined at construction time). */
053       public static int KS_BTREE = 4;
054    
055       /** Use to indicate that you need all the methods. */
056       public static String ALL_METHODS = "ALL";
057       /** Use to indicate that you need all the modifiers. */
058       public static String ALL_MODIFIERS = "ALL_MODIFIERS";
059       /** Use to indicate that you need all the getters. */
060       public static String ALL_GETTERS = "ALL_GETTERS";
061    
062       /** The wrapper type that implements the consistency protocol. */
063       Class consistencyWrapperType;
064       /** The knowledge style. */
065       int knowledgeStyle = 0;
066       /** The knowledge graph. */
067       int[] knowledgeGraph = null;
068       
069       /**
070        * Creates a new consistency.
071        *
072        * <p>The knowledge style can be one the following:
073        *
074        * <ul><li>KS_USER: the knowledge style is defined by the user (the
075        * whole knowledge graph has to be defined in the int[] argument
076        * that defines the edges of the graph)</li>
077        *
078        * <li>KS_ONE: with this knowledge style, all the replicas know the
079        * same unique replica (the knowledge graph argument contains only
080        * one element)</li>
081        *
082        * <li>KS_ALL: with this knowledge style, all the replicas know all
083        * the other replicas (the knowledge graph is empty)</li>
084        *
085        * <li>KS_NEXT: with this knowledge style, each replica knows only
086        * one replica which is its neighbour in the replicas list (and
087        * last knows the first) (the knowledge graph is empty)</li>
088        *
089        * <li>KS_BTREE: with this knowledge style, each replica knows only
090        * one replica which is its father in a binary tree (the knowledge
091        * graph argument contains only one element wich is the top of the
092        * tree).</li></ul>
093        * 
094        * @param consistencyWrapperType the wrapper type that actually
095        * implements the consistency protocol
096        * @param knowledgeStyle can be KS_USER, KS_ONE, KS_ALL, KS_NEXT,
097        * or KS_BTREE
098        * @param knowledgeGraph depending on the knowledge style, can be
099        * empty or describing what set of replicas are known by other
100        * replicas */
101    
102       public Consistency ( Class consistencyWrapperType,
103                            int knowledgeStyle, int[] knowledgeGraph ) {
104          this.consistencyWrapperType = consistencyWrapperType;
105          this.knowledgeStyle = knowledgeStyle;
106          this.knowledgeGraph = knowledgeGraph;
107       }
108    
109      /** 
110        * Says if a replica is deployed on the given site.
111        *
112        * @param name the name of the replica
113        * @param container the remote container to check
114        * @return true if a replica of the given name is found on the
115        * given container */
116       
117       public static boolean isReplicatedOn ( String name, RemoteContainer container ) {
118          RemoteRef rr = container.bindTo ( "JAC_name_repository" );
119          Object distobj = rr.invoke ( 
120             "callOrgMethod", new Object[] { "getObject", new Object[] { name } } );
121          if ( distobj == null ) {
122             return false;
123          }
124          return true;
125       }
126    
127       /**
128        * Construct a real methods array with an array that can contain
129        * consistency specific strings (like the one that indicates that
130        * we need all the modifiers).
131        *
132        * @param type the class to expand
133        * @param methods a set of methods to expand (can contain
134        * ALL_METHODS, ALL_MODIFIERS, and ALL_GETTERS keywords)
135        * @return a set of methods where the keywords have been expanded
136        * with the corresponding method of the type */
137    
138       protected String[] expandMethods( Class type, String[] methods ) {
139          if ( methods == null ) return null;
140          Vector newVM = new Vector();
141          for ( int i = 0; i < methods.length; i++ ) {
142             if ( methods[i].equals(ALL_METHODS) ) {
143                newVM.addAll( Arrays.asList(
144                   ClassRepository.getMethodsName(type) ) );
145             }
146             else if ( methods[i].equals(ALL_MODIFIERS) ) {
147                newVM.addAll( Arrays.asList( 
148                   ClassRepository.getModifiersNames(type) ) );
149             }
150             else if ( methods[i].equals(ALL_GETTERS) ) {
151                newVM.addAll( Arrays.asList( 
152                   ClassRepository.getGettersNames(type) ) );
153             }
154             else {
155                newVM.add( methods[i] );
156             }
157          }
158          String[] newMethods = new String[newVM.size()];
159          for ( int i = 0; i < newMethods.length; i++ ) {
160             newMethods[i] = (String) newVM.get(i);
161          }
162          return newMethods;
163       }
164    
165     
166       /**
167        * Deploy the consistency on a set of remote objects.
168        *
169        * <p>PRE: the objects must have been previously deployed.
170        * 
171        * @param members the references on the replicated members
172        * @param type the class of these members
173        * @param readMethods the names of the methods of the type that
174        * read the objects states
175        * @param writeMethods the names of the methods of the type that
176        * write the objects states
177        * @param callMethods the names of the methods of the type that
178        * neither read or write the objects states
179        *
180        * @see Deployment#deployStruct(Object[])
181        * @see Deployment#deploy(Object[])
182        * @see Deployment#replicateStruct(Object)
183        * @see Deployment#replicate(Object)
184        */
185    
186       public void deploy ( RemoteRef[] members, Class type, 
187                            String[] readMethods,
188                            String[] writeMethods,
189                            String[] callMethods )
190          throws WrongConsistencyDefinitionException {
191    
192          ConsistencyWrapper curwrapper;
193          RemoteRef referee = null;
194          boolean ok = false;
195    
196          readMethods = expandMethods( type, readMethods );
197          writeMethods = expandMethods( type, writeMethods );
198          callMethods = expandMethods( type, callMethods );
199    
200          try {
201    
202             String kstag = "";   
203    
204             if (knowledgeStyle == KS_ONE) {
205                
206                referee = members[knowledgeGraph[0]];
207                for (int i = 0; i < members.length; i++) {
208                   wrapMember ( members[i],
209                                new String[] {"whenRead", "whenWrite", "whenCall"},
210                                new String[][] {readMethods, writeMethods, callMethods},
211                                new RemoteRef[] { referee }, kstag );
212                }
213                ok = true;
214             }
215             
216             if (knowledgeStyle == KS_ALL) {
217                
218                for (int i = 0; i < members.length; i++) {
219                   wrapMember ( members[i],
220                                new String[] {"whenRead", "whenWrite", "whenCall"},
221                                new String[][] {readMethods, writeMethods, callMethods},
222                                members, kstag );
223                }
224                ok = true;
225             }
226             
227             if (knowledgeStyle == KS_NEXT) {
228                
229                for (int i = 0; i < members.length; i++) {
230                   if ( i == members.length - 1 ) {
231                      referee = members[0];
232                   } else {
233                      referee = members[i + 1];
234                   }
235                   wrapMember ( members[i],
236                                new String[] {"whenRead", "whenWrite", "whenCall"},
237                                new String[][] {readMethods, writeMethods, callMethods},
238                                new RemoteRef[] { referee }, kstag );
239                }
240                ok = true;
241             }
242          } catch ( Exception e ) { e.printStackTrace(); }
243    
244          if (!ok) {
245             throw new WrongConsistencyDefinitionException();
246          }
247       }
248    
249       /** 
250        * Internally used to wrap a remote member with a consistency
251        * wrapper.
252        *
253        * @param member the member to wrap
254        * @param wrappingMethods the methods of the consistency wrapper
255        * that will wrap this member
256        * @param wrappedMethods for each wrapping method, the set of
257        * methods of the member that will be actually wrapped
258        * @param knowledge the set of other members known by the newly
259        * wrapped member
260        * @param kstag the knowledge style tag */
261    
262       protected void wrapMember ( RemoteRef member, String[] wrappingMethods,
263                                   String[][] wrappedMethods, RemoteRef[] knowledge,
264                                   String kstag  )
265       throws InstantiationException {
266    
267          if ( wrappedMethods != null && wrappingMethods != null ) {
268    
269             Class wrapper_type = consistencyWrapperType;
270             ConsistencyWrapper wrapper = null;
271             
272             try {
273    
274                wrapper = (ConsistencyWrapper) wrapper_type.newInstance();
275                
276                if (wrapper == null) {
277                   throw new InstantiationException();
278                }
279                
280                //wrapper.setKnownReplicas( knowledge );
281                //wrapper.knowledgeStyle = knowledgeStyle;
282                //wrapper.kstag = kstag;
283                wrapper.setReadMethods ( wrappedMethods[0] );
284                wrapper.setWriteMethods ( wrappedMethods[1] );
285                wrapper.setCallMethods ( wrappedMethods[2] );
286             
287             } catch ( Exception e ) {
288                throw new InstantiationException();
289             }
290    
291             member.invoke(
292                "wrap",
293                new Object[] {
294                   wrapper,
295                   wrappingMethods,
296                   wrappedMethods
297                }
298             );
299          }
300       }
301    
302       /**
303        * This method binds a new object to the group of replicas of this
304        * consistency.
305        *
306        * @param name the name of the replica to bind to
307        * @param tobind the object to be put in consistency with the group
308        */
309       public static void bindToDistObj(String name, Wrappee tobind) {
310          Topology topology = Topology.get();
311          if (topology.countContainers() < 1) 
312             return;
313          RemoteContainer rc = topology.getContainer(0);
314          RemoteRef rr = rc.bindTo(name);
315          rr.invokeRoleMethod (
316             "addMember", 
317             new Object[] { RemoteRef.create(NameRepository.get().getName(tobind), tobind) } );
318      }   
319                         
320    }
321    
322    class WrongConsistencyDefinitionException extends Exception {}
323    
324    
325    
326    
327    
328    
329    
330