Skip to content
This repository has been archived by the owner on Nov 9, 2017. It is now read-only.

Commit

Permalink
HAWKULAR-487 Reorg collected traits so that they can be reasonably
Browse files Browse the repository at this point in the history
displayed
  • Loading branch information
ppalaga committed Jul 26, 2015
1 parent d36c887 commit 946ac84
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 99 deletions.
115 changes: 59 additions & 56 deletions modules/pinger/src/main/java/org/hawkular/component/pinger/Traits.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeSet;

import org.apache.http.Header;
Expand All @@ -45,7 +43,6 @@ public class Traits {
public enum TraitHeader {
SERVER("server"), X_ASPNET_VERSION("x-aspnet-version"),
X_POWERED_BY("x-powered-by"),
X_RUNTIME("x-runtime"),
X_VERSION("x-version");

private static final Map<String, TraitHeader> index;
Expand Down Expand Up @@ -84,8 +81,7 @@ public String toString() {
}
}

/** An empty map to use for {@link #items} */
private static final Map<TraitHeader, String> NO_ITEMS = Collections.emptyMap();
private static final String ASP_NET = "ASP.NET";

/**
* Collects the traits from the given {@link HttpResponse}.
Expand All @@ -98,12 +94,10 @@ public String toString() {
* @return a new {@link Traits}
*/
public static Traits collect(HttpResponse httpResponse, long timestamp, InetAddress remoteAddress) {
/* We assume that the header keys will typically be unique
* Therefore, we store the value into items Map on first hit
* and only if there is a second hit, we lazily create a sorted Set in multiItems.
*/
Map<TraitHeader, String> items = null;
Map<TraitHeader, Set<String>> multiItems = null;

TreeSet<String> xPoweredBy = null;
StringBuilder poweredByBuilder = new StringBuilder();
boolean hasAspNet = false;

HeaderIterator headers = httpResponse.headerIterator();
while (headers.hasNext()) {
Expand All @@ -113,48 +107,57 @@ public static Traits collect(HttpResponse httpResponse, long timestamp, InetAddr
if (traitHeader != null) {
Log.LOG.tracef("Found a trait header: %s:%s from %s", header.getName(), header.getValue(),
remoteAddress);
if (items == null) {
items = new HashMap<>();
items.put(traitHeader, header.getValue());
} else {
String value = items.get(traitHeader);
if (value == null) {
/* no value so far - this is the first hit of the present key */
items.put(traitHeader, header.getValue());
} else {
/* value available - let's fall back to the multiValues map */
if (multiItems == null) {
multiItems = new HashMap<>();
}
Set<String> multiValues = multiItems.get(traitHeader);
if (multiValues == null) {
multiValues = new TreeSet<>();
multiValues.add(value);
multiItems.put(traitHeader, multiValues);

switch (traitHeader) {
case SERVER:
if (poweredByBuilder.length() != 0) {
/* multiple server headers do not make much sense, but let us be prepared */
poweredByBuilder.append(", ");
}
poweredByBuilder.append(header.getValue());
break;
case X_POWERED_BY:
String powBy = header.getValue();
if (xPoweredBy == null) {
xPoweredBy = new TreeSet<>();
}
if (ASP_NET.equals(powBy)) {
if (!hasAspNet) {
xPoweredBy.add(powBy);
}
multiValues.add(header.getValue());
hasAspNet = true;
} else {
xPoweredBy.add(powBy);
}
break;
case X_ASPNET_VERSION:
if (hasAspNet) {
xPoweredBy.remove(ASP_NET);
}
if (xPoweredBy == null) {
xPoweredBy = new TreeSet<>();
}
xPoweredBy.add(ASP_NET +"/"+ header.getValue());
break;
default:
break;
}

}
}

if (multiItems != null) {
/* Lets serialize the entries in multiItems and put them back to items. */
for (Entry<TraitHeader, Set<String>> en : multiItems.entrySet()) {
StringBuilder sb = new StringBuilder();
for (String item : en.getValue()) {
if (sb.length() > 0) {
sb.append(", ");
}
sb.append(item);
/* server was added to poweredByBuilder already
* now lets add the x-powered-by items in alphabetic order */
if (xPoweredBy != null) {
for (String val : xPoweredBy) {
if (poweredByBuilder.length() != 0) {
poweredByBuilder.append(", ");
}
items.put(TraitHeader.X_POWERED_BY, sb.toString());
poweredByBuilder.append(val);
}
}

return new Traits(timestamp, remoteAddress, items == null ? Collections.emptyMap()
: Collections.unmodifiableMap(items));
return new Traits(timestamp, remoteAddress,
poweredByBuilder.length() == 0 ? null : poweredByBuilder.toString());
};

/**
Expand All @@ -164,11 +167,11 @@ public static Traits collect(HttpResponse httpResponse, long timestamp, InetAddr
* @return a new {@link Traits} with the given {@code timestamp} and no {@link #items}
*/
public static Traits empty(long timestamp) {
return new Traits(timestamp, null, NO_ITEMS);
return new Traits(timestamp, null, null);
}

/** The header name - header value map storing the traits */
private final Map<TraitHeader, String> items;
/** A comma separated list of "powered by" items */
private final String poweredBy;

/** The remote IP address that replied to the ping, can be {@code null} */
private final InetAddress remoteAddress;
Expand All @@ -184,18 +187,18 @@ public static Traits empty(long timestamp) {
*
* @see #collect(HttpResponse, long)
*/
Traits(long timestamp, InetAddress remoteAddress, Map<TraitHeader, String> items) {
Traits(long timestamp, InetAddress remoteAddress, String poweredBy) {
super();
this.timestamp = timestamp;
this.remoteAddress = remoteAddress;
this.items = items;
this.poweredBy = poweredBy;
}

/**
* @return an unmodifiable {@link Map} of trait headers
* @return a comma separated list of "powered by" items
*/
public Map<TraitHeader, String> getItems() {
return items;
public String getPoweredBy() {
return poweredBy;
}

/**
Expand Down Expand Up @@ -229,10 +232,10 @@ public boolean equals(Object obj) {
return false;
} else if (!remoteAddress.equals(other.remoteAddress))
return false;
if (items == null) {
if (other.items != null)
if (poweredBy == null) {
if (other.poweredBy != null)
return false;
} else if (!items.equals(other.items))
} else if (!poweredBy.equals(other.poweredBy))
return false;
return true;
}
Expand All @@ -242,7 +245,7 @@ public boolean equals(Object obj) {
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((items == null) ? 0 : items.hashCode());
result = prime * result + ((poweredBy == null) ? 0 : poweredBy.hashCode());
result = prime * result + (int) (timestamp ^ (timestamp >>> 32));
result = prime * result + ((remoteAddress == null) ? 0 : remoteAddress.hashCode());
return result;
Expand All @@ -251,7 +254,7 @@ public int hashCode() {
/** @see java.lang.Object#toString() */
@Override
public String toString() {
return "Traits [items=" + items + ", timestamp=" + timestamp + ", remoteAddress=" + remoteAddress + "]";
return "Traits [poweredBy=" + poweredBy + ", timestamp=" + timestamp + ", remoteAddress=" + remoteAddress + "]";
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,10 @@
package org.hawkular.component.pinger;

import java.net.InetAddress;
import java.util.Map.Entry;

import javax.ejb.Asynchronous;
import javax.ejb.Stateless;

import org.hawkular.component.pinger.Traits.TraitHeader;
import org.hawkular.inventory.api.EntityNotFoundException;
import org.hawkular.inventory.api.Inventory;
import org.hawkular.inventory.api.Resources;
Expand Down Expand Up @@ -73,8 +71,9 @@ public void publish(PingStatus status) {
if (remoteAddress != null) {
updateBuilder.withProperty(TRAIT_PROPERTY_PREFIX + "remote-address", remoteAddress.getHostAddress());
}
for (Entry<TraitHeader, String> entry : traits.getItems().entrySet()) {
updateBuilder.withProperty(TRAIT_PROPERTY_PREFIX + entry.getKey().toString(), entry.getValue());
String poweredBy = traits.getPoweredBy();
if (poweredBy != null) {
updateBuilder.withProperty(TRAIT_PROPERTY_PREFIX + "powered-by", poweredBy);
}

inventory.tenants().get(dest.getTenantId()).environments().get(dest.getEnvironmentId()).feedlessResources()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,12 @@
*/
package org.hawkular.component.pinger;

import java.util.Map;

import org.hawkular.component.pinger.Traits.TraitHeader;
import org.hawkular.inventory.api.model.Resource;
import org.junit.Assert;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;

import com.google.common.collect.ImmutableMap;

/**
* Simple test for the pinger
*
Expand All @@ -52,26 +47,25 @@ public void testScheduleWork() throws Exception {

PingDestination expectedDest = PingerTestUtils.createTestPingDestination();

Map<TraitHeader, String> expectedTraitsItems = new ImmutableMap.Builder<TraitHeader, String>().put(
TraitHeader.SERVER, "GitHub.com").build();
String expectedPoweredBy = "GitHub.com";

ArgumentCaptor<PingStatus> metricsRestStatusCaptor = ArgumentCaptor.forClass(PingStatus.class);
Mockito.verify(manager.metricPublisher).sendToMetricsViaRest(metricsRestStatusCaptor.capture());
assertStatus(expectedDest, expectedTraitsItems, metricsRestStatusCaptor.getValue());
assertStatus(expectedDest, expectedPoweredBy, metricsRestStatusCaptor.getValue());

ArgumentCaptor<PingStatus> metricsStatusCaptor = ArgumentCaptor.forClass(PingStatus.class);
Mockito.verify(manager.metricPublisher).publishToTopic(metricsStatusCaptor.capture());
assertStatus(expectedDest, expectedTraitsItems, metricsStatusCaptor.getValue());
assertStatus(expectedDest, expectedPoweredBy, metricsStatusCaptor.getValue());

ArgumentCaptor<PingStatus> traitsStatusCaptor = ArgumentCaptor.forClass(PingStatus.class);
Mockito.verify(manager.traitsPublisher).publish(traitsStatusCaptor.capture());
assertStatus(expectedDest, expectedTraitsItems, traitsStatusCaptor.getValue());
assertStatus(expectedDest, expectedPoweredBy, traitsStatusCaptor.getValue());

}

private static void assertStatus(PingDestination expectedDest, Map<TraitHeader, String> expectedTraitsItems,
private static void assertStatus(PingDestination expectedDest, String expectedPoweredBy,
PingStatus foundStatus) {
Assert.assertEquals(expectedDest, foundStatus.getDestination());
Assert.assertEquals(expectedTraitsItems, foundStatus.getTraits().getItems());
Assert.assertEquals(expectedPoweredBy, foundStatus.getTraits().getPoweredBy());
}
}

0 comments on commit 946ac84

Please sign in to comment.