private Stats getLastCallTimeCollection(
      String requestName, Map<String, Map<String, Number>> fallbackValues, long fallbackStartTime)
      throws IOException {

    File dataFile = new File(context.getResourceDataDirectory(), requestName);
    if (!dataFile.exists()) {
      return Stats.fromMap(
          fallbackValues, requestName, System.currentTimeMillis(), fallbackStartTime);
    } else {
      ObjectInputStream in = null;
      try {
        in = new ObjectInputStream(new FileInputStream(dataFile));

        Stats stats = (Stats) in.readObject();
        if (stats.serverStartTime == 0) {
          // we might get serverStartTime == 0 if the datafile comes from the old version of the
          // plugin
          // in that case just fallback to the old behavior that assumed no server restarts.
          // After that we save the new version of the stats with the start time remembered and we
          // will
          // switch to the new correct behavior from the next collection.
          stats.serverStartTime = fallbackStartTime;
        }

        return stats;
      } catch (IOException e) {
        throw new IOException(
            "Couldn't read the stored calltime data from file " + dataFile + ".", e);
      } catch (ClassNotFoundException e) {
        throw new IllegalStateException("Couldn't find plugin API classes. This is serious!", e);
      } finally {
        StreamUtil.safeClose(in);
      }
    }
  }
  @Override
  public void getValues(MeasurementReport report, Set<MeasurementScheduleRequest> metrics)
      throws Exception {
    // we'll handling the rest of the metrics using the super method, but we may leave out some of
    // the requests
    // if we handle them here. Right now, just use the obtained set. We only create a copy of the
    // (unmodifiable) set
    // of requests if necessary.
    Set<MeasurementScheduleRequest> metricsToPassDown = metrics;

    for (MeasurementScheduleRequest request : metrics) {
      if (request.getDataType() == DataType.CALLTIME) {
        ensureGlobalEJB3StatisticsEnabled();
        // make a copy to pass down to super class if necessary
        if (metricsToPassDown == metrics) {
          metricsToPassDown = new HashSet<MeasurementScheduleRequest>(metrics);
        }

        metricsToPassDown.remove(request);

        // handle this ourselves
        // the name of the metric is actually the name of the stat collected for each method. we
        // then provide
        // the calltime data for each method.

        Result result = getASConnection().execute(new ReadAttribute(address, METHODS_ATTRIBUTE));
        Object value = result.getResult();
        if (value instanceof Map) {
          @SuppressWarnings("unchecked")
          Map<String, Map<String, Number>> allMethodStats =
              (Map<String, Map<String, Number>>) value;

          if (allMethodStats.isEmpty()) {
            continue;
          }

          // first we need to know since when the values were collected
          result =
              getASConnection()
                  .execute(new ReadAttribute(RUNTIME_MBEAN_ADDRESS, START_TIME_ATTRIBUTE));
          long serverStartTime = (Long) result.getResult();

          // now process the calltime value
          String requestedMetric = request.getName().substring(CALLTIME_METRIC_NAME_PREFIX_LENGTH);

          Stats lastCollection =
              getLastCallTimeCollection(requestedMetric, allMethodStats, serverStartTime);
          Stats thisCollection =
              Stats.fromMap(
                  allMethodStats, requestedMetric, System.currentTimeMillis(), serverStartTime);

          CallTimeData callTime = new CallTimeData(request);

          fillCallTimeData(callTime, thisCollection, lastCollection);

          saveCallTimeCollection(requestedMetric, thisCollection);

          report.addData(callTime);
        } else {
          OSGiVersion currentAsVersion = getASVersion();
          if (currentAsVersion == null) {
            getLog()
                .warn(
                    "Could not determine the AS version while reporting unexpected result of method"
                        + " stats. Request: "
                        + request);
          } else if (FIRST_VERSION_SUPPORTING_METHOD_STATS.compareTo(currentAsVersion) <= 0) {
            getLog()
                .error(
                    "Unexpected type of results when querying method stats for measurement request "
                        + request
                        + ". Expected map but got "
                        + (value == null ? "null" : value.getClass().getName()));
          }
        }
      }
    }

    super.getValues(report, metricsToPassDown);
  }