/**
   * Called by MetricsRecordImpl.update(). Creates or updates a row in the internal table of metric
   * data.
   */
  protected void update(MetricsRecord record) {
    String recordName = record.getRecordName();
    TagMap tagTable = record.getTagTable();
    Map<String, MetricValue> metricUpdates = record.getMetricTable();

    RecordMap recordMap = getRecordMap(recordName);
    synchronized (recordMap) {
      MetricMap metricMap = recordMap.get(tagTable);
      if (metricMap == null) {
        metricMap = new MetricMap();
        TagMap tagMap = new TagMap(tagTable); // clone tags
        recordMap.put(tagMap, metricMap);
      }
      for (String metricName : metricUpdates.keySet()) {
        MetricValue updateValue = metricUpdates.get(metricName);
        Number updateNumber = updateValue.getNumber();
        Number currentNumber = metricMap.get(metricName);
        if (currentNumber == null || updateValue.isAbsolute()) {
          metricMap.put(metricName, updateNumber);
        } else {
          Number newNumber = sum(updateNumber, currentNumber);
          metricMap.put(metricName, newNumber);
        }
      }
    }
  }
 /**
  * This gathers more information about a host than is available by querying the host list table
  * directly.
  *
  * @param host The host to populate with more information
  * @param items The data items to enrich the host with
  * @return The host object with more information attached.
  */
 private Host fullyDescribeHost(Host host, Collection<MetricValue> items) {
   for (MetricValue item : items) {
     if (item.getKey().equals(MEMORY_TOTAL_KPI_NAME)) { // Convert to Mb
       // Original value given in bytes. 1024 * 1024 = 1048576
       host.setRamMb((int) (item.getValue() / 1048576));
     }
     if (item.getKey().equals(DISK_TOTAL_KPI_NAME)) { // Convert to Mb
       // Original value given in bytes. 1024 * 1024 * 1024 = 1073741824
       host.setDiskGb((item.getValue() / 1073741824));
     }
   }
   return host;
 }
 /**
  * This gathers more information about a vm than is available by querying the host list table
  * directly.
  *
  * @param vm The vm to populate with more information
  * @param items The data for a given vm.
  * @return The vm object with more information attached.
  */
 private VmDeployed fullyDescribeVM(VmDeployed vm, Collection<MetricValue> items) {
   for (MetricValue item : items) {
     if (item.getKey().equals(MEMORY_TOTAL_KPI_NAME)) { // Convert to Mb
       // Original value given in bytes. 1024 * 1024 = 1048576
       vm.setRamMb((int) (Double.valueOf(item.getValue()) / 1048576));
     }
     if (item.getKey().equals(DISK_TOTAL_KPI_NAME)) { // covert to Gb
       // Original value given in bytes. 1024 * 1024 * 1024 = 1073741824
       vm.setDiskGb((Double.valueOf(item.getValue()) / 1073741824));
     }
     if (item.getKey().equals(BOOT_TIME_KPI_NAME)) {
       Calendar cal = new GregorianCalendar();
       // This converts from milliseconds into the correct time value
       cal.setTimeInMillis(TimeUnit.SECONDS.toMillis(Long.valueOf(item.getValueAsString())));
       vm.setCreated(cal);
     }
     if (item.getKey().equals(VM_PHYSICAL_HOST_NAME)) {
       vm.setAllocatedTo(getHostByName(item.getValueAsString()));
     }
     if (item.getKey().equals(CPU_COUNT_KPI_NAME)) {
       vm.setCpus(Integer.valueOf(item.getValueAsString()));
     }
     // TODO set the information correctly below!
     vm.setIpAddress("127.0.0.1");
     vm.setState("Work in Progress");
   }
   // A fall back incase the information is not available!
   if (vm.getCpus() == 0) {
     vm.setCpus(Integer.valueOf(1));
   }
   return vm;
 }