001: /* ProxyObjectGate.java
002: */
003:
004: package org.ozoneDB.core.DbRemote;
005:
006: import java.util.HashMap;
007: import java.util.Iterator;
008:
009: import org.ozoneDB.OzoneProxy;
010: import org.ozoneDB.core.GarbageCollector;
011: import org.ozoneDB.core.ObjectID;
012:
013: /**
014: A gate for Proxy objects. Every Proxy which leaves the Database should wander
015: through a ProxyObjectGate to be registered (so that the objects referenced by such a Proxy
016: are known to be referenced and thus reachable).
017:
018: Every Proxy which left the Database, was registered and is now known to be unreachable should
019: sign itself off exactly one time.
020:
021: @author <A HREF="http://www.medium.net/">Medium.net</A>
022: */
023: public class ProxyObjectGate {
024: /**
025: This is a Mapping from {@link ObjectID} to Integer. It represents the
026: count of references this client holds to the database object represented by the objectID.
027:
028: Entries have to be added when returning {@link OzoneProxy}s directly or indirectly.
029: Entries have to be removed if a {#link OzoneProxy} is finalize()d on the client side.
030: This way, the ozoneDB always know which objects are referenced and thus have to be
031: considered reachable, even if they were not reachable internally.
032: */
033: protected HashMap objectsReferencesByClient;
034:
035: protected GarbageCollector garbageCollectorToBeNotifiedOfExportedReferences;
036:
037: /**
038: This is an Integer which represents the number "1".
039: */
040: protected final static Integer one = new Integer(1);
041:
042: /**
043: Creates a new ProxyObjectGate.
044: */
045: protected ProxyObjectGate() {
046: objectsReferencesByClient = new HashMap();
047: }
048:
049: public void addObjectReferencedByClient(OzoneProxy proxy) {
050: if (proxy != null) {
051: synchronized (objectsReferencesByClient) {
052: ObjectID id = proxy.remoteID();
053:
054: if (garbageCollectorToBeNotifiedOfExportedReferences != null) {
055: garbageCollectorToBeNotifiedOfExportedReferences
056: .notifyDatabaseObjectIsAboutToBeExported(id);
057: }
058:
059: Object oldEntry = objectsReferencesByClient
060: .put(id, one);
061:
062: if (oldEntry != null) {
063: objectsReferencesByClient.put(id, new Integer(
064: ((Integer) oldEntry).intValue() + 1));
065: }
066: }
067: }
068: }
069:
070: protected void removeObjectReferencedByClient(OzoneProxy proxy) {
071: removeObjectReferencedByClient(proxy.remoteID());
072: }
073:
074: protected void removeObjectReferencedByClient(ObjectID id) {
075: synchronized (objectsReferencesByClient) {
076: Object oldEntry = objectsReferencesByClient.remove(id);
077:
078: if (oldEntry != null) {
079: if (oldEntry != one) {
080: int count = ((Integer) oldEntry).intValue();
081:
082: count--;
083:
084: if (count > 0) {
085: if (count > 1) {
086: objectsReferencesByClient.put(id,
087: new Integer(count));
088: } else {
089: objectsReferencesByClient.put(id, one);
090: }
091: }
092: } else {
093: // The reference count was exactly one, now the reference is removed from the map.
094: }
095: } else {
096: // oldEntry never may be null. What should we do here?
097: }
098: }
099: }
100:
101: /**
102: Starts filtering references to database objects ({@link OzoneProxy}s) which
103: are exported to the client.
104: Every reference which is exported will be notified to the given GarbageCollector.
105: Additionally, references which are known to be used by the client are notified to the
106: given GarbageCollector within this call.
107: */
108: public void startFilterDatabaseObjectReferencesExports(
109: GarbageCollector garbageCollector) {
110:
111: synchronized (objectsReferencesByClient) {
112: this .garbageCollectorToBeNotifiedOfExportedReferences = garbageCollector;
113:
114: Iterator i = objectsReferencesByClient.keySet().iterator();
115:
116: while (i.hasNext()) {
117: garbageCollector
118: .notifyDatabaseObjectIsExported((ObjectID) i
119: .next());
120: }
121: }
122: }
123: }
|