/* The contents of this file are subject to the terms
* of the Common Development and Distribution License
* (the License). You may not use this file except in
* compliance with the License.
*
* You can obtain a copy of the License at
* http://www.sun.com/cddl/cddl.html or
* install_dir/legal/LICENSE
* See the License for the specific language governing
* permission and limitations under the License.
*
* When distributing Covered Code, include this CDDL
* Header Notice in each file and include the License file
* at install_dir/legal/LICENSE.
* If applicable, add the following below the CDDL Header,
* with the fields enclosed by brackets [] replaced by
* your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*
* $Id$
*
* Copyright 2005-2009 Sun Microsystems Inc. All Rights Reserved
*/
package com.sun.faban.harness.common;
import com.sun.faban.common.NameValuePair;
import com.sun.faban.common.Utilities;
import com.sun.faban.harness.ConfigurationException;
import com.sun.faban.harness.ParamRepository;
import com.sun.faban.harness.engine.CmdService;
import java.io.*;
import java.util.*;
/**
* The HostRoles class maintains the role - host - alias relationship.
* @author Akara Sucharitakul
*/
public class HostRoles {
private static final String FS = "\t"; // Field Separator
LinkedHashMap<String, Role> roleMap = new LinkedHashMap<String, Role>();
LinkedHashMap<String, Host> hostMap = new LinkedHashMap<String, Host>();
LinkedHashMap<String, Alias> aliasMap = new LinkedHashMap<String, Alias>();
// Maps the short alias to the full domain name being used in config file.
HashMap<String, String> domainMap = new HashMap<String, String>();
/**
* Constructs the HostRoles at benchmark run time from the benchmark
* parameter file and run information.
* @param par The parameter repository/file
* @throws ConfigurationException If there is a configuration error
*/
public HostRoles(ParamRepository par) throws ConfigurationException {
CmdService cmds = CmdService.getHandle();
List<NameValuePair<String>> hostRoles = par.getHostRoles();
ArrayList<String> drivers = new ArrayList<String>();
for (NameValuePair<String> hostRole : hostRoles) {
// We need to map certain role names to be more understandable.
String roleName = hostRole.value;
if (roleName.endsWith(":runConfig")) {
// Save the drivers for last. The result stats will be ordered
// this way and the drivers are least relevant in a run.
// In some cases, we have 60 driver systems and we don't want
// the user to wade through the 60 entries to find the
// SUT components last.
drivers.add(hostRole.name);
continue;
}
StringBuilder b = new StringBuilder(roleName);
if (roleName.endsWith("Config"))
b.setLength(roleName.length() - "Config".length());
b.setCharAt(0, Character.toUpperCase(b.charAt(0)));
roleName = b.toString();
constructHostRole(hostRole.name, roleName, cmds);
}
// Now process the drivers
for (String aliasName : drivers)
constructHostRole(aliasName, "Driver", cmds);
}
private void constructHostRole(String aliasName, String roleName,
CmdService cmds)
throws ConfigurationException {
Alias a = aliasMap.get(aliasName);
if (a == null) {
// Map short name and domain names.
int idx = aliasName.indexOf('.');
if (idx > 0 && !Utilities.isIpv4Address(aliasName)) {
String shortName = aliasName.substring(0, idx);
String fullName = domainMap.get(shortName);
if (fullName == null) {
domainMap.put(shortName, aliasName);
} else if (!fullName.equals(aliasName)) {
throw new ConfigurationException(
"Duplicate host names with different domains: " +
fullName + " and " + aliasName);
}
}
// Then use the name referred in the config file for the alias.
a = new Alias();
a.name = aliasName;
aliasMap.put(aliasName, a);
}
// Then we use this new name in our role map.
Role r = roleMap.get(roleName);
if (r == null) {
r = new Role();
r.name = roleName;
roleMap.put(roleName, r);
}
a.roles.add(r);
r.aliases.add(a);
String hostName = null;
if (a.host == null) {
hostName = cmds.getHostName(a.name);
a.host = hostMap.get(hostName);
}
if (a.host == null) {
a.host = new Host();
a.host.name = hostName;
hostMap.put(a.host.name, a.host);
}
a.host.aliases.add(a);
a.host.roles.add(r);
r.hosts.add(a.host);
}
/**
* Constructs the HostRoles after the benchmark run time.
* @param fileName The file containing the stored HostRoles configuration
* @throws IOException Error reading the file or invalid file format
*/
public HostRoles(String fileName) throws IOException {
BufferedReader reader = new BufferedReader(new FileReader(fileName));
for (;;) {
String line = reader.readLine();
if (line == null)
break;
if (line.startsWith("#")) // Commented line
continue;
StringTokenizer tk = new StringTokenizer(line, FS);
try {
String host = tk.nextToken();
String alias = tk.nextToken();
String role = tk.nextToken();
Host h = hostMap.get(host);
if (h == null) {
h = new Host();
h.name = host;
hostMap.put(host, h);
}
Alias a = aliasMap.get(alias);
if (a == null) {
// Map short name and domain names.
int idx = alias.indexOf('.');
if (idx > 0 && !Utilities.isIpv4Address(alias)) {
String shortName = alias.substring(0, idx);
String fullName = domainMap.get(shortName);
if (fullName == null) {
domainMap.put(shortName, alias);
}
}
a = new Alias();
a.name = alias;
aliasMap.put(alias, a);
}
Role r = roleMap.get(role);
if (r == null) {
r = new Role();
r.name = role;
roleMap.put(role, r);
}
h.aliases.add(a);
h.roles.add(r);
if (a.host == null)
a.host = h;
a.roles.add(r);
r.hosts.add(h);
r.aliases.add(a);
} catch (NoSuchElementException e) {
throw new IOException("File " + fileName +
" : Invalid format!");
}
}
}
/**
* Writes the HostRoles out to file for later reading.
* @param fileName The file name to store the information
* @throws IOException A write error occurred
*/
public void write(String fileName) throws IOException {
BufferedWriter b = new BufferedWriter(new FileWriter(fileName));
write(b);
b.flush();
b.close();
}
/**
* Writes the HostRoles out to an appendable for later reading.
* @param b The appendable buffer.
* @throws IOException A write error occurred
*/
public void write(Appendable b) throws IOException {
b.append("#Host\t\tAlias\t\tRole\n");
for (Host h : hostMap.values()) {
String host = h.name;
for (Alias a : h.aliases) {
String alias = a.name;
for (Role r : a.roles) {
String role = r.name;
b.append(host).append(FS).append(alias).append(FS).
append(role).append('\n');
}
}
}
}
/**
* Returns the list of hosts in the run in the order their aliases
* are referred to in the configuration file.
* @return The host list
*/
public String[] getHostsInOrder() {
Set<String> hostSet = hostMap.keySet();
String[] hosts = new String[hostSet.size()];
hosts = hostSet.toArray(hosts);
return hosts;
}
/**
* Obtains the hosts pertaining to a certain role or function in the
* benchmark run.
* @param role The role name.
* @return An array of host names used for the role in question.
*/
public String[] getHostsByRole(String role) {
Role r = roleMap.get(role);
if (r == null)
return null;
String[] hosts = new String[r.hosts.size()];
int i = 0;
for (Host h : r.hosts) {
hosts[i++] = h.name;
}
return hosts;
}
/**
* Obtains the host aliases used for a certain role or function in the
* benchmark run. The alias is usually an interface name used to refer to
* a host.
* @param role The role name.
* @return An array of aliases used for the role in question
*/
public String[] getAliasesByRole(String role) {
Role r = roleMap.get(role);
if (r == null)
return null;
String[] aliases = new String[r.aliases.size()];
int i = 0;
for (Alias a : r.aliases) {
aliases[i++] = a.name;
}
return aliases;
}
/**
* Obtains the function roles the host in question is used for.
* @param host The host name
* @return An array of role names the host is used for
*/
public String[] getRolesByHost(String host) {
Host h = hostMap.get(host);
if (h == null)
return null;
String[] roles = new String[h.roles.size()];
int i = 0;
for (Role r : h.roles) {
roles[i++] = r.name;
}
return roles;
}
/**
* Obtains all aliases or interface names used to refer to the host.
* @param host The host name
* @return An array of aliases used to refer to this host.
*/
public String[] getAliasesByHost(String host) {
Host h = hostMap.get(host);
if (h == null)
return null;
String[] aliases = new String[h.aliases.size()];
int i = 0;
for (Alias a : h.aliases) {
aliases[i++] = a.name;
}
return aliases;
}
/**
* Obtains the aliases that are used for a certain host in a certain
* function.
* @param host The host name
* @param role The role name
* @return An array of applicable aliases
*/
public String[] getAliasesByHostAndRole(String host, String role) {
Host h = hostMap.get(host);
Role r = roleMap.get(role);
HashSet<Alias> aliasSet = new HashSet<Alias>(h.aliases);
aliasSet.retainAll(r.aliases); // Intersect between the two sets.
String[] aliases = new String[aliasSet.size()];
int i = 0;
for (Alias a : aliasSet) {
aliases[i++] = a.name;
}
return aliases;
}
/**
* Obtains the real host name referred to by an alias.
* @param alias The alias name
* @return The real host name
*/
public String getHostByAlias(String alias) {
Alias a = aliasMap.get(alias);
// Sometimes the short name without the domain is used.
if (a == null && alias.indexOf('.') < 0) {
String fullName = domainMap.get(alias);
if (fullName != null)
a = aliasMap.get(fullName);
}
// Sometimes this is the host name itself, not an alias
if (a == null) {
if (hostMap.containsKey(alias))
return alias;
return null;
}
return a.host.name;
}
/**
* Obtains the roles or function an interface or alias is used for.
* @param alias The alias name
* @return An array of function roles the alias is used for.
*/
public String[] getRolesByAlias(String alias) {
String[] roles = null;
Alias a = aliasMap.get(alias);
// Sometimes the short name without the domain is used.
if (a == null && alias.indexOf('.') < 0) {
String fullName = domainMap.get(alias);
if (fullName != null)
a = aliasMap.get(fullName);
}
// Sometimes this is the host name itself, not an alias
if (a == null) {
Host h = hostMap.get(alias);
if (h != null) {
roles = new String[h.roles.size()];
int i = 0;
for (Role r : h.roles) {
roles[i++] = r.name;
}
}
} else { // In the case of really an alias...
roles = new String[a.roles.size()];
int i = 0;
for (Role r : a.roles) {
roles[i++] = r.name;
}
}
return roles;
}
static class Role {
public String name;
public LinkedHashSet<Host> hosts = new LinkedHashSet<Host>();
public LinkedHashSet<Alias> aliases = new LinkedHashSet<Alias>();
@Override public boolean equals(Object obj) {
boolean retVal = false;
if (obj instanceof Role) {
Role other = (Role) obj;
if (name != null)
retVal = name.equals(other.name);
}
return retVal;
}
@Override public int hashCode() {
return name.hashCode();
}
}
static class Host {
public String name;
public LinkedHashSet<Role> roles = new LinkedHashSet<Role>();
public LinkedHashSet<Alias> aliases = new LinkedHashSet<Alias>();
@Override public boolean equals(Object obj) {
boolean retVal = false;
if (obj instanceof Host) {
Host other = (Host) obj;
if (name != null)
retVal = name.equals(other.name);
}
return retVal;
}
@Override public int hashCode() {
return name.hashCode();
}
}
static class Alias {
public String name;
public Host host;
public LinkedHashSet<Role> roles = new LinkedHashSet<Role>();
@Override public boolean equals(Object obj) {
boolean retVal = false;
if (obj instanceof Alias) {
Alias other = (Alias) obj;
if (name != null)
retVal = name.equals(other.name);
}
return retVal;
}
@Override public int hashCode() {
return name.hashCode();
}
}
}