/**
   * Tries to create a new slice on this instance.
   *
   * @param reqType the type describing the hardware characteristics of the slice
   * @param jobID the ID of the job the new slice belongs to
   * @return a new {@AllocatedSlice} object if a slice with the given hardware characteristics could
   *     still be accommodated on this instance or <code>null</code> if the instance's remaining
   *     resources were insufficient to host the desired slice
   */
  synchronized AllocatedSlice createSlice(final InstanceType reqType, final JobID jobID) {

    // check whether we can accommodate the instance
    if (remainingCapacity.getNumberOfComputeUnits() >= reqType.getNumberOfComputeUnits()
        && remainingCapacity.getNumberOfCores() >= reqType.getNumberOfCores()
        && remainingCapacity.getMemorySize() >= reqType.getMemorySize()
        && remainingCapacity.getDiskCapacity() >= reqType.getDiskCapacity()) {

      // reduce available capacity by what has been requested
      remainingCapacity =
          InstanceTypeFactory.construct(
              remainingCapacity.getIdentifier(),
              remainingCapacity.getNumberOfComputeUnits() - reqType.getNumberOfComputeUnits(),
              remainingCapacity.getNumberOfCores() - reqType.getNumberOfCores(),
              remainingCapacity.getMemorySize() - reqType.getMemorySize(),
              remainingCapacity.getDiskCapacity() - reqType.getDiskCapacity(),
              remainingCapacity.getPricePerHour());

      final long allocationTime = System.currentTimeMillis();

      final AllocatedSlice slice = new AllocatedSlice(this, reqType, jobID, allocationTime);
      this.allocatedSlices.put(slice.getAllocationID(), slice);
      return slice;
    }

    // we cannot accommodate the instance
    return null;
  }
  /**
   * Reads the instance types configured in the config file. Each instance type is defined by a
   * key/value pair. The format of the key is <code>instancemanager.cluster.type.X</code> where X is
   * an ongoing integer number starting at 1. The format of the value follows the pattern
   * "instancename,numComputeUnits,numCores,memorySize,diskCapacity,pricePerHour" (see {@link
   * InstanceType}).
   *
   * @return list of available instance types sorted by price (cheapest to most expensive)
   */
  private InstanceType[] populateInstanceTypeArray() {

    final List<InstanceType> instanceTypes = new ArrayList<InstanceType>();

    // read instance types
    int count = 1;
    while (true) {

      final String key = INSTANCE_TYPE_PREFIX_KEY + Integer.toString(count);
      String descr = GlobalConfiguration.getString(key, null);

      if (descr == null) {
        if (count == 1) {
          LOG.info(
              "Configuration does not contain at least one definition for an instance type, "
                  + "using default instance type: "
                  + ConfigConstants.DEFAULT_INSTANCE_TYPE);

          descr = ConfigConstants.DEFAULT_INSTANCE_TYPE;
        } else {
          break;
        }
      }

      // parse entry
      try {
        // if successful add new instance type
        final InstanceType instanceType = InstanceTypeFactory.constructFromDescription(descr);
        LOG.info(
            "Loaded instance type " + instanceType.getIdentifier() + " from the configuration");
        instanceTypes.add(instanceType);
      } catch (Throwable t) {
        LOG.error(
            "Error parsing "
                + key
                + ":"
                + descr
                + ". Using default using default instance type: "
                + ConfigConstants.DEFAULT_INSTANCE_TYPE
                + " for instance type "
                + count
                + ".",
            t);

        break;
      }

      // Increase key index
      ++count;
    }

    return instanceTypes.toArray(new InstanceType[instanceTypes.size()]);
  }
  /**
   * Removes the slice identified by the given allocation ID from this instance and frees up the
   * allocated resources.
   *
   * @param allocationID the allocation ID of the slice to be removed
   * @return the slice with has been removed from the instance or <code>null</code> if no slice with
   *     the given allocation ID could be found
   */
  synchronized AllocatedSlice removeAllocatedSlice(final AllocationID allocationID) {

    final AllocatedSlice slice = this.allocatedSlices.remove(allocationID);
    if (slice != null) {

      this.remainingCapacity =
          InstanceTypeFactory.construct(
              this.remainingCapacity.getIdentifier(),
              this.remainingCapacity.getNumberOfComputeUnits()
                  + slice.getType().getNumberOfComputeUnits(),
              this.remainingCapacity.getNumberOfCores() + slice.getType().getNumberOfCores(),
              this.remainingCapacity.getMemorySize() + slice.getType().getMemorySize(),
              this.remainingCapacity.getDiskCapacity() + slice.getType().getDiskCapacity(),
              this.remainingCapacity.getPricePerHour());
    }

    return slice;
  }