/interpreter/tags/at2dist090708/src/com/thoughtworks/xstream/core/util/ObjectIdDictionary.java

http://ambienttalk.googlecode.com/ · 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. */
  12. package com.thoughtworks.xstream.core.util;
  13. import java.lang.ref.WeakReference;
  14. import java.util.HashMap;
  15. import java.util.Iterator;
  16. import java.util.Map;
  17. /**
  18. * Store IDs against given object references.
  19. * <p>
  20. * Behaves similar to java.util.IdentityHashMap, but in JDK1.3 as well. Additionally the implementation
  21. * keeps track of orphaned IDs by using a WeakReference to store the reference object.
  22. * </p>
  23. */
  24. public class ObjectIdDictionary {
  25. private final Map map = new HashMap();
  26. private int invalidCounter;
  27. private static interface Wrapper {
  28. int hashCode();
  29. boolean equals(Object obj);
  30. String toString();
  31. Object get();
  32. }
  33. private static class IdWrapper implements Wrapper {
  34. private final Object obj;
  35. public IdWrapper(Object obj) {
  36. this.obj = obj;
  37. }
  38. public int hashCode() {
  39. return System.identityHashCode(obj);
  40. }
  41. public boolean equals(Object other) {
  42. return obj == ((Wrapper)other).get();
  43. }
  44. public String toString() {
  45. return obj.toString();
  46. }
  47. public Object get() {
  48. return obj;
  49. }
  50. }
  51. private class WeakIdWrapper implements Wrapper {
  52. private final int hashCode;
  53. private final WeakReference ref;
  54. public WeakIdWrapper(Object obj) {
  55. hashCode = System.identityHashCode(obj);
  56. ref = new WeakReference(obj);
  57. }
  58. public int hashCode() {
  59. return hashCode;
  60. }
  61. public boolean equals(Object other) {
  62. return get() == ((Wrapper)other).get();
  63. }
  64. public String toString() {
  65. Object obj = get();
  66. return obj == null ? "(null)" : obj.toString();
  67. }
  68. public Object get() {
  69. Object obj = ref.get();
  70. if (obj == null) {
  71. // it was a lot faster and more efficient simply to count the number of
  72. // evidences instead of keeping the Wrapper somewhere in a remove list
  73. ++ObjectIdDictionary.this.invalidCounter;
  74. }
  75. return obj;
  76. }
  77. }
  78. public void associateId(Object obj, Object id) {
  79. map.put(new WeakIdWrapper(obj), id);
  80. cleanup();
  81. }
  82. public Object lookupId(Object obj) {
  83. Object id = map.get(new IdWrapper(obj));
  84. cleanup();
  85. return id;
  86. }
  87. public boolean containsId(Object item) {
  88. boolean b = map.containsKey(new IdWrapper(item));
  89. cleanup();
  90. return b;
  91. }
  92. public void removeId(Object item) {
  93. map.remove(new IdWrapper(item));
  94. cleanup();
  95. }
  96. public int size() {
  97. return map.size();
  98. }
  99. private void cleanup() {
  100. if (invalidCounter > 100) {
  101. // much more efficient to remove any orphaned wrappers at once
  102. for (final Iterator iterator = map.keySet().iterator(); iterator.hasNext();) {
  103. final WeakIdWrapper key = (WeakIdWrapper)iterator.next();
  104. if (key.get() == null) {
  105. iterator.remove();
  106. }
  107. }
  108. invalidCounter = 0;
  109. }
  110. }
  111. }