/* * %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.IOException; import java.lang.ref.WeakReference; import java.util.Collection; import java.util.Enumeration; import java.util.Hashtable; import java.util.Iterator; /** *
* Represents a local OTP node. This class is used when you do not wish to * manage connections yourself - outgoing connections are established as needed, * and incoming connections accepted automatically. This class supports the use * of a mailbox API for communication, while management of the underlying * communication mechanism is automatic and hidden from the application * programmer. *
* ** Once an instance of this class has been created, obtain one or more mailboxes * in order to send or receive messages. The first message sent to a given node * will cause a connection to be set up to that node. Any messages received will * be delivered to the appropriate mailboxes. *
* ** To shut down the node, call {@link #close close()}. This will prevent the * node from accepting additional connections and it will cause all existing * connections to be closed. Any unread messages in existing mailboxes can still * be read, however no new messages will be delivered to the mailboxes. *
* ** Note that the use of this class requires that Epmd (Erlang Port Mapper * Daemon) is running on each cooperating host. This class does not start Epmd * automatically as Erlang does, you must start it manually or through some * other means. See the Erlang documentation for more information about this. *
*/ public class OtpNode extends OtpLocalNode { private boolean initDone = false; // thread to manage incoming connections private Acceptor acceptor = null; // keep track of all connections Hashtable* Create a node using the default cookie. The default cookie is found by * reading the first line of the .erlang.cookie file in the user's home * directory. The home directory is obtained from the System property * "user.home". *
* ** If the file does not exist, an empty string is used. This method makes no * attempt to create the file. *
* * @param node * the name of this node. * * @exception IOException * if communication could not be initialized. * */ public OtpNode(final String node) throws IOException { super(node); init(0); } /** ** Create a node using the default cookie. The default cookie is found by * reading the first line of the .erlang.cookie file in the user's home * directory. The home directory is obtained from the System property * "user.home". *
* ** If the file does not exist, an empty string is used. This method makes no * attempt to create the file. *
* * @param node * the name of this node. * * @param transportFactory * the transport factory to use when creating connections. * * @exception IOException * if communication could not be initialized. * */ public OtpNode(final String node, final OtpTransportFactory transportFactory) throws IOException { super(node, transportFactory); init(0); } /** * Create a node. * * @param node * the name of this node. * * @param cookie * the authorization cookie that will be used by this node when * it communicates with other nodes. * * @exception IOException * if communication could not be initialized. * */ public OtpNode(final String node, final String cookie) throws IOException { this(node, cookie, 0); } /** * Create a node. * * @param node * the name of this node. * * @param cookie * the authorization cookie that will be used by this node when * it communicates with other nodes. * * @param transportFactory * the transport factory to use when creating connections. * * @exception IOException * if communication could not be initialized. * */ public OtpNode(final String node, final String cookie, final OtpTransportFactory transportFactory) throws IOException { this(node, cookie, 0, transportFactory); } /** * Create a node. * * @param node * the name of this node. * * @param cookie * the authorization cookie that will be used by this node when * it communicates with other nodes. * * @param port * the port number you wish to use for incoming connections. * Specifying 0 lets the system choose an available port. * * @exception IOException * if communication could not be initialized. * */ public OtpNode(final String node, final String cookie, final int port) throws IOException { super(node, cookie); init(port); } /** * Create a node. * * @param node * the name of this node. * * @param cookie * the authorization cookie that will be used by this node when * it communicates with other nodes. * * @param port * the port number you wish to use for incoming connections. * Specifying 0 lets the system choose an available port. * * @param transportFactory * the transport factory to use when creating connections. * * @exception IOException * if communication could not be initialized. * */ public OtpNode(final String node, final String cookie, final int port, final OtpTransportFactory transportFactory) throws IOException { super(node, cookie, transportFactory); init(port); } private synchronized void init(final int aport) throws IOException { if (!initDone) { connections = new Hashtable* After this operation, the mailbox will no longer be able to * receive messages. Any delivered but as yet unretrieved * messages can still be retrieved however. *
* ** If there are links from the mailbox to other * {@link OtpErlangPid pids}, they will be broken when this * method is called and exit signals with reason 'normal' will be * sent. *
* */ public void closeMbox(final OtpMbox mbox) { closeMbox(mbox, new OtpErlangAtom("normal")); } /** * Close the specified mailbox with the given reason. * * @param mbox * the mailbox to close. * @param reason * an Erlang term describing the reason for the termination. * ** After this operation, the mailbox will no longer be able to * receive messages. Any delivered but as yet unretrieved * messages can still be retrieved however. *
* ** If there are links from the mailbox to other * {@link OtpErlangPid pids}, they will be broken when this * method is called and exit signals with the given reason will * be sent. *
* */ public void closeMbox(final OtpMbox mbox, final OtpErlangObject reason) { if (mbox != null) { mboxes.remove(mbox); mbox.name = null; mbox.breakLinks(reason); } } /** * Create an named mailbox that can be used to send and receive messages * with other, similar mailboxes and with Erlang processes. Messages can be * sent to this mailbox by using its registered name or the associated * {@link OtpMbox#self() pid}. * * @param name * a name to register for this mailbox. The name must be unique * within this OtpNode. * * @return a mailbox, or null if the name was already in use. * */ public OtpMbox createMbox(final String name) { return mboxes.create(name); } /** ** Register or remove a name for the given mailbox. Registering a name for a * mailbox enables others to send messages without knowing the * {@link OtpErlangPid pid} of the mailbox. A mailbox can have at most one * name; if the mailbox already had a name, calling this method will * supercede that name. *
* * @param name * the name to register for the mailbox. Specify null to * unregister the existing name from this mailbox. * * @param mbox * the mailbox to associate with the name. * * @return true if the name was available, or false otherwise. */ public boolean registerName(final String name, final OtpMbox mbox) { return mboxes.register(name, mbox); } /** * Get a list of all known registered names on this node. * * @return an array of Strings, containins all known registered names on * this node. */ public String[] getNames() { return mboxes.names(); } /** * Determine the {@link OtpErlangPid pid} corresponding to a registered name * on this node. * * @return the {@link OtpErlangPid pid} corresponding to the registered * name, or null if the name is not known on this node. */ public OtpErlangPid whereis(final String name) { final OtpMbox m = mboxes.get(name); if (m != null) { return m.self(); } return null; } /** * Register interest in certain system events. The {@link OtpNodeStatus * OtpNodeStatus} handler object contains callback methods, that will be * called when certain events occur. * * @param ahandler * the callback object to register. To clear the handler, specify * null as the handler to use. * */ public synchronized void registerStatusHandler(final OtpNodeStatus ahandler) { handler = ahandler; } /** ** Determine if another node is alive. This method has the side effect of * setting up a connection to the remote node (if possible). Only a single * outgoing message is sent; the timeout is how long to wait for a response. *
* ** Only a single attempt is made to connect to the remote node, so for * example it is not possible to specify an extremely long timeout and * expect to be notified when the node eventually comes up. If you wish to * wait for a remote node to be started, the following construction may be * useful: *
* *
* // ping every 2 seconds until positive response
* while (!me.ping(him, 2000))
* ;
*
*
* @param anode
* the name of the node to ping.
*
* @param timeout
* the time, in milliseconds, to wait for response before
* returning false.
*
* @return true if the node was alive and the correct ping response was
* returned. false if the correct response was not returned on time.
*/
/*
* internal info about the message formats...
*
* the request: -> REG_SEND {6,#Pid