/*=============================================================================# # Copyright (c) 2009-2016 Stephan Wahlbrink (WalWare.de) and others. # All rights reserved. This program and the accompanying materials # are made available under the terms of either (per the licensee's choosing) # - the Eclipse Public License v1.0 # which accompanies this distribution, and is available at # http://www.eclipse.org/legal/epl-v10.html, or # - the GNU Lesser General Public License v2.1 or newer # which accompanies this distribution, and is available at # http://www.gnu.org/licenses/lgpl.html # # Contributors: # Stephan Wahlbrink - initial API and implementation #=============================================================================*/ package de.walware.rj.server.srvImpl; import java.net.InetAddress; import java.net.MalformedURLException; import java.net.UnknownHostException; import java.rmi.registry.Registry; /** * Address for RMI naming */ class RMIAddress { public static final InetAddress LOOPBACK; public static void validate(final String address) throws MalformedURLException { try { new RMIAddress(address, false); } catch (final UnknownHostException e) { } } private static String checkChars(final String s) throws MalformedURLException { for (int i = 0; i < s.length(); i++) { final char c = s.charAt(i); if (c == '?' || c == '#' || c == '[' || c == ']' || c == '@' || c == '!' || c == '$' || c == '&' || c == '\'' || c == '(' || c == ')' || c == '*' || c == '+' || c == ',' || c == ';' || c == '=' || c == '"' || c == '\\') { throw new MalformedURLException("Character '"+c+"' is not allowed."); } } return s; } private static int checkPort(final String port) throws MalformedURLException { final int portNum; try { portNum = (port != null) ? Integer.parseInt(port) : Registry.REGISTRY_PORT; } catch (final NumberFormatException e) { throw new MalformedURLException("Invalid port, " + e.getMessage()); } return checkPort(portNum); } private static int checkPort(final int portNum) throws MalformedURLException { if (portNum < 0 || portNum > 65535) { throw new MalformedURLException("Invalid port, " + "Value must be in range 0-65535"); } return portNum; } private static String build(final String host, final int portNum, final String name) { final StringBuilder sb = new StringBuilder("//"); //$NON-NLS-1$ if (host != null) { sb.append(host); } sb.append(':'); if (portNum >= 0) { sb.append(Integer.toString(portNum)); } sb.append('/'); if (name != null) { sb.append(name); } return sb.toString(); } static { InetAddress loopbackAddress; try { loopbackAddress = InetAddress.getByAddress("localhost", new byte[] { 127, 0, 0, 1 }); //$NON-NLS-1$ } catch (final UnknownHostException e) { loopbackAddress = null; e.printStackTrace(); } LOOPBACK = loopbackAddress; } private final String host; private InetAddress hostAddress; private final String port; private final int portNum; private final boolean ssl; private final String path; private String address; private String ser; public RMIAddress(final String address) throws UnknownHostException, MalformedURLException { this(address, true); } public RMIAddress(final String host, final int portNum, final String name) throws UnknownHostException, MalformedURLException { this(build(host, portNum, name), true); } public RMIAddress(final InetAddress address, final int port, final String name) throws MalformedURLException { this(address.getHostAddress(), address, Integer.toString(port), checkPort(port), false, (name != null) ? checkChars(name) : ""); } public RMIAddress(final InetAddress address, final int port, final boolean ssl, final String name) throws MalformedURLException { this(address.getHostAddress(), address, Integer.toString(port), checkPort(port), ssl, (name != null) ? checkChars(name) : ""); } public RMIAddress(final RMIAddress registry, final String name) throws MalformedURLException { this(registry.host, registry.hostAddress, registry.port, registry.portNum, registry.ssl, (name != null) ? checkChars(name) : ""); } private RMIAddress(String address, final boolean resolve) throws UnknownHostException, MalformedURLException { address = checkChars(address); if (address.startsWith("ssl:")) { //$NON-NLS-1$ address = address.substring(4); this.ssl = true; } else { this.ssl = false; } if (address.startsWith("rmi:")) { //$NON-NLS-1$ address = address.substring(4); } if (!address.startsWith("//")) { //$NON-NLS-1$ address = "//"+address; //$NON-NLS-1$ } final int idxPort = address.indexOf(':', 2); final int idxPath = address.indexOf('/', 2); if (idxPort > 0) { if (idxPath <= idxPort) { throw new IllegalArgumentException(); } this.host = (2 < idxPort) ? address.substring(2, idxPort) : null; this.port = (idxPort+1 < idxPath) ? address.substring(idxPort+1, idxPath) : null; this.path = address.substring(idxPath+1); } else if (idxPath > 0){ this.host = (2 < idxPath) ? address.substring(2, idxPath) : null; this.port = null; this.path = address.substring(idxPath+1); } else { this.host = null; this.port = null; this.path = address.substring(2); } try { this.portNum = checkPort(this.port); } catch (final NumberFormatException e) { throw new MalformedURLException("Invalid port, " + e.getLocalizedMessage()); } if (resolve) { this.hostAddress = (this.host != null) ? InetAddress.getByName(this.host) : LOOPBACK; } } private RMIAddress(final String host, final InetAddress hostAddress, final String port, final int portNum, final boolean ssl, final String path) { this.host = host; this.hostAddress = hostAddress; this.port = port; this.portNum = portNum; this.ssl = ssl; this.path = path; } /** * @return the host as specified when creating the address */ public String getHost() { return (this.host != null) ? this.host : this.hostAddress.getHostAddress(); } public InetAddress getHostAddress() { return this.hostAddress; } public boolean isLocalHost() { if (this.hostAddress.isLoopbackAddress()) { return true; } try { final InetAddress localhost = InetAddress.getLocalHost(); if (this.hostAddress.equals(localhost)) { return true; } } catch (final UnknownHostException e) {} catch (final ArrayIndexOutOfBoundsException e) { /* JVM bug */ } return false; } /** * @return the port */ public String getPort() { return this.port; } public int getPortNum() { return this.portNum; } /** * @return the name */ public String getName() { return this.path; } /** * Standard string presentation to use for rmi * @return */ public String getAddress() { if (this.address == null) { final StringBuilder sb = new StringBuilder(32); sb.append("rmi://"); //$NON-NLS-1$ if (this.host != null) { sb.append(this.host); } if (this.portNum != Registry.REGISTRY_PORT) { sb.append(':'); sb.append(this.port); } sb.append('/'); sb.append(this.path); this.address = sb.toString(); } return this.address; } public RMIAddress getRegistryAddress() { return new RMIAddress(this.host, this.hostAddress, this.port, this.portNum, this.ssl, ""); } /** * * @return if SSL is enabled * * @since 1.4 */ public boolean isSSL() { return this.ssl; } @Override public String toString() { if (this.ser == null) { final String address = getAddress(); if (this.ssl) { this.ser = "ssl:" + address; } else { this.ser = address; } } return this.ser; } @Override public int hashCode() { return toString().hashCode(); } @Override public boolean equals(final Object obj) { if (!(obj instanceof RMIAddress)) { return false; } final RMIAddress other = (RMIAddress) obj; return (this.hostAddress.equals(other.hostAddress) && this.portNum == other.portNum && this.ssl == other.ssl && this.path.equals(other.path) ); } }