PageRenderTime 25ms CodeModel.GetById 12ms app.highlight 9ms RepoModel.GetById 2ms app.codeStats 0ms

/interpreter/tags/at2dist160410/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 */
 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}