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 }