From: <isp...@rh...> - 2009-09-29 20:50:39
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head><style type="text/css"><!-- #msg DL { border : 1px #006 solid; background-color : #369; padding : 6px; color : #fff; } #msg DT { float : left; width : 6em; font-weight : bold; } #msg DL, #msg DT, #msg UL, #msg LI { font-family : arial,helvetica,sans-serif; font-size : 10pt; } h3 { font-family : arial,helvetica,sans-serif; font-size : 10pt; font-weight : bold; } #msg PRE { overflow : auto; white-space : normal; background-color : #ffc; border : 1px #fc0 solid; padding : 6px; } #msg UL, PRE, .diff { overflow : auto; } #patch h4 { font-family : arial,helvetica,sans-serif; font-size : 10pt; } #patch h4 { padding: 8px; background : #369; color : #fff; margin : 0; } #patch .propset h4, #patch .binary h4 {margin: 0;} #patch pre {padding:0;line-height:1.2em;margin:0;} #patch .diff {background:#eeeeee;padding: 0 0 10px 0;} #patch .propset .diff, #patch .binary .diff {padding: 10px 0;} #patch span {display:block;padding:0 10px;} #patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;} #patch .add {background:#ddffdd;} #patch .rem {background:#ffdddd;} #patch .lines, .info {color:#888888;background:#ffffff;} .diff { width : 100%; } #msg DL { border : 1px #006 solid; background-color : #369; padding : 6px; color : #fff; } #msg DT { float : left; width : 6em; font-weight : bold; } #msg DL, #msg DT, #msg UL, #msg LI { font-family : arial,helvetica,sans-serif; font-size : 10pt; } h3 { font-family : arial,helvetica,sans-serif; font-size : 10pt; font-weight : bold; } #msg PRE { overflow : auto; white-space : normal; background-color : #ffc; border : 1px #fc0 solid; padding : 6px; } #msg UL, PRE, .diff { overflow : auto; } #patch h4 { font-family : arial,helvetica,sans-serif; font-size : 10pt; } #patch h4 { padding: 8px; background : #369; color : #fff; margin : 0; } #patch .propset h4, #patch .binary h4 {margin: 0;} #patch pre {padding:0;line-height:1.2em;margin:0;} #patch .diff {background:#eeeeee;padding: 0 0 10px 0;} #patch .propset .diff, #patch .binary .diff {padding: 10px 0;} #patch span {display:block;padding:0 10px;} #patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;} #patch .add {background:#ddffdd;} #patch .rem {background:#ffdddd;} #patch .lines, .info {color:#888888;background:#ffffff;} .diff { width : 100%; } --></style> <title>[rhq-project.org rhq] [5225] 2nd rev of the new hosts plugin - it actually works now</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>5225</dd> <dt>Author</dt> <dd>ispringer</dd> <dt>Date</dt> <dd>2009-09-29 15:50:29 -0500 (Tue, 29 Sep 2009)</dd> </dl> <h3>Log Message</h3> <pre>2nd rev of the new hosts plugin - it actually works now</pre> <h3>Modified Paths</h3> <ul> <li><a href="#rhqtrunkmodulespluginshostspomxml">rhq/trunk/modules/plugins/hosts/pom.xml</a></li> <li><a href="#rhqtrunkmodulespluginshostssrcmainjavaorgrhqpluginshostsHostsComponentjava">rhq/trunk/modules/plugins/hosts/src/main/java/org/rhq/plugins/hosts/HostsComponent.java</a></li> <li><a href="#rhqtrunkmodulespluginshostssrcmainjavaorgrhqpluginshostsHostsDiscoveryComponentjava">rhq/trunk/modules/plugins/hosts/src/main/java/org/rhq/plugins/hosts/HostsDiscoveryComponent.java</a></li> <li><a href="#rhqtrunkmodulespluginshostssrcmainjavaorgrhqpluginshostshelperHostsjava">rhq/trunk/modules/plugins/hosts/src/main/java/org/rhq/plugins/hosts/helper/Hosts.java</a></li> <li><a href="#rhqtrunkmodulespluginshostssrcmainjavaorgrhqpluginshostshelperHostsComponentHelperjava">rhq/trunk/modules/plugins/hosts/src/main/java/org/rhq/plugins/hosts/helper/HostsComponentHelper.java</a></li> <li><a href="#rhqtrunkmodulespluginshostssrcmainjavaorgrhqpluginshostshelperHostsEntryjava">rhq/trunk/modules/plugins/hosts/src/main/java/org/rhq/plugins/hosts/helper/HostsEntry.java</a></li> <li><a href="#rhqtrunkmodulespluginshostssrcmainjavaorgrhqpluginshostshelperSimpleUnixConfigFileLinejava">rhq/trunk/modules/plugins/hosts/src/main/java/org/rhq/plugins/hosts/helper/SimpleUnixConfigFileLine.java</a></li> <li><a href="#rhqtrunkmodulespluginshostssrcmainjavaorgrhqpluginshostshelperSimpleUnixConfigFileReaderjava">rhq/trunk/modules/plugins/hosts/src/main/java/org/rhq/plugins/hosts/helper/SimpleUnixConfigFileReader.java</a></li> <li><a href="#rhqtrunkmodulespluginshostssrcmainresourcesMETAINFrhqpluginxml">rhq/trunk/modules/plugins/hosts/src/main/resources/META-INF/rhq-plugin.xml</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="rhqtrunkmodulespluginshostspomxml"></a> <div class="modfile"><h4>Modified: rhq/trunk/modules/plugins/hosts/pom.xml (5224 => 5225)</h4> <pre class="diff"> <span class="info">--- rhq/trunk/modules/plugins/hosts/pom.xml 2009-09-29 19:27:08 UTC (rev 5224) +++ rhq/trunk/modules/plugins/hosts/pom.xml 2009-09-29 20:50:29 UTC (rev 5225) </span><span class="lines">@@ -146,7 +146,7 @@ </span><span class="cx"> <execution> <id>deploy</id> </span><span class="rem">- <!--<phase>compile</phase>--> </span><span class="add">+ <phase>compile</phase> </span><span class="cx"> <configuration> <tasks> <mkdir dir="${rhq.deploymentDir}" /> </span><span class="lines">@@ -162,7 +162,7 @@ </span><span class="cx"> <execution> <id>deploy-jar-meta-inf</id> </span><span class="rem">- <!--<phase>package</phase>--> </span><span class="add">+ <phase>package</phase> </span><span class="cx"> <configuration> <tasks> <property name="deployment.file" location="${rhq.deploymentDir}/${project.build.finalName}.jar" /> </span><span class="lines">@@ -181,7 +181,7 @@ </span><span class="cx"> <execution> <id>undeploy</id> </span><span class="rem">- <!--<phase>clean</phase>--> </span><span class="add">+ <phase>clean</phase> </span><span class="cx"> <configuration> <tasks> <property name="deployment.file" location="${rhq.deploymentDir}/${project.build.finalName}.jar" /> </span></pre></div> <a id="rhqtrunkmodulespluginshostssrcmainjavaorgrhqpluginshostsHostsComponentjava"></a> <div class="modfile"><h4>Modified: rhq/trunk/modules/plugins/hosts/src/main/java/org/rhq/plugins/hosts/HostsComponent.java (5224 => 5225)</h4> <pre class="diff"> <span class="info">--- rhq/trunk/modules/plugins/hosts/src/main/java/org/rhq/plugins/hosts/HostsComponent.java 2009-09-29 19:27:08 UTC (rev 5224) +++ rhq/trunk/modules/plugins/hosts/src/main/java/org/rhq/plugins/hosts/HostsComponent.java 2009-09-29 20:50:29 UTC (rev 5225) </span><span class="lines">@@ -22,10 +22,13 @@ </span><span class="cx"> import java.io.IOException; import java.util.Date; import java.util.HashSet; </span><span class="add">+import java.util.LinkedHashSet; </span><span class="cx"> import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; </span><span class="add">+ +import org.rhq.core.domain.configuration.ConfigurationUpdateStatus; </span><span class="cx"> import org.rhq.core.domain.configuration.Property; import org.rhq.core.pluginapi.inventory.ResourceComponent; import org.rhq.core.pluginapi.inventory.ResourceContext; </span><span class="lines">@@ -42,6 +45,8 @@ </span><span class="cx"> import org.rhq.plugins.hosts.helper.HostsEntry; /** </span><span class="add">+ * The ResourceComponent for the "Hosts File" ResourceType. + * </span><span class="cx"> * @author Ian Springer */ public class HostsComponent implements ResourceComponent, ConfigurationFacet { </span><span class="lines">@@ -83,17 +88,47 @@ </span><span class="cx"> PropertyList entriesProp = new PropertyList("entries"); resourceConfig.put(entriesProp); </span><span class="rem">- for (HostsEntry entry : hosts.getEntries().values()) { </span><span class="add">+ Set<String> ipAddressesWithDuplicateEntries = hosts.getIpAddressesWithDuplicateEntries(); + if (!ipAddressesWithDuplicateEntries.isEmpty()) { + log.debug("Hosts file [" + this.hostsFile + "] contains duplicate entries for the following IP addresses: " + + ipAddressesWithDuplicateEntries); + } + Set<String> namesWithDuplicateEntries = hosts.getNamesWithDuplicateEntries(); + if (!namesWithDuplicateEntries.isEmpty()) { + log.error("Hosts file [" + this.hostsFile + "] contains duplicate entries for the following names: " + + namesWithDuplicateEntries); + } + + for (HostsEntry entry : hosts.getEntries()) { </span><span class="cx"> PropertyMap entryProp = new PropertyMap("entry"); entriesProp.add(entryProp); </span><span class="rem">- entryProp.put(new PropertySimple("ipAddress", entry.getIpAddress())); - entryProp.put(new PropertySimple("canonicalName", entry.getCanonicalName())); </span><span class="add">+ PropertySimple ipAddressProp = new PropertySimple("ipAddress", entry.getIpAddress()); + entryProp.put(ipAddressProp); + + PropertySimple canonicalNameProp = new PropertySimple("canonicalName", entry.getCanonicalName()); + if (namesWithDuplicateEntries.contains(entry.getCanonicalName())) { + canonicalNameProp.setErrorMessage("At the time of loading, there was more than one entry containing this name - please remove or fix duplicate entries before saving."); + } + entryProp.put(canonicalNameProp); + </span><span class="cx"> StringBuilder aliasesPropValue = new StringBuilder(); </span><span class="add">+ boolean foundDuplicateName = false; </span><span class="cx"> for (String alias : entry.getAliases()) { </span><span class="add">+ if (namesWithDuplicateEntries.contains(alias)) { + foundDuplicateName = true; + } </span><span class="cx"> aliasesPropValue.append(alias).append("\n"); } </span><span class="rem">- entryProp.put(new PropertySimple("aliases", aliasesPropValue)); </span><span class="add">+ if (!entry.getAliases().isEmpty()) { + // Chop the final newline char. + aliasesPropValue.deleteCharAt(aliasesPropValue.length() - 1); + } + PropertySimple aliasesProp = new PropertySimple("aliases", aliasesPropValue); + if (foundDuplicateName) { + aliasesProp.setErrorMessage("At the time of loading, there was more than one entry containing this name - please remove or fix duplicate entries before saving."); + } + entryProp.put(aliasesProp); </span><span class="cx"> } return resourceConfig; </span><span class="lines">@@ -108,16 +143,28 @@ </span><span class="cx"> PropertyMap entryPropMap = (PropertyMap) entryProp; String ipAddress = entryPropMap.getSimple("ipAddress").getStringValue(); String canonicalName = entryPropMap.getSimple("canonicalName").getStringValue(); </span><span class="rem">- String aliases = entryPropMap.getSimpleValue("aliases", ""); - String[] aliasArray = aliases.split("\\s+"); - Set<String> aliasSet = new HashSet<String>(aliasArray.length); - for (String alias : aliasArray) { - aliasSet.add(alias); </span><span class="add">+ String aliases = entryPropMap.getSimpleValue("aliases", null); + Set<String> aliasSet; + if (aliases == null) { + aliasSet = null; + } else { + String[] aliasArray = aliases.trim().split("\\s+"); + aliasSet = new LinkedHashSet<String>(aliasArray.length); + for (String alias : aliasArray) { + aliasSet.add(alias); + } </span><span class="cx"> } HostsEntry entry = new HostsEntry(ipAddress, canonicalName, aliasSet); newHosts.addEntry(entry); } </span><span class="add">+ Set<String> namesWithDuplicateEntries = newHosts.getNamesWithDuplicateEntries(); + if (!namesWithDuplicateEntries.isEmpty()) { + report.setErrorMessage("There are duplicate entries for the following names: " + + namesWithDuplicateEntries); + return; + } + </span><span class="cx"> try { Hosts.store(newHosts, this.hostsFile); } </span><span class="lines">@@ -125,6 +172,7 @@ </span><span class="cx"> throw new RuntimeException("Failed to write hosts file [" + this.hostsFile + "].", e); } </span><span class="add">+ report.setStatus(ConfigurationUpdateStatus.SUCCESS); </span><span class="cx"> return; } } </span></pre></div> <a id="rhqtrunkmodulespluginshostssrcmainjavaorgrhqpluginshostsHostsDiscoveryComponentjava"></a> <div class="modfile"><h4>Modified: rhq/trunk/modules/plugins/hosts/src/main/java/org/rhq/plugins/hosts/HostsDiscoveryComponent.java (5224 => 5225)</h4> <pre class="diff"> <span class="info">--- rhq/trunk/modules/plugins/hosts/src/main/java/org/rhq/plugins/hosts/HostsDiscoveryComponent.java 2009-09-29 19:27:08 UTC (rev 5224) +++ rhq/trunk/modules/plugins/hosts/src/main/java/org/rhq/plugins/hosts/HostsDiscoveryComponent.java 2009-09-29 20:50:29 UTC (rev 5225) </span><span class="lines">@@ -34,6 +34,8 @@ </span><span class="cx"> import org.rhq.plugins.hosts.helper.HostsComponentHelper; /** </span><span class="add">+ * The ResourceDiscoveryComponent for the "Hosts File" ResourceType. + * </span><span class="cx"> * @author Ian Springer */ public class HostsDiscoveryComponent implements ResourceDiscoveryComponent, ManualAddFacet { </span><span class="lines">@@ -58,6 +60,8 @@ </span><span class="cx"> pluginConfig.put(new PropertySimple(HostsComponent.PATH_PROP, hostsFile.getPath())); DiscoveredResourceDetails resource = createResourceDetails(discoveryContext, pluginConfig); discoveredResources.add(resource); </span><span class="add">+ log.debug("Discovered " + discoveryContext.getResourceType().getName() + " Resource with key [" + + resource.getResourceKey() + "]."); </span><span class="cx"> } else { log.warn("Hosts file not found at [" + hostsFile + "]."); } </span></pre></div> <a id="rhqtrunkmodulespluginshostssrcmainjavaorgrhqpluginshostshelperHostsjava"></a> <div class="modfile"><h4>Modified: rhq/trunk/modules/plugins/hosts/src/main/java/org/rhq/plugins/hosts/helper/Hosts.java (5224 => 5225)</h4> <pre class="diff"> <span class="info">--- rhq/trunk/modules/plugins/hosts/src/main/java/org/rhq/plugins/hosts/helper/Hosts.java 2009-09-29 19:27:08 UTC (rev 5224) +++ rhq/trunk/modules/plugins/hosts/src/main/java/org/rhq/plugins/hosts/helper/Hosts.java 2009-09-29 20:50:29 UTC (rev 5225) </span><span class="lines">@@ -2,133 +2,263 @@ </span><span class="cx"> * JBoss, a division of Red Hat. * Copyright 2006, Red Hat Middleware, LLC. All rights reserved. */ </span><span class="rem">- </span><span class="cx"> package org.rhq.plugins.hosts.helper; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; </span><span class="add">+import org.jetbrains.annotations.NotNull; </span><span class="cx"> import org.jetbrains.annotations.Nullable; import java.io.File; </span><span class="add">+import java.io.FileOutputStream; </span><span class="cx"> import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; </span><span class="rem">-import java.util.Arrays; </span><span class="add">+import java.util.Collections; </span><span class="cx"> import java.util.HashMap; import java.util.HashSet; </span><span class="add">+import java.util.LinkedHashSet; </span><span class="cx"> import java.util.Map; import java.util.Set; </span><span class="rem">-import java.util.regex.Matcher; -import java.util.regex.Pattern; </span><span class="cx"> /** </span><span class="add">+ * A set of hosts file entries. The set may contain duplicate entries (i.e. entries for different IP addresses + * containing the same name, either as the canonical name or as an alias). + * </span><span class="cx"> * @author Ian Springer */ public class Hosts { </span><span class="rem">- private static final Log LOG = LogFactory.getLog(Hosts.class); </span><span class="add">+ private static final Log LOG = LogFactory.getLog(Hosts.class); </span><span class="cx"> </span><span class="rem">- private static final Pattern ENTRY_PATTERN = Pattern.compile("(\\S+)\\s+(\\S+)\\s+(.*)"); </span><span class="add">+ private Set<HostsEntry> entries = new LinkedHashSet<HostsEntry>(); + private Map<String, Set<HostsEntry>> ipAddressToEntriesMap = new HashMap<String, Set<HostsEntry>>(); + private Map<String, Set<HostsEntry>> nameToEntriesMap = new HashMap<String, Set<HostsEntry>>(); + private Set<String> namesWithDuplicateEntries = new HashSet<String>(); + private Set<String> ipAddressesWithDuplicateEntries = new HashSet<String>(); </span><span class="cx"> </span><span class="rem">- private Map<String, HostsEntry> entries = new HashMap<String, HostsEntry>(); - </span><span class="cx"> public Hosts() { } </span><span class="rem">- public void addEntry(HostsEntry hostsEntry) { - this.entries.put(hostsEntry.getIpAddress(), hostsEntry); </span><span class="add">+ public void addEntry(HostsEntry entry) { + this.entries.add(entry); + String ipAddress = entry.getIpAddress(); + Set<HostsEntry> entriesForIpAddress = this.ipAddressToEntriesMap.get(ipAddress); + if (entriesForIpAddress == null) { + entriesForIpAddress = new LinkedHashSet(1); + this.ipAddressToEntriesMap.put(ipAddress, entriesForIpAddress); + } else { + this.ipAddressesWithDuplicateEntries.add(ipAddress); + } + entriesForIpAddress.add(entry); + String canonicalName = entry.getCanonicalName(); + updateNameToEntriesMap(entry, canonicalName); + for (String alias : entry.getAliases()) { + updateNameToEntriesMap(entry, alias); + } </span><span class="cx"> } </span><span class="rem">- public Map<String, HostsEntry> getEntries() { </span><span class="add">+ private void updateNameToEntriesMap(HostsEntry entry, String canonicalName) { + Set<HostsEntry> entriesForCanonicalName = this.nameToEntriesMap.get(canonicalName); + if (entriesForCanonicalName == null) { + entriesForCanonicalName = new LinkedHashSet(1); + this.nameToEntriesMap.put(canonicalName, entriesForCanonicalName); + } else { + this.namesWithDuplicateEntries.add(canonicalName); + } + entriesForCanonicalName.add(entry); + } + + public Set<HostsEntry> getEntries() { </span><span class="cx"> return this.entries; } </span><span class="add">+ @NotNull + public Set<HostsEntry> getEntriesByIpAddress(String ipAddress) { + Set<HostsEntry> entries = this.ipAddressToEntriesMap.get(ipAddress); + return (entries != null) ? entries : Collections.<HostsEntry>emptySet(); + } + + public Set<HostsEntry> getEntriesByName(String canonicalName) { + Set<HostsEntry> entries = this.nameToEntriesMap.get(canonicalName); + return (entries != null) ? entries : Collections.<HostsEntry>emptySet(); + } + + public Set<String> getIpAddressesWithDuplicateEntries() { + return this.ipAddressesWithDuplicateEntries; + } + + public Set<String> getNamesWithDuplicateEntries() { + return this.namesWithDuplicateEntries; + } + </span><span class="cx"> public static Hosts load(File hostsFile) throws IOException { Hosts hosts = new Hosts(); SimpleUnixConfigFileReader reader = new SimpleUnixConfigFileReader(new FileReader(hostsFile)); </span><span class="rem">- SimpleUnixConfigFileLine line; - while ((line = reader.readLine()) != null) { - String entry = line.getNonComment(); - Matcher matcher = ENTRY_PATTERN.matcher(entry); - if (matcher.matches()) { - String ipAddress = matcher.group(0); - String canonicalName = matcher.group(1); - String aliases = matcher.group(2); - Set<String> aliasSet = new HashSet<String>(); - if (aliases != null) { - String[] aliasArray = aliases.split("\\s+"); - aliasSet.addAll(Arrays.asList(aliasArray)); </span><span class="add">+ try { + SimpleUnixConfigFileLine line; + while ((line = reader.readLine()) != null) { + String nonComment = line.getNonComment(); + HostsEntry entry = parseEntry(nonComment, hostsFile); + if (entry != null) { + hosts.addEntry(entry); </span><span class="cx"> } </span><span class="rem">- HostsEntry hostsEntry = new HostsEntry(ipAddress, canonicalName, aliasSet); - hosts.addEntry(hostsEntry); </span><span class="cx"> } } </span><span class="add">+ finally { + reader.close(); + } + </span><span class="cx"> return hosts; } public static void store(Hosts hosts, File hostsFile) throws IOException { </span><span class="rem">- SimpleUnixConfigFileReader reader = new SimpleUnixConfigFileReader(new FileReader(hostsFile)); - PrintWriter writer = new PrintWriter(new FileWriter(hostsFile)); - SimpleUnixConfigFileLine line; - while ((line = reader.readLine()) != null) { - StringBuilder newLine = createNewLine(hosts, hostsFile, line); - if (newLine != null) { - writer.println(newLine); </span><span class="add">+ Set<String> namesWithDuplicateEntries = hosts.getNamesWithDuplicateEntries(); + if (!namesWithDuplicateEntries.isEmpty()) { + throw new IllegalArgumentException("Hosts contains duplicate entries for the following names: " + + namesWithDuplicateEntries); + } + + if (!hostsFile.exists()) { + // If a hosts file doesn't already exist, create an empty one. + FileOutputStream hostsFileWriter = new FileOutputStream(hostsFile); + hostsFileWriter.close(); + } + + Set<String> storedCanonicalNames = new HashSet<String>(); + File newHostsFile = new File(hostsFile.getPath() + "-" + System.currentTimeMillis()); + PrintWriter newHostsFileWriter = new PrintWriter(new FileWriter(newHostsFile)); + try { + SimpleUnixConfigFileLine line; + SimpleUnixConfigFileReader hostsFileReader = new SimpleUnixConfigFileReader(new FileReader(hostsFile)); + try { + while ((line = hostsFileReader.readLine()) != null) { + StringBuilder newLine = createNewLine(hosts, hostsFile, line, storedCanonicalNames); + if (newLine != null) { + newHostsFileWriter.println(newLine); + } + } </span><span class="cx"> } </span><span class="add">+ finally { + hostsFileReader.close(); + } + + // Write out any entries for IP addresses that did not have entries in the original file. + for (HostsEntry newEntry : hosts.getEntries()) { + if (!storedCanonicalNames.contains(newEntry.getCanonicalName())) { + StringBuilder newLine = new StringBuilder(newEntry.getIpAddress()).append("\t").append(newEntry.getCanonicalName()); + for (String alias : newEntry.getAliases()) { + newLine.append("\t").append(alias); + } + newHostsFileWriter.println(newLine); + } + } </span><span class="cx"> } </span><span class="add">+ finally { + newHostsFileWriter.close(); + } + + // Backup the original hosts file (e.g. /etc/hosts) to hosts~ (e.g. /etc/hosts~). + File backupHostsFile = new File(hostsFile.getPath() + "~"); + if (backupHostsFile.exists()) { + // renameTo() will fail on Windows if the destination file already exists. Lame, eh? + boolean deleteSucceeded = backupHostsFile.delete(); + } + boolean backupSucceeded = hostsFile.renameTo(backupHostsFile); + if (!backupSucceeded) { + throw new IOException("Failed to backup original hosts file [" + hostsFile + "] to [" + backupHostsFile + "]."); + } + + // And finally, rename the new hosts file (e.g. /etc/hosts-1234567890) to the actual hosts file (e.g. /etc/hosts). + if (hostsFile.exists()) { + // renameTo() will fail on Windows if the destination file already exists. Lame, eh? + boolean deleteSucceeded = hostsFile.delete(); + } + boolean updateSucceeded = newHostsFile.renameTo(hostsFile); + if (!updateSucceeded) { + throw new IOException("Failed to rename updated hosts file [" + newHostsFile + "] to [" + hostsFile + "]."); + } + </span><span class="cx"> return; } </span><span class="add">+ private static HostsEntry parseEntry(String string, File hostsFile) { + if (string == null) { + // comment-only line + return null; + } + + String trimmedString = string.trim(); + if (trimmedString.equals("")) { + // comment-only line + return null; + } + + String[] tokens = trimmedString.split("\\s+"); + if (tokens.length == 0) { + // comment-only line + return null; + } + + String ipAddress = tokens[0]; + if (tokens.length == 1) { + LOG.warn("Hosts file [" + hostsFile + "] contains invalid entry for IP address " + ipAddress + + " - no canonical name is specified."); + } + + String canonicalName = null; + Set<String> aliasSet = null; + if (tokens.length >= 2) { + canonicalName = tokens[1]; + if (tokens.length >= 3) { + aliasSet = new LinkedHashSet<String>(tokens.length - 2); + for (int i = 2; i < tokens.length; i++) { + aliasSet.add(tokens[i]); + } + } + } + + return new HostsEntry(ipAddress, canonicalName, aliasSet); + } + </span><span class="cx"> @Nullable </span><span class="rem">- private static StringBuilder createNewLine(Hosts hosts, File hostsFile, SimpleUnixConfigFileLine existingLine) { </span><span class="add">+ private static StringBuilder createNewLine(Hosts hosts, File hostsFile, SimpleUnixConfigFileLine existingLine, + Set<String> storedCanonicalNames) { </span><span class="cx"> StringBuilder newLine; String nonComment = existingLine.getNonComment(); </span><span class="rem">- String trimmedNonComment = (nonComment == null) ? null : nonComment.trim(); </span><span class="cx"> String comment = existingLine.getComment(); </span><span class="rem">- if (trimmedNonComment != null && !trimmedNonComment.equals("")) { - Matcher matcher = ENTRY_PATTERN.matcher(trimmedNonComment); - if (matcher.matches()) { - String ipAddress = matcher.group(0); - String canonicalName = matcher.group(1); - String aliases = matcher.group(2); - String[] aliasArray = aliases.split("\\s+"); - Set<String> aliasSet = new HashSet<String>(Arrays.asList(aliasArray)); - HostsEntry existingEntry = new HostsEntry(ipAddress, canonicalName, aliasSet); - if (hosts.getEntries().containsKey(ipAddress)) { - // replace the existing entry - HostsEntry newEntry = hosts.getEntries().get(ipAddress); - LOG.debug("Replacing existing entry in hosts file [" + existingEntry + "] with new entry [" - + newEntry + "]..."); - newLine = new StringBuilder(newEntry.getIpAddress()).append("\t").append(newEntry.getCanonicalName()); - for (String alias : newEntry.getAliases()) { - newLine.append("\t").append(alias); - } - // but still write out the existing comment - if (comment != null) { - newLine.append(" #").append(comment); - } - } else { - LOG.debug("Removing entry [" + existingEntry + "] from hosts file..."); - newLine = null; </span><span class="add">+ HostsEntry existingEntry = parseEntry(nonComment, hostsFile); + if (existingEntry != null) { + Set<HostsEntry> newEntries = hosts.getEntriesByName(existingEntry.getCanonicalName()); + // TODO: Look up entries for existing entry's aliases too? + if (!newEntries.isEmpty()) { + // replace the existing entry + HostsEntry newEntry = newEntries.iterator().next(); + LOG.debug("Replacing existing entry in hosts file [" + existingEntry + "] with new entry [" + + newEntry + "]..."); + newLine = new StringBuilder(newEntry.getIpAddress()).append("\t").append(newEntry.getCanonicalName()); + for (String alias : newEntry.getAliases()) { + newLine.append("\t").append(alias); </span><span class="cx"> } </span><span class="add">+ // but still write out the existing comment + if (comment != null) { + newLine.append(" #").append(comment); + } + storedCanonicalNames.add(newEntry.getCanonicalName()); </span><span class="cx"> } else { </span><span class="rem">- // invalid entry - log a warning but write it out as is - LOG.warn("Hosts file [" + hostsFile + "] contains invalid entry [" + trimmedNonComment + "]."); - newLine = new StringBuilder(nonComment).append(" #").append(comment); </span><span class="add">+ LOG.debug("Removing entry [" + existingEntry + "] from hosts file..."); + newLine = null; </span><span class="cx"> } } else { </span><span class="add">+ // comment-only line - write it back out exactly as is </span><span class="cx"> newLine = new StringBuilder(); </span><span class="rem">- // comment-only line - write it back out as is </span><span class="add">+ </span><span class="cx"> if (nonComment != null) { newLine.append(nonComment); </span><span class="rem">- if (comment != null) { - newLine.append(' '); - } </span><span class="cx"> } if (comment != null) { newLine.append('#').append(comment); } </span><span class="rem">- newLine = new StringBuilder(nonComment).append(""); </span><span class="cx"> } return newLine; } </span></pre></div> <a id="rhqtrunkmodulespluginshostssrcmainjavaorgrhqpluginshostshelperHostsComponentHelperjava"></a> <div class="modfile"><h4>Modified: rhq/trunk/modules/plugins/hosts/src/main/java/org/rhq/plugins/hosts/helper/HostsComponentHelper.java (5224 => 5225)</h4> <pre class="diff"> <span class="info">--- rhq/trunk/modules/plugins/hosts/src/main/java/org/rhq/plugins/hosts/helper/HostsComponentHelper.java 2009-09-29 19:27:08 UTC (rev 5224) +++ rhq/trunk/modules/plugins/hosts/src/main/java/org/rhq/plugins/hosts/helper/HostsComponentHelper.java 2009-09-29 20:50:29 UTC (rev 5225) </span><span class="lines">@@ -2,7 +2,6 @@ </span><span class="cx"> * JBoss, a division of Red Hat. * Copyright 2006, Red Hat Middleware, LLC. All rights reserved. */ </span><span class="rem">- </span><span class="cx"> package org.rhq.plugins.hosts.helper; import org.rhq.core.domain.configuration.Configuration; </span></pre></div> <a id="rhqtrunkmodulespluginshostssrcmainjavaorgrhqpluginshostshelperHostsEntryjava"></a> <div class="modfile"><h4>Modified: rhq/trunk/modules/plugins/hosts/src/main/java/org/rhq/plugins/hosts/helper/HostsEntry.java (5224 => 5225)</h4> <pre class="diff"> <span class="info">--- rhq/trunk/modules/plugins/hosts/src/main/java/org/rhq/plugins/hosts/helper/HostsEntry.java 2009-09-29 19:27:08 UTC (rev 5224) +++ rhq/trunk/modules/plugins/hosts/src/main/java/org/rhq/plugins/hosts/helper/HostsEntry.java 2009-09-29 20:50:29 UTC (rev 5225) </span><span class="lines">@@ -2,7 +2,6 @@ </span><span class="cx"> * JBoss, a division of Red Hat. * Copyright 2006, Red Hat Middleware, LLC. All rights reserved. */ </span><span class="rem">- </span><span class="cx"> package org.rhq.plugins.hosts.helper; import java.util.Collections; </span></pre></div> <a id="rhqtrunkmodulespluginshostssrcmainjavaorgrhqpluginshostshelperSimpleUnixConfigFileLinejava"></a> <div class="modfile"><h4>Modified: rhq/trunk/modules/plugins/hosts/src/main/java/org/rhq/plugins/hosts/helper/SimpleUnixConfigFileLine.java (5224 => 5225)</h4> <pre class="diff"> <span class="info">--- rhq/trunk/modules/plugins/hosts/src/main/java/org/rhq/plugins/hosts/helper/SimpleUnixConfigFileLine.java 2009-09-29 19:27:08 UTC (rev 5224) +++ rhq/trunk/modules/plugins/hosts/src/main/java/org/rhq/plugins/hosts/helper/SimpleUnixConfigFileLine.java 2009-09-29 20:50:29 UTC (rev 5225) </span><span class="lines">@@ -2,7 +2,6 @@ </span><span class="cx"> * JBoss, a division of Red Hat. * Copyright 2006, Red Hat Middleware, LLC. All rights reserved. */ </span><span class="rem">- </span><span class="cx"> package org.rhq.plugins.hosts.helper; import org.jetbrains.annotations.Nullable; </span></pre></div> <a id="rhqtrunkmodulespluginshostssrcmainjavaorgrhqpluginshostshelperSimpleUnixConfigFileReaderjava"></a> <div class="modfile"><h4>Modified: rhq/trunk/modules/plugins/hosts/src/main/java/org/rhq/plugins/hosts/helper/SimpleUnixConfigFileReader.java (5224 => 5225)</h4> <pre class="diff"> <span class="info">--- rhq/trunk/modules/plugins/hosts/src/main/java/org/rhq/plugins/hosts/helper/SimpleUnixConfigFileReader.java 2009-09-29 19:27:08 UTC (rev 5224) +++ rhq/trunk/modules/plugins/hosts/src/main/java/org/rhq/plugins/hosts/helper/SimpleUnixConfigFileReader.java 2009-09-29 20:50:29 UTC (rev 5225) </span><span class="lines">@@ -2,7 +2,6 @@ </span><span class="cx"> * JBoss, a division of Red Hat. * Copyright 2006, Red Hat Middleware, LLC. All rights reserved. */ </span><span class="rem">- </span><span class="cx"> package org.rhq.plugins.hosts.helper; import org.jetbrains.annotations.Nullable; </span></pre></div> <a id="rhqtrunkmodulespluginshostssrcmainresourcesMETAINFrhqpluginxml"></a> <div class="modfile"><h4>Modified: rhq/trunk/modules/plugins/hosts/src/main/resources/META-INF/rhq-plugin.xml (5224 => 5225)</h4> <pre class="diff"> <span class="info">--- rhq/trunk/modules/plugins/hosts/src/main/resources/META-INF/rhq-plugin.xml 2009-09-29 19:27:08 UTC (rev 5224) +++ rhq/trunk/modules/plugins/hosts/src/main/resources/META-INF/rhq-plugin.xml 2009-09-29 20:50:29 UTC (rev 5225) </span><span class="lines">@@ -7,11 +7,22 @@ </span><span class="cx"> xmlns:c="urn:xmlns:rhq-configuration"> <service name="Hosts File" </span><span class="rem">- description="the local file used for mapping hostnames to IP addresses" </span><span class="add">+ description="the local file used for mapping host names to IP addresses" </span><span class="cx"> discovery="HostsDiscoveryComponent" class="HostsComponent" supportsManualAdd="true"> </span><span class="add">+ <runs-inside> + <parent-resource-type name="Linux" plugin="Platforms"/> + <parent-resource-type name="Windows" plugin="Platforms"/> + <parent-resource-type name="Solaris" plugin="Platforms"/> + <parent-resource-type name="HP-UX" plugin="Platforms"/> + <parent-resource-type name="AIX" plugin="Platforms"/> + <parent-resource-type name="FreeBSD" plugin="Platforms"/> + <parent-resource-type name="Mac OS X" plugin="Platforms"/> + <parent-resource-type name="Java" plugin="Platforms"/> + </runs-inside> + </span><span class="cx"> <plugin-configuration> <c:simple-property name="path" displayName="Hosts File Path" type="file" required="true" description="the absolute path of the hosts file (e.g. /etc/hosts on Unix systems or C:\windows\system32\drivers\etc\hosts)"/> </span><span class="lines">@@ -22,10 +33,10 @@ </span><span class="cx"> <c:map-property name="entry"> <c:simple-property name="ipAddress" displayName="IP Address" type="string" required="true" activationPolicy="immediate" description="The IP address of the host entry. The address may be an IPv4 address (e.g., 192.168.1.10) or an IPv6 address (e.g., fec0:0:0:bebe::2)."/> </span><span class="rem">- <c:simple-property name="canonicalName" displayName="Canonical Hostname" type="string" required="true" activationPolicy="immediate" - description="The canonical hostname to refer to the IP address. Host names may contain only alphanumeric characters, minus signs ('-'), and periods ('.'). They must begin with an alphabetic character and end with an alphanumeric character. (e.g., foo.mydomain.org)"/> </span><span class="add">+ <c:simple-property name="canonicalName" displayName="Canonical Host Name" type="string" required="true" activationPolicy="immediate" + description="The canonical host name to refer to the IP address. Host names may contain only alphanumeric characters, minus signs ('-'), and periods ('.'). They must begin with an alphabetic character and end with an alphanumeric character. (e.g., foo.mydomain.org)"/> </span><span class="cx"> <c:simple-property name="aliases" displayName="Aliases" type="longString" required="false" activationPolicy="immediate" </span><span class="rem">- description="Optional aliases provide for name changes, alternate spellings, shorter hostnames, or generic hostnames (e.g., localhost); aliases should be newline or space separated)."/> </span><span class="add">+ description="Optional aliases provide for name changes, alternate spellings, shorter host names, or generic host names (e.g., localhost); aliases should be newline or space separated)."/> </span><span class="cx"> </c:map-property> </c:list-property> </resource-configuration> </span> </pre> </div> </div> </body> </html> |