/* AOM.java --
   Copyright (C) 2005 Free Software Foundation, Inc.

This file is part of GNU Classpath.

GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.

GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING.  If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.

Linking this library statically or dynamically with other modules is
making a combined work based on this library.  Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.

As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module.  An independent module is a module which is not derived from
or based on this library.  If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so.  If you do not wish to do so, delete this
exception statement from your version. */


package gnu.CORBA.Poa;

import gnu.CORBA.ByteArrayComparator;

import org.omg.CORBA.portable.Delegate;
import org.omg.CORBA.portable.ObjectImpl;
import org.omg.PortableServer.Servant;

import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

/**
 * Implements the conception of the Active Object Map.
 * If the POA supports the RETAIN policy, it maintains an Active
 * Object Map, that associates Object Ids with active servants.
 * Each association constitutes an active object. We use a single map
 * for all POAs on the given orb.
 *
 * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
 */
public class AOM
{
  /**
   * The reference data about the object, placed on the AOM.
   */
  public class Obj
  {
    /**
     * Create an initialised instance.
     */
    Obj(gnuServantObject _object, byte[] _key, Servant _servant, gnuPOA _poa)
    {
      object = _object;
      key = _key;
      servant = _servant;
      poa = _poa;
    }

    /**
     * The object.
     */
    public final gnuServantObject object;

    /**
     * The servant, serving the given object.
     */
    public Servant servant;

    /**
     * The local servant that once served this object.
     * This field is used by {@link ForwardedServant} when it discovers that
     * the forwarding chaing returns back to the original location.
     * It should not be used anywhere else.
     */
    Servant primary_servant;

    /**
     * The POA, where the object is connected.
     */
    public final gnuPOA poa;

    /**
     * The object key.
     */
    public final byte[] key;

    /**
     * If true, this entry is deactivated.
     */
    public boolean deactivated;

    /**
     * Set the servant value, preserving any non null
     * value as the primary servant.
     */
    public void setServant(Servant s)
    {
      if (primary_servant == null)
        primary_servant = s;
      servant = s;
    }

    /**
     * Get the servant.
     */
    public Servant getServant()
    {
      return servant;
    }

    /**
     * Get the deactivation state.
     */
    public boolean isDeactiveted()
    {
      return deactivated;
    }

    /**
     * Set the deactivation state.
     */
    public void setDeactivated(boolean state)
    {
      deactivated = state;
    }
  }

  /**
   * The free number to give for the next instance.
   * This field is incremented each time the
   * new collection of the connected objects is created.
   * Each collection has its own unique instance number.
   */
  private static long free_id;

  /**
   * The map of the all connected objects, maps the object key to the
   * object.
   */
  Map objects = new TreeMap(new ByteArrayComparator());

  /**
   * Get the record of the stored object. If the object is mapped several times
   * under the different keys, one of the mappings is used.
   * 
   * @param stored_object the stored object
   * 
   * @return the record about the stored object, null if this object is not
   * stored here.
   */
  public Obj findObject(org.omg.CORBA.Object stored_object)
  {
    if (stored_object == null)
      return null;

    Map.Entry item;
    Iterator iter;
    Obj ref;

    if (stored_object instanceof ObjectImpl)
      {
        // If the delegate is available, search by delegate.
        Delegate d = ((ObjectImpl) stored_object)._get_delegate();
        Delegate d2;

        if (d != null)
          {
            iter = objects.entrySet().iterator();
            while (iter.hasNext())
              {
                item = (Map.Entry) iter.next();
                ref = (Obj) item.getValue();
                d2 = ref.object._get_delegate();

                if (d == d2 || (d2 != null && d2.equals(d)))
                  return ref;
              }
          }
      }

    // For other objects (or if not possible to get the delegate),
    // search by .equals
    iter = objects.entrySet().iterator();
    while (iter.hasNext())
      {
        item = (Map.Entry) iter.next();
        ref = (Obj) item.getValue();
        if (stored_object.equals(ref.object))
          return ref;
      }
    return null;
  }

  /**
   * Find the reference info for the given servant. If the servant is mapped to
   * several objects, this returns the first found occurence.
   * 
   * @param servant a servant to find.
   * 
   * @return the servant/object/POA binding or null if no such found.
   */
  public Obj findServant(Servant servant)
  {
    if (servant == null)
      return null;

    Map.Entry item;
    Iterator iter = objects.entrySet().iterator();
    Obj ref;

    while (iter.hasNext())
      {
        item = (Map.Entry) iter.next();
        ref = (Obj) item.getValue();
        if (servant.equals(ref.servant))
          return ref;
      }
    return null;
  }

  /**
   * Find the reference info for the given servant.
   * If the servant is mapped to several objects, this
   * returns the first found occurence.
   *
   * @param servant a servant to find.
   * @param speficies if to search for the inactive (true) or active
   * (false) servant. A servant with unmatching activity is ignored
   * by this method.
   *
   * @return the servant/object/POA binding or null if no such found.
   */
  public Obj findServant(Servant servant, boolean inactive)
  {
    if (servant == null)
      return null;

    Map.Entry item;
    Iterator iter = objects.entrySet().iterator();
    Obj ref;

    while (iter.hasNext())
      {
        item = (Map.Entry) iter.next();
        ref = (Obj) item.getValue();
        if (ref.deactivated == inactive)
          if (ref.servant != null)
            if (servant.equals(ref.servant))
              return ref;
      }
    return null;
  }

  /**
   * Add the new object to the repository. The object key is
   * generated automatically.
   *
   * @param object the object to add.
   * @param servant a servant, serving the given object.
   * @param poa the poa, where the object is connected.
   *
   * @return the newly created object record.
   */
  public Obj add(gnuServantObject object, Servant servant, gnuPOA poa)
  {
    return add(generateObjectKey(object), object, servant, poa);
  }

  /**
   * Add the new object to the repository.
   *
   * @param key the object key.
   * @param object the object to add.
   * @param servant a servant, serving the given object.
   * @param poa the POA, where the object is connected.
   */
  public Obj add(byte[] key, gnuServantObject object, Servant servant,
                 gnuPOA poa
                )
  {
    Obj rec = new Obj(object, key, servant, poa);
    objects.put(key, rec);
    return rec;
  }

  /**
   * Add the new object to the repository.
   *
   * @param delegate the delegate, providing data about the servant, key, POA
   * and object.
   * @param port the port that this object would take.
   */
  public Obj add(ServantDelegateImpl delegate)
  {
    Obj rec =
      new Obj(delegate.object, delegate.servant_id, delegate.servant,
              delegate.poa
             );
    objects.put(delegate.servant_id, rec);
    return rec;
  }

  /**
   * Put back the definition structure that has probably been removed earlier.
   */
  public void put(Obj obj)
  {
    objects.put(obj.key, obj);
  }

  /**
   * Get the stored object.
   *
   * @param key the key (in the byte array form).
   *
   * @return the matching object, null if none is matching.
   */
  public Obj get(byte[] key)
  {
    return (Obj) objects.get(key);
  }

  /**
   * Get the map key set.
   */
  public Set keySet()
  {
    return objects.keySet();
  }

  /**
   * Remove the given object, indiciating it by the key.
   *
   * @param object the object to remove.
   */
  public void remove(byte[] key)
  {
    objects.remove(key);
  }

  /**
   * Generate the object key, unique in the currently
   * running java virtual machine. The passed object
   * parameter is currently not in use.
   *
   * @return the generated key.
   */
  protected byte[] generateObjectKey(org.omg.CORBA.Object object)
  {
    byte[] key;

    // The repetetive keys cannot be generated, but theoretically
    // the same keys can be passed when calling add(byte[]...).
    // Hence we check if the key is not already in the map and,
    // if it is, use the subsequent value.
    do
      {
        key = getFreeId();
      }
    while (objects.containsKey(key));
    return key;
  }

  /**
   * Get the next free 8 byte id, surely unique between calls of this
   * method for the currently running virtual machine.
   */
  public static synchronized byte[] getFreeId()
  {
    byte[] r = new byte[ 8 ];

    // Start from the faster-changing.
    r [ 0 ] = ((byte) (0xff & free_id));
    r [ 1 ] = ((byte) (0xff & (free_id >> 8)));
    r [ 2 ] = ((byte) (0xff & (free_id >> 16)));
    r [ 3 ] = ((byte) (0xff & (free_id >> 24)));
    r [ 4 ] = ((byte) (0xff & (free_id >> 32)));
    r [ 5 ] = ((byte) (0xff & (free_id >> 40)));
    r [ 6 ] = ((byte) (0xff & (free_id >> 48)));
    r [ 7 ] = ((byte) (0xff & (free_id >> 56)));

    free_id++;

    return r;
  }
}