org.python.modules._weakref.GlobalRef Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jython-standalone Show documentation
Show all versions of jython-standalone Show documentation
Jython is an implementation of the high-level, dynamic, object-oriented
language Python written in 100% Pure Java, and seamlessly integrated with
the Java platform. It thus allows you to run Python on any Java platform.
/* Copyright (c) Jython Developers */
package org.python.modules._weakref;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentMap;
import org.python.core.Py;
import org.python.core.PyList;
import org.python.core.PyObject;
import org.python.util.Generic;
public class GlobalRef extends WeakReference {
/**
* This reference's hashCode: the System.identityHashCode of the referent. Only used
* internally.
*/
private int hashCode;
/**
* The public hashCode for the Python AbstractReference wrapper. Derived from the
* referent's hashCode.
*/
private int pythonHashCode;
/** Whether pythonHashCode was already determined. */
private boolean havePythonHashCode;
private List references = new ArrayList();
private static ReferenceQueue referenceQueue = new ReferenceQueue();
private static RefReaperThread reaperThread;
private static ConcurrentMap objects = Generic.concurrentMap();
static {
initReaperThread();
}
public GlobalRef(PyObject object) {
super(object, referenceQueue);
hashCode = System.identityHashCode(object);
}
public synchronized void add(AbstractReference ref) {
Reference r = new WeakReference(ref);
references.add(r);
}
private final AbstractReference getReferenceAt(int idx) {
WeakReference wref = (WeakReference)references.get(idx);
return (AbstractReference)wref.get();
}
/**
* Search for a reusable refrence. To be reused, it must be of the
* same class and it must not have a callback.
*/
synchronized AbstractReference find(Class cls) {
for (int i = references.size() - 1; i >= 0; i--) {
AbstractReference r = getReferenceAt(i);
if (r == null) {
references.remove(i);
} else if (r.callback == null && r.getClass() == cls) {
return r;
}
}
return null;
}
/**
* Call each of the registered references.
*/
synchronized void call() {
for (int i = references.size() - 1; i >= 0; i--) {
AbstractReference r = getReferenceAt(i);
if (r == null) {
references.remove(i);
} else {
r.call();
}
}
}
synchronized public int count() {
for (int i = references.size() - 1; i >= 0; i--) {
AbstractReference r = getReferenceAt(i);
if (r == null) {
references.remove(i);
}
}
return references.size();
}
synchronized public PyList refs() {
List list = new ArrayList();
for (int i = references.size() - 1; i >= 0; i--) {
AbstractReference r = getReferenceAt(i);
if (r == null) {
references.remove(i);
} else {
list.add(r);
}
}
return new PyList(list);
}
/**
* Create a new tracked GlobalRef.
*
* @param object a PyObject to reference
* @return a new tracked GlobalRef
*/
public static GlobalRef newInstance(PyObject object) {
GlobalRef ref = objects.get(new GlobalRef(object));
if (ref == null) {
ref = new GlobalRef(object);
objects.put(ref, ref);
}
return ref;
}
/**
* Return the number of references to the specified PyObject.
*
* @param object a PyObject
* @return an int reference count
*/
public static int getCount(PyObject object) {
GlobalRef ref = objects.get(new GlobalRef(object));
return ref == null ? 0 : ref.count();
}
/**
* Return a list of references to the specified PyObject.
*
* @param object a PyObject
* @return a PyList of references. may be empty
*/
public static PyList getRefs(PyObject object) {
GlobalRef ref = objects.get(new GlobalRef(object));
return ref == null ? new PyList() : ref.refs();
}
/**
* Allow GlobalRef's to be used as hashtable keys.
*/
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof GlobalRef)) {
return false;
}
Object t = this.get();
Object u = ((GlobalRef)o).get();
if ((t == null) || (u == null)) {
return false;
}
if (t == u) {
return true;
}
// Don't consult the objects' equals (__eq__) method, it can't be trusted
return false;
}
/**
* Allows GlobalRef to be used as hashtable keys.
*
* @return a hashCode int value
*/
public int hashCode() {
return hashCode;
}
/**
* The publicly used hashCode, for the AbstractReference wrapper.
*
* @return a hashCode int value
*/
public int pythonHashCode() {
if (havePythonHashCode) {
return pythonHashCode;
}
Object referent = get();
if (referent == null) {
throw Py.TypeError("weak object has gone away");
}
pythonHashCode = referent.hashCode();
havePythonHashCode = true;
return pythonHashCode;
}
private static void initReaperThread() {
reaperThread = new RefReaperThread();
reaperThread.setDaemon(true);
reaperThread.start();
}
private static class RefReaperThread extends Thread {
RefReaperThread() {
super("weakref reaper");
}
public void collect() throws InterruptedException {
GlobalRef gr = (GlobalRef)referenceQueue.remove();
gr.call();
objects.remove(gr);
gr = null;
}
public void run() {
while (true) {
try {
collect();
} catch (InterruptedException exc) {
// ok
}
}
}
}
}