00001 00009 package jvn; 00010 00011 import java.io.Serializable; 00012 00013 00017 public class JvnObjectImpl implements JvnObject { 00021 private static final long serialVersionUID = -1348964285294975085L; 00022 00029 protected Serializable __containedObject = null; 00030 00044 JvnObjectState __containedObjectLockState = null; 00045 00049 private int numberOfReadLocks = -1; 00050 00058 private int jvnObjectId = -1; 00059 00071 public JvnObjectImpl( Serializable o ) /*throws JvnException*/ { 00072 __containedObject = o; 00073 numberOfReadLocks = 0; 00074 __containedObjectLockState = JvnObjectState.STATE_WLOCKT; 00075 } 00076 00092 public void jvnLockRead() throws JvnException { 00093 // Only process one lock request at a time 00094 synchronized(__containedObjectLockState) { 00095 // Whether we should ask the server for the read lock or not 00096 // Asking needs to be done OUTSIDE a synchronized block (deadlock) 00097 boolean askServer = false; 00098 00099 synchronized(this) { 00100 if( __containedObjectLockState == JvnObjectState.STATE_RLOCKC ) { 00101 // We already have a cached read lock 00102 numberOfReadLocks = 1; 00103 __containedObjectLockState = JvnObjectState.STATE_RLOCKT; 00104 // System.out.println("Read lock: upgrading from \"cached\" to \"taken\"."); 00105 } else if( __containedObjectLockState == JvnObjectState.STATE_RLOCKT ) { 00106 // We already have a lock: simply increment reference count 00107 numberOfReadLocks++; 00108 // System.out.println("Read lock: one more reader (total: "+numberOfReadLocks+")"); 00109 } else { 00110 // We don't have any read lock, ask the server 00111 // System.out.println("Read lock: obtaining via server"); 00112 askServer = true; 00113 } 00114 } 00115 00116 // Ask the server if needed 00117 if(askServer){ 00118 Serializable temp = JvnServerImpl.jvnGetServer().jvnLockRead(jvnObjectId); 00119 00120 // Ask server OK, now resync and update datum 00121 synchronized(this) { 00122 if(temp==null) { 00123 throw new JvnException("Invalid object received when asking for read lock!"); 00124 } else { 00125 numberOfReadLocks = 1; 00126 __containedObject = temp; 00127 __containedObjectLockState = JvnObjectState.STATE_RLOCKT; 00128 // System.out.println("Read lock: obtained via server"); 00129 } 00130 } 00131 } 00132 } 00133 } 00134 00144 public void jvnLockWrite() throws JvnException { 00145 // Only process one lock request at a time 00146 synchronized(__containedObjectLockState) { 00147 // Whether we should ask the server for the write lock or not 00148 // Asking needs to be done OUTSIDE a synchronized block (deadlock) 00149 boolean askServer = false; 00150 00151 synchronized(this) { 00152 if( __containedObjectLockState == JvnObjectState.STATE_WLOCKC ) { 00153 // We already have a write lock cached 00154 __containedObjectLockState = JvnObjectState.STATE_WLOCKT; 00155 // System.out.println("Write lock: upgrading from \"cached\" to \"taken\"."); 00156 } else { 00157 // The server will contact the coordinator if required 00158 // System.out.println("Write lock: obtaining via server"); 00159 askServer = true; 00160 } 00161 } 00162 00163 // Ask the server if needed 00164 if(askServer) { 00165 Serializable temp = JvnServerImpl.jvnGetServer().jvnLockWrite(jvnObjectId); 00166 00167 // Ask server OK, now resync and update datum 00168 synchronized(this) { 00169 if( temp!=null ) { 00170 __containedObject = temp; 00171 __containedObjectLockState = JvnObjectState.STATE_WLOCKT; 00172 // System.out.println("Write lock: obtained via server"); 00173 } else { 00174 throw new JvnException("Invalid object received when asking for write lock!"); 00175 } 00176 } 00177 } 00178 } 00179 } 00180 00194 public void jvnUnLock() throws JvnException { 00195 synchronized(this) 00196 { 00197 // Perform the change locally: see "Cohérence: cas de figure 1". 00198 if (__containedObjectLockState == JvnObjectState.STATE_WLOCKT) { 00199 __containedObjectLockState = JvnObjectState.STATE_WLOCKC; 00200 // System.out.println("Write lock: downgrading from \"taken\" to \"cached\"."); 00201 00202 // Wake threads that are lazily sleeping. 00203 this.notifyAll(); 00204 } else if (__containedObjectLockState == JvnObjectState.STATE_RLOCKT) { 00205 numberOfReadLocks--; 00206 // System.out.println("Read lock: one less reader (total: "+numberOfReadLocks+")"); 00207 00208 if( numberOfReadLocks <= 0 ) { 00209 // No more read locks left: set lock status as "read lock 00210 // cached" and notify people that are waiting 00211 // System.out.println("Read lock: downgrading from \"taken\" to \"cached\"."); 00212 __containedObjectLockState = JvnObjectState.STATE_RLOCKC; 00213 this.notifyAll(); 00214 } 00215 } else { 00216 throw new JvnException("Tried to unlock an object that's not locked !?!"); 00217 } 00218 } 00219 } 00220 00226 public int jvnGetObjectId() throws JvnException { 00227 if( jvnObjectId <= 0 ) { 00228 throw new JvnException("Current Javanaise Object ID is invalid!"); 00229 } else { 00230 return jvnObjectId; 00231 } 00232 } 00233 00239 public void jvnSetObjectId(int id) throws JvnException { 00240 if( id <= 0 ) { 00241 throw new JvnException("Invalid Javanaise Object ID!"); 00242 } else { 00243 jvnObjectId = id; 00244 } 00245 } 00246 00256 public Serializable jvnGetObjectState() throws JvnException { 00257 if( __containedObjectLockState != JvnObjectState.STATE_RLOCKT && 00258 __containedObjectLockState != JvnObjectState.STATE_WLOCKT ) { 00259 throw new JvnException("Please make sure you obtain a read or write lock BEFORE getting the object state!"); 00260 } else { 00261 return __containedObject; 00262 } 00263 } 00264 00272 public void jvnInvalidateReader() throws JvnException { 00273 synchronized(this) { 00274 if( __containedObjectLockState == JvnObjectState.STATE_RLOCKT ) { 00275 // System.out.println("Invalidating reader: current state is \"taken\" ("+numberOfReadLocks+" readers)."); 00276 try { 00277 // Wait while not ready. 00278 while( __containedObjectLockState == JvnObjectState.STATE_RLOCKT ) { 00279 this.wait(); 00280 } 00281 } catch (InterruptedException e) { 00282 throw new JvnException( "InterruptedException has occured while invalidating reader!\n" + e); 00283 } 00284 00285 __containedObjectLockState = JvnObjectState.STATE_NOLOCK; 00286 } else if( __containedObjectLockState == JvnObjectState.STATE_RLOCKC ) { 00287 // System.out.println("Invalidating reader: current state is \"cached\"."); 00288 __containedObjectLockState = JvnObjectState.STATE_NOLOCK; 00289 } else { 00290 // Don't throw this: we sometimes have some small sync issues 00291 // for states (duplicate messages are sent), but it's ignorable 00292 // throw new JvnException( "Tried to invalidate a reader but object state is not a reading state, it is: " + __containedObjectLockState ); 00293 } 00294 00295 // System.out.println("Reader invalidation OK: current state is \"no lock\"."); 00296 } 00297 } 00298 00309 public Serializable jvnInvalidateWriter() throws JvnException { 00310 synchronized(this) { 00311 if( __containedObjectLockState == JvnObjectState.STATE_WLOCKT ) { 00312 // System.out.println("Invalidating writer: current state is \"taken\"."); 00313 try { 00314 // Wait while not ready. 00315 while( __containedObjectLockState == JvnObjectState.STATE_WLOCKT ) { 00316 this.wait(); 00317 } 00318 } catch (InterruptedException e) { 00319 throw new JvnException( "InterruptedException has occured while invalidating writer!\n" + e); 00320 } 00321 00322 __containedObjectLockState = JvnObjectState.STATE_NOLOCK; 00323 } else if( __containedObjectLockState == JvnObjectState.STATE_WLOCKC ) { 00324 // System.out.println("Invalidating writer: current state is \"cached\"."); 00325 __containedObjectLockState = JvnObjectState.STATE_NOLOCK; 00326 } else { 00327 // Don't throw this: we sometimes have some small sync issues 00328 // for states (duplicate messages are sent), but it's ignorable 00329 // throw new JvnException( "Tried to invalidate a writer but object state is not a writing state, it is: " + __containedObjectLockState ); 00330 } 00331 00332 // System.out.println("Writer invalidation OK: current state is \"no lock\"."); 00333 return __containedObject; 00334 } 00335 } 00336 00348 public Serializable jvnInvalidateWriterForReader() throws JvnException { 00349 synchronized(this) { 00350 if( __containedObjectLockState == JvnObjectState.STATE_WLOCKT ) { 00351 // System.out.println("Invalidating writer for reader: current state is \"write lock taken\"."); 00352 try { 00353 // Wait while not ready. 00354 while( __containedObjectLockState == JvnObjectState.STATE_WLOCKT ) { 00355 this.wait(); 00356 } 00357 } catch (InterruptedException e) { 00358 throw new JvnException( "InterruptedException has occured while invalidating writer for reader!\n" + e); 00359 } 00360 00361 __containedObjectLockState = JvnObjectState.STATE_RLOCKC; 00362 } else if( __containedObjectLockState == JvnObjectState.STATE_WLOCKC ) { 00363 // System.out.println("Invalidating writer for reader: current state is \"write lock cached\"."); 00364 __containedObjectLockState = JvnObjectState.STATE_RLOCKC; 00365 } else { 00366 // Don't throw this: we sometimes have some small sync issues 00367 // for states (duplicate messages are sent), but it's ignorable 00368 // throw new JvnException( "Tried to invalidate a writer but object state is not a writing state, it is: " + __containedObjectLockState ); 00369 } 00370 00371 // System.out.println("Writer invalidation OK: current state is \"read lock cached\"."); 00372 return __containedObject; 00373 } 00374 } 00375 }