Author: peter_firmstone Date: Thu Jul 4 20:31:55 2013 New Revision: 1499861
URL: http://svn.apache.org/r1499861 Log: Synchronization fixes relating to LeaseMap implementations. The LeaseMap interface was originally specified as an unsynchronized Map, however relaxing this requirement allows for some implementations to be synchronized or concurrent. Updated ClassServer to use Starter interface. Changed ReadyState to be non blocking when ready. Fixed unsynchronized access to proxy references in FiddlerImpl. Modified: river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/test/impl/mahalo/NoOpLease.java river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/test/impl/norm/LocalLease.java river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/test/impl/norm/OurAbstractLeaseMap.java river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/test/spec/servicediscovery/lookup/LookupMinEqualsMax.java river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/fiddler/FiddlerImpl.java river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/landlord/ConstrainableLandlordLeaseMap.java river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/landlord/LandlordLeaseMap.java river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/lease/AbstractLeaseMap.java river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/norm/DeformedClientLeaseMapWrapper.java river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/reggie/EntryRep.java river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/reggie/RegistrarLeaseMap.java river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/thread/ReadyState.java river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/tool/ClassServer.java river/jtsk/skunk/qa_refactor/trunk/src/net/jini/core/lease/Lease.java river/jtsk/skunk/qa_refactor/trunk/src/net/jini/core/lease/LeaseMap.java river/jtsk/skunk/qa_refactor/trunk/src/net/jini/core/lease/LeaseMapException.java river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/SerialReflectionFactory.java Modified: river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/test/impl/mahalo/NoOpLease.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/test/impl/mahalo/NoOpLease.java?rev=1499861&r1=1499860&r2=1499861&view=diff ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/test/impl/mahalo/NoOpLease.java (original) +++ river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/test/impl/mahalo/NoOpLease.java Thu Jul 4 20:31:55 2013 @@ -17,19 +17,15 @@ */ package com.sun.jini.test.impl.mahalo; -import java.io.ObjectInputStream; +import com.sun.jini.lease.AbstractLease; import java.io.IOException; import java.io.InvalidObjectException; +import java.io.ObjectInputStream; import java.rmi.RemoteException; - import net.jini.core.lease.Lease; -import net.jini.core.lease.LeaseMap; import net.jini.core.lease.LeaseDeniedException; +import net.jini.core.lease.LeaseMap; import net.jini.core.lease.UnknownLeaseException; -import net.jini.id.Uuid; -import net.jini.id.ReferentUuid; -import net.jini.id.ReferentUuids; -import com.sun.jini.lease.AbstractLease; /** * No-op implementation of <code>net.jini.core.lease.Lease</code> that works Modified: river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/test/impl/norm/LocalLease.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/test/impl/norm/LocalLease.java?rev=1499861&r1=1499860&r2=1499861&view=diff ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/test/impl/norm/LocalLease.java (original) +++ river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/test/impl/norm/LocalLease.java Thu Jul 4 20:31:55 2013 @@ -278,6 +278,7 @@ class LocalLease implements Lease, Seria } private static class LocalLeaseMap extends OurAbstractLeaseMap { + private static final long serialVersionUID = 1L; /** * Two <code>LocalLeases</code> with the same bundle value can * be batched together Modified: river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/test/impl/norm/OurAbstractLeaseMap.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/test/impl/norm/OurAbstractLeaseMap.java?rev=1499861&r1=1499860&r2=1499861&view=diff ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/test/impl/norm/OurAbstractLeaseMap.java (original) +++ river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/test/impl/norm/OurAbstractLeaseMap.java Thu Jul 4 20:31:55 2013 @@ -17,14 +17,14 @@ */ package com.sun.jini.test.impl.norm; -import net.jini.core.lease.*; -import java.rmi.RemoteException; import java.io.Serializable; -import java.util.Map; -import java.util.Set; import java.util.AbstractSet; import java.util.Collection; import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import net.jini.core.lease.Lease; +import net.jini.core.lease.LeaseMap; /** * Lifted from com.sun.jini.lease.AbstractLeaseMap so we can have a codebase Modified: river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/test/spec/servicediscovery/lookup/LookupMinEqualsMax.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/test/spec/servicediscovery/lookup/LookupMinEqualsMax.java?rev=1499861&r1=1499860&r2=1499861&view=diff ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/test/spec/servicediscovery/lookup/LookupMinEqualsMax.java (original) +++ river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/test/spec/servicediscovery/lookup/LookupMinEqualsMax.java Thu Jul 4 20:31:55 2013 @@ -57,9 +57,9 @@ import com.sun.jini.qa.harness.Test; */ public class LookupMinEqualsMax extends AbstractBaseTest { - protected long waitDur = 30*1000; - protected int minMatches = 0; - protected int maxMatches = 0; + protected volatile long waitDur = 30*1000; + protected volatile int minMatches = 0; + protected volatile int maxMatches = 0; /** Performs actions necessary to prepare for execution of the * current test. @@ -176,7 +176,85 @@ public class LookupMinEqualsMax extends waitDur); long endTime = System.currentTimeMillis(); long actualBlockTime = endTime-startTime; - long waitError = (actualBlockTime-waitDur)/1000; + /* 7th May 2013 - Peter Firmstone. + * According to section SD4.1.3 The blocking feature of lookup + * waitDur is measured in milliseconds. + * + * Quote: + * the method will wait a finite period of time until either an + * acceptable minimum number of service references are discovered + * or the specified time period has passed. + * + * waitError is specified incorrectly here, since it is converted to + * seconds and hence requires that the lookup method wait no longer than one second less + * of waitDur if the acceptable minimum number of services are + * discovered, this is appears incorrect. + * + * long waitError = (actualBlockTime-waitDur)/1000 + * + * } else { //(nExpectedSrvcs>=minMatches) + * // Blocking time should be less than the full amount + * if(waitError >= 0) { + * throw new TestException(" -- blocked longer than expected " + * +"-- requested block = " + * + waitDurSecs +" second(s), actual " + * +"block = "+(actualBlockTime/1000) + * +" second(s)"); + * } + * }//endif(nExpectedSrvcs<maxMatches) + * + * In addition it was previously considered an error if the wait period + * was exactly equal to waitDur after being rounded to seconds, + * this is in conflict with the spec that specifies UNTIL either an + * acceptable minimum number of service references are discovered + * or the specified time period has passed. + * + * The test failed to allow for a corner case where an acceptable minimum + * number of service references are discovered concurrently to the + * specified time period elapsing. + * + * Additionally however, Object.wait(waitDur) may not wake up at the + * correct wait time if another object happens to be holding the lock. + * + * The spec doesn't specify limits on the wait period, except that it + * has passed. Originally this test allowed 30 seconds to elapse after + * waitDur + * + * I have changed waitDur to milliseconds to comply with the spec + * on the 7th of May 2013 + * + * The limits were changed to allow 300 milliseconds to elapse after the + * wait period completes. + * + * In addtion Item number 3 below states: + * + * 3. while lookup() is blocking, if enough new services are + * registered so that the acceptable minimum is achieved, + * lookup() will return immediately; that is, even if there + * is more time left on the wait period, lookup() will not + * wait for more services beyond the minimum. + * + * For example, if 3 services are initially registered and + * lookup is called with min = 4 and max = 7, then lookup() + * will find the 3 services and then wait for more services to + * be registered. Suppose that while lookup() is blocking + * another 5 services are registered, bringing the total number + * of services to 8. In this case, lookup() will stopping + * waiting and return 4 services (the minimum), not the + * maximum 7. + * + * The problem with this statement is if additonal threads are waiting + * for the object monitor, there's no guarantee the waiting thread can + * obtain the monitor first and return the minimum number. In fact + * the jvm is more likely to prefer a thread that's still + * in cpu cache rather than a thread that's been waiting for a long + * time and isn't loaded in the cpu cache. + * + * The specification doesn't make this distinction, it only limits + * the result to maxMatches. So we need to check that maxMatches isn't + * exceeded. + */ + long waitError = (actualBlockTime-waitDur); /* Delay to allow all of the services to finish registering */ DiscoveryServiceUtil.delayMS(regCompletionDelay); /* populate the expected info after lookup to prevent delay */ @@ -206,23 +284,12 @@ public class LookupMinEqualsMax extends * first is less than the acceptable minimum, then lookup() * will wait for the desired services to be registered with * the lookups - * 3. while lookup() is blocking, if enough new services are - * registered so that the acceptable minimum is achieved, - * lookup() will return immediately; that is, even if there - * is more time left on the wait period, lookup() will not - * wait for more services beyond the minimum. - * - * For example, if 3 services are initially registered and - * lookup is called with min = 4 and max = 7, then lookup() - * will find the 3 services and then wait for more services to - * be registered. Suppose that while lookup() is blocking - * another 5 services are registered, bringing the total number - * of services to 8. In this case, lookup() will stopping - * waiting and return 4 services (the minimum), not the - * maximum 7. + * 3. DELETED 7th May 2013 see comments * 4. if the minimum number of services have not been registered * during the wait period, lookup() will return what it has * found. + * 5. ADDED 7th May 2013 The maximum number of services returned + * never exceeds maxMatches. * * Below, determine the number of services to expect based on * the specified behavior described above. @@ -245,15 +312,18 @@ public class LookupMinEqualsMax extends } else {//(nPreReg >= minMatches) ==> won't block logger.log(Level.FINE, "" +": lookup() will NOT block"); - if(nPreReg == minMatches) {//return min immediately - nExpectedSrvcs = minMatches; - } else {//(nPreReg > minMatches) + /* 7th May 2013: This requirement complicates + * thread synchronization and is superflous to the specification. + */ +// if(nPreReg == minMatches) {//return min immediately +// nExpectedSrvcs = minMatches; +// } else {//(nPreReg > minMatches) if(nPreReg < maxMatches) { nExpectedSrvcs = nPreReg; } else {//(nPreReg >= maxMatches) nExpectedSrvcs = maxMatches; }//endif - }//endif +// }//endif }//endif logger.log(Level.FINE, "" +": minMatches = "+minMatches); @@ -272,24 +342,24 @@ public class LookupMinEqualsMax extends if(waitError<-3) { throw new TestException(" -- failed to block requested " +"time -- requested block = " - +waitDurSecs+" second(s), actual " - +"block = "+(actualBlockTime/1000) - +" second(s)"); - } else if(waitError>30) { + +waitDur+" millisecond(s), actual " + +"block = "+(actualBlockTime) + +" millisecond(s)"); + } else if(waitError>300) { throw new TestException(" -- exceeded requested block " +"time -- requested block = " - +waitDurSecs+" second(s), actual " - +"block = "+(actualBlockTime/1000) - +" second(s)"); + +waitDur+" millisecond(s), actual " + +"block = "+(actualBlockTime) + +" millisecond(s)"); }//endif } else { //(nExpectedSrvcs>=minMatches) - /* Blocking time should be less than the full amount */ - if(waitError >= 0) { + /* Blocking time will likely be less than the full wait period */ + if(waitError > 300) { throw new TestException(" -- blocked longer than expected " +"-- requested block = " - +waitDurSecs+" second(s), actual " - +"block = "+(actualBlockTime/1000) - +" second(s)"); + + waitDur +" millisecond(s), actual " + +"block = "+(actualBlockTime) + +" millisecond(s) wait error = " + waitError); } }//endif(nExpectedSrvcs<maxMatches) verifyServiceItems(srvcItems, Modified: river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/fiddler/FiddlerImpl.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/fiddler/FiddlerImpl.java?rev=1499861&r1=1499860&r2=1499861&view=diff ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/fiddler/FiddlerImpl.java (original) +++ river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/fiddler/FiddlerImpl.java Thu Jul 4 20:31:55 2013 @@ -578,7 +578,7 @@ class FiddlerImpl implements ServerProxy * (HashSet is used to prevent duplicates.) * @serial */ - public HashSet groups; + public HashSet<String> groups; /** The managed set containing the locators of the specific lookup * services the lookup discovery service should attempt to discover * for the current registration. (HashSet is used to prevent @@ -649,7 +649,7 @@ class FiddlerImpl implements ServerProxy this.registrationID = registrationID; /* Initialize the groups field, removing nulls and duplicates */ if(groups != null) { - this.groups = new HashSet(); + this.groups = new HashSet<String>(); for(int i=0;i<groups.length;i++) { if(groups[i] == null) continue; this.groups.add(groups[i]); @@ -1705,8 +1705,9 @@ class FiddlerImpl implements ServerProxy private void removeRegInfoGroups(RegistrationInfo regInfo, String[] groups) { - HashSet removeSet = new HashSet(); - for(int i=0;i<groups.length;i++) { + HashSet<String> removeSet = new HashSet<String>(); + int l = groups.length; + for(int i = 0; i < l; i++) { removeSet.add(groups[i]); }//end loop (regInfo.groups).removeAll(removeSet); @@ -2644,7 +2645,12 @@ class FiddlerImpl implements ServerProxy */ public Object getAdmin() throws NoSuchObjectException, RemoteException { readyState.check(); - return adminProxy; + concurrentObj.readLock(); + try { + return adminProxy; + } finally { + concurrentObj.readUnlock(); + } } /* END com.sun.jini.fiddler.Fiddler --> net.jini.admin.Administrable */ /* -------------------------------------------------------------------- */ @@ -3323,7 +3329,12 @@ class FiddlerImpl implements ServerProxy */ public Object getServiceProxy() throws NoSuchObjectException { readyState.check(); - return outerProxy; + concurrentObj.readLock(); + try { + return outerProxy; + } finally { + concurrentObj.readUnlock(); + } }//end getServiceProxy /* END com.sun.jini.fiddler.Fiddler @@ -3354,7 +3365,12 @@ class FiddlerImpl implements ServerProxy */ public Uuid getProxyID() throws NoSuchObjectException, RemoteException { readyState.check(); - return proxyID; + concurrentObj.readLock(); + try { + return proxyID; + } finally { + concurrentObj.readUnlock(); + } }//end getProxyID /** @@ -5162,6 +5178,7 @@ class FiddlerImpl implements ServerProxy if (started) return; started = true; } + concurrentObj.writeLock(); try { AccessController.doPrivileged(new PrivilegedExceptionAction(){ @@ -5330,6 +5347,7 @@ class FiddlerImpl implements ServerProxy } finally { logHandler = null; context = null; + concurrentObj.writeUnlock(); } } /* END public start method */ Modified: river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/landlord/ConstrainableLandlordLeaseMap.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/landlord/ConstrainableLandlordLeaseMap.java?rev=1499861&r1=1499860&r2=1499861&view=diff ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/landlord/ConstrainableLandlordLeaseMap.java (original) +++ river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/landlord/ConstrainableLandlordLeaseMap.java Thu Jul 4 20:31:55 2013 @@ -54,7 +54,7 @@ final public class ConstrainableLandlord * @throws NullPointerException if landlord is <code>null</code>. */ ConstrainableLandlordLeaseMap(Landlord landlord, Uuid landlordUuid, - Lease lease, long duration) + LandlordLease lease, long duration) { super(landlord, landlordUuid, lease, duration); if (!(landlord instanceof RemoteMethodControl)) Modified: river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/landlord/LandlordLeaseMap.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/landlord/LandlordLeaseMap.java?rev=1499861&r1=1499860&r2=1499861&view=diff ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/landlord/LandlordLeaseMap.java (original) +++ river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/landlord/LandlordLeaseMap.java Thu Jul 4 20:31:55 2013 @@ -69,7 +69,9 @@ public class LandlordLeaseMap extends Ab LandlordLeaseMap(Landlord landlord, Uuid landlordUuid, Lease lease, long duration) { - super(lease, duration); + super(new HashMap(), lease, duration); + if (!(lease instanceof LandlordLease)) throw + new ClassCastException("Lease must be of type LandlordLease"); if (landlord == null) throw new NullPointerException("Landlord must be non-null"); @@ -91,17 +93,20 @@ public class LandlordLeaseMap extends Ab // inherit doc comment public void cancelAll() throws LeaseMapException, RemoteException { - Uuid[] cookies = new Uuid[size()]; - LandlordLease[] leases = new LandlordLease[cookies.length]; - Iterator it = keySet().iterator(); - for (int i = 0; it.hasNext(); i++) { - LandlordLease lease = (LandlordLease) it.next(); - leases[i] = lease; - cookies[i] = lease.cookie(); - } - - final Map rslt = landlord.cancelAll(cookies); - + final Map rslt; + Uuid[] cookies; + LandlordLease[] leases; + synchronized (mapLock){ + cookies = new Uuid[size()]; + leases = new LandlordLease[cookies.length]; + Iterator it = keySet().iterator(); + for (int i = 0; it.hasNext(); i++) { + LandlordLease lease = (LandlordLease) it.next(); + leases[i] = lease; + cookies[i] = lease.cookie(); + } + rslt = landlord.cancelAll(cookies); + } if (rslt == null) { // Everything worked out, normal return return; @@ -134,17 +139,21 @@ public class LandlordLeaseMap extends Ab // inherit doc comment public void renewAll() throws LeaseMapException, RemoteException { - Uuid[] cookies = new Uuid[size()]; - long[] extensions = new long[cookies.length]; - LandlordLease[] leases = new LandlordLease[cookies.length]; - Iterator it = keySet().iterator(); - for (int i = 0; it.hasNext(); i++) { - LandlordLease lease = (LandlordLease) it.next(); - leases[i] = lease; - cookies[i] = lease.cookie(); - extensions[i] = ((Long) get(lease)).longValue(); - } - + Uuid[] cookies; + long[] extensions; + LandlordLease[] leases; + synchronized (mapLock){ + cookies = new Uuid[size()]; + extensions = new long[cookies.length]; + leases = new LandlordLease[cookies.length]; + Iterator it = keySet().iterator(); + for (int i = 0; it.hasNext(); i++) { + LandlordLease lease = (LandlordLease) it.next(); + leases[i] = lease; + cookies[i] = lease.cookie(); + extensions[i] = ((Long) get(lease)).longValue(); + } + } long now = System.currentTimeMillis(); Landlord.RenewResults results = landlord.renewAll(cookies, extensions); Modified: river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/lease/AbstractLeaseMap.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/lease/AbstractLeaseMap.java?rev=1499861&r1=1499860&r2=1499861&view=diff ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/lease/AbstractLeaseMap.java (original) +++ river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/lease/AbstractLeaseMap.java Thu Jul 4 20:31:55 2013 @@ -40,14 +40,14 @@ import net.jini.core.lease.LeaseMapExcep * @author Sun Microsystems, Inc. * */ -public abstract class AbstractLeaseMap implements LeaseMap<Lease, Long>, ConcurrentMap<Lease, Long> { +public abstract class AbstractLeaseMap implements LeaseMap, ConcurrentMap { /** * Map from Lease to Long(duration), where all leases have the same * destination. * * @serial */ - protected final Map<Lease, Long> map; + protected final Map map; protected final Object mapLock; @@ -58,16 +58,15 @@ public abstract class AbstractLeaseMap i * @param duration */ protected AbstractLeaseMap(Lease lease, long duration) { - this(new ConcurrentHashMap<Lease, Long>(13), lease, duration); + this(new ConcurrentHashMap(13), lease, duration); } /** * Provide a map of your choice. It is assumed that * canContainKey(lease) is true. - * @deprecated to get peoples attention that map may require synchronized access. + * @param map */ - @Deprecated - protected AbstractLeaseMap(Map<Lease, Long> map, Lease lease, long duration) { + protected AbstractLeaseMap(Map map, Lease lease, long duration) { if (map instanceof ConcurrentMap) { this.map = map; mapLock = null; @@ -92,7 +91,7 @@ public abstract class AbstractLeaseMap i * @param value */ protected static void checkValue(Object value) { - if (!(value instanceof Long)) { + if (!(value instanceof java.lang.Long)) { throw new IllegalArgumentException("value is not a Long"); } } @@ -120,20 +119,20 @@ public abstract class AbstractLeaseMap i } // inherit javadoc - public Long get(Object key) { + public Object get(Object key) { checkKey(key); return map.get(key); } // inherit javadoc - public Long put(Lease key, Long value) { + public Object put(Object key, Object value) { checkKey(key); checkValue(value); return map.put(key, value); } // inherit javadoc - public Long remove(Object key) { + public Object remove(Object key) { checkKey(key); return map.remove(key); } @@ -142,11 +141,11 @@ public abstract class AbstractLeaseMap i * of the keys and values. */ // inherit javadoc - public void putAll(Map<? extends Lease, ? extends Long> m) { + public void putAll(Map m) { Iterator iter = m.entrySet().iterator(); while (iter.hasNext()) { @SuppressWarnings("unchecked") - Map.Entry<? extends Lease, ? extends Long> e = (Map.Entry<? extends Lease, ? extends Long>) iter.next(); + Map.Entry e = (Map.Entry) iter.next(); put(e.getKey(), e.getValue()); } } @@ -157,12 +156,12 @@ public abstract class AbstractLeaseMap i } // inherit javadoc - public Set<Lease> keySet() { + public Set keySet() { return map.keySet(); } // inherit javadoc - public Collection<Long> values() { + public Collection values() { return map.values(); } @@ -170,7 +169,7 @@ public abstract class AbstractLeaseMap i * Map.Entry.setValue. */ // inherit javadoc - public Set<Map.Entry<Lease, Long>> entrySet() { + public Set entrySet() { return new EntrySet(map.entrySet()); } @@ -185,38 +184,54 @@ public abstract class AbstractLeaseMap i } @Override - public Long putIfAbsent(final Lease key, final Long value) { + public Object putIfAbsent(final Object key, final Object value) { + checkKey(key); + checkValue(value); if (map instanceof ConcurrentMap){ - ConcurrentMap<Lease, Long> m = (ConcurrentMap<Lease, Long>) map; + ConcurrentMap m = (ConcurrentMap) map; return m.putIfAbsent(key, value); } else { synchronized (mapLock){ - Set<Map.Entry<Lease, Long>> entries; + Set entries; entries = map.entrySet(); - Map.Entry<Lease, Long> entry = new Map.Entry<Lease, Long>(){ + Map.Entry entry = new Map.Entry(){ @Override - public Lease getKey() { + public Object getKey() { return key; } @Override - public Long getValue() { + public Object getValue() { return value; } @Override - public Long setValue(Long value) { + public Object setValue(Object value) { throw new UnsupportedOperationException("Not supported."); } + public boolean equals(Object o){ + if (!(o instanceof Map.Entry)) return false; + Map.Entry e2 = (Map.Entry) o; + Map.Entry e1 = this; + return (e1.getKey()==null ? e2.getKey()==null : e1.getKey().equals(e2.getKey())) && + (e1.getValue()==null ? e2.getValue()==null : e1.getValue().equals(e2.getValue())); + } + + public int hashCode(){ + Map.Entry e = this; + return (e.getKey()==null ? 0 : e.getKey().hashCode()) ^ + (e.getValue()==null ? 0 : e.getValue().hashCode()); + } + }; if (entries.contains(entry)){ // Not absent return long. return value; } else if ( map.containsKey(key)) { // Might contain null value; - Long result = map.get(key); + Object result = map.get(key); if (result == null) map.put(key, value); // If result is not null it is returned and no put was made // or if it is null, the key value pair was added and null value @@ -236,7 +251,7 @@ public abstract class AbstractLeaseMap i if (map instanceof ConcurrentMap){ return ((ConcurrentMap) map).remove(key, value); } else { - Set<Map.Entry<Lease,Long>> entries; + Set entries; entries = map.entrySet(); Map.Entry entry = new Map.Entry(){ @@ -255,39 +270,68 @@ public abstract class AbstractLeaseMap i throw new UnsupportedOperationException("Not supported."); } + public boolean equals(Object o){ + if (!(o instanceof Map.Entry)) return false; + Map.Entry e2 = (Map.Entry) o; + Map.Entry e1 = this; + return (e1.getKey()==null ? e2.getKey()==null : e1.getKey().equals(e2.getKey())) && + (e1.getValue()==null ? e2.getValue()==null : e1.getValue().equals(e2.getValue())); + } + + public int hashCode(){ + Map.Entry e = this; + return (e.getKey()==null ? 0 : e.getKey().hashCode()) ^ + (e.getValue()==null ? 0 : e.getValue().hashCode()); + } }; return entries.remove(entry); } } @Override - public boolean replace(final Lease key, final Long oldValue, Long newValue) { + public boolean replace(final Object key, final Object oldValue, Object newValue) { + checkKey(key); + checkValue(newValue); if (map instanceof ConcurrentMap){ return ((ConcurrentMap)map).replace(key, oldValue, newValue); } else { synchronized (mapLock){ - Set<Map.Entry<Lease,Long>> entries; + Set entries; entries = map.entrySet(); - Map.Entry<Lease, Long> entry = new Map.Entry<Lease, Long>(){ + Map.Entry entry = new Map.Entry(){ @Override - public Lease getKey() { + public Object getKey() { return key; } @Override - public Long getValue() { + public Object getValue() { return oldValue; } @Override - public Long setValue(Long value) { + public Object setValue(Object value) { throw new UnsupportedOperationException("Not supported."); } + public boolean equals(Object o){ + if (!(o instanceof Map.Entry)) return false; + Map.Entry e2 = (Map.Entry) o; + Map.Entry e1 = this; + return (e1.getKey()==null ? e2.getKey()==null : e1.getKey().equals(e2.getKey())) && + (e1.getValue()==null ? e2.getValue()==null : e1.getValue().equals(e2.getValue())); + } + + public int hashCode(){ + Map.Entry e = this; + return (e.getKey()==null ? 0 : e.getKey().hashCode()) ^ + (e.getValue()==null ? 0 : e.getValue().hashCode()); + } + }; if (entries.contains(entry)){ - Long result = map.put(key, newValue); + Object result = map.put(key, newValue); assert result.equals(oldValue); return true; } else { @@ -298,33 +342,49 @@ public abstract class AbstractLeaseMap i } @Override - public Long replace(final Lease key, final Long value) { + public Object replace(final Object key, final Object value) { + checkKey(key); + checkValue(value); if (map instanceof ConcurrentMap){ - return ((ConcurrentMap<Lease, Long>)map).replace(key, value); + return ((ConcurrentMap)map).replace(key, value); } else { synchronized (mapLock){ - Set<Map.Entry<Lease,Long>> entries; + Set entries; entries = map.entrySet(); - Map.Entry<Lease, Long> entry = new Map.Entry<Lease, Long>(){ + Map.Entry entry = new Map.Entry(){ @Override - public Lease getKey() { + public Object getKey() { return key; } @Override - public Long getValue() { + public Object getValue() { return value; } @Override - public Long setValue(Long value) { + public Object setValue(Object value) { throw new UnsupportedOperationException("Not supported."); } + public boolean equals(Object o){ + if (!(o instanceof Map.Entry)) return false; + Map.Entry e2 = (Map.Entry) o; + Map.Entry e1 = this; + return (e1.getKey()==null ? e2.getKey()==null : e1.getKey().equals(e2.getKey())) && + (e1.getValue()==null ? e2.getValue()==null : e1.getValue().equals(e2.getValue())); + } + + public int hashCode(){ + Map.Entry e = this; + return (e.getKey()==null ? 0 : e.getKey().hashCode()) ^ + (e.getValue()==null ? 0 : e.getValue().hashCode()); + } + }; if (entries.contains(entry)){ - Long result = map.put(key, value); + Object result = map.put(key, value); return result; } else { return null; @@ -340,15 +400,15 @@ public abstract class AbstractLeaseMap i * also use an AbstractSet for this set, so we're really not * making things that much worse. */ - private final static class EntrySet extends AbstractSet<Map.Entry<Lease,Long>> { - private final Set<Map.Entry<Lease, Long>> set; + private final static class EntrySet extends AbstractSet { + private final Set set; - public EntrySet(Set<Map.Entry<Lease, Long>> set) { + public EntrySet(Set set) { this.set = set; } /** Wrap so we can do type checking on Map.Entry.setValue. */ - public Iterator<Map.Entry<Lease, Long>> iterator() { + public Iterator iterator() { return new EntryIterator(set.iterator()); } @@ -370,10 +430,10 @@ public abstract class AbstractLeaseMap i } /** A wrapper so that we can wrap each Entry returned. */ - private static final class EntryIterator implements Iterator<Map.Entry<Lease,Long>> { - private final Iterator<Map.Entry<Lease,Long>> iter; + private static final class EntryIterator implements Iterator { + private final Iterator iter; - public EntryIterator(Iterator<Map.Entry<Lease,Long>> iter) { + public EntryIterator(Iterator iter) { this.iter = iter; } @@ -381,8 +441,8 @@ public abstract class AbstractLeaseMap i return iter.hasNext(); } - public Map.Entry<Lease,Long> next() { - return new Entry(iter.next()); + public Map.Entry next() { + return new Entry((Map.Entry) iter.next()); } public void remove() { @@ -391,22 +451,22 @@ public abstract class AbstractLeaseMap i } /** Pass through, except for type checking on setValue */ - private static final class Entry implements Map.Entry<Lease, Long> { - private final Map.Entry<Lease, Long> e; + private static final class Entry implements Map.Entry { + private final Map.Entry e; - public Entry(Map.Entry<Lease, Long> e) { + public Entry(Map.Entry e) { this.e = e; } - public Lease getKey() { + public Object getKey() { return e.getKey(); } - public Long getValue() { + public Object getValue() { return e.getValue(); } - public Long setValue(Long value) { + public Object setValue(Object value) { checkValue(value); return e.setValue(value); } Modified: river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/norm/DeformedClientLeaseMapWrapper.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/norm/DeformedClientLeaseMapWrapper.java?rev=1499861&r1=1499860&r2=1499861&view=diff ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/norm/DeformedClientLeaseMapWrapper.java (original) +++ river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/norm/DeformedClientLeaseMapWrapper.java Thu Jul 4 20:31:55 2013 @@ -77,11 +77,11 @@ class DeformedClientLeaseMapWrapper exte private void renewAl() throws LeaseMapException, RemoteException { ClientLeaseWrapper l = (ClientLeaseWrapper) (map.keySet().iterator().next()); - long d = ( (map.get(l))).longValue(); + long d = ( (Long)(map.get(l))).longValue(); try { l.renew(d); } catch (LeaseException e) { - final Map<ClientLeaseWrapper, LeaseException> m = new HashMap<ClientLeaseWrapper, LeaseException>(1); + final Map<Lease, Exception> m = new HashMap<Lease, Exception>(1); m.put(l, e); throw new LeaseMapException(e.getMessage(), m); } Modified: river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/reggie/EntryRep.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/reggie/EntryRep.java?rev=1499861&r1=1499860&r2=1499861&view=diff ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/reggie/EntryRep.java (original) +++ river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/reggie/EntryRep.java Thu Jul 4 20:31:55 2013 @@ -50,7 +50,7 @@ class EntryRep implements Serializable, public EntryClass eclass; /** * The codebase of the entry class. - * + * * @serial */ public String codebase; Modified: river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/reggie/RegistrarLeaseMap.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/reggie/RegistrarLeaseMap.java?rev=1499861&r1=1499860&r2=1499861&view=diff ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/reggie/RegistrarLeaseMap.java (original) +++ river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/reggie/RegistrarLeaseMap.java Thu Jul 4 20:31:55 2013 @@ -22,6 +22,7 @@ import java.rmi.RemoteException; import java.util.HashMap; import java.util.Iterator; import java.util.Map; +import net.jini.core.lease.Lease; import net.jini.core.lease.LeaseMapException; import net.jini.core.lookup.ServiceID; import net.jini.id.Uuid; @@ -57,7 +58,7 @@ class RegistrarLeaseMap extends Abstract /** Constructor used by ConstrainableRegistrarLeaseMap */ RegistrarLeaseMap(Registrar server, RegistrarLease lease, long duration) { - super(lease, duration); + super(new HashMap(), lease, duration); this.server = server; registrarID = lease.getRegistrarID(); } @@ -70,66 +71,69 @@ class RegistrarLeaseMap extends Abstract // This method's javadoc is inherited from an interface of this class public void renewAll() throws LeaseMapException, RemoteException { - int size = map.size(); - if (size == 0) - return; - Object[] regIDs = new Object[size]; - Uuid[] leaseIDs = new Uuid[size]; - long[] durations = new long[size]; - int i = 0; - for (Iterator iter = map.entrySet().iterator(); iter.hasNext(); i++) { - Map.Entry e = (Map.Entry)iter.next(); - RegistrarLease ls = (RegistrarLease)e.getKey(); - regIDs[i] = ls.getRegID(); - leaseIDs[i] = ls.getReferentUuid(); - durations[i] = ((Long)e.getValue()).longValue(); - } - RenewResults results = server.renewLeases(regIDs, leaseIDs, durations); - long now = System.currentTimeMillis(); - HashMap emap = (results.exceptions != null) ? - new HashMap(2 * results.exceptions.length + 1) : null; - i = 0; - int j = 0; - for (Iterator iter = map.entrySet().iterator(); iter.hasNext(); i++) { - Map.Entry e = (Map.Entry)iter.next(); - long duration = results.durations[i]; - if (duration >= 0) { - ((RegistrarLease)e.getKey()).setExpiration(duration + now); - } else { - emap.put(e.getKey(), results.exceptions[j++]); - iter.remove(); - } - } - if (emap != null) - throw new LeaseMapException("lease renewal failures", emap); + synchronized (mapLock){ + int size = map.size(); + if (size == 0) return; + Object[] regIDs = new Object[size]; + Uuid[] leaseIDs = new Uuid[size]; + long[] durations = new long[size]; + int i = 0; + for (Iterator<Map.Entry<RegistrarLease,Long>> iter = map.entrySet().iterator(); iter.hasNext(); i++) { + Map.Entry<RegistrarLease,Long> e = iter.next(); + RegistrarLease ls = e.getKey(); + regIDs[i] = ls.getRegID(); + leaseIDs[i] = ls.getReferentUuid(); + durations[i] = (e.getValue()).longValue(); + } + RenewResults results = server.renewLeases(regIDs, leaseIDs, durations); + long now = System.currentTimeMillis(); + HashMap<Lease,Exception> emap = (results.exceptions != null) ? + new HashMap<Lease,Exception>(2 * results.exceptions.length + 1) : null; + i = 0; + int j = 0; + for (Iterator<Map.Entry<RegistrarLease,Long>> iter = map.entrySet().iterator(); iter.hasNext(); i++) { + Map.Entry<RegistrarLease,Long> e = iter.next(); + long duration = results.durations[i]; + if (duration >= 0) { + e.getKey().setExpiration(duration + now); + } else { + emap.put(e.getKey(), results.exceptions[j++]); + iter.remove(); + } + } + if (emap != null) + throw new LeaseMapException("lease renewal failures", emap); + } } // This method's javadoc is inherited from an interface of this class public void cancelAll() throws LeaseMapException, RemoteException { - int size = map.size(); - if (size == 0) - return; - Object[] regIDs = new Object[size]; - Uuid[] leaseIDs = new Uuid[size]; - int i = 0; - for (Iterator iter = map.keySet().iterator(); iter.hasNext(); i++) { - RegistrarLease ls = (RegistrarLease)iter.next(); - regIDs[i] = ls.getRegID(); - leaseIDs[i] = ls.getReferentUuid(); - } - Exception[] exceptions = server.cancelLeases(regIDs, leaseIDs); - if (exceptions == null) - return; - i = 0; - HashMap emap = new HashMap(13); - for (Iterator iter = map.keySet().iterator(); iter.hasNext(); i++) { - RegistrarLease ls = (RegistrarLease)iter.next(); - Exception ex = exceptions[i]; - if (ex != null) { - emap.put(ls, ex); - iter.remove(); - } - } - throw new LeaseMapException("lease cancellation failures", emap); + synchronized (mapLock){ + int size = map.size(); + if (size == 0) + return; + Object[] regIDs = new Object[size]; + Uuid[] leaseIDs = new Uuid[size]; + int i = 0; + for (Iterator iter = map.keySet().iterator(); iter.hasNext(); i++) { + RegistrarLease ls = (RegistrarLease)iter.next(); + regIDs[i] = ls.getRegID(); + leaseIDs[i] = ls.getReferentUuid(); + } + Exception[] exceptions = server.cancelLeases(regIDs, leaseIDs); + if (exceptions == null) + return; + i = 0; + HashMap emap = new HashMap(13); + for (Iterator iter = map.keySet().iterator(); iter.hasNext(); i++) { + RegistrarLease ls = (RegistrarLease)iter.next(); + Exception ex = exceptions[i]; + if (ex != null) { + emap.put(ls, ex); + iter.remove(); + } + } + throw new LeaseMapException("lease cancellation failures", emap); + } } } Modified: river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/thread/ReadyState.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/thread/ReadyState.java?rev=1499861&r1=1499860&r2=1499861&view=diff ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/thread/ReadyState.java (original) +++ river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/thread/ReadyState.java Thu Jul 4 20:31:55 2013 @@ -38,7 +38,7 @@ public class ReadyState { // flag to indicate the service is shutting down private static final int SHUTDOWN = 2; - private int state = INITIALIZE; + private volatile int state = INITIALIZE; /** * Checks if the service is ready to use, waiting if it is @@ -46,14 +46,19 @@ public class ReadyState { * shutting down. Note that the <code>NoSuchObjectException</code> will be * wrapped in a <code>RemoteExceptionWrapper</code>. */ - public synchronized void check() { + public void check() { while (true) { switch (state) { case INITIALIZE: - try { - wait(); - } catch (InterruptedException e) {} - break; + synchronized (this){ + try { + wait(500L); + } catch (InterruptedException e) { + // Restore interrupt. + Thread.currentThread().interrupt(); + } + } + continue; case READY: return; default: Modified: river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/tool/ClassServer.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/tool/ClassServer.java?rev=1499861&r1=1499860&r2=1499861&view=diff ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/tool/ClassServer.java (original) +++ river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/tool/ClassServer.java Thu Jul 4 20:31:55 2013 @@ -19,6 +19,7 @@ package com.sun.jini.tool; import com.sun.jini.logging.Levels; import com.sun.jini.start.LifeCycle; +import com.sun.jini.start.Starter; import java.io.BufferedInputStream; import java.io.DataInputStream; import java.io.DataOutputStream; @@ -161,7 +162,7 @@ import java.util.logging.Logger; * @author Sun Microsystems, Inc. * */ -public class ClassServer extends Thread { +public class ClassServer extends Thread implements Starter { /** Default HTTP port */ private static int DEFAULT_PORT = 8080; /** Default directory to serve files from on non-Windows OS */ @@ -331,31 +332,15 @@ public class ClassServer extends Thread } } } - - /** - * Construct an un-started server, accepting the same command line options - * supported by {@link #main main}, except for the <code>-stop</code> - * option. - * - * {@link Thread#start() } must be called to start the server. - * - * @param args command line options - * @param lifeCycle life cycle control object, or <code>null</code> - * @throws IOException if the server socket cannot be created - * @throws IllegalArgumentException if a command line option is not - * understood - * @throws NullPointerException if <code>args</code> or any element - * of <code>args</code> is <code>null</code> - * @since 2.3.0 - */ - public ClassServer(LifeCycle lifeCycle, String [] args)throws IOException { - this(new Initializer(lifeCycle, args)); - } /** - * Construct a running server, accepting the same command line options + * Construct a server, accepting the same command line options * supported by {@link #main main}, except for the <code>-stop</code> * option. + * + * If constructed by {@link com.sun.jini.start.ServiceStarter}, + * {@link Starter#start() }, is called automatically, otherwise {@link #start()} + * must be called manually after construction. * * @param args command line options * @param lifeCycle life cycle control object, or <code>null</code> @@ -364,13 +349,10 @@ public class ClassServer extends Thread * understood * @throws NullPointerException if <code>args</code> or any element * of <code>args</code> is <code>null</code> - * @deprecated {@link Thread#start() } is called from within constructor, - * this is non compliant with safe construction rules in the JMM. + * @see Starter */ - @Deprecated public ClassServer(String[] args, LifeCycle lifeCycle) throws IOException { this(new Initializer(lifeCycle, args)); - start(); } /** Add transitive Class-Path JARs to jflist. */ Modified: river/jtsk/skunk/qa_refactor/trunk/src/net/jini/core/lease/Lease.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/net/jini/core/lease/Lease.java?rev=1499861&r1=1499860&r2=1499861&view=diff ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/src/net/jini/core/lease/Lease.java (original) +++ river/jtsk/skunk/qa_refactor/trunk/src/net/jini/core/lease/Lease.java Thu Jul 4 20:31:55 2013 @@ -138,7 +138,7 @@ public interface Lease { * * @return the created <tt>LeaseMap</tt> object */ - LeaseMap<Lease, Long> createLeaseMap(long duration); + LeaseMap createLeaseMap(long duration); /** * Returns a boolean indicating whether or not the lease given as a Modified: river/jtsk/skunk/qa_refactor/trunk/src/net/jini/core/lease/LeaseMap.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/net/jini/core/lease/LeaseMap.java?rev=1499861&r1=1499860&r2=1499861&view=diff ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/src/net/jini/core/lease/LeaseMap.java (original) +++ river/jtsk/skunk/qa_refactor/trunk/src/net/jini/core/lease/LeaseMap.java Thu Jul 4 20:31:55 2013 @@ -21,7 +21,7 @@ package net.jini.core.lease; import java.rmi.RemoteException; /** - * An unsynchronized Map from Lease to Long (the duration to use when + * An Map from Lease to Long (the duration to use when * renewing the lease). For all methods of LeaseMap except canContainKey, * an IllegalArgumentException is thrown if a key is not a Lease or a value * is not a Long. Null keys and values are not supported. @@ -30,7 +30,7 @@ import java.rmi.RemoteException; * * @since 1.0 */ -public interface LeaseMap<Lease, Long> extends java.util.Map<Lease, Long> { +public interface LeaseMap extends java.util.Map { /** * Returns true if the given object is a Lease which can be renewed * and cancelled in a batch with other leases in the map. Whether Modified: river/jtsk/skunk/qa_refactor/trunk/src/net/jini/core/lease/LeaseMapException.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/net/jini/core/lease/LeaseMapException.java?rev=1499861&r1=1499860&r2=1499861&view=diff ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/src/net/jini/core/lease/LeaseMapException.java (original) +++ river/jtsk/skunk/qa_refactor/trunk/src/net/jini/core/lease/LeaseMapException.java Thu Jul 4 20:31:55 2013 @@ -45,7 +45,7 @@ public class LeaseMapException extends L * * @serial */ - public Map exceptionMap; + public final Map<Lease,Exception> exceptionMap; /** * Constructs a LeaseMapException for the specified map with a @@ -62,7 +62,7 @@ public class LeaseMapException extends L * {@link Lease}, or any value which is not an instance of * <code>Throwable</code> */ - public LeaseMapException(String s, Map exceptionMap) { + public LeaseMapException(String s, Map<Lease,Exception> exceptionMap) { super(s); final Set mapEntries = exceptionMap.entrySet(); @@ -133,4 +133,23 @@ public class LeaseMapException extends L throw new InvalidObjectException( "LeaseMapException should always have data"); } + + public String getMessage(){ + String lease = "Lease: "; + String exception = "Exception: "; + String ret = "\n"; + StringBuilder sb = new StringBuilder(1024); + sb.append(super.getMessage()); + sb.append(ret); + Iterator<Map.Entry<Lease,Exception>> it = exceptionMap.entrySet().iterator(); + while (it.hasNext()){ + Entry<Lease,Exception> entry = it.next(); + sb.append(lease); + sb.append(entry.getKey()); + sb.append(exception); + sb.append(entry.getValue().getMessage()); + sb.append(ret); + } + return sb.toString(); + } } Modified: river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/SerialReflectionFactory.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/SerialReflectionFactory.java?rev=1499861&r1=1499860&r2=1499861&view=diff ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/SerialReflectionFactory.java (original) +++ river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/SerialReflectionFactory.java Thu Jul 4 20:31:55 2013 @@ -24,6 +24,7 @@ import java.io.Serializable; import java.io.StreamCorruptedException; import java.lang.reflect.Constructor; import java.lang.reflect.Method; +import java.net.ProtocolException; import java.security.AccessControlContext; import java.security.AccessController; import java.security.CodeSource; @@ -70,8 +71,8 @@ public final class SerialReflectionFacto * proceeded by a byte header indicating its type. For null values, only the * byte header is written to stream. * - * This protocol is fixed and cannot be changed after release. */ + private static byte VERSION = 1; private static final byte BOOLEAN = 0; private static final byte BYTE = 1; private static final byte CHAR = 2; @@ -210,6 +211,7 @@ public final class SerialReflectionFacto public void writeExternal(ObjectOutput out) throws IOException { distributable.checkGuard(null); if (! constructed) throw new IOException("Attempt to write blank SerialReflectionFactory"); + out.writeByte(VERSION); out.writeObject(classOrObject); out.writeObject(method); /* don't clone arrays for defensive copies, it's up to constructing @@ -329,6 +331,10 @@ public final class SerialReflectionFacto * not accessed again, it is up to creator methods themselves to * preserve invariants. */ + byte version = in.readByte(); + // In future we could potentially handle different versions, but for now, + // bail out. + if (version != VERSION) throw new ProtocolException("Incompatible SerialReflectionFactory protocol"); classOrObject = in.readObject(); method = (String) in.readObject(); parameterTypes = (Class[]) in.readObject();
