/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.ignite.configuration; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.UnknownHostException; import java.util.Collection; import java.util.Collections; import java.util.Map; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.internal.U; /** * Basic implementation of {@link AddressResolver}. * <p> * Allows to provide simple mapping between different address, which is useful * different parts of the cluster are located in different subnetworks and port * forwarding on the router is used for communication between them. Another * common case is Docker environment which can create a pair of public and private * address per container. * <p> * There are two different types of mapping supported by this implementation of * {@link AddressResolver}. * <p> * First type maps specific socket addresses (host and port pairs) are mapped to * each other. This is useful for port forwarding, where multiple nodes will * typically map to the same external address (router), but with different port * numbers. Here is the example: * <pre name="code" class="xml"> * <property name="addressResolver"> * <bean class="org.apache.ignite.configuration.BasicAddressResolver"> * <constructor-arg> * <map> * <entry key="10.0.0.1:47100" value="123.123.123.123:1111"/> * <entry key="10.0.0.2:47100" value="123.123.123.123:2222"/> * <entry key="10.0.0.3:47100" value="123.123.123.123:3333"/> * </map> * </constructor-arg> * </bean> * </property> * </pre> * <p> * Second type maps one host to another. In this case any internal address a node * is bound to will be mapped to the corresponding external host with the same * host number. Here is the example: * <pre name="code" class="xml"> * <property name="addressResolver"> * <bean class="org.apache.ignite.configuration.BasicAddressResolver"> * <constructor-arg> * <map> * <entry key="10.0.0.1" value="123.123.123.123"/> * </map> * </constructor-arg> * </bean> * </property> * </pre> * Here any port on {@code 10.0.0.1} will be mapped to the same port number on {@code 123.123.123.123}. * E.g., {@code 10.0.0.1:47100} will be mapped to {@code 123.123.123.123:47100}, and {@code 10.0.0.1:47500} * will be mapped to {@code 123.123.123.123:47500}. * <p> * Two types of mappings described above can be mixed within one address resolver. */ public class BasicAddressResolver implements AddressResolver { /** Address map. */ private final Map<InetAddress, InetAddress> inetAddrMap; /** Socket address map. */ private final Map<InetSocketAddress, InetSocketAddress> inetSockAddrMap; /** * Created the address resolver. * * @param addrMap Address mappings. * @throws UnknownHostException If any of the hosts can't be resolved. */ public BasicAddressResolver(Map<String, String> addrMap) throws UnknownHostException { if (addrMap == null || addrMap.isEmpty()) throw new IllegalArgumentException("At least one address mapping is required."); inetAddrMap = U.newHashMap(addrMap.size()); inetSockAddrMap = U.newHashMap(addrMap.size()); for (Map.Entry<String, String> e : addrMap.entrySet()) { String from = e.getKey(); String to = e.getValue(); if (F.isEmpty(from) || F.isEmpty(to)) throw new IllegalArgumentException("Invalid address mapping: " + e); String[] fromArr = from.split(":"); String[] toArr = to.split(":"); assert fromArr.length > 0; assert toArr.length > 0; if (fromArr.length == 1) { if (toArr.length != 1) throw new IllegalArgumentException("Invalid address mapping: " + e); inetAddrMap.put(InetAddress.getByName(fromArr[0]), InetAddress.getByName(toArr[0])); } else if (fromArr.length == 2) { if (toArr.length != 2) throw new IllegalArgumentException("Invalid address mapping: " + e); inetSockAddrMap.put(new InetSocketAddress(fromArr[0], Integer.parseInt(fromArr[1])), new InetSocketAddress(toArr[0], Integer.parseInt(toArr[1]))); } else throw new IllegalArgumentException("Invalid address mapping: " + e); } } /** {@inheritDoc} */ @Override public Collection<InetSocketAddress> getExternalAddresses(InetSocketAddress addr) throws IgniteCheckedException { InetSocketAddress inetSockAddr = inetSockAddrMap.get(addr); if (inetSockAddr != null) return Collections.singletonList(inetSockAddr); InetAddress inetAddr = inetAddrMap.get(addr.getAddress()); if (inetAddr != null) return Collections.singletonList(new InetSocketAddress(inetAddr, addr.getPort())); return Collections.emptyList(); } }