Package com.starlight.intrepid.tools

Source Code of com.starlight.intrepid.tools.ObjectDrop$ID

package com.starlight.intrepid.tools;

import com.starlight.IOKit;
import com.starlight.intrepid.ChannelAcceptor;
import com.starlight.intrepid.Intrepid;
import com.starlight.intrepid.IntrepidContext;
import com.starlight.intrepid.VMID;
import com.starlight.intrepid.exception.ChannelRejectedException;
import com.starlight.locale.FormattedTextResourceKey;
import com.starlight.thread.ObjectSlot;
import gnu.trove.map.TShortObjectMap;
import gnu.trove.map.hash.TShortObjectHashMap;

import java.io.*;
import java.lang.ref.WeakReference;
import java.nio.channels.ByteChannel;
import java.nio.channels.Channels;
import java.text.MessageFormat;
import java.util.Map;
import java.util.Random;
import java.util.WeakHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;


/**
*
*/
public class ObjectDrop implements ChannelAcceptor {
  // NOTE: only a short is used
  private static final AtomicInteger DROP_INSTANCE_COUNTER =
    new AtomicInteger( new Random().nextInt() );
  private static final TShortObjectMap<WeakReference<ObjectDrop>> DROP_INSTANCE_MAP =
    new TShortObjectHashMap<WeakReference<ObjectDrop>>();
  private static final Lock DROP_INSTANCE_MAP_LOCK = new ReentrantLock();


  private final short instance_id;

  private final Map<ID,ObjectSlot> object_map =
    new WeakHashMap<ID, ObjectSlot>();
  private final Lock object_map_lock = new ReentrantLock();

  private final AtomicInteger id_counter = new AtomicInteger( new Random().nextInt() );

  public ObjectDrop() {
    instance_id = ( short ) DROP_INSTANCE_COUNTER.incrementAndGet();

    DROP_INSTANCE_MAP_LOCK.lock();
    try {
      DROP_INSTANCE_MAP.put( instance_id, new WeakReference<ObjectDrop>( this ) );
    }
    finally {
      DROP_INSTANCE_MAP_LOCK.unlock();
    }
  }


  public <T> ID<T> prepareForDrop() {
    int id = id_counter.getAndIncrement();
    ID<T> id_obj = new ID<T>( instance_id, id );

    object_map_lock.lock();
    try {
      object_map.put( id_obj, new ObjectSlot<Object>() );
    }
    finally {
      object_map_lock.unlock();
    }

    return id_obj;
  }


  public <T> T retrieve( ID<T> id ) throws InterruptedException, IOException {
    return retrieve( id, Long.MAX_VALUE, TimeUnit.MILLISECONDS );
  }

  public <T> T retrieve( ID<T> id, long timeout, TimeUnit timeout_unit )
    throws InterruptedException, IOException {

    if ( timeout_unit == null ) timeout_unit = TimeUnit.MILLISECONDS;

    ObjectSlot<Object> slot;
    object_map_lock.lock();
    try {
      slot = object_map.remove( id );
    }
    finally {
      object_map_lock.unlock();
    }

    if ( slot == null ) {
      throw new IllegalStateException( MessageFormat.format(
        Resources.ERROR_UNKNOWN_ID.getValue(), id ) );
    }

    Object result = slot.waitForValue( timeout_unit.toMillis( timeout ) );
    if ( result == null ) return null;
    else if ( result instanceof ExceptionWrapper ) {
      Throwable root_exception = ( ( ExceptionWrapper ) result ).exception;
      if ( root_exception instanceof IOException ) {
        throw ( IOException ) root_exception;
      }
      else if ( root_exception instanceof InterruptedException ) {
        throw ( InterruptedException ) root_exception;
      }
      else throw new IOException( root_exception );
    }
    else {
      //noinspection unchecked
      return ( T ) result;
    }
  }


  public static <T> void dropToCaller( ID<T> id, T object, boolean compress )
    throws ChannelRejectedException, IOException {

    VMID vmid = IntrepidContext.getCallingVMID();
    Intrepid instance = IntrepidContext.getActiveInstance();

    if ( vmid != null && instance == null ) {
      throw new IllegalStateException(
        Resources.ERROR_DROP_WITH_VMID_BUT_NO_INSTANCE.getValue() );
    }

    drop( vmid, id, instance, object, compress );
  }

  public static <T> void drop( VMID destination, ID<T> id, Intrepid instance,
    T object, boolean compress ) throws ChannelRejectedException, IOException {

    if ( destination == null ) {
      // Find the ObjectDrop instance
      ObjectDrop drop_instance;
      DROP_INSTANCE_MAP_LOCK.lock();
      try {
        WeakReference<ObjectDrop> ref =
          DROP_INSTANCE_MAP.get( id.getDropInstanceID() );
        if ( ref == null ) {
          throw new IllegalStateException( MessageFormat.format(
            Resources.ERROR_DROP_INSTANCE_NOT_FOUND.getValue(),
            Short.valueOf( id.getDropInstanceID() ) ) );
        }

        drop_instance = ref.get();
        if ( drop_instance == null ) {
          DROP_INSTANCE_MAP.remove( id.getDropInstanceID() );

          throw new IllegalStateException( MessageFormat.format(
            Resources.ERROR_DROP_INSTANCE_GCED.getValue(),
            Short.valueOf( id.getDropInstanceID() ) ) );
        }
      }
      finally {
        DROP_INSTANCE_MAP_LOCK.unlock();
      }

      // NOTE: drop_instance can't be null

      ObjectSlot<T> slot;
      drop_instance.object_map_lock.lock();
      try {
        //noinspection unchecked
        slot = drop_instance.object_map.get( id );
      }
      finally {
        drop_instance.object_map_lock.unlock();
      }

      if ( slot == null ) {
        throw new IllegalStateException( new FormattedTextResourceKey(
          Resources.ERROR_UNKNOWN_ID, id ).getValue() );
      }
      else slot.set( object );

      return;
    }

    ByteChannel channel = null;
    OutputStream out = null;
    ObjectOutputStream oout = null;
    try {
      channel = instance.createChannel( destination, id );
      out = new BufferedOutputStream( Channels.newOutputStream( channel ),
        100 * 1024 );

      // VERSION
      out.write( 0 );

      // COMPRESS
      out.write( compress ? 1 : 0 );

      if ( compress ) oout = new ObjectOutputStream( new GZIPOutputStream( out ) );
      else oout = new ObjectOutputStream( out );

      oout.writeUnshared( object );
      oout.flush();
    }
    finally {
      IOKit.close( ( Closeable ) oout );
      IOKit.close( out );
      IOKit.close( channel );
    }
  }


  @Override
  public void newChannel( ByteChannel channel, VMID source_vmid,
    Serializable attachment ) throws ChannelRejectedException {

    // Verify the expected type
    if ( !( attachment instanceof ID ) ) {
      throw new ChannelRejectedException( Resources.ERROR_ATTACHMENT_NOT_ID );
    }

    ObjectSlot<Object> slot;
    object_map_lock.lock();
    try {
      //noinspection SuspiciousMethodCalls
      slot = object_map.get( attachment );
    }
    finally {
      object_map_lock.unlock();
    }

    // Make sure we're expecting the object
    if ( slot == null ) {
      throw new ChannelRejectedException(
        new FormattedTextResourceKey( Resources.ERROR_UNKNOWN_ID, attachment ) );
    }
    // Make sure the object hasn't already been read
    else if ( slot.get() != null ) {
      throw new ChannelRejectedException(
        new FormattedTextResourceKey( Resources.ERROR_SLOT_FULL, attachment ) );
    }

    new ChannelReader( channel, slot ).start();
  }


  private final class ChannelReader extends Thread {
    private final ByteChannel channel;
    private final ObjectSlot<Object> slot;

    ChannelReader( ByteChannel channel, ObjectSlot<Object> slot ) {
      this.channel = channel;
      this.slot = slot;
    }

    @Override
    public void run() {
      InputStream in = null;
      ObjectInputStream oin = null;
      try {
        in = Channels.newInputStream( channel );

        // VERSION
        //noinspection ResultOfMethodCallIgnored
        in.read();

        // COMPRESSED
        boolean compressed = in.read() > 0;

        if ( compressed ) oin = new ObjectInputStream( new GZIPInputStream( in ) );
        else oin = new ObjectInputStream( in );

        slot.set( oin.readObject() );
      }
      catch( Exception ex ) {
        slot.set( new ExceptionWrapper( ex ) );
      }
      finally {
        IOKit.close( ( Closeable ) oin );
        IOKit.close( in );
      }
    }
  }


  private class ExceptionWrapper {
    private final Exception exception;

    ExceptionWrapper( Exception exception ) {
      this.exception = exception;
    }
  }


  @SuppressWarnings( { "UnusedDeclaration" } )
  public static class ID<T> implements Externalizable {
    private short drop_instance_id;
    private int id;

    /** FOR EXTERNALIZATION ONLY!!! */
    public ID() {
      assert IOKit.isBeingDeserialized();
    }

    private ID( short drop_instance_id, int id ) {
      this.drop_instance_id = drop_instance_id;
      this.id = id;
    }

    private short getDropInstanceID() {
      return drop_instance_id;
    }

    private int getID() {
      return id;
    }


    @Override
    public boolean equals( Object o ) {
      if ( this == o ) return true;
      if ( o == null || getClass() != o.getClass() ) return false;

      ID id1 = ( ID ) o;

      return drop_instance_id == id1.drop_instance_id && id == id1.id;
    }

    @Override
    public int hashCode() {
      int result = ( int ) drop_instance_id;
      result = 31 * result + id;
      return result;
    }

    @Override
    public String toString() {
      final StringBuilder sb = new StringBuilder();
      sb.append( "ID" );
      sb.append( "{drop_instance_id=" ).append( drop_instance_id );
      sb.append( ", id=" ).append( id );
      sb.append( '}' );
      return sb.toString();
    }

    @Override
    public void readExternal( ObjectInput in )
      throws IOException, ClassNotFoundException {

      // VERSION
      in.readByte();

      // DROP INSTANCE ID
      drop_instance_id = in.readShort();

      // ID
      id = in.readInt();

    }

    @Override
    public void writeExternal( ObjectOutput out ) throws IOException {
      // VERSION
      out.writeByte( 0 );

      // DROP INSTANCE ID
      out.writeShort( drop_instance_id );

      // ID
      out.writeInt( id );
    }
  }
}
TOP

Related Classes of com.starlight.intrepid.tools.ObjectDrop$ID

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.