From fd76d49c7d7bbed4775818390e47b958ee50f469 Mon Sep 17 00:00:00 2001
From: Dmitriy Kargapolov
@@ -78,8 +77,8 @@ public class OtpCookedConnection extends AbstractConnection { * error */ // package scope - OtpCookedConnection(final OtpNode self, final Socket s) throws IOException, - OtpAuthException { + OtpCookedConnection(final OtpNode self, final OtpTransport s) + throws IOException, OtpAuthException { super(self, s); this.self = self; links = new Links(25); diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpEpmd.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpEpmd.java index 796babee1b..6c7c8fe951 100644 --- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpEpmd.java +++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpEpmd.java @@ -21,13 +21,12 @@ package com.ericsson.otp.erlang; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.net.InetAddress; -import java.net.Socket; /** * Provides methods for registering, unregistering and looking up nodes with the * Erlang portmapper daemon (Epmd). For each registered node, Epmd maintains * information about the port on which incoming connections are accepted, as - * well as which versions of the Erlang communication protocolt the node + * well as which versions of the Erlang communication protocol the node * supports. * *
@@ -136,7 +135,7 @@ public class OtpEpmd { */ public static boolean publishPort(final OtpLocalNode node) throws IOException { - Socket s = null; + OtpTransport s = null; s = r4_publish(node); @@ -156,16 +155,16 @@ public class OtpEpmd { * This method does not report any failures. */ public static void unPublishPort(final OtpLocalNode node) { - Socket s = null; + OtpTransport s = null; try { - s = new Socket((String) null, EpmdPort.get()); + s = node.createTransport((String) null, EpmdPort.get()); @SuppressWarnings("resource") final OtpOutputStream obuf = new OtpOutputStream(); obuf.write2BE(node.alive().length() + 1); obuf.write1(stopReq); obuf.writeN(node.alive().getBytes()); - obuf.writeTo(s.getOutputStream()); + obuf.writeToAndFlush(s.getOutputStream()); // don't even wait for a response (is there one?) if (traceLevel >= traceThreshold) { System.out.println("-> UNPUBLISH " + node + " port=" @@ -187,12 +186,12 @@ public class OtpEpmd { private static int r4_lookupPort(final AbstractNode node) throws IOException { int port = 0; - Socket s = null; + OtpTransport s = null; try { @SuppressWarnings("resource") final OtpOutputStream obuf = new OtpOutputStream(); - s = new Socket(node.host(), EpmdPort.get()); + s = node.createTransport(node.host(), EpmdPort.get()); // build and send epmd request // length[2], tag[1], alivename[n] (length = n+1) @@ -201,7 +200,7 @@ public class OtpEpmd { obuf.writeN(node.alive().getBytes()); // send request - obuf.writeTo(s.getOutputStream()); + obuf.writeToAndFlush(s.getOutputStream()); if (traceLevel >= traceThreshold) { System.out.println("-> LOOKUP (r4) " + node); @@ -242,7 +241,7 @@ public class OtpEpmd { System.out.println("<- (no response)"); } throw new IOException("Nameserver not responding on " + node.host() - + " when looking up " + node.alive()); + + " when looking up " + node.alive(), e); } catch (final OtpErlangDecodeException e) { if (traceLevel >= traceThreshold) { System.out.println("<- (invalid response)"); @@ -276,14 +275,14 @@ public class OtpEpmd { * fatal. If we manage to successfully communicate with an r4 epmd, we * return either the socket, or null, depending on the result. */ - private static Socket r4_publish(final OtpLocalNode node) + private static OtpTransport r4_publish(final OtpLocalNode node) throws IOException { - Socket s = null; + OtpTransport s = null; try { @SuppressWarnings("resource") final OtpOutputStream obuf = new OtpOutputStream(); - s = new Socket((String) null, EpmdPort.get()); + s = node.createTransport((String) null, EpmdPort.get()); obuf.write2BE(node.alive().length() + 13); @@ -301,7 +300,7 @@ public class OtpEpmd { obuf.write2BE(0); // No extra // send request - obuf.writeTo(s.getOutputStream()); + obuf.writeToAndFlush(s.getOutputStream()); if (traceLevel >= traceThreshold) { System.out.println("-> PUBLISH (r4) " + node + " port=" @@ -356,23 +355,34 @@ public class OtpEpmd { } public static String[] lookupNames() throws IOException { - return lookupNames(InetAddress.getByName(null)); + return lookupNames(InetAddress.getByName(null), + new OtpSocketTransportFactory()); + } + + public static String[] lookupNames( + final OtpTransportFactory transportFactory) throws IOException { + return lookupNames(InetAddress.getByName(null), transportFactory); } public static String[] lookupNames(final InetAddress address) throws IOException { - Socket s = null; + return lookupNames(address, new OtpSocketTransportFactory()); + } + + public static String[] lookupNames(final InetAddress address, + final OtpTransportFactory transportFactory) throws IOException { + OtpTransport s = null; try { @SuppressWarnings("resource") final OtpOutputStream obuf = new OtpOutputStream(); try { - s = new Socket(address, EpmdPort.get()); + s = transportFactory.createTransport(address, EpmdPort.get()); obuf.write2BE(1); obuf.write1(names4req); // send request - obuf.writeTo(s.getOutputStream()); + obuf.writeToAndFlush(s.getOutputStream()); if (traceLevel >= traceThreshold) { System.out.println("-> NAMES (r4) "); diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpLocalNode.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpLocalNode.java index b996ba6f6c..dd1d299297 100644 --- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpLocalNode.java +++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpLocalNode.java @@ -29,12 +29,7 @@ public class OtpLocalNode extends AbstractNode { private int refId[]; protected int port; - protected java.net.Socket epmd; - - protected OtpLocalNode() { - super(); - init(); - } + protected OtpTransport epmd; /** * Create a node with the given name and the default cookie. @@ -44,6 +39,16 @@ public class OtpLocalNode extends AbstractNode { init(); } + /** + * Create a node with the given name, transport factory and the default + * cookie. + */ + protected OtpLocalNode(final String node, + final OtpTransportFactory transportFactory) { + super(node, transportFactory); + init(); + } + /** * Create a node with the given name and cookie. */ @@ -52,6 +57,15 @@ public class OtpLocalNode extends AbstractNode { init(); } + /** + * Create a node with the given name, cookie and transport factory. + */ + protected OtpLocalNode(final String node, final String cookie, + final OtpTransportFactory transportFactory) { + super(node, cookie, transportFactory); + init(); + } + private void init() { serial = 0; pidCount = 1; @@ -77,7 +91,7 @@ public class OtpLocalNode extends AbstractNode { * @param s * The socket connecting this node to Epmd. */ - protected void setEpmd(final java.net.Socket s) { + protected void setEpmd(final OtpTransport s) { epmd = s; } @@ -86,7 +100,7 @@ public class OtpLocalNode extends AbstractNode { * * @return The socket connecting this node to Epmd. */ - protected java.net.Socket getEpmd() { + protected OtpTransport getEpmd() { return epmd; } diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpNode.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpNode.java index d5edd135cf..7512d34c21 100644 --- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpNode.java +++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpNode.java @@ -20,8 +20,6 @@ package com.ericsson.otp.erlang; import java.io.IOException; import java.lang.ref.WeakReference; -import java.net.ServerSocket; -import java.net.Socket; import java.util.Collection; import java.util.Enumeration; import java.util.Hashtable; @@ -97,7 +95,39 @@ public class OtpNode extends OtpLocalNode { * */ public OtpNode(final String node) throws IOException { - this(node, defaultCookie, 0); + 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); } /** @@ -118,6 +148,28 @@ public class OtpNode extends OtpLocalNode { 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. * @@ -143,6 +195,34 @@ public class OtpNode extends OtpLocalNode { 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+ * Create a self node using the default cookie and custom transport factory. + * 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 + * in case of server transport failure + * + */ + public OtpSelf(final String node, + final OtpTransportFactory transportFactory) throws IOException { + this(node, defaultCookie, 0, transportFactory); + } + /** * Create a self node. * @@ -81,16 +110,95 @@ public class OtpSelf extends OtpLocalNode { * @param cookie * the authorization cookie that will be used by this node when * it communicates with other nodes. + * + * @exception IOException + * in case of server transport failure */ public OtpSelf(final String node, final String cookie) throws IOException { this(node, cookie, 0); } + /** + * Create a self 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 + * in case of server transport failure + */ + public OtpSelf(final String node, final String cookie, + final OtpTransportFactory transportFactory) throws IOException { + this(node, cookie, 0, transportFactory); + } + + /** + * Create a self 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 + * in case of server transport failure + */ public OtpSelf(final String node, final String cookie, final int port) throws IOException { super(node, cookie); - sock = new ServerSocket(port); + sock = createServerTransport(port); + + if (port != 0) { + this.port = port; + } else { + this.port = sock.getLocalPort(); + } + + pid = createPid(); + } + + /** + * Create a self 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 + * in case of server transport failure + */ + public OtpSelf(final String node, final String cookie, final int port, + final OtpTransportFactory transportFactory) throws IOException { + super(node, cookie, transportFactory); + + sock = createServerTransport(port); if (port != 0) { this.port = port; @@ -179,7 +287,7 @@ public class OtpSelf extends OtpLocalNode { * authorized to connect. */ public OtpConnection accept() throws IOException, OtpAuthException { - Socket newsock = null; + OtpTransport newsock = null; while (true) { try { diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpServerSocketTransport.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpServerSocketTransport.java new file mode 100644 index 0000000000..0e25b6bfb7 --- /dev/null +++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpServerSocketTransport.java @@ -0,0 +1,68 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2015. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +package com.ericsson.otp.erlang; + +import java.io.IOException; +import java.net.ServerSocket; +import java.net.Socket; + +/** + * Default socket-based server transport + * + * @author Dmitriy Kargapolov + */ +public class OtpServerSocketTransport implements OtpServerTransport { + + /** + * Underlying server socket + */ + private final ServerSocket socket; + + /** + * @see ServerSocket#ServerSocket(int) + */ + public OtpServerSocketTransport(final int port) throws IOException { + socket = new ServerSocket(port); + } + + /** + * @see ServerSocket#getLocalPort() + */ + public int getLocalPort() { + return socket.getLocalPort(); + } + + /** + * @see ServerSocket#accept() + */ + public OtpTransport accept() throws IOException { + final Socket sock = socket.accept(); + sock.setTcpNoDelay(true); + return new OtpSocketTransport(sock); + } + + /** + * @see ServerSocket#close() + */ + public void close() throws IOException { + socket.close(); + } + +} diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpServerTransport.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpServerTransport.java new file mode 100644 index 0000000000..4d31380bee --- /dev/null +++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpServerTransport.java @@ -0,0 +1,46 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2015. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +package com.ericsson.otp.erlang; + +import java.io.IOException; +import java.net.ServerSocket; + +/** + * Server-side connection-oriented transport interface. + * + * @author Dmitriy Kargapolov + */ +public interface OtpServerTransport { + + /** + * @see ServerSocket#getLocalPort() + */ + int getLocalPort(); + + /** + * @see ServerSocket#accept() + */ + OtpTransport accept() throws IOException; + + /** + * @see ServerSocket#close() + */ + void close() throws IOException; +} diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpSocketTransport.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpSocketTransport.java new file mode 100644 index 0000000000..f690ab59ed --- /dev/null +++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpSocketTransport.java @@ -0,0 +1,89 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2015. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +package com.ericsson.otp.erlang; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.Socket; +import java.net.UnknownHostException; + +/** + * Default socket-based client transport + * + * @author Dmitriy Kargapolov + */ +public class OtpSocketTransport implements OtpTransport { + + /** + * Underlying socket + */ + private final Socket socket; + + /** + * @see Socket#Socket(String, int) + */ + public OtpSocketTransport(final String addr, final int port) + throws UnknownHostException, IOException { + socket = new Socket(addr, port); + socket.setTcpNoDelay(true); + } + + /** + * @see Socket#Socket(InetAddress, int) + */ + public OtpSocketTransport(final InetAddress addr, final int port) + throws UnknownHostException, IOException { + socket = new Socket(addr, port); + socket.setTcpNoDelay(true); + } + + /** + * Socket wrapping constructor + * + * @param s + * socket to wrap + */ + public OtpSocketTransport(final Socket s) { + socket = s; + } + + /** + * @see Socket#getInputStream() + */ + public InputStream getInputStream() throws IOException { + return socket.getInputStream(); + } + + /** + * @see Socket#getOutputStream() + */ + public OutputStream getOutputStream() throws IOException { + return socket.getOutputStream(); + } + + /** + * @see Socket#close() + */ + public void close() throws IOException { + socket.close(); + } +} diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpSocketTransportFactory.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpSocketTransportFactory.java new file mode 100644 index 0000000000..f6b5bfc86d --- /dev/null +++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpSocketTransportFactory.java @@ -0,0 +1,56 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2015. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +package com.ericsson.otp.erlang; + +import java.io.IOException; +import java.net.InetAddress; + +/** + * Default socket-based transport factory + * + * @author Dmitriy Kargapolov + */ +public class OtpSocketTransportFactory implements OtpTransportFactory { + + /** + * @see OtpTransportFactory#createTransport(String, int) + */ + public OtpTransport createTransport(final String addr, final int port) + throws IOException { + return new OtpSocketTransport(addr, port); + } + + /** + * @see OtpTransportFactory#createTransport(InetAddress, int) + */ + public OtpTransport createTransport(final InetAddress addr, final int port) + throws IOException { + return new OtpSocketTransport(addr, port); + } + + /** + * @see OtpTransportFactory#createServerTransport(int) + */ + public OtpServerTransport createServerTransport(final int port) + throws IOException { + return new OtpServerSocketTransport(port); + } + +} diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpTransport.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpTransport.java new file mode 100644 index 0000000000..51c62d9ef0 --- /dev/null +++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpTransport.java @@ -0,0 +1,49 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2015. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +package com.ericsson.otp.erlang; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Socket; + +/** + * Client-side connection-oriented transport interface. + * + * @author Dmitriy Kargapolov + */ +public interface OtpTransport { + + /** + * @see Socket#getInputStream() + */ + public abstract InputStream getInputStream() throws IOException; + + /** + * @see Socket#getOutputStream() + */ + public abstract OutputStream getOutputStream() throws IOException; + + /** + * @see Socket#close() + */ + public abstract void close() throws IOException; + +} diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpTransportFactory.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpTransportFactory.java new file mode 100644 index 0000000000..bd404daea5 --- /dev/null +++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpTransportFactory.java @@ -0,0 +1,124 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2015. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +package com.ericsson.otp.erlang; + +import java.io.IOException; +import java.net.InetAddress; + +/** + * Factory class used to create client- and server-side transport instances. One + * static instance of class implementing this interface is created when program + * loaded. Default implementation used is {@link OtpSocketTransportFactory}. + * JInterface user can specify custom transport factory implementing this + * interface in the following ways: + *System.getProperty("sun.java.command")
, user can define static
+ * class OtpErlangSystemTuner internal to the main class, providing at
+ * least one static method with the name getOtpTransportFactory, with no
+ * parameters, returning object of class implementing
+ * OtpTransportFactory, for example:
+ *
+ * + * + * public class MyMainClass { + * + * public static class OtpErlangSystemTuner { + * ... + * public static OtpTransportFactory getOtpTransportFactory() { + * return new MyTransportFactory(); + * } + * } + * + * public static class MyTransportFactory implements OtpTransportFactory { + * ... + * } + * + * public static void main(String[] args) { + * ... + * } + * } + * + * + *+ * + *
+ * + * package com.my.company; + * + * public static class MyTransportFactory implements OtpTransportFactory { + * ... + * } + *+ * + * In such case program may be run with + * -DOtpTransportFactory=com.my.company.MyTransportFactory, or other way of + * setting system property before execution of static initializers may be + * used.