001 /* 002 Copyright (C) 2001-2003 Lionel Seinturier, 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.core.dist; 019 020 import java.io.Serializable; 021 import java.lang.reflect.Constructor; 022 import java.util.Arrays; 023 import org.apache.log4j.Logger; 024 import org.objectweb.jac.core.Collaboration; 025 import org.objectweb.jac.core.JacPropLoader; 026 import org.objectweb.jac.core.ObjectRepository; 027 import org.objectweb.jac.core.SerializedJacObject; 028 import org.objectweb.jac.util.WrappedThrowableException; 029 030 /** 031 * <code>RemoteRef</code> stores the reference of a remote object. 032 * The way the remote object is accessed depends on 033 * the underlying communication protocol (eg CORBA or RMI).<p> 034 * 035 * Supporting a new communication protocol requires to subclass RemoteRef 036 * (eg RMIRemoteRef or CORBARemoteRef) and to implement the resolve and 037 * reresolve methods.<p> 038 * 039 * @see org.objectweb.jac.core.dist.RemoteRef#resolve(java.lang.String) 040 * @see org.objectweb.jac.core.dist.RemoteRef#reresolve() 041 * @see org.objectweb.jac.core.dist.rmi.RMIRemoteRef 042 * 043 * @author <a href="http://www-src.lip6.fr/homepages/Lionel.Seinturier/index-eng.html">Lionel Seinturier</a> 044 * @author <a href="http://cedric.cnam.fr/~pawlak/index-english.html">Renaud Pawlak</a> 045 */ 046 public class RemoteRef implements Serializable { 047 static Logger logger = Logger.getLogger("dist"); 048 static Logger loggerSerial = Logger.getLogger("serialization"); 049 050 /** The reference of the container that handles the remote object. */ 051 protected RemoteContainer remCont; 052 053 /** The index (see org.objectweb.jac.core.JacObject) of the remote object. */ 054 protected int remIndex; 055 056 /** The name of the remote object that is of will be associated to 057 the remote ref. */ 058 protected String name = null; 059 060 /** Property key for the remote reference class. */ 061 //protected static final String remRefClassProp = "Jac.remoteRefClass"; 062 063 /** Default remote reference class. */ 064 //protected static final String remRefDefaultClassName = "org.objectweb.jac.core.dist.rmi.RMIRemoteRef"; 065 066 /** 067 * This class method returns a new RemoteRef object.<p> 068 * 069 * Property org.objectweb.jac.dist.remoteRefClass defines the class of the actual 070 * RemoteRef returned (e.g. CORBARemoteRef). If the property is not 071 * defined or if the class does not exist, RMIRemoteRef is the 072 * default.<p> 073 * 074 * @param name the name to give to the remote ref (should be equal 075 * to the pointed object name) 076 * @return a new RemoteRef object 077 */ 078 public static RemoteRef create(String name) { 079 080 RemoteRef remoteRef = null; 081 String remoteRefClassName = JacPropLoader.remoteRefClassName; 082 083 try { 084 Class remoteRefClass = Class.forName(remoteRefClassName); 085 remoteRef = (RemoteRef) remoteRefClass.newInstance(); 086 } catch (Exception e) { 087 logger.error("create "+name,e); 088 } 089 090 remoteRef.setName(name); 091 092 return remoteRef; 093 } 094 095 /** 096 * This class method returns a remote reference 097 * for an existing remote JAC object.<p> 098 * 099 * Property org.objectweb.jac.dist.remoteRefClass defines the class of the actual 100 * RemoteRef returned (e.g. CORBARemoteRef). If the property is not 101 * defined or if the class does not exist, RMIRemoteRef is the 102 * default.<p> 103 * 104 * @param name the remote object name (can be null if not needed) 105 * @param remCont the remote container where the JAC object is 106 * instantiated 107 * @param remIndex the index of the JAC object in the remote 108 * container 109 * @return the remote reference of the JAC object 110 */ 111 public static RemoteRef create(String name, 112 RemoteContainer remCont, 113 int remIndex) 114 { 115 logger.debug("creating remote ref " + name + ", " + 116 remCont + ", " + remIndex); 117 118 RemoteRef remoteRef = null; 119 String remoteRefClassName = JacPropLoader.remoteRefClassName; 120 /* 121 String remoteRefClassName = null; 122 123 if (JacObject.props != null) { 124 remoteRefClassName = JacObject.props.getProperty(remRefClassProp); 125 } 126 127 if ( remoteRefClassName == null ) { 128 remoteRefClassName = "org.objectweb.jac.core.dist.rmi.RMIRemoteRef"; 129 } 130 */ 131 try { 132 Class remoteRefClass = Class.forName(remoteRefClassName); 133 134 Constructor c = 135 remoteRefClass.getConstructor( 136 new Class[] { RemoteContainer.class, int.class } 137 ); 138 remoteRef = 139 (RemoteRef)c.newInstance( 140 new Object[] { remCont, new Integer(remIndex) }); 141 } catch(Exception e) { 142 logger.error("create "+name+","+remCont+","+remIndex,e); 143 } 144 145 remoteRef.setName(name); 146 logger.debug("returning remote ref " + remoteRef); 147 148 return remoteRef; 149 } 150 151 /** 152 * Create a remote reference from a local JAC object (in order, for 153 * example, to transmit it to a remote container).<p> 154 * 155 * @param name the name to be given to the remote reference 156 * @param localObject the object to create the reference from 157 * @return the new remote reference */ 158 159 public static RemoteRef create(String name, Object localObject) { 160 logger.debug("creating remote ref "+name+" for "+localObject); 161 return RemoteRef.create( 162 name, RemoteContainer.resolve(Distd.getLocalContainerName()), 163 ObjectRepository.getMemoryObjectIndex(localObject)); 164 } 165 166 /** 167 * This is a full constructor for RemoteRef.<p> 168 * 169 * @param remCont the ref of the container that handles the remote 170 * object. 171 * @param remIndex the index of the remote object */ 172 173 public RemoteRef(RemoteContainer remCont, int remIndex) { 174 this.remCont = remCont; 175 this.remIndex = remIndex; 176 } 177 178 179 /** 180 * This is a more friendly constructor for RemoteRef.<p> 181 * 182 * @param remCont the name of the container that handles the remote 183 * object. 184 * @param remIndex the index of the remote object. */ 185 186 public RemoteRef(String remCont, int remIndex) { 187 this.remCont = resolve(remCont); 188 this.remIndex = remIndex; 189 } 190 191 192 /** 193 * Empty default constructor for RemoteRef needed by the compiler whenever 194 * RemoteRef is subclasses (eg RMIRemoteRef or CORBARemoteRef).<p> 195 * 196 * This constructor should never be called in other cases (this is why it is 197 * protected).<p> 198 */ 199 200 protected RemoteRef() {} 201 202 203 /** 204 * The getter method for the remCont field.<p> 205 * 206 * It returns a the container that handles the remote object. If 207 * the remote container is local, then the object pointed by the 208 * remote reference is also local.<p> 209 * 210 * @return the remCont field value */ 211 212 public RemoteContainer getRemCont() { return remCont; } 213 214 215 /** 216 * The setter method for the name.<p> 217 * 218 * @param name the new name */ 219 220 public void setName(String name) { 221 this.name = name; 222 } 223 224 /** 225 * The getter method for the name. 226 * 227 * @return the reference name */ 228 229 public String getName() { 230 return name; 231 } 232 233 /** 234 * The getter method for the <code>remIndex</code> field.<p> 235 * 236 * <code>remIndex</code> is the index (see org.objectweb.jac.core.JacObject) of 237 * the remote object. 238 * 239 * @return the remIndex field value */ 240 241 public int getRemIndex() { return remIndex; } 242 243 /** 244 * This method resolves a container from a container name.<p> 245 * 246 * Its implementation is protocol dependent (eg RMI or CORBA). 247 * Most concrete implementations of this method (see RMIRemoteRef) 248 * simply delegate the resolution to a resolve() class method defined 249 * in a container class (see RMIRemoteContainer).<p> 250 * 251 * @param contName the name of the container 252 * @return the container 253 * 254 * @see org.objectweb.jac.core.dist.rmi.RMIRemoteRef#resolve(String) 255 */ 256 public RemoteContainer resolve(String contName) { return null; } 257 258 /** 259 * This method re-gets the reference of a remote container.<p> 260 * 261 * Its implementation is protocol dependent (eg RMI or CORBA). 262 * Some communication protocols (eg CORBA) do not linearalize 263 * remote references in a standard way. Thus a remote reference 264 * may need to be adapted whenever it is transmitted.<p> 265 * 266 * This method is called when a remote reference 267 * is recieved by a <code>RemoteContainer</code>.<p> 268 * 269 * @return the container reference 270 * 271 * @see org.objectweb.jac.core.dist.rmi.RMIRemoteRef#reresolve() 272 */ 273 public RemoteContainer reresolve() { return null; } 274 275 276 /** Following constants are property keys used by remoteNew(). */ 277 278 final protected static String toAdaptProp = "org.objectweb.jac.toAdapt"; 279 280 281 /** 282 * Remotely instantiate a class.<p> 283 * 284 * Make the current <code>RemoteRef</code> instance reference the 285 * created object.<p> 286 * 287 * @param host the host machine 288 * @param clName the class to instantiate */ 289 290 public void remoteNew(String host, String clName) { 291 remoteNewWithCopy(host, clName, null, null, null); 292 } 293 294 /** 295 * Remotely instantiate a class.<p> 296 * 297 * Make the current <code>RemoteRef</code> instance reference the 298 * created object.<p> 299 * 300 * @param host the host machine 301 * @param clName the class to instantiate 302 * @param args initialization arguments for the instantiation */ 303 304 public void remoteNew(String host, String clName, Object[] args) { 305 remoteNewWithCopy(host, clName, args, null, null); 306 } 307 308 /** 309 * Remotely instantiate a class.<p> 310 * 311 * Make the current <code>RemoteRef</code> instance reference the 312 * created object and copy the state of the given object into the 313 * remote object.<p> 314 * 315 * All the fields of the object are copied.<p> 316 * 317 * @param host the host machine 318 * @param clName the class to instantiate 319 * @param src the source object containing the data to copy */ 320 321 public void remoteNewWithCopy(String host, String clName, Object src) { 322 remoteNewWithCopy(host, clName, null, src, null); 323 } 324 325 /** 326 * Remotely instantiate a class.<p> 327 * 328 * Make the current <code>RemoteRef</code> instance reference the 329 * created object and copy the state of the given object into the 330 * remote object.<p> 331 * 332 * All the fields of the object are copied.<p> 333 * 334 * @param host the host machine 335 * @param clName the class to instantiate 336 * @param args initialization arguments for the instantiation 337 * @param src the source object containing the data to copy */ 338 339 public void remoteNewWithCopy(String host, 340 String clName, 341 Object[] args, 342 Object src) { 343 remoteNewWithCopy(host, clName, args, src, null); 344 } 345 346 347 /** 348 * Remotely instantiate a class.<p> 349 * 350 * Make the current <code>RemoteRef</code> instance reference the 351 * created object and copy the state of the given object into the 352 * remote object.<p> 353 * 354 * Only specified fields are copied.<p> 355 * 356 * @param host the host machine 357 * @param clName the class to instantiate 358 * @param src the source object containing the data to copy 359 * @param fieldsName the fields name to copy */ 360 361 public void remoteNewWithCopy(String host, 362 String clName, 363 Object src, 364 String[] fieldsName) { 365 remoteNewWithCopy(host, clName, null, src, fieldsName); 366 } 367 368 369 /** 370 * Remotely instantiate a class. 371 * 372 * Make the current <code>RemoteRef</code> instance reference the 373 * created object and copy the state of the given object into the 374 * remote object.<p> 375 * 376 * Only specified fields are copied.<p> 377 * 378 * @param host the host machine 379 * @param clName the class to instantiate 380 * @param args initialization arguments for the instantiation 381 * @param src the source object containing the data to copy 382 * @param fieldsName the fields name to copy */ 383 384 public void remoteNewWithCopy(String host, 385 String clName, 386 Object[] args, 387 Object src, 388 String[] fieldsName) 389 { 390 /** 391 * Resolving the host consists in getting the concrete remote reference 392 * (e.g. RMIRemoteRef or CORBARemoteRef) associated to the remote 393 * container where the remote instantiation is to be performed. 394 */ 395 396 remCont = resolve(host); 397 398 /** Prepare the fields name and value */ 399 400 Object[] fieldsValue = null; 401 402 if (src!=null) { 403 if ( fieldsName == null ) { 404 Object[] state = ObjectState.getState(src); 405 fieldsName = (String[])state[0]; 406 fieldsValue = (Object[])state[1]; 407 } 408 else { 409 Object[] state = ObjectState.getState(src,fieldsName ); 410 fieldsName = (String[])state[0]; 411 fieldsValue = (Object[])state[1]; 412 } 413 } 414 415 if (fieldsName!=null) 416 loggerSerial.debug( 417 "serializing fields "+Arrays.asList(fieldsName)+ 418 " values = "+Arrays.asList(fieldsValue)); 419 420 byte[] sfieldsValue = SerializedJacObject.serialize(fieldsValue); 421 if (sfieldsValue!=null) 422 Distd.outputCount += sfieldsValue.length; 423 424 /** Remotely create an instance of className */ 425 426 remIndex = 427 remCont.instantiates( 428 name, clName, args, fieldsName, 429 sfieldsValue, 430 SerializedJacObject.serialize(Collaboration.get()) 431 ); 432 433 } 434 435 /** 436 * Copy the state of a given object into the remote object 437 * referenced by the current reference.<p> 438 * 439 * All the fields of the object are copied.<p> 440 * 441 * @param src the source object containing the data to copy 442 */ 443 public void remoteCopy(Object src) { 444 445 Object[] state = ObjectState.getState(src); 446 byte[] sstate = SerializedJacObject.serialize( (Object[]) state[1] ); 447 448 if ( sstate != null ) Distd.outputCount += sstate.length; 449 450 /** Perform the remote copy */ 451 remCont.copy( 452 name, remIndex, 453 (String[]) state[0], 454 sstate, 455 SerializedJacObject.serialize(Collaboration.get()) 456 ); 457 } 458 459 460 /** 461 * Copy the state of a given object into the remote object 462 * referenced by the current reference.<p> 463 * 464 * Only specified fields are copied.<p> 465 * 466 * @param src the source object containing the data to copy 467 * @param fieldsName the fields name to copy 468 */ 469 public void remoteCopy(Object src, String[] fieldsName) { 470 471 Object[] state = ObjectState.getState(src,fieldsName ); 472 byte[] sstate = SerializedJacObject.serialize( (Object[]) state[1] ); 473 474 if ( sstate != null ) Distd.outputCount += sstate.length; 475 476 /** Perform the remote copy */ 477 478 remCont.copy( 479 name, 480 remIndex, 481 (String[]) state[0], 482 sstate, 483 SerializedJacObject.serialize(Collaboration.get()) 484 ); 485 } 486 487 /** 488 * Forward a call to the referenced object.<p> 489 * 490 * @param methodName the called method name 491 * @param methodArgs the called method arguments 492 * @return the result 493 */ 494 public Object invoke(String methodName, Object[] methodArgs) { 495 return invoke(methodName,methodArgs,null); 496 } 497 498 /** 499 * Forward a call to the referenced object.<p> 500 * 501 * @param methodName the called method name 502 * @param methodArgs the called method arguments 503 * @return the result 504 */ 505 public Object invoke(String methodName, Object[] methodArgs, 506 Boolean[] refs) 507 { 508 logger.debug("invoking "+methodName+" on "+this); 509 510 byte[] ret = null; 511 byte[] args = SerializedJacObject.serializeArgs(methodArgs,refs); 512 513 if (args != null) 514 Distd.outputCount += args.length; 515 516 // System.out.println("Collab = "+Collaboration.get()); 517 try { 518 ret = remCont.invoke( 519 remIndex, 520 methodName, 521 args, 522 SerializedJacObject.serialize(Collaboration.get()) 523 ); 524 } catch (Exception e) { 525 if (e instanceof WrappedThrowableException) { 526 throw (RuntimeException) e; 527 } 528 logger.error("Failed to remotely invoke "+methodName+": "+e); 529 } 530 531 if ( ret != null ) Distd.inputCount += ret.length; 532 533 return SerializedJacObject.deserialize( ret ); 534 } 535 536 /** 537 * Forward a role method call to the referenced object.<p> 538 * 539 * @param methodName the called role method name 540 * @param methodArgs the called role method arguments 541 * @return the result 542 */ 543 public Object invokeRoleMethod(String methodName,Object[] methodArgs) { 544 545 logger.debug("invoking role method "+methodName+" on "+ 546 this+"-"+remCont); 547 548 byte[] ret = null; 549 byte[] args = SerializedJacObject.serialize(methodArgs); 550 551 if (args != null) Distd.outputCount += args.length; 552 553 try { 554 ret = remCont.invokeRoleMethod( 555 remIndex, 556 methodName, 557 args, 558 SerializedJacObject.serialize(Collaboration.get()) 559 ); 560 } catch ( Exception e ) { 561 if ( e instanceof WrappedThrowableException ) { 562 throw (RuntimeException) e; 563 } 564 logger.error("Failed to remotely invoke "+methodName+": "+e); 565 } 566 567 if ( ret != null ) Distd.inputCount += ret.length; 568 569 return SerializedJacObject.deserialize(ret); 570 } 571 572 /** 573 * Create a textual representation of the remote reference. 574 * 575 * @return the textual representation of the current reference 576 */ 577 public String toString() { 578 return ( "#" + getRemCont().getName() + "/" + 579 name + "[" + getRemIndex() + "]#" ); 580 } 581 582 /** 583 * Test the equality of 2 remote references. 584 * 585 * @param o the remote reference to check 586 * @return true if equals the current one 587 */ 588 public boolean equals(Object o) { 589 if ( ! (o instanceof RemoteRef) ) return false; 590 RemoteRef r = (RemoteRef) o; 591 return ( r.getRemIndex() == remIndex ) 592 && ( r.getRemCont().equals (remCont) ); 593 } 594 595 }