/interpreter/tags/at2dist110511/src/com/thoughtworks/xstream/core/util/ObjectIdDictionary.java
Java | 135 lines | 90 code | 24 blank | 21 comment | 9 complexity | 2882dad88c72d73269d9e8f877c07ba3 MD5 | raw file
1/* 2 * Copyright (C) 2004 Joe Walnes. 3 * Copyright (C) 2006, 2007 XStream Committers. 4 * All rights reserved. 5 * 6 * The software in this package is published under the terms of the BSD 7 * style license a copy of which has been included with this distribution in 8 * the LICENSE.txt file. 9 * 10 * Created on 09. May 2004 by Joe Walnes 11 */ 12package com.thoughtworks.xstream.core.util; 13 14import java.lang.ref.WeakReference; 15import java.util.HashMap; 16import java.util.Iterator; 17import java.util.Map; 18 19/** 20 * Store IDs against given object references. 21 * <p> 22 * Behaves similar to java.util.IdentityHashMap, but in JDK1.3 as well. Additionally the implementation 23 * keeps track of orphaned IDs by using a WeakReference to store the reference object. 24 * </p> 25 */ 26public class ObjectIdDictionary { 27 28 private final Map map = new HashMap(); 29 private int invalidCounter; 30 31 private static interface Wrapper { 32 int hashCode(); 33 boolean equals(Object obj); 34 String toString(); 35 Object get(); 36 } 37 38 private static class IdWrapper implements Wrapper { 39 40 private final Object obj; 41 42 public IdWrapper(Object obj) { 43 this.obj = obj; 44 } 45 46 public int hashCode() { 47 return System.identityHashCode(obj); 48 } 49 50 public boolean equals(Object other) { 51 return obj == ((Wrapper)other).get(); 52 } 53 54 public String toString() { 55 return obj.toString(); 56 } 57 58 public Object get() { 59 return obj; 60 } 61 } 62 63 private class WeakIdWrapper implements Wrapper { 64 65 private final int hashCode; 66 private final WeakReference ref; 67 68 public WeakIdWrapper(Object obj) { 69 hashCode = System.identityHashCode(obj); 70 ref = new WeakReference(obj); 71 } 72 73 public int hashCode() { 74 return hashCode; 75 } 76 77 public boolean equals(Object other) { 78 return get() == ((Wrapper)other).get(); 79 } 80 81 public String toString() { 82 Object obj = get(); 83 return obj == null ? "(null)" : obj.toString(); 84 } 85 86 public Object get() { 87 Object obj = ref.get(); 88 if (obj == null) { 89 // it was a lot faster and more efficient simply to count the number of 90 // evidences instead of keeping the Wrapper somewhere in a remove list 91 ++ObjectIdDictionary.this.invalidCounter; 92 } 93 return obj; 94 } 95 } 96 97 public void associateId(Object obj, Object id) { 98 map.put(new WeakIdWrapper(obj), id); 99 cleanup(); 100 } 101 102 public Object lookupId(Object obj) { 103 Object id = map.get(new IdWrapper(obj)); 104 cleanup(); 105 return id; 106 } 107 108 public boolean containsId(Object item) { 109 boolean b = map.containsKey(new IdWrapper(item)); 110 cleanup(); 111 return b; 112 } 113 114 public void removeId(Object item) { 115 map.remove(new IdWrapper(item)); 116 cleanup(); 117 } 118 119 public int size() { 120 return map.size(); 121 } 122 123 private void cleanup() { 124 if (invalidCounter > 100) { 125 // much more efficient to remove any orphaned wrappers at once 126 for (final Iterator iterator = map.keySet().iterator(); iterator.hasNext();) { 127 final WeakIdWrapper key = (WeakIdWrapper)iterator.next(); 128 if (key.get() == null) { 129 iterator.remove(); 130 } 131 } 132 invalidCounter = 0; 133 } 134 } 135}