package org.limewire.core.impl.inspections;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.zip.GZIPInputStream;
import org.limewire.bittorrent.bencoding.Token;
import org.limewire.io.InvalidDataException;
import org.limewire.logging.Log;
import org.limewire.logging.LogFactory;
/**
* inspections communicator encapsulates individual inspection results
*
* map
* "t" -> 173627467343
* "i" -> list
* map0
* "k" -> "inspection point1"
* "d" -> Map
* "data point1" -> Map<String, Object>, ... primitive
* "data_point2" -> Map<String, whatever>...
* "data_point3" -> 3
*
* map1
* "k" -> "inspection point2"
* "d" -> Map
* "data pointA" -> Map<String, Object>, ... primitive
* "data_pointB" -> Map<String, whatever>...
* "data_pointC" -> 3
* map2 ...
*
*/
public class InspectionDataContainer {
private static final Log LOG = LogFactory.getLog(InspectionDataContainer.class);
/**
* Map of inspection keys to inspection data.
*/
private final Map<String, Object> inspectionResults = new ConcurrentHashMap<String, Object>();
/**
* Timestamp of when the inspection data in this class was collected.
*/
private final long collectionTimestamp;
/**
* Creates with current timestamp, no inspections results
*/
public InspectionDataContainer() {
this(System.currentTimeMillis());
}
/**
* Creates with timestamp parameter, no inspections results
*
* @param collectionTimestamp milliseconds since epoch
*/
public InspectionDataContainer(long collectionTimestamp) {
this.collectionTimestamp = collectionTimestamp;
}
/**
* Creates this object by decoding wire protocol data
* (bencoded and gzipped bytes)
*
* @param bencodedGzipBytes BEncoded and gzipped bytes
* @throws InvalidDataException if input byte[] contains invalid data
*/
public InspectionDataContainer(byte[] bencodedGzipBytes) throws InvalidDataException {
ByteArrayInputStream bais = new ByteArrayInputStream(bencodedGzipBytes);
try {
GZIPInputStream gzip = new GZIPInputStream(bais);
ReadableByteChannel rbc = Channels.newChannel(gzip);
Map<?, ?> containerMap = (Map<?, ?>) Token.parse(rbc, "UTF-8");
this.collectionTimestamp = (Long)containerMap.get("t");
List<?> listOfInspectionMaps = (List<?>)containerMap.get("i");
for (Object inspDataContainer : listOfInspectionMaps) {
Map<?, ?> inspDataContainerMap = (Map<?, ?>)inspDataContainer;
String inspKey = new String((byte[])inspDataContainerMap.get("k"));
Object inspDataMap = inspDataContainerMap.get("d");
addInspectionResult(inspKey, inspDataMap);
}
} catch (IOException e) {
LOG.debugf(e, "Error in parsing bytes into inspection data");
throw new InvalidDataException(e);
} catch (ClassCastException e) {
LOG.debugf(e, "Invalid encoding in data");
throw new InvalidDataException(e);
}
}
Map<String, Object> asBencodedMap() {
Map<String, Object> bencodingMap = new HashMap<String, Object>();
List<Map<String, Object>> inspPointsMapList = new ArrayList<Map<String, Object>>();
bencodingMap.put("t", collectionTimestamp);
bencodingMap.put("i", inspPointsMapList);
for (Map.Entry<String, Object> entry : inspectionResults.entrySet()) {
Map<String, Object> inspKeyAndData = new HashMap<String, Object>();
inspKeyAndData.put("k", entry.getKey());
inspKeyAndData.put("d", entry.getValue());
inspPointsMapList.add(inspKeyAndData);
}
return bencodingMap;
}
/**
* Add inspection result data.
*
* @param key String identifying inspection point.
* @param inspectionData bencodable inspection data.
*/
public void addInspectionResult(String key, Object inspectionData) {
inspectionResults.put(key, inspectionData);
}
long getTimestamp() {
return collectionTimestamp;
}
Object getData(String key) {
return inspectionResults.get(key);
}
int getResultCount() {
return inspectionResults.size();
}
}