93 */
94 public abstract static class Key {
95 private static HashMap<Object,Object> identitymap = new HashMap<>(17);
96
97 private String getIdentity() {
98 // Note that the identity string is dependent on 3 variables:
99 // - the name of the subclass of Key
100 // - the identityHashCode of the subclass of Key
101 // - the integer key of the Key
102 // It is theoretically possible for 2 distinct keys to collide
103 // along all 3 of those attributes in the context of multiple
104 // class loaders, but that occurrence will be extremely rare and
105 // we account for that possibility below in the recordIdentity
106 // method by slightly relaxing our uniqueness guarantees if we
107 // end up in that situation.
108 return getClass().getName()+"@"+
109 Integer.toHexString(System.identityHashCode(getClass()))+":"+
110 Integer.toHexString(privatekey);
111 }
112
113 private synchronized static void recordIdentity(Key k) {
114 Object identity = k.getIdentity();
115 Object otherref = identitymap.get(identity);
116 if (otherref != null) {
117 Key otherkey = (Key) ((WeakReference) otherref).get();
118 if (otherkey != null && otherkey.getClass() == k.getClass()) {
119 throw new IllegalArgumentException(identity+
120 " already registered");
121 }
122 // Note that this system can fail in a mostly harmless
123 // way. If we end up generating the same identity
124 // String for 2 different classes (a very rare case)
125 // then we correctly avoid throwing the exception above,
126 // but we are about to drop through to a statement that
127 // will replace the entry for the old Key subclass with
128 // an entry for the new Key subclass. At that time the
129 // old subclass will be vulnerable to someone generating
130 // a duplicate Key instance for it. We could bail out
131 // of the method here and let the old identity keep its
132 // record in the map, but we are more likely to see a
133 // duplicate key go by for the new class than the old
|
93 */
94 public abstract static class Key {
95 private static HashMap<Object,Object> identitymap = new HashMap<>(17);
96
97 private String getIdentity() {
98 // Note that the identity string is dependent on 3 variables:
99 // - the name of the subclass of Key
100 // - the identityHashCode of the subclass of Key
101 // - the integer key of the Key
102 // It is theoretically possible for 2 distinct keys to collide
103 // along all 3 of those attributes in the context of multiple
104 // class loaders, but that occurrence will be extremely rare and
105 // we account for that possibility below in the recordIdentity
106 // method by slightly relaxing our uniqueness guarantees if we
107 // end up in that situation.
108 return getClass().getName()+"@"+
109 Integer.toHexString(System.identityHashCode(getClass()))+":"+
110 Integer.toHexString(privatekey);
111 }
112
113 private static synchronized void recordIdentity(Key k) {
114 Object identity = k.getIdentity();
115 Object otherref = identitymap.get(identity);
116 if (otherref != null) {
117 Key otherkey = (Key) ((WeakReference) otherref).get();
118 if (otherkey != null && otherkey.getClass() == k.getClass()) {
119 throw new IllegalArgumentException(identity+
120 " already registered");
121 }
122 // Note that this system can fail in a mostly harmless
123 // way. If we end up generating the same identity
124 // String for 2 different classes (a very rare case)
125 // then we correctly avoid throwing the exception above,
126 // but we are about to drop through to a statement that
127 // will replace the entry for the old Key subclass with
128 // an entry for the new Key subclass. At that time the
129 // old subclass will be vulnerable to someone generating
130 // a duplicate Key instance for it. We could bail out
131 // of the method here and let the old identity keep its
132 // record in the map, but we are more likely to see a
133 // duplicate key go by for the new class than the old
|