Package erjang.m.erlang

Source Code of erjang.m.erlang.ErlPort

/**
* This file is part of Erjang - A JVM-based Erlang VM
*
* Copyright (c) 2009 by Trifork
*
* 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 erjang.m.erlang;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import kilim.Pausable;
import erjang.BIF;
import erjang.EAtom;
import erjang.EInternalPID;
import erjang.EInternalPort;
import erjang.EObject;
import erjang.EPort;
import erjang.EProc;
import erjang.ERT;
import erjang.ESeq;
import erjang.ESmall;
import erjang.EString;
import erjang.ETask;
import erjang.ETuple;
import erjang.ETuple2;
import erjang.ETuple3;
import erjang.driver.EDriver;
import erjang.driver.EDriverInstance;
import erjang.driver.EDriverTask;
import erjang.driver.EExecDriverTask;
import erjang.driver.EFDDriverTask;
import erjang.driver.ESpawnDriverTask;
import erjang.driver.tcp_inet.TCPINet;

/**
*
*/
public class ErlPort {
  static Logger log = Logger.getLogger("erjang.port");

  public static final EAtom am_fd = EAtom.intern("fd");
  private static final ByteBuffer EMPTY_BYTEBUFFER = ByteBuffer.allocate(0);
  public static EAtom am_spawn = EAtom.intern("spawn");
  static EAtom am_spawn_driver = EAtom.intern("spawn_driver");
  static EAtom am_spawn_executable = EAtom.intern("spawn_executable");

  @BIF
  static EObject port_connect(EProc proc, EObject arg_port, EObject arg_pid) throws Pausable
  {
    EInternalPort iport;
    EInternalPID ipid;
   
    if ((iport=arg_port.testInternalPort()) == null) {
      EAtom port_name = arg_port.testAtom();
      EObject resolved;
      if (port_name != null
        && (resolved=ERT.whereis(port_name)) != ERT.am_undefined
        && (iport=resolved.testInternalPort()) != null) {
        // ok //
      } else {
        throw ERT.badarg(arg_port, arg_pid);
      }
    }

    if ((ipid=arg_pid.testInternalPID()) == null) {
      EAtom pid_name = arg_pid.testAtom();
      EObject resolved;
      if (pid_name != null
        && (resolved=ERT.whereis(pid_name)) != ERT.am_undefined
        && (ipid=resolved.testInternalPID()) != null) {
        // ok //
      } else {
        throw ERT.badarg(arg_port, arg_pid);
      }
    }

    // TODO: what if port or pid args are already dead?
   
    iport.set_owner(ipid);
    ipid.task().link_to(iport);
   
    return ERT.TRUE;
   
  }
 
  @BIF
  static EObject port_command(EProc proc, EObject port, EObject data)
      throws Pausable {
    EInternalPort p = port.testInternalPort();

    if (log.isLoggable(Level.FINER))
    log.finer("port_command "+port+", "+data);
   

   
    if (p == null) {
      port = ERT.whereis(port);
      if (port == ERT.am_undefined)
        port = null;
      else
        p = port.testInternalPort();
    }

    List<ByteBuffer> ovec = new ArrayList<ByteBuffer>();
    if (p == null || !data.collectIOList(ovec)) {
      if (log.isLoggable(Level.WARNING)) {
        log.warning("collect failed! or p==null: "+p);
      }
      throw ERT.badarg(port, data);
    }

    ByteBuffer[] out = new ByteBuffer[ovec.size()];
    ovec.toArray(out);

    if (log.isLoggable(Level.FINE)) {
      log.fine("EVEC: ");
      TCPINet.dump_buffer(out);
    }
   
    // log.finer("packing "+data+"::"+data.getClass().getName()+" -> "+ovec);

    p.command(proc.self_handle(), out);

    return ERT.TRUE;
  }

  /* TODO: worry about the options argument */
  @BIF
  static EObject port_command(EProc proc, EObject port, EObject data, EObject options)
      throws Pausable {
    EInternalPort p = port.testInternalPort();

    if (log.isLoggable(Level.FINE))
      log.fine("port_command "+port+", "+data);
   

   
    if (p == null) {
      port = ERT.whereis(port);
      if (port == ERT.am_undefined)
        port = null;
      else
        p = port.testInternalPort();
    }

    List<ByteBuffer> ovec = new ArrayList<ByteBuffer>();
    if (p == null || !data.collectIOList(ovec)) {
      if (log.isLoggable(Level.FINE)) {
        log.fine("collect failed! or p==null: "+p);
      }
      throw ERT.badarg(port, data);
    }

    ByteBuffer[] out = new ByteBuffer[ovec.size()];
    ovec.toArray(out);

    EDriverInstance.dump_buffer(log, "EVEC: ", out);
   
    // log.fine("packing "+data+"::"+data.getClass().getName()+" -> "+ovec);

    p.command(proc.self_handle(), out);

    return ERT.TRUE;
  }


  @BIF
  static EObject port_control(EProc proc, EObject port, EObject operation,
      EObject data) throws Pausable {
   
      try {
        return port_control0(proc, port, operation, data);
      } catch (RuntimeException e) {
        e.printStackTrace();
        throw e;
      } catch (Error e) {
        e.printStackTrace();
        throw e;
      }
    }

  static EObject port_control0(EProc proc, EObject port, EObject operation,
      EObject data) throws Pausable {
    EInternalPort p = port.testInternalPort();

    if (p == null) {
      port = ERT.whereis(port);
      if (port == ERT.am_undefined)
        port = null;

      p = port.testInternalPort();
    }

    ESmall op = operation.testSmall();

    List<ByteBuffer> ovec = new ArrayList<ByteBuffer>();
    if (p == null || op == null || !data.collectIOList(ovec)) {
      throw ERT.badarg(port, operation, data);
    }

    ByteBuffer cmd = flatten(ovec);
   
    // TODO: improve exception handling/wrapping here so we get
    // ErlangException types only!
    return p.control(proc, op.value, cmd);
  }

  private static ByteBuffer flatten(List<ByteBuffer> ovec) {
    if (ovec.size() == 0) {
      return EMPTY_BYTEBUFFER;
    } else if (ovec.size() == 1) {
      return ovec.get(0);
    }
   
    int len = 0;
    for (int i = 0; i < ovec.size(); i++) {
      len += ovec.get(i).remaining();
    }
   
    ByteBuffer res = ByteBuffer.allocate(len);
    for (ByteBuffer bb : ovec) {
      res.put(bb);
    }
   
    res.rewind();
    return res;   
  }

  @BIF
  static EObject port_call(EProc proc, EObject port, EObject operation,
      EObject data) throws Pausable {
    EInternalPort p = port.testInternalPort();

    if (p == null) {
      port = ERT.whereis(port);
      if (port == ERT.am_undefined)
        port = null;

      p = port.testInternalPort();
    }

    ESmall op = operation.testSmall();

    if (p == null || op == null) {
      throw ERT.badarg(port, operation, data);
    }

    // TODO: improve exception handling/wrapping here so we get
    // ErlangException types only!
    return p.call(proc, op.value, data);
  }

  @BIF
  static EPort open_port(EProc proc, EObject portName, EObject portSetting)
      throws Pausable {

    ETuple t;
    if ((t = portName.testTuple()) == null)
      throw ERT.badarg(portName, portSetting);

    ETask<? extends EPort> task = null;

    ETuple2 name;
    ETuple3 name3;
    if ((name = ETuple2.cast(t)) != null) {

      EAtom am = name.elem2.testAtom();
      EString command = (am == null)
          ? (EString)EString.make(name.elem2)
          : EString.fromString(am.getName());

      if (name.elem1 == am_spawn) {
        EDriver drv = ERT.find_driver(command);

        if (drv == null) {
          task = new EExecDriverTask(proc, name, command, portSetting);
        } else {
          task = new ESpawnDriverTask(proc, drv, command, portSetting);
        }

      } else if (name.elem1 == am_spawn_driver) {
        EDriver drv = ERT.find_driver(command);
        if (drv == null) {
          throw ERT.badarg(portName, portSetting);
        }
        task = new ESpawnDriverTask(proc, drv, command, portSetting);

      } else if (name.elem1 == am_spawn_executable) {
        task = new EExecDriverTask(proc, name, command, portSetting);

      }
    } else if ((name3 = ETuple3.cast(portName)) != null
        && name3.elem1 == am_fd) {

      ESmall in = name3.elem2.testSmall();
      ESmall out = name3.elem3.testSmall();
     
      if (in == null || out == null) throw ERT.badarg(portName, portSetting);
     
      // log.finer("creating fd driver in="+in+"; out="+out);
      task = new EFDDriverTask(proc, in.value, out.value, portSetting);
     
    }

    if (task != null) {
      // link this proc and the driver task
      proc.link_to(task);
      ERT.run(task);

      return task.self_handle();
    }

    throw ERT.badarg(portName, portSetting);
  }

  @BIF
  static public EObject port_close(EProc proc, EObject port) throws Pausable {
    EPort p;
    if ((p = port.testPort()) == null) {

      EObject obj = ERT.whereis(port);

      if (obj == ERT.am_undefined || ((p = obj.testPort()) == null)) {
        throw ERT.badarg(port);
      }
    }

    if (!p.isOpen()) {
      throw ERT.badarg(port);
    }

    proc.unlink(p);

    p.close();

    return ERT.TRUE;
  }

  @BIF
  static public ESeq ports()
  {
    return EDriverTask.all_ports();
  }
 
  @BIF
  static public EObject port_info(EProc proc, EObject a1, EObject a2) {
    EPort p = a1.testPort();
    EAtom spec = a2.testAtom();
    if (p==null || spec==null) throw ERT.badarg();
    EObject info = p.port_info(spec);
    //log.finer(""+proc.self_handle()+"::port_info ("+a1+") => "+info);
    return info;
  }
 
  @BIF
  static public EObject port_set_data(EObject port, EObject data) {
    EPort p = id_or_name2port(port);
    if (p == null) {
      throw ERT.badarg(port, data);
    }

    p.set_data(data);
   
    return data;
  }
 
  @BIF
  static public EObject port_get_data(EObject port) {
    EPort p = id_or_name2port(port);
    if (p == null) {
      throw ERT.badarg(port);
    }
   
    return p.get_data();
  }

  private static EPort id_or_name2port(EObject port) {
    EPort p = port.testPort();
    if (p != null) return p;
     
    EObject p2 = ERT.whereis(port);
   
    // p2 is ERT.am_undefined if not found
   
    return p2.testPort();
  }
 
}
TOP

Related Classes of erjang.m.erlang.ErlPort

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.