Commit c533186d authored by Carlos Galindo's avatar Carlos Galindo
Browse files

jinterface 1.9.1

parent 200903af
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -3,3 +3,10 @@
This project is a copy of Erlang's JInterface library to link Erlang and Java programs,
packaged for Maven in order to use it in other projects.

Available versions:

| JInterface | Erlang versions supported |
|------------|---------------------------|
| 1.9.1      | >=21.1, <22               |

All versions support Java 8 and higher.
+1391 −0

File added.

Preview size limit exceeded, changes collapsed.

+310 −0
Original line number Diff line number Diff line
/*
 * %CopyrightBegin%
 *
 * Copyright Ericsson AB 2000-2016. All Rights Reserved.
 *
 * 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.
 *
 * %CopyrightEnd%
 */
package com.ericsson.otp.erlang;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;

/**
 * <p>
 * Represents an OTP node.
 * </p>
 *
 * <p>
 * About nodenames: Erlang nodenames consist of two components, an alivename and
 * a hostname separated by '@'. Additionally, there are two nodename formats:
 * short and long. Short names are of the form "alive@hostname", while long
 * names are of the form "alive@host.fully.qualified.domainname". Erlang has
 * special requirements regarding the use of the short and long formats, in
 * particular they cannot be mixed freely in a network of communicating nodes,
 * however Jinterface makes no distinction. See the Erlang documentation for
 * more information about nodenames.
 * </p>
 *
 * <p>
 * The constructors for the AbstractNode classes will create names exactly as
 * you provide them as long as the name contains '@'. If the string you provide
 * contains no '@', it will be treated as an alivename and the name of the local
 * host will be appended, resulting in a shortname. Nodenames longer than 255
 * characters will be truncated without warning.
 * </p>
 *
 * <p>
 * Upon initialization, this class attempts to read the file .erlang.cookie in
 * the user's home directory, and uses the trimmed first line of the file as the
 * default cookie by those constructors lacking a cookie argument. If for any
 * reason the file cannot be found or read, the default cookie will be set to
 * the empty string (""). The location of a user's home directory is determined
 * using the system property "user.home", which may not be automatically set on
 * all platforms.
 * </p>
 *
 * <p>
 * Instances of this class cannot be created directly, use one of the subclasses
 * instead.
 * </p>
 */
public class AbstractNode implements OtpTransportFactory {
    static String localHost = null;
    String node;
    String host;
    String alive;
    String cookie;
    static String defaultCookie = null;
    final OtpTransportFactory transportFactory;

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

    // 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 dFlagUnicodeIo = 0x1000;
    static final int dFlagUtf8Atoms = 0x10000;
    static final int dFlagMapTag = 0x20000;
    static final int dFlagBigCreation = 0x40000;

    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 | dFlagUtf8Atoms | dFlagMapTag
	    | dFlagBigCreation;

    /* 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 homeDir = getHomeDir();
        final String dotCookieFilename = homeDir + File.separator
                + ".erlang.cookie";
        BufferedReader br = null;

        try {
            final File dotCookieFile = new File(dotCookieFilename);

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

    protected AbstractNode(final OtpTransportFactory transportFactory) {
        this.transportFactory = transportFactory;
    }

    /**
     * Create a node with the given name and default cookie and transport
     * factory.
     */
    protected AbstractNode(final String node) {
        this(node, defaultCookie, new OtpSocketTransportFactory());
    }

    /**
     * Create a node with the given name, transport factory and the default
     * cookie.
     */
    protected AbstractNode(final String node,
            final OtpTransportFactory transportFactory) {
        this(node, defaultCookie, transportFactory);
    }

    /**
     * Create a node with the given name, cookie and default transport factory.
     */
    protected AbstractNode(final String name, final String cookie) {
        this(name, cookie, new OtpSocketTransportFactory());
    }

    /**
     * Create a node with the given name, cookie and transport factory.
     */
    protected AbstractNode(final String name, final String cookie,
            final OtpTransportFactory transportFactory) {
        this.cookie = cookie;
        this.transportFactory = transportFactory;

        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);
        }

        node = alive + "@" + host;
    }

    /**
     * Get the name of this node.
     *
     * @return the name of the node represented by this object.
     */
    public String 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 String 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 String setCookie(final String cookie) {
        final String prev = this.cookie;
        this.cookie = cookie;
        return prev;
    }

    @Override
    public String toString() {
        return node();
    }

    private static String getHomeDir() {
        final String home = System.getProperty("user.home");
        if (System.getProperty("os.name").toLowerCase().contains("windows")) {
            final String drive = System.getenv("HOMEDRIVE");
            final String path = System.getenv("HOMEPATH");
            return drive != null && path != null ? drive + path : home;
        }
        return home;
    }

    public OtpTransport createTransport(final String addr, final int port)
            throws IOException {
        return transportFactory.createTransport(addr, port);
    }

    public OtpTransport createTransport(final InetAddress addr, final int port)
            throws IOException {
        return transportFactory.createTransport(addr, port);
    }

    public OtpServerTransport createServerTransport(final int port)
            throws IOException {
        return transportFactory.createServerTransport(port);
    }
}
+187 −0
Original line number Diff line number Diff line
/*
 * %CopyrightBegin%
 *
 * Copyright Ericsson AB 2000-2016. All Rights Reserved.
 *
 * 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.
 *
 * %CopyrightEnd%
 */
package com.ericsson.otp.erlang;

/**
 * This class implements a generic FIFO queue. There is no upper bound on the
 * length of the queue, items are linked.
 */

public class GenericQueue {
    private static final int open = 0;
    private static final int closing = 1;
    private static final int closed = 2;

    private int status;
    private Bucket head;
    private Bucket tail;
    private int count;

    private void init() {
        head = null;
        tail = null;
        count = 0;
    }

    /** Create an empty queue */
    public GenericQueue() {
        init();
        status = open;
    }

    /** Clear a queue */
    public void flush() {
        init();
    }

    public void close() {
        status = closing;
    }

    /**
     * Add an object to the tail of the queue.
     *
     * @param o
     *            Object to insert in the queue
     */
    public synchronized void put(final Object o) {
        final Bucket b = new Bucket(o);

        if (tail != null) {
            tail.setNext(b);
            tail = b;
        } else {
            // queue was empty but has one element now
            head = tail = b;
        }
        count++;

        // notify any waiting tasks
        notify();
    }

    /**
     * Retrieve an object from the head of the queue, or block until one
     * arrives.
     *
     * @return The object at the head of the queue.
     */
    public synchronized Object get() {
        Object o = null;

        while ((o = tryGet()) == null) {
            try {
                this.wait();
            } catch (final InterruptedException e) {
            }
        }
        return o;
    }

    /**
     * Retrieve an object from the head of the queue, blocking until one arrives
     * or until timeout occurs.
     *
     * @param timeout
     *            Maximum time to block on queue, in ms. Use 0 to poll the
     *            queue.
     *
     * @exception InterruptedException
     *                if the operation times out.
     *
     * @return The object at the head of the queue, or null if none arrived in
     *         time.
     */
    public synchronized Object get(final long timeout)
            throws InterruptedException {
        if (status == closed) {
            return null;
        }

        long currentTime = System.currentTimeMillis();
        final long stopTime = currentTime + timeout;
        Object o = null;

        while (true) {
            if ((o = tryGet()) != null) {
                return o;
            }

            currentTime = System.currentTimeMillis();
            if (stopTime <= currentTime) {
                throw new InterruptedException("Get operation timed out");
            }

            try {
                this.wait(stopTime - currentTime);
            } catch (final InterruptedException e) {
                // ignore, but really should retry operation instead
            }
        }
    }

    // attempt to retrieve message from queue head
    public Object tryGet() {
        Object o = null;

        if (head != null) {
            o = head.getContents();
            head = head.getNext();
            count--;

            if (head == null) {
                tail = null;
                count = 0;
            }
        }

        return o;
    }

    public synchronized int getCount() {
        return count;
    }

    /*
     * The Bucket class. The queue is implemented as a linked list of Buckets.
     * The container holds the queued object and a reference to the next Bucket.
     */
    class Bucket {
        private Bucket next;
        private final Object contents;

        public Bucket(final Object o) {
            next = null;
            contents = o;
        }

        public void setNext(final Bucket newNext) {
            next = newNext;
        }

        public Bucket getNext() {
            return next;
        }

        public Object getContents() {
            return contents;
        }
    }
}
+59 −0
Original line number Diff line number Diff line
/*
 * %CopyrightBegin%
 *
 * Copyright Ericsson AB 2000-2016. All Rights Reserved.
 *
 * 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.
 *
 * %CopyrightEnd%
 */
package com.ericsson.otp.erlang;

// package scope
class Link {
    private final OtpErlangPid local;
    private final OtpErlangPid remote;
    private int hashCodeValue = 0;

    public Link(final OtpErlangPid local, final OtpErlangPid remote) {
        this.local = local;
        this.remote = remote;
    }

    public OtpErlangPid local() {
        return local;
    }

    public OtpErlangPid remote() {
        return remote;
    }

    public boolean contains(final OtpErlangPid pid) {
        return local.equals(pid) || remote.equals(pid);
    }

    public boolean equals(final OtpErlangPid alocal, final OtpErlangPid aremote) {
        return local.equals(alocal) && remote.equals(aremote)
                || local.equals(aremote) && remote.equals(alocal);
    }

    @Override
    public int hashCode() {
        if (hashCodeValue == 0) {
            final OtpErlangObject.Hash hash = new OtpErlangObject.Hash(5);
            hash.combine(local.hashCode() + remote.hashCode());
            hashCodeValue = hash.valueOf();
        }
        return hashCodeValue;
    }
}
Loading