HostsManager.java
/*
** Module : HostsManager.java
** Abstract : Defines common methods to add host and to get port name.
**
** Copyright (c) 2020-2024, Golden Code Development Corporation.
**
** -#- -I- --Date-- ---------------------------------Description----------------------------------
** 001 SBI 20200317 Added common methods addHost and getPortName.
** 002 SBI 20230509 Added hosts resources map, fixed addHost.
** 003 SBI 20240501 Added loopback address entry to hosts map with its localhost entry, fixed
** entry key to be the host address.
** 004 GBB 20240709 WebClientConfig renamed to WebAllocatedResources.
*/
/*
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Affero General Public License as
** published by the Free Software Foundation, either version 3 of the
** License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Affero General Public License for more details.
**
** You may find a copy of the GNU Affero GPL version 3 at the following
** location: https://www.gnu.org/licenses/agpl-3.0.en.html
**
** Additional terms under GNU Affero GPL version 3 section 7:
**
** Under Section 7 of the GNU Affero GPL version 3, the following additional
** terms apply to the works covered under the License. These additional terms
** are non-permissive additional terms allowed under Section 7 of the GNU
** Affero GPL version 3 and may not be removed by you.
**
** 0. Attribution Requirement.
**
** You must preserve all legal notices or author attributions in the covered
** work or Appropriate Legal Notices displayed by works containing the covered
** work. You may not remove from the covered work any author or developer
** credit already included within the covered work.
**
** 1. No License To Use Trademarks.
**
** This license does not grant any license or rights to use the trademarks
** Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
** of Golden Code Development Corporation. You are not authorized to use the
** name Golden Code, FWD, or the names of any author or contributor, for
** publicity purposes without written authorization.
**
** 2. No Misrepresentation of Affiliation.
**
** You may not represent yourself as Golden Code Development Corporation or FWD.
**
** You may not represent yourself for publicity purposes as associated with
** Golden Code Development Corporation, FWD, or any author or contributor to
** the covered work, without written authorization.
**
** 3. No Misrepresentation of Source or Origin.
**
** You may not represent the covered work as solely your work. All modified
** versions of the covered work must be marked in a reasonable way to make it
** clear that the modified work is not originating from Golden Code Development
** Corporation or FWD. All modified versions must contain the notices of
** attribution required in this license.
*/
package com.goldencode.p2j.main;
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.Map.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
/**
* The host manager defines methods to add host and to get port name.
*/
public class HostsManager
{
/** The path to the hosts file */
private static final String HOSTS_FILE_PATH = "./hosts.txt";
/** The host manager instance */
private static HostsManager instance;
/** Dynamic hosts map of registered brokers agents */
private final Map<String, Integer> hosts;
/** Dynamic hosts map of registered brokers agents */
private final Map<String, InetAddress> resolvedHosts;
/** Next registered broker agent */
private final AtomicInteger nextRegisteredHost;
/** Path to the hosts file */
private final String hostsFilePath;
/** Map a host name or its ip address to the web client resource queue */
private final Map<String, BlockingQueue<WebAllocatedResources>> hostsResources;
/**
* The instance method to create the hosts manager instance.
*
* @return The hosts manager
*/
public static synchronized HostsManager getInstance()
{
if (instance == null)
{
instance = new HostsManager(HOSTS_FILE_PATH);
}
return instance;
}
/**
* Creates the hosts manager.
*
* @param file
* The hosts file path
*/
private HostsManager(String file)
{
this.hostsFilePath = file;
this.hosts = new ConcurrentHashMap<String, Integer>();
this.resolvedHosts = new ConcurrentHashMap<String, InetAddress>();
this.hostsResources = new ConcurrentHashMap<String, BlockingQueue<WebAllocatedResources>>();
this.nextRegisteredHost = new AtomicInteger(0);
// read hosts file
Map<String, Integer> hostsFileMap;
try
{
hostsFileMap = ClientsToPortsGenerator.readHostsFile(hostsFilePath);
}
catch (IOException e)
{
hostsFileMap = new LinkedHashMap<String, Integer>();
hostsFileMap.put("localhost", 1);
hostsFileMap.put("127.0.0.1", 1);
}
int lastHostNumber = 0;
for(Entry<String, Integer> entry : hostsFileMap.entrySet())
{
hosts.put(entry.getKey(), entry.getValue());
if (lastHostNumber < entry.getValue())
{
lastHostNumber = entry.getValue();
}
}
nextRegisteredHost.set(lastHostNumber);
}
/**
* Add new host.
*
* @param hostNameOrIpAddress
* The host network address
* @param resourceQueue
* The queue of web resources to be allocated to the clients.
*
* @throws UnknownHostException
*/
public synchronized void addHost(String hostNameOrIpAddress, BlockingQueue<WebAllocatedResources> resourceQueue)
throws UnknownHostException
{
if (resourceQueue == null)
{
return;
}
int id = nextRegisteredHost.incrementAndGet();
if (hosts.putIfAbsent(hostNameOrIpAddress, id) == null)
{
ClientsToPortsGenerator.appendHost(hostsFilePath, hostNameOrIpAddress, id);
}
else
{
//host is already registered, so the next host number must be decreased by 1.
nextRegisteredHost.compareAndSet(id, id - 1);
}
hostsResources.putIfAbsent(hostNameOrIpAddress, resourceQueue);
InetAddress resolvedHost = resolvedHosts.get(hostNameOrIpAddress);
if (resolvedHost == null)
{
resolvedHost = InetAddress.getByName(hostNameOrIpAddress);
resolvedHosts.put(hostNameOrIpAddress, resolvedHost);
}
}
/**
* Getter for the queue of web resources to be allocated to the clients.
*
* @param hostNameOrIpAddress
* The host network address
*
* @return The queue of web resources to be allocated to the clients.
*/
public BlockingQueue<WebAllocatedResources> getHostResource(String hostNameOrIpAddress)
{
return hostsResources.get(hostNameOrIpAddress);
}
/**
* Get the resolved host name or IP address.
*
* @param host
* The host name.
*
* @return The resolved host name or IP address
*/
public InetAddress getResolvedHost(String host)
{
return resolvedHosts.get(host);
}
/**
* Represents a well-defined mapping from host ports numbers to their names.
*
* @param prefix
* The client prefix
* @param from
* The beginning port number from the given port range
* @param host
* The host
* @param port
* The port number
*
* @return The port name
*/
public String getPortName(String prefix,
int from,
String host,
int port)
{
try
{
InetAddress hostInetAddress = InetAddress.getByName(host);
return getPortName(prefix, from, hostInetAddress, port);
}
catch (UnknownHostException e)
{
StringBuilder message = new StringBuilder("Unknown host: ");
message.append(host);
throw new IllegalStateException(message.toString());
}
}
/**
* Represents a well-defined mapping from host ports numbers to their names.
*
* @param prefix
* The client prefix
* @param from
* The beginning port number from the given port range
* @param hostInetAddress
* The host IP4 address
* @param port
* The port number
*
* @return The port name
*/
private String getPortName(String prefix,
int from,
InetAddress hostInetAddress,
int port)
{
Integer hostIndex = hosts.get(hostInetAddress.getHostAddress());
if (hostIndex == null)
{
StringBuilder message = new StringBuilder("Add host: ");
message.append(hostInetAddress.getHostAddress());
throw new IllegalStateException(message.toString());
}
return ClientsToPortsGenerator.getPortName(prefix, from, hostIndex, port);
}
}