Package erjang

Source Code of erjang.EAbstractNode

/**
* 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;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

import erjang.m.erlang.ErlDist;

import kilim.Pausable;


/**
*
*/
public abstract class EAbstractNode {

    /**
   *
   */
  public static final EAtom am_nonode_at_nohost = EAtom.intern("nonode@nohost");
  public static final EAtom am_nodedown = EAtom.intern("nodedown");
  public static final EAtom am_nodeup   = EAtom.intern("nodeup");
  public static final EAtom am_nodedown_reason = EAtom.intern("nodedown_reason");
  public static final EAtom am_node_type = EAtom.intern("node_type");
  public static final EAtom am_visible   = EAtom.intern("visible");
  public static final EAtom am_hidden    = EAtom.intern("hidden");
  public static final EAtom am_all       = EAtom.intern("all");

  static String localHost = null;
    EAtom node = am_nonode_at_nohost;
    String host;
    String alive;
    EAtom cookie;
    static EAtom defaultCookie = null;

    // Node types
    static final int NTYPE_R6 = 110; // 'n' post-r5, all nodes
    static final int NTYPE_R4_ERLANG = 109; // 'm' Only for source compatibility
    static final int NTYPE_R4_HIDDEN = 104; // 'h' Only for source compatibility


  public static final int ERTS_NODES_MON_OPT_TYPE_VISIBLE = 1<<0;
  public static final int ERTS_NODES_MON_OPT_TYPE_HIDDEN = 1<<1;
  public static final int ERTS_NODES_MON_OPT_DOWN_REASON = 1<<2;

  public static final int ERTS_NODES_MON_OPT_TYPES =
      ERTS_NODES_MON_OPT_TYPE_VISIBLE | ERTS_NODES_MON_OPT_TYPE_HIDDEN;

    // Node capability flags
    static final int dFlagPublished = 1;
    static final int dFlagAtomCache = 2;
    static final int dFlagExtendedReferences = 4;
    static final int dFlagDistMonitor = 8;
    static final int dFlagFunTags = 0x10;
    static final int dFlagDistMonitorName = 0x20; // NOT USED
    static final int dFlagHiddenAtomCache = 0x40; // NOT SUPPORTED
    static final int dflagNewFunTags = 0x80;
    static final int dFlagExtendedPidsPorts = 0x100;
    static final int dFlagExportPtrTag = 0x200; // NOT SUPPORTED
    static final int dFlagBitBinaries = 0x400;
    static final int dFlagNewFloats = 0x800;

    static final int dFUnicodeIO = 0x1000;
    static final int dFDistHdrAtomCache = 0x2000;
    static final int dFlagSmallAtoms = 0x4000;

    int ntype = NTYPE_R6;
    int proto = 0; // tcp/ip
    int distHigh = 5; // Cannot talk to nodes before R6
    int distLow = 5; // Cannot talk to nodes before R6
    int creation = 0;
    int flags = dFlagExtendedReferences | dFlagExtendedPidsPorts
            | dFlagBitBinaries | dFlagNewFloats | dFlagFunTags
            | dflagNewFunTags;

   
    /* initialize hostname and default cookie */
    static {
        try {
            localHost = InetAddress.getLocalHost().getHostName();
            /*
             * Make sure it's a short name, i.e. strip of everything after first
             * '.'
             */
            final int dot = localHost.indexOf(".");
            if (dot != -1) {
                localHost = localHost.substring(0, dot);
            }
        } catch (final UnknownHostException e) {
            localHost = "localhost";
        }

        final String dotCookieFilename = System.getProperty("user.home")
                + File.separator + ".erlang.cookie";
        BufferedReader br = null;

        try {
            final File dotCookieFile = ERT.newFile(dotCookieFilename);

            br = new BufferedReader(new FileReader(dotCookieFile));
            defaultCookie = EAtom.intern( br.readLine().trim() );
        } catch (final IOException e) {
            defaultCookie = EAtom.intern("");
        } finally {
            try {
                if (br != null) {
                    br.close();
                }
            } catch (final IOException e) {
            }
        }
    }

 
  /**
   * @param node
   */
  public EAbstractNode(EAtom node) {
    this(node, defaultCookie);
  }

  /**
   *
   */
  public EAbstractNode() {
    this(am_nonode_at_nohost);
  }

  /**
   * @param node
   * @param cookie
   */
  public EAbstractNode(EAtom node, EAtom cookie) {

        this.cookie = cookie;
        set(node, 0);
 
  }
 
  public void set(EAtom node, int cr) {
 

        String name = node.getName();

        final int i = name.indexOf('@', 0);
        if (i < 0) {
            alive = name;
            host = localHost;
        } else {
            alive = name.substring(0, i);
            host = name.substring(i + 1, name.length());
        }

        if (alive.length() > 0xff) {
            alive = alive.substring(0, 0xff);
        }

        this.node = EAtom.intern( alive + "@" + host );

        this.creation = cr;
   
  }


 
    /**
     * Get the name of this node.
     *
     * @return the name of the node represented by this object.
     */
    public EAtom node() {
        return node;
    }

    /**
     * Get the hostname part of the nodename. Nodenames are composed of two
     * parts, an alivename and a hostname, separated by '@'. This method returns
     * the part of the nodename following the '@'.
     *
     * @return the hostname component of the nodename.
     */
    public String host() {
        return host;
    }

    /**
     * Get the alivename part of the hostname. Nodenames are composed of two
     * parts, an alivename and a hostname, separated by '@'. This method returns
     * the part of the nodename preceding the '@'.
     *
     * @return the alivename component of the nodename.
     */
    public String alive() {
        return alive;
    }

    /**
     * Get the authorization cookie used by this node.
     *
     * @return the authorization cookie used by this node.
     */
    public EAtom cookie() {
        return cookie;
    }

    // package scope
    int type() {
        return ntype;
    }

    // package scope
    int distHigh() {
        return distHigh;
    }

    // package scope
    int distLow() {
        return distLow;
    }

    // package scope: useless information?
    int proto() {
        return proto;
    }

    // package scope
    int creation() {
        return creation;
    }

    /**
     * Set the authorization cookie used by this node.
     *
     * @return the previous authorization cookie used by this node.
     */
    public EAtom setCookie(final EAtom cookie) {
        final EAtom prev = this.cookie;
        this.cookie = cookie;
        return prev;
    }


  /*==================== Monitoring of a specific node ====================*/
  ConcurrentHashMap<EHandle,AtomicInteger> node_monitors = new ConcurrentHashMap<EHandle,AtomicInteger>();

  public void monitor_node(EHandle caller, boolean on) {
    node_monitors.putIfAbsent(caller, new AtomicInteger());
    AtomicInteger ami = node_monitors.get(caller);
    if (on) {
      ami.incrementAndGet();
    } else {
      ami.decrementAndGet();
    }
  }

  /*==================== Monitoring of node changes in general ==========*/

  static ConcurrentHashMap<EHandle,ConcurrentHashMap<Integer,AtomicInteger> > nodes_monitors = new ConcurrentHashMap();
 

  /** @return whether monitoring was already active for the given opts_list,
   *          or null if the opts_list was invalid.
   */
  public static Boolean monitor_nodes(EHandle caller, boolean on, ESeq opts_list) {
    boolean all = false, visible = false, hidden = false;
    int opts = 0;
   
    for (; !opts_list.isNil(); opts_list = opts_list.tail()) {
      EObject opt = opts_list.head();

      ETuple2 tp;
      if (opt == am_nodedown_reason) {
        opts |= ERTS_NODES_MON_OPT_DOWN_REASON;
      } else if ((tp = ETuple2.cast(opt)) != null) {
        if (tp.elem1 == am_node_type) {
   
          if (tp.elem2 == am_visible) {
   
            if (hidden || all) return null;
            opts |= ERTS_NODES_MON_OPT_TYPE_VISIBLE;
            visible = true;
           
          } else if (tp.elem2 == am_hidden) {
            if (visible || all) return null;
            opts |= ERTS_NODES_MON_OPT_TYPE_HIDDEN;
            hidden = true;
           
          } else if (tp.elem2 == am_all) {
            if (visible || hidden) return null;
            opts |= ERTS_NODES_MON_OPT_TYPES;
          } else {
            return null;
          }
         
        } else {
          return null;
        }
       
      } else {
        return null;
      }
     
    }

    return Boolean.valueOf(monitor_nodes(caller, on, opts));
  }

  public static boolean monitor_nodes(EHandle caller, boolean on, int opts) {
    if (on) nodes_monitors.putIfAbsent(caller, new ConcurrentHashMap());
    ConcurrentHashMap<Integer,AtomicInteger> forHandle = nodes_monitors.get(caller);
    if (forHandle==null) return false; // We're disabling but entry wasn't there.

    if (on) {
      forHandle.putIfAbsent(opts, new AtomicInteger(0));
      AtomicInteger ami = forHandle.get(opts);
      if (ami==null) return false; // We're disabling but entry wasn't there.
       int old = ami.getAndIncrement();
      return old > 0;
    } else {
      AtomicInteger old = forHandle.remove(opts);
      return old != null && old.get() > 0;
    }
  }

  /** network driver exited!
   * @throws Pausable */
  public void node_going_down(EHandle sender, EObject reason) throws Pausable {
   
    for (Map.Entry<EHandle,AtomicInteger> ent : node_monitors.entrySet()) {
      EHandle handle = ent.getKey();
      AtomicInteger howmany = ent.getValue();
     
      ETuple nd = ETuple.make(am_nodedown, this.node());
      while (howmany.decrementAndGet() >= 0) {     
        handle.send(sender, nd);
      }
    }
   
    node_monitors.clear();
   
  }

  public void node_up(EHandle sender, EObject reason) throws Pausable {
    // TODO: Send only to those which subscribe to the kind of node in question (visible/hidden).
    for (Map.Entry<EHandle,ConcurrentHashMap<Integer,AtomicInteger> > ent : nodes_monitors.entrySet()) {
      EHandle handle = ent.getKey();
      ConcurrentHashMap<Integer,AtomicInteger> submap = ent.getValue();
      // TODO: Add exit hook under the right circumstances.

      for (Map.Entry<Integer,AtomicInteger> subent : submap.entrySet()) {
        int opts = subent.getKey().intValue();
        int howmany = subent.getValue().get();

        final ETuple msg;
        if (opts == 0) {
          msg = ETuple.make(am_nodeup, this.node());
        } else {
          /* TODO: Respect opts.
           * (1) Don't send if opts and type don't agree
           * (2) Add to the property list in the third element:
           * optionally with {'node_type', Type},
           * optionally with {'nodedown_reason', Reason}.
           */
          ECons info = ERT.NIL;
          // TODO: construct correct info value
          msg = ETuple.make(am_nodeup, this.node(), info);
        }
        for (int i=0; i < howmany; i++) {
          handle.send(sender, msg);
        }
      }
    }
  }

  public abstract EObject dsig_reg_send(EInternalPID caller, EAtom name,
      EObject msg) throws Pausable;

  public abstract void dsig_demonitor(EHandle sender, ERef ref,
      EObject to_pid_or_name) throws Pausable;

 
 
  public static EAbstractNode get_or_connect(ETask<?> proc, EAtom n) throws Pausable {
    EAbstractNode res = EPeer.get(n);
    if (res == null && (proc instanceof EProc)) {     
      if (ErlDist.net_kernel__connect__1.invoke((EProc) proc, new EObject[] { n }) == ERT.TRUE) {
        return EPeer.get(n);
      }
    }
    return res;
  }
}
TOP

Related Classes of erjang.EAbstractNode

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.