/* * Copyright 2015 Odnoklassniki Ltd, Mail.Ru Group * * 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 one.nio.net; import java.io.IOException; import java.net.Inet4Address; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.NetworkInterface; import java.net.SocketException; import java.nio.channels.DatagramChannel; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import java.util.StringTokenizer; import java.util.regex.Matcher; import java.util.regex.Pattern; public class ConnectionString { private static final Pattern INTERFACE_PATTERN = Pattern.compile("\\{(.+)\\}"); protected String protocol; protected String host; protected String path; protected int port; protected Map<String, String> params; protected ConnectionString() { } public ConnectionString(String connectionString) { connectionString = expand(connectionString); int p = connectionString.indexOf("//"); if (p > 1) { this.protocol = connectionString.substring(0, p - 1); } int addrStart = p >= 0 ? p + 2 : 0; int queryString = connectionString.indexOf('?', addrStart); if (queryString >= 0) { this.params = parseParameters(connectionString.substring(queryString + 1)); } else { queryString = connectionString.length(); this.params = Collections.emptyMap(); } p = connectionString.indexOf('/', addrStart); int addrEnd = p >= 0 && p < queryString ? p : queryString; p = connectionString.lastIndexOf(':', addrEnd); if (p >= addrStart && p < addrEnd) { this.host = connectionString.substring(addrStart, p); this.port = Integer.parseInt(connectionString.substring(p + 1, addrEnd)); } else { this.host = connectionString.substring(addrStart, addrEnd); this.port = 0; } this.path = connectionString.substring(addrEnd); } public String getProtocol() { return protocol; } public String getHost() { return host; } public int getPort() { return port; } public String getPath() { return path; } public String[] getHosts() { return host.indexOf('|') >= 0 ? host.split("\\|") : new String[] { host }; } public String getStringParam(String key) { return params.get(key); } public String getStringParam(String key, String defaultValue) { String result = params.get(key); return result != null ? result : defaultValue; } public int getIntParam(String key, int defaultValue) { String result = params.get(key); return result != null ? Integer.parseInt(result) : defaultValue; } public long getLongParam(String key, long defaultValue) { String result = params.get(key); return result != null ? Long.parseLong(result) : defaultValue; } public boolean getBooleanParam(String key, boolean defaultValue) { String result = params.get(key); return result != null ? result.equalsIgnoreCase("true") : defaultValue; } public static String expand(String url) { Matcher matcher = INTERFACE_PATTERN.matcher(url); if (!matcher.find()) { return url; } StringBuilder sb = new StringBuilder(url.length() + 32); int lastPosition = 0; do { String interfaceAddress; String interfaceName = matcher.group(1); if (interfaceName.startsWith("auto:")) { interfaceAddress = getRoutingAddress(interfaceName.substring(5)); } else { interfaceAddress = getInterfaceAddress(interfaceName); } if (interfaceAddress != null) { sb.append(url, lastPosition, matcher.start()).append(interfaceAddress); } else { sb.append(url, lastPosition, matcher.end()); } lastPosition = matcher.end(); } while (matcher.find(lastPosition)); return sb.append(url, lastPosition, url.length()).toString(); } public static String getRoutingAddress(String targetIP) { try { DatagramChannel ch = DatagramChannel.open(); try { ch.connect(new InetSocketAddress(targetIP, 7)); return ch.socket().getLocalAddress().getHostAddress(); } finally { ch.close(); } } catch (IOException e) { throw new IllegalArgumentException(e); } } public static String getInterfaceAddress(String interfaceName) { try { NetworkInterface intf = NetworkInterface.getByName(interfaceName); if (intf == null) { return null; } Enumeration<InetAddress> addrs = intf.getInetAddresses(); if (!addrs.hasMoreElements()) { return null; } InetAddress result = addrs.nextElement(); while (!(result instanceof Inet4Address) && addrs.hasMoreElements()) { result = addrs.nextElement(); } return result.getHostAddress(); } catch (SocketException e) { throw new IllegalArgumentException(e); } } private static Map<String, String> parseParameters(String parameters) { HashMap<String, String> result = new HashMap<String, String>(); for (StringTokenizer tokenizer = new StringTokenizer(parameters, "&"); tokenizer.hasMoreElements(); ) { String param = tokenizer.nextToken(); int p = param.indexOf('='); if (p > 0) { result.put(param.substring(0, p), param.substring(p + 1)); } } return result; } }