All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.gwt.dev.shell.RemoteObjectTable Maven / Gradle / Ivy

There is a newer version: 2.10.0
Show newest version
/*
 * Copyright 2009 Google Inc.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.google.gwt.dev.shell;

import com.google.gwt.dev.shell.BrowserChannel.RemoteObjectRef;

import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * Keeps track of references to remote objects.  When the objects are no longer
 * needed, their ids are returned in {@link #getRefIdsForCleanup()}.
 * 
 * @param  subtype of RemoteObjectRef contained in this table
 */
public class RemoteObjectTable {

  /**
   * This maps References to RemoteObjectRefs back to the original refId.
   * Because we need the refId of the RemoteObjectRef after it's been
   * garbage-collected, this state must be stored externally.
   */
  private final Map, Integer> idFromRemoteObject;
  
  /**
   * This accumulates remote objects that are no longer referenced on this side
   * of the channel.
   */
  private final ReferenceQueue refQueue;

  /**
   * This map associates a remote object ID with a Reference to the
   * RemoteObjectRef that currently represents that id.
   */
  private final Map> remoteObjectFromId;

  /**
   * Create a new RemoteObjectTable.
   */
  public RemoteObjectTable() {
    refQueue = new ReferenceQueue();
    remoteObjectFromId = new HashMap>();
    idFromRemoteObject = new IdentityHashMap, Integer>();
  }

  /**
   * @return the set of remote object reference IDs that should be freed.
   */
  public synchronized Set getRefIdsForCleanup() {
    // Access to these objects is inherently synchronous
    Map> objectMap = remoteObjectFromId;
    Map, Integer> refIdMap = idFromRemoteObject;
    Set toReturn = new HashSet();

    // Find all refIds associated with previous garbage collection cycles
    Reference ref;
    while ((ref = refQueue.poll()) != null) {
      Integer i = refIdMap.remove(ref);
      assert i != null;
      toReturn.add(i);
    }

    /*
     * Check for liveness. This is necessary because the last reference to a
     * RemoteObjectRef could have been cleared and a new reference to that refId
     * created before this method has been called.
     */
    for (Iterator i = toReturn.iterator(); i.hasNext();) {
      Integer refId = i.next();
      if (objectMap.containsKey(refId)) {
        if (objectMap.get(refId).get() != null) {
          i.remove();
        } else {
          objectMap.remove(refId);
        }
      }
    }

    return toReturn;
  }

  /**
   * Obtain the RemoteObjectRef that is currently in use to act as a proxy for
   * the given remote object ID.
   * 
   * @return the RemoteObjectRef or null if the ID is not currently in use
   */
  public synchronized T getRemoteObjectRef(int refId) {
    if (remoteObjectFromId.containsKey(refId)) {
      Reference ref = remoteObjectFromId.get(refId);
      T toReturn = ref.get();
      if (toReturn != null) {
        return toReturn;
      }
    }
    return null;
  }

  /**
   * Check to see if this ID does not already exist.
   * 
   * @param refId reference ID to check
   * @return true if this ID is not currently in use
   */
  public synchronized boolean isNewObjectId(int refId) {
    return !remoteObjectFromId.containsKey(refId)
    || (remoteObjectFromId.get(refId).get() == null);
  }

  /**
   * Store a remote object reference in the table.
   * 
   * @param refId
   * @param remoteObjectRef
   */
  public synchronized void putRemoteObjectRef(int refId,
      T remoteObjectRef) {
    Reference ref = new WeakReference(remoteObjectRef, refQueue);
    remoteObjectFromId.put(refId, ref);
    idFromRemoteObject.put(ref, refId);
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy