Coverage report

  %line %branch
mnemosyne.core.PersistentObjectImpl
97% 
98% 

 1  
 /*
 2  
  * Copyright 2004 Charles Blaxland
 3  
  *
 4  
  * Licensed under the Apache License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  *
 8  
  *     http://www.apache.org/licenses/LICENSE-2.0
 9  
  *
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 package mnemosyne.core;
 17  
 
 18  
 import mnemosyne.guid.Guid;
 19  
 import mnemosyne.lock.Lock;
 20  
 import mnemosyne.util.CloneException;
 21  
 import mnemosyne.util.PersistenceRuntimeException;
 22  
 import mnemosyne.util.Util;
 23  
 import org.apache.commons.logging.Log;
 24  
 import org.apache.commons.logging.LogFactory;
 25  
 
 26  
 import java.io.*;
 27  
 import java.util.Set;
 28  
 
 29  
 /**
 30  
  * // TODO - Review synchronization
 31  
  * @version $Id: PersistentObjectImpl.java,v 1.1.1.1 2004/08/07 06:41:11 charlesblaxland Exp $
 32  
  */
 33  
 public class PersistentObjectImpl implements PersistentObject, Serializable
 34  
 {
 35  4
     private static final Log log = LogFactory.getLog(PersistentObjectImpl.class);
 36  
 
 37  
     private Guid guid;
 38  
     private transient VersionManager versionMgr;
 39  
     private transient Enhancer enhancer;
 40  18
     private transient VersionCollection committedVersions = new ListVersionCollection();
 41  
     private transient Object writeVersion;
 42  
     private transient Object deserializedVersion;
 43  18
     private transient boolean deserializedVersionIsAnUnresolvedReference = false;
 44  
     private transient Lock lock;
 45  
 
 46  
     // TODO - remove when we can detect mutating methods
 47  18
     private transient boolean isMutableMethodsWorkaroundEnabled = true;
 48  
 
 49  
     public PersistentObjectImpl(Guid guid, VersionManager versionMgr, Enhancer enhancer, Lock lock)
 50  18
     {
 51  18
         this.guid = guid;
 52  18
         this.versionMgr = versionMgr;
 53  18
         this.enhancer = enhancer;
 54  18
         this.lock = lock;
 55  18
     }
 56  
 
 57  
     public void initialize(Object initialObject)
 58  
     {
 59  9
         PersistentContext context = PersistentContext.get(versionMgr);
 60  9
         Version currentVersion = context.getVersion();
 61  9
         committedVersions.addVersion(currentVersion, initialObject);
 62  9
         deserializedVersion = null;
 63  9
     }
 64  
 
 65  
     public void initializeAsNewObject(Object initialObject)
 66  
     {
 67  4
         PersistentContext context = PersistentContext.get(versionMgr);
 68  4
         Transaction transaction = context.getTransaction();
 69  4
         lock.acquireWriteLock(transaction);
 70  4
         writeVersion = initialObject;
 71  4
         deserializedVersion = null;
 72  4
     }
 73  
 
 74  
     public Guid getGuid()
 75  
     {
 76  13
         return guid;
 77  
     }
 78  
 
 79  
     public Object findTargetObject()
 80  
     {
 81  15
         return findTargetObject(false);
 82  
     }
 83  
 
 84  
     public Object findWritableTargetObject()
 85  
     {
 86  8
         return findTargetObject(true);
 87  
     }
 88  
 
 89  
     protected synchronized Object findTargetObject(boolean isForMutatingCall)
 90  
     {
 91  23
         if (writeVersion == null && committedVersions.size() == 0 && deserializedVersion != class="keyword">null)
 92  
         {
 93  0
             return deserializedVersion;
 94  
         }
 95  
 
 96  23
         Object target = null;
 97  23
         PersistentContext context = PersistentContext.get(versionMgr);
 98  23
         Version currentVersion = context.getVersion();
 99  
 
 100  
         // TODO - these lines to be removed when we can detect mutating methods
 101  23
         if (isMutableMethodsWorkaroundEnabled)
 102  15
             isForMutatingCall = context.isInTransaction();
 103  
 
 104  23
         if (context.isInTransaction())
 105  
         {
 106  13
             log.trace("Thread is in a transaction");
 107  13
             Transaction transaction = context.getTransaction();
 108  13
             if (isForMutatingCall)
 109  
             {
 110  10
                 log.trace("Method is mutable, obtaining write lock");
 111  10
                 lock.acquireWriteLock(transaction);
 112  
 
 113  
                 // TODO - there is an issue here if another transaction modifies and commits this object
 114  
                 // after this transaction has started, but before it attempts to write to it.
 115  
                 // In this situation, committedVersions.retrieveVersion(currentVersion) will no
 116  
                 // longer retrieve the latest version. Transaction should fail in this case.
 117  
 
 118  10
                 if (writeVersion == null)
 119  
                 {
 120  3
                     log.trace("Cloning object " + guid);
 121  3
                     Object objForCurrentVersion = committedVersions.retrieveVersion(currentVersion);
 122  3
                     writeVersion = clonePersistentObjectVersion(objForCurrentVersion);
 123  3
                     transaction.addModifiedObject(this);
 124  
                 }
 125  
 
 126  10
                 target = writeVersion;
 127  
             }
 128  
             else
 129  
             {
 130  3
                 log.trace("Method is not mutable, acquiring read lock");
 131  3
                 lock.acquireReadLock(transaction);
 132  3
                 if (writeVersion != null)
 133  
                 {
 134  1
                     target = writeVersion;
 135  
                 }
 136  
                 else
 137  
                 {
 138  2
                     target = committedVersions.retrieveVersion(currentVersion);
 139  
                 }
 140  
             }
 141  
         }
 142  
         else
 143  
         {
 144  10
             if (!isForMutatingCall)
 145  
             {
 146  9
                 target = committedVersions.retrieveVersion(currentVersion);
 147  
             }
 148  
             else
 149  
             {
 150  1
                 throw new NoTransactionException("Attempt to modify persistent object outside transaction");
 151  
             }
 152  
         }
 153  
 
 154  20
         return target;
 155  
     }
 156  
 
 157  
     public Set prepareForCommit()
 158  
     {
 159  1
         return enhancer.enhance(writeVersion);
 160  
     }
 161  
 
 162  
     public synchronized void commit(Version versionToCommitAs)
 163  
     {
 164  1
         committedVersions.addVersion(versionToCommitAs, writeVersion);
 165  1
         writeVersion = null;
 166  1
         releaseLocks();
 167  1
     }
 168  
 
 169  
     public synchronized void rollback()
 170  
     {
 171  1
         if (committedVersions.size() == 0 && writeVersion != null)
 172  
         {
 173  
             // There are as yet no committed versions, so presumably this is a "new" persistent object.
 174  
             // In this situation we also reset the PersistentObject of the new object to null,
 175  
             // otherwise calls on it would be treated incorrectly as calls on a persistent object.
 176  1
             Persistable persistable = (Persistable) writeVersion;
 177  1
             persistable.setPersistentObject(null);
 178  
         }
 179  1
         writeVersion = null;
 180  1
         releaseLocks();
 181  1
     }
 182  
 
 183  
     private void releaseLocks()
 184  
     {
 185  2
         PersistentContext context = PersistentContext.get(versionMgr);
 186  2
         Transaction transaction = context.getTransaction();
 187  2
         lock.releaseLock(transaction);
 188  2
     }
 189  
 
 190  
     private void writeObject(ObjectOutputStream s) throws IOException
 191  
     {
 192  4
         s.defaultWriteObject();
 193  4
         PersistentContext context = PersistentContext.get(versionMgr);
 194  4
         Transaction transaction = context.getTransaction();
 195  4
         if (context.isInTransaction() && !transaction.hasModclass="keyword">ifiedOrAddedObject(this))
 196  
         {
 197  2
             s.writeObject(findTargetObject().getClass());
 198  
         }
 199  
         else
 200  
         {
 201  2
             Object clonedTarget = clonePersistentObjectVersion(findTargetObject());
 202  2
             ((Persistable) clonedTarget).setArchiveVersion(true);
 203  2
             s.writeObject(clonedTarget);
 204  
         }
 205  4
     }
 206  
 
 207  
     private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException
 208  
     {
 209  4
         s.defaultReadObject();
 210  4
         Object obj = s.readObject();
 211  4
         if (obj instanceof Class)
 212  
         {
 213  2
             Class clazz = (Class) obj;
 214  
             try
 215  
             {
 216  
                 // TODO - apparently there's a way to create new instances even if they don't have a default constructor
 217  
                 // using JDK 1.4 undocumented features.
 218  2
                 obj = clazz.newInstance();
 219  1
                 deserializedVersionIsAnUnresolvedReference = true;
 220  1
             }
 221  
             catch (InstantiationException e)
 222  
             {
 223  1
                 throw new PersistenceRuntimeException("Failed to create new instance of class " + clazz.getName() + ".  Check that it has a public default constructor.");
 224  
             }
 225  
             catch (IllegalAccessException e)
 226  
             {
 227  0
                 throw new PersistenceRuntimeException("Failed to create new instance of class " + clazz.getName() + ".  Check that it has a public default constructor.");
 228  
             }
 229  
         }
 230  
 
 231  3
         deserializedVersion = obj;
 232  3
     }
 233  
 
 234  
     protected Object readResolve()
 235  
     {
 236  3
         PersistentObjectFactory factory = ArchiveContext.get().getPersistentObjectFactory();
 237  3
         PersistentObject result = factory.createPersistentObject(guid);
 238  3
         result.initialize(deserializedVersion);
 239  3
         Persistable persistable = (Persistable) deserializedVersion;
 240  3
         persistable.setPersistentObject(result);
 241  
 
 242  3
         AggregatedTransaction aggregatedTransaction = ArchiveContext.get().getAggregatedTransaction();
 243  
 
 244  3
         if (deserializedVersionIsAnUnresolvedReference)
 245  
         {
 246  1
             result = aggregatedTransaction.addUnresolvedReference(result);
 247  
         }
 248  
         else
 249  
         {
 250  2
             if (aggregatedTransaction.isComplete())
 251  
             {
 252  1
                 result = aggregatedTransaction.resolveObject(result);
 253  
             }
 254  
             else
 255  
             {
 256  1
                 result = aggregatedTransaction.addModifiedObject(result);
 257  
             }
 258  
         }
 259  
 
 260  3
         return result;
 261  
     }
 262  
 
 263  
     private Object clonePersistentObjectVersion(Object obj)
 264  
     {
 265  5
         Object clonedObj = null;
 266  
         try
 267  
         {
 268  5
             clonedObj = Util.callCloneViaReflection(obj);
 269  5
         }
 270  
         catch (CloneException e)
 271  
         {
 272  0
             throw new NotPersistableException("Object not persistable, as the clone method in this object raised an exception", e);
 273  
         }
 274  
 
 275  5
         return clonedObj;
 276  
     }
 277  
 
 278  
     public int hashCode()
 279  
     {
 280  1
         return guid.hashCode();
 281  
     }
 282  
 
 283  
     public boolean equals(Object obj)
 284  
     {
 285  3
         if (obj instanceof PersistentObjectImpl)
 286  
         {
 287  2
             PersistentObjectImpl other = (PersistentObjectImpl) obj;
 288  2
             return guid.equals(other.guid);
 289  
         }
 290  
         else
 291  
         {
 292  1
             return false;
 293  
         }
 294  
     }
 295  
 
 296  
     public String toString()
 297  
     {
 298  2
         return guid.toString();
 299  
     }
 300  
 
 301  
     public void setMutableMethodsWorkaroundEnabled(boolean mutableMethodsWorkaroundEnabled)
 302  
     {
 303  4
         isMutableMethodsWorkaroundEnabled = mutableMethodsWorkaroundEnabled;
 304  4
     }
 305  
 }

This report is generated by jcoverage, Maven and Maven JCoverage Plugin.