il.ac.technion.datacenter.sla.TableSLA.java Source code

Java tutorial

Introduction

Here is the source code for il.ac.technion.datacenter.sla.TableSLA.java

Source

/**
 * Greedy_Recovery - Technion, Israel Institute of Technology
 * 
 * Author: Assaf Israel, 2012
 * Created: 12/03/2012
 */
package il.ac.technion.datacenter.sla;

import il.ac.technion.misc.PeriodConverter;

import java.util.Iterator;
import java.util.Map;
import java.util.Random;
import java.util.Set;

import org.joda.time.Period;

import com.google.java.contract.Requires;
import com.thoughtworks.xstream.annotations.XStreamAlias;

/**
 * Custom Implementation of Service License Agreement. Configurable from XML
 * files, validated by sla.xsd
 */
@XStreamAlias("tableSLA")
public class TableSLA extends SLA {

    private Map<Range, Double> compensationTable;
    private double contractAvailability;
    private static Random coin = new Random(System.currentTimeMillis());

    @Requires({ "billingPeriod != null", "compensationTable != null" })
    public TableSLA(Period billingPeriod, Map<Range, Double> compensationTable) {
        super(billingPeriod);
        if (billingPeriod.equals(Period.ZERO))
            throw new IllegalArgumentException("SLA definition must have a non-empty billing period");
        if (!verifyTable(compensationTable))
            throw new IllegalArgumentException("Invalid compensationTable");
        this.compensationTable = compensationTable;
        this.contractAvailability = findRange(100.0, compensationTable.keySet()).left;
    }

    @Override
    public double availabilityContract() {
        return contractAvailability;
    }

    @Override
    @Requires("estimatedDownTime != null")
    public double compensation(Period estimatedDownTime) {
        double availability = availability(estimatedDownTime);
        Range r = null;
        if (availability != 0.0)
            r = findRange(availability);
        else
            r = getLowestRange();
        return compensationTable.get(r);
    }

    private Range getLowestRange() {
        return getLowestRange(compensationTable.keySet());
    }

    private Range findRange(double availability) {
        return findRange(availability, compensationTable.keySet());
    }

    @Override
    public double compensation() {
        return compensation(Period.ZERO);
    }

    private boolean verifyTable(Map<Range, Double> cTable) {
        double rValue = 100.0;
        double lastCompensation = 0.0;

        Range startRange = findRange(rValue, cTable.keySet());
        if (startRange == null || cTable.get(startRange) != 0.0)
            return false;

        while (rValue > 0.0) {
            if (rangeCount(rValue, cTable.keySet()) > 1)
                return false; // Ranges overlaping
            Range range = findRange(rValue, cTable.keySet());
            if (range == null) {
                return false;
            }
            rValue = range.left;
            double compensationPerc = cTable.get(range);
            if (100 >= compensationPerc && compensationPerc >= lastCompensation) {
                lastCompensation = compensationPerc;
                continue;
            }
            return false;
        }
        return rValue == 0.0;
    }

    private int rangeCount(double value, Set<Range> ranges) {
        int count = 0;
        for (Range range : ranges) {
            if (range.inRange(value)) {
                ++count;
            }
        }
        return count;
    }

    public Range getLowestRange(Set<Range> ranges) {
        Range $ = null;
        for (Range range : ranges) {
            if ($ == null || $.left > range.left)
                $ = range;
        }
        return $;
    }

    private Range findRange(double value, Set<Range> ranges) {
        for (Range range : ranges) {
            if (range.inRange(value)) {
                return range;
            }
        }
        return null;
    }

    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof TableSLA))
            return false;
        TableSLA sla = (TableSLA) obj;
        if (!sla.compensationTable.equals(this.compensationTable)
                || sla.contractAvailability != this.contractAvailability)
            return false;
        return true;
    }

    @Override
    @Requires("old(noise) <= 1.0 && old(noise) >= 0")
    public Period addRandomDowntime(double noise) {
        Iterator<Range> iter = new RangeIterator(compensationTable.keySet());
        Range r = iter.next();
        while (iter.hasNext()) {
            if (coin.nextDouble() >= noise)
                break;
            r = iter.next();
        }
        double downTimePerc = 100.0 - (coin.nextDouble() * r.size + r.left);
        long downtimeInMillis = (long) (PeriodConverter.toMillis(billingPeriod) * (downTimePerc / 100.0));
        Period $ = new Period(downtimeInMillis);
        reportDownTime($);
        return $;
    }

    /**
     * Range iterator, starting from the highest range to the lower.
     * Ranges must be mutually exclusive and complete.
     */
    private class RangeIterator implements Iterator<Range> {

        private Set<Range> ranges;
        private Range current = null;
        private Range next = null;

        public RangeIterator(Set<Range> ranges) {
            this.ranges = ranges;
            next = getHighestRange();
        }

        public Range getHighestRange() {
            Range $ = null;
            for (Range range : ranges) {
                if ($ == null || $.right < range.right)
                    $ = range;
            }
            return $;
        }

        public Range findRange(double value) {
            for (Range range : ranges) {
                if (range.inRange(value)) {
                    return range;
                }
            }
            return null;
        }

        @Override
        public boolean hasNext() {
            return next != null;
        }

        @Override
        public Range next() {
            current = next;
            if (next != null) {
                next = findRange(current.left);
            }
            return current;
        }

        @Override
        public void remove() {
            if (current != null) {
                ranges.remove(current);
            }
        }
    }
}