/*
 * Aleph Toolkit
 *
 * Copyright 1997, Brown University, Providence, RI.
 * 
 *                         All Rights Reserved
 * 
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose other than its incorporation into a
 * commercial product is hereby granted without fee, provided that the
 * above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of Brown University not be used in
 * advertising or publicity pertaining to distribution of the software
 * without specific, written prior permission.
 * 
 * BROWN UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ANY
 * PARTICULAR PURPOSE.  IN NO EVENT SHALL BROWN UNIVERSITY BE LIABLE FOR
 * ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package aleph.dir.home;


import aleph.Aleph;
import aleph.AlephDebug;
import aleph.AlephException;
import aleph.GlobalObject;
import aleph.PE;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.Hashtable;

/**
 * Home Based Directory implementation.
 *
 * @author Mike Demmer
 * @author Maurice Herlihy
 * @date May 1998
 */
public class HomeDirectory extends aleph.dir.DirectoryManager {

  static final boolean DEBUG = false; // Top of the world, Ma!

  static Hashtable clientTable, serverTable;
  
  public HomeDirectory () {
    clientTable = new Hashtable(); // Client-side object information.
    serverTable = new Hashtable(); // Server-side object information.
    AlephDebug.register("Home Directory", this);
  }

  /**
   * Open an object.
   * @param object      The object.
   * @param mode        E.g., Read, Write, Copy, etc.
   **/
  public Object open (GlobalObject object, String mode) {
    return getClientSide(object).open(mode);
  }

  /**
   * Register newly-imported global object.
   * Has no effect if object already registered.
   * @param key    Global object
   **/
  public void importObject (GlobalObject key) {}

  /**
   * Register newly-created global object.
   * @param key    Global object ID
   * @param object Initial state for global object.
   * @param hint   currently ignored
   **/
  public void newObject (GlobalObject key, Object object, String hint) {
    if (DEBUG)
      AlephDebug.println("HomeDirectory: registering " + key + " " + object);
    serverTable.put(key, new ServerSide(key, object));
  }

  /**
   * Called when object no longer needed.
   * @param object Formerly interesting object.
   **/
  public void release (GlobalObject key) {
    if (DEBUG)
      AlephDebug.println("HomeDirectory: releasing " + key);
    getClientSide(key).release();
  }

  /**
   * Called by RetrieveResponse message.
   * @param key global object's unique ID
   * @param object new value
   * @param mode in which object granted
   * @see aleph.dir.home.RetrieveResponse
   **/
  public void retrieveResponse (GlobalObject key, Object object, int mode) {
    getClientSide(key).retrieveResponse(object, mode);
  }

  /**
   * Called by RetrieveRequest message to acquire new object.
   * @param key global object's unique ID
   * @param object new value
   * @param mode in which object granted
   * @see aleph.dir.home.RetrieveRequest
   **/
  public void retrieveRequest (GlobalObject key, PE from, int mode) {
    getServerSide(key).retrieveRequest(from, mode);
  }

  /**
   * Called by ReleaseRequest message.
   * @param from request originated here
   * @param key object in question
   * @see aleph.dir.home.RetrieveRequest
   **/
  public void releaseRequest (PE from, GlobalObject key) {
    getClientSide(key).releaseRequest(from);
  }

  /**
   * Called by ReleaseResponse message.
   * @param key object in question
   * @param object actual data
   * @param from request originated here
   * @see aleph.dir.home.ReleaseResponse
   **/
  public void releaseResponse (GlobalObject key, Object object, PE from) {
    getServerSide(key).releaseResponse(object, from);
  }

  private static ClientSide getClientSide (GlobalObject key) {
    try {
      ClientSide clientSide = (ClientSide) clientTable.get(key);
      if (clientSide == null) {
        clientSide = new ClientSide(key);
        clientTable.put(key, clientSide);
      }
      return clientSide;
    } catch (Exception e) {
      Aleph.panic(e);
      return null;		// never reached
    }
  }
  private static ServerSide getServerSide (GlobalObject key) {
    try {
      ServerSide serverSide = (ServerSide) serverTable.get(key);
      if (serverSide == null) {
        Aleph.panic("HomeDirectoryManager: missing server side " + key);
      }
      return serverSide;
    } catch (Exception e) {
      Aleph.panic(e);
      return null;		// never reached
    }
  }

  /**
   * @return who we are
   **/
  public String getLabel () {
    return "Home";
  }

  /**
   * Produce a human-readable snapshot of all global objects.  Very helpful in
   * a panic.
   **/
  public String toString() {
    return "ServerSide " + serverTable + "\nClientSide " + clientTable;
  }

}

  
  
