private DirectNetworkUsageAnswer getPublicIpBytesSentAndReceived(DirectNetworkUsageCommand cmd)
      throws ExecutionException {
    DirectNetworkUsageAnswer answer = new DirectNetworkUsageAnswer(cmd);

    try {
      // Direct Network Usage
      URL trafficSentinel;
      try {
        // Query traffic Sentinel
        trafficSentinel =
            new URL(
                _url
                    + "/inmsf/Query?script="
                    + URLEncoder.encode(
                        getScript(cmd.getPublicIps(), cmd.getStart(), cmd.getEnd()), "UTF-8")
                    + "&authenticate=basic&resultFormat=txt");

        BufferedReader in = new BufferedReader(new InputStreamReader(trafficSentinel.openStream()));

        String inputLine;

        while ((inputLine = in.readLine()) != null) {
          // Parse the script output
          StringTokenizer st = new StringTokenizer(inputLine, ",");
          if (st.countTokens() == 3) {
            String publicIp = st.nextToken();
            Long bytesSent = new Long(st.nextToken());
            Long bytesRcvd = new Long(st.nextToken());
            if (bytesSent == null || bytesRcvd == null) {
              s_logger.debug("Incorrect bytes for IP: " + publicIp);
            }
            long[] bytesSentAndReceived = new long[2];
            bytesSentAndReceived[0] = bytesSent;
            bytesSentAndReceived[1] = bytesRcvd;
            answer.put(publicIp, bytesSentAndReceived);
          }
        }
        in.close();
      } catch (MalformedURLException e1) {
        s_logger.info("Invalid Traffic Sentinel URL", e1);
        throw new ExecutionException(e1.getMessage());
      } catch (IOException e) {
        s_logger.debug("Error in direct network usage accounting", e);
        throw new ExecutionException(e.getMessage());
      }
    } catch (Exception e) {
      s_logger.debug(e);
      throw new ExecutionException(e.getMessage());
    }
    return answer;
  }
    private boolean collectDirectNetworkUsage(HostVO host) {
      s_logger.debug("Direct Network Usage stats collector is running...");

      long zoneId = host.getDataCenterId();
      DetailVO lastCollectDetail = _detailsDao.findDetail(host.getId(), "last_collection");
      if (lastCollectDetail == null) {
        s_logger.warn(
            "Last collection time not available. Skipping direct usage collection for Traffic Monitor: "
                + host.getId());
        return false;
      }
      Date lastCollection = new Date(new Long(lastCollectDetail.getValue()));

      // Get list of IPs currently allocated
      List<IPAddressVO> allocatedIps = listAllocatedDirectIps(zoneId);
      Calendar rightNow = Calendar.getInstance();

      // Allow 2 hours for traffic sentinel to populate historical traffic
      // This coule be made configurable

      rightNow.add(Calendar.HOUR_OF_DAY, -2);
      Date now = rightNow.getTime();

      if (lastCollection.after(now)) {
        s_logger.debug(
            "Current time is less than 2 hours after last collection time : "
                + lastCollection.toString()
                + ". Skipping direct network usage collection");
        return false;
      }

      // Get IP Assign/Release events from lastCollection time till now
      List<UsageEventVO> IpEvents = _eventDao.listDirectIpEvents(lastCollection, now, zoneId);

      Map<String, Date> ipAssigment = new HashMap<String, Date>();
      List<UsageIPAddressVO> IpPartialUsage =
          new ArrayList<
              UsageIPAddressVO>(); // Ips which were allocated only for the part of collection
                                   // duration
      List<UsageIPAddressVO> fullDurationIpUsage =
          new ArrayList<
              UsageIPAddressVO>(); // Ips which were allocated only for the entire collection
                                   // duration

      // Use UsageEvents to track the IP assignment
      // Add them to IpUsage list with account_id , ip_address, alloc_date, release_date

      for (UsageEventVO IpEvent : IpEvents) {
        String address = IpEvent.getResourceName();
        if (EventTypes.EVENT_NET_IP_ASSIGN.equals(IpEvent.getType())) {
          ipAssigment.put(address, IpEvent.getCreateDate());
        } else if (EventTypes.EVENT_NET_IP_RELEASE.equals(IpEvent.getType())) {
          if (ipAssigment.containsKey(address)) {
            Date assigned = ipAssigment.get(address);
            ipAssigment.remove(address);
            IpPartialUsage.add(
                new UsageIPAddressVO(
                    IpEvent.getAccountId(), address, assigned, IpEvent.getCreateDate()));
          } else {
            // Ip was assigned prior to lastCollection Date
            IpPartialUsage.add(
                new UsageIPAddressVO(
                    IpEvent.getAccountId(), address, lastCollection, IpEvent.getCreateDate()));
          }
        }
      }

      List<String> IpList = new ArrayList<String>();
      for (IPAddressVO ip : allocatedIps) {
        if (ip.getAllocatedToAccountId() == AccountVO.ACCOUNT_ID_SYSTEM) {
          // Ignore usage for system account
          continue;
        }
        String address = (ip.getAddress()).toString();
        if (ipAssigment.containsKey(address)) {
          // Ip was assigned during the current period but not release till Date now
          IpPartialUsage.add(
              new UsageIPAddressVO(
                  ip.getAllocatedToAccountId(), address, ipAssigment.get(address), now));
        } else {
          // Ip was not assigned or released during current period. Consider entire duration for
          // usage calculation (lastCollection to now)
          fullDurationIpUsage.add(
              new UsageIPAddressVO(ip.getAllocatedToAccountId(), address, lastCollection, now));
          // Store just the Ips to send the list as part of DirectNetworkUsageCommand
          IpList.add(address);
        }
      }

      List<UserStatisticsVO> collectedStats = new ArrayList<UserStatisticsVO>();

      // Get usage for Ips which were assigned for the entire duration
      if (fullDurationIpUsage.size() > 0) {
        DirectNetworkUsageCommand cmd =
            new DirectNetworkUsageCommand(IpList, lastCollection, now, _TSinclZones, _TSexclZones);
        DirectNetworkUsageAnswer answer =
            (DirectNetworkUsageAnswer) _agentMgr.easySend(host.getId(), cmd);
        if (answer == null || !answer.getResult()) {
          String details = (answer != null) ? answer.getDetails() : "details unavailable";
          String msg =
              "Unable to get network usage stats from "
                  + host.getId()
                  + " due to: "
                  + details
                  + ".";
          s_logger.error(msg);
          return false;
        } else {
          for (UsageIPAddressVO usageIp : fullDurationIpUsage) {
            String publicIp = usageIp.getAddress();
            long[] bytesSentRcvd = answer.get(publicIp);
            Long bytesSent = bytesSentRcvd[0];
            Long bytesRcvd = bytesSentRcvd[1];
            if (bytesSent == null || bytesRcvd == null) {
              s_logger.debug("Incorrect bytes for IP: " + publicIp);
              continue;
            }
            if (bytesSent == 0L && bytesRcvd == 0L) {
              s_logger.trace("Ignore zero bytes for IP: " + publicIp);
              continue;
            }
            UserStatisticsVO stats =
                new UserStatisticsVO(usageIp.getAccountId(), zoneId, null, null, null, null);
            stats.setCurrentBytesSent(bytesSent);
            stats.setCurrentBytesReceived(bytesRcvd);
            collectedStats.add(stats);
          }
        }
      }

      // Get usage for Ips which were assigned for part of the duration period
      for (UsageIPAddressVO usageIp : IpPartialUsage) {
        IpList = new ArrayList<String>();
        IpList.add(usageIp.getAddress());
        DirectNetworkUsageCommand cmd =
            new DirectNetworkUsageCommand(
                IpList, usageIp.getAssigned(), usageIp.getReleased(), _TSinclZones, _TSexclZones);
        DirectNetworkUsageAnswer answer =
            (DirectNetworkUsageAnswer) _agentMgr.easySend(host.getId(), cmd);
        if (answer == null || !answer.getResult()) {
          String details = (answer != null) ? answer.getDetails() : "details unavailable";
          String msg =
              "Unable to get network usage stats from "
                  + host.getId()
                  + " due to: "
                  + details
                  + ".";
          s_logger.error(msg);
          return false;
        } else {
          String publicIp = usageIp.getAddress();
          long[] bytesSentRcvd = answer.get(publicIp);
          Long bytesSent = bytesSentRcvd[0];
          Long bytesRcvd = bytesSentRcvd[1];
          if (bytesSent == null || bytesRcvd == null) {
            s_logger.debug("Incorrect bytes for IP: " + publicIp);
            continue;
          }
          if (bytesSent == 0L && bytesRcvd == 0L) {
            s_logger.trace("Ignore zero bytes for IP: " + publicIp);
            continue;
          }
          UserStatisticsVO stats =
              new UserStatisticsVO(usageIp.getAccountId(), zoneId, null, null, null, null);
          stats.setCurrentBytesSent(bytesSent);
          stats.setCurrentBytesReceived(bytesRcvd);
          collectedStats.add(stats);
        }
      }

      if (collectedStats.size() == 0) {
        s_logger.debug("No new direct network stats. No need to persist");
        return false;
      }
      // Persist all the stats and last_collection time in a single transaction
      Transaction txn = Transaction.open(Transaction.CLOUD_DB);
      try {
        txn.start();
        for (UserStatisticsVO stat : collectedStats) {
          UserStatisticsVO stats =
              _statsDao.lock(
                  stat.getAccountId(),
                  stat.getDataCenterId(),
                  0L,
                  null,
                  host.getId(),
                  "DirectNetwork");
          if (stats == null) {
            stats =
                new UserStatisticsVO(
                    stat.getAccountId(), zoneId, null, host.getId(), "DirectNetwork", 0L);
            stats.setCurrentBytesSent(stat.getCurrentBytesSent());
            stats.setCurrentBytesReceived(stat.getCurrentBytesReceived());
            _statsDao.persist(stats);
          } else {
            stats.setCurrentBytesSent(stats.getCurrentBytesSent() + stat.getCurrentBytesSent());
            stats.setCurrentBytesReceived(
                stats.getCurrentBytesReceived() + stat.getCurrentBytesReceived());
            _statsDao.update(stats.getId(), stats);
          }
        }
        lastCollectDetail.setValue("" + now.getTime());
        _detailsDao.update(lastCollectDetail.getId(), lastCollectDetail);
        txn.commit();
      } finally {
        txn.close();
      }

      return true;
    }