at.ac.tuwien.dsg.quelle.elasticityQuantification.engines.RequirementsMatchingEngine.java Source code

Java tutorial

Introduction

Here is the source code for at.ac.tuwien.dsg.quelle.elasticityQuantification.engines.RequirementsMatchingEngine.java

Source

/*
 * Copyright (c) 2013 Technische Universitat Wien (TUW), Distributed Systems Group. http://dsg.tuwien.ac.at
 *
 * This work was partially supported by the European Commission in terms of the CELAR FP7 project (FP7-ICT-2011-8 #317790), http://www.celarcloud.eu/
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package at.ac.tuwien.dsg.quelle.elasticityQuantification.engines;

import at.ac.tuwien.dsg.quelle.cloudServicesModel.concepts.CloudProvider;
import at.ac.tuwien.dsg.quelle.cloudServicesModel.concepts.ElasticityCapability;
import at.ac.tuwien.dsg.quelle.cloudServicesModel.concepts.Unit;
import at.ac.tuwien.dsg.quelle.cloudServicesModel.concepts.Quality;
import at.ac.tuwien.dsg.quelle.cloudServicesModel.concepts.Resource;
import at.ac.tuwien.dsg.quelle.cloudServicesModel.concepts.CloudOfferedService;
import at.ac.tuwien.dsg.quelle.cloudServicesModel.requirements.MultiLevelRequirements;
import at.ac.tuwien.dsg.quelle.elasticityQuantification.requirements.RequirementsResolutionResult;
import at.ac.tuwien.dsg.mela.common.monitoringConcepts.Metric;
import at.ac.tuwien.dsg.mela.common.monitoringConcepts.MetricValue;
import at.ac.tuwien.dsg.mela.common.requirements.Condition;
import at.ac.tuwien.dsg.mela.common.requirements.Requirement;
import at.ac.tuwien.dsg.mela.common.requirements.Requirements;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.EnumMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

/**
 * matches ServiceUnits with Requirements
 *
 * @Author Daniel Moldovan
 * @E-mail: d.moldovan@dsg.tuwien.ac.at
 *
 */
@Service
public class RequirementsMatchingEngine {

    static final Logger log = LoggerFactory.getLogger(RequirementsMatchingEngine.class);

    /**
     * 
     * @param cloudProviders completely described cloud providers, with units
     * @param requirements
     * @return 
     */
    public RequirementsResolutionResult analyzeMultiLevelRequirements(List<CloudProvider> cloudProviders,
            MultiLevelRequirements requirements) {
        //get all service units from the supplied cloud providers and search for match between them
        List<CloudOfferedService> serviceUnits = new ArrayList<CloudOfferedService>();
        for (CloudProvider cloudProvider : cloudProviders) {
            //            CloudProvider retrieved = CloudProviderDAO.searchForCloudProvidersUniqueResult(cloudProvider);
            if (cloudProvider != null) {
                serviceUnits.addAll(cloudProvider.getCloudOfferedServices());
            } else {
                log.warn("Retrieved CloudProvider " + cloudProvider + " has no units");
            }
        }

        //match them all in turn
        RequirementsResolutionResult requirementsResolutionResult = new RequirementsResolutionResult();

        for (MultiLevelRequirements multiLevelRequirements : requirements) {
            Collection<Requirements> requirementsGroups = multiLevelRequirements.getUnitRequirements();

            for (Requirements r : requirementsGroups) {
                for (CloudOfferedService serviceUnit : serviceUnits) {
                    ServiceUnitOptions option = analyzeServiceUnitMatching(serviceUnit, r);
                    if (option.getOverallMatched().size() > 0) {
                        requirementsResolutionResult.addMatchedOption(multiLevelRequirements, r, option);
                    }
                }
            }
        }
        return requirementsResolutionResult;
    }

    /**
     * Tries to match as many requirements on a single ServiceUnit. If the unit
     * can have multiple Optional_Associations to Quality, Resource, each
     * possible association is inspected, and the SMALLEST (in terms of
     * quality/resources) that matches the requirements is chosen (intuitively
     * this should be the cheapest) in a greedy manner. Then, for all the
     * MANDATORY service unit associations, their concrete configurations are
     * chosen, and the number of requirements that they match also reported
     *
     * 1 Requirements group means that it should be instantiated on one cloud
     * offered ServiceUnit
     *
     * @param unitToMatch
     * @param requirements
     * @return
     */
    public ServiceUnitOptions analyzeServiceUnitMatching(CloudOfferedService unitToMatch,
            Requirements requirements) {

        //hold matched requirements by type
        Map<Metric.MetricType, List<Requirement>> matchedRequirementsMap = new EnumMap<Metric.MetricType, List<Requirement>>(
                Metric.MetricType.class);
        matchedRequirementsMap.put(Metric.MetricType.RESOURCE, new ArrayList<Requirement>());
        matchedRequirementsMap.put(Metric.MetricType.COST, new ArrayList<Requirement>());
        matchedRequirementsMap.put(Metric.MetricType.QUALITY, new ArrayList<Requirement>());
        matchedRequirementsMap.put(Metric.MetricType.ELASTICITY, new ArrayList<Requirement>());

        ServiceUnitOptions serviceUnitOptions = new ServiceUnitOptions(unitToMatch);
        //        serviceUnitOptions.setMatchedRequirementsByServiceUnit(matchedRequirementsMap);
        serviceUnitOptions.setOverallUnMatched(new ArrayList<Requirement>(requirements.getRequirements()));

        if (requirements == null || unitToMatch == null) {
            return serviceUnitOptions;
        }

        //1 split requirements by type: Cost, Quality, Resource, Elasticity
        Map<Metric.MetricType, List<Requirement>> requirementsMapByType = new EnumMap<Metric.MetricType, List<Requirement>>(
                Metric.MetricType.class);

        for (Requirement requirement : requirements.getRequirements()) {
            Metric.MetricType requirementType = requirement.getMetric().getType();
            if (requirementsMapByType.containsKey(requirementType)) {
                requirementsMapByType.get(requirementType).add(requirement);
            } else {
                List<Requirement> list = new ArrayList<Requirement>();
                list.add(requirement);
                requirementsMapByType.put(requirementType, list);
            }
        }

        //2 match requirements 
        //2.1 match Resource requirements
        if (requirementsMapByType.containsKey(Metric.MetricType.RESOURCE)) {
            List<Requirement> matchedRequirements = matchedRequirementsMap.get(Metric.MetricType.RESOURCE);

            List<Requirement> resourceRequirements = requirementsMapByType.get(Metric.MetricType.RESOURCE);
            //2.1.1 match requirements on fixed resources
            for (Resource resource : unitToMatch.getResourceProperties()) {
                Map<Metric, MetricValue> resourceProperties = resource.getProperties();
                List<Requirement> requirementsMatchedForThisResource = matchRequirementsToProperties(
                        resourceProperties, resourceRequirements);
                resourceRequirements.removeAll(requirementsMatchedForThisResource);
                matchedRequirements.addAll(requirementsMatchedForThisResource);
                serviceUnitOptions.addMatchedRequirements(requirementsMatchedForThisResource);
            }

            //the rest of the unmatched requirements are matched on the optional resources, 
            //and the optional resource which matches the most requirements is selected
            //I need set cover here
            //2.1.2 match requirements on optional resources
            //first on mandatory reqs
            for (ElasticityCapability optionalResourceCapability : unitToMatch.getResourceAssociations()) {
                //get optional resources BECAUSE it is more tricky to get them
                //the  unitToMatch.getOptionalResourceAssociations() ACTUAllY returns the target of the ElasticityCharacteristic,
                //which is a generic Entity: Example Computing.
                //The ResourceDAO returns example Computing x64, Computing x86
                //                List<Resource> optionalResourcesOptions = ResourceDAO.geResourceOptionsForServiceUnitNode(unitToMatch.getId(), optionalResource.getId());
                //now match the remaining requirements on these options and sort them after how many req they fulfill
                Set<RequirementsMatchingReport<Resource>> matchingReports = matchOptionalResourceConfiguration(
                        optionalResourceCapability.getMandatoryDependencies(), resourceRequirements);
                if (!matchingReports.isEmpty()) {
                    serviceUnitOptions.addResourceOptions(optionalResourceCapability, matchingReports);

                    //remove the requirements matched by the LARGEST match
                    //get iterator next as the first in the matchingReports must be the BEST match (sorted in decreasing nr of matched policies)
                    List<Requirement> matched = matchingReports.iterator().next().matchedRequirements
                            .get(Metric.MetricType.RESOURCE);
                    serviceUnitOptions.addMatchedRequirements(matched);
                    resourceRequirements.removeAll(matched);
                }
            }

            for (ElasticityCapability optionalResourceCapability : unitToMatch.getResourceAssociations()) {
                //get optional resources BECAUSE it is more tricky to get them
                //the  unitToMatch.getOptionalResourceAssociations() ACTUAllY returns the target of the ElasticityCharacteristic,
                //which is a generic Entity: Example Computing.
                //The ResourceDAO returns example Computing x64, Computing x86
                //                List<Resource> optionalResourcesOptions = ResourceDAO.geResourceOptionsForServiceUnitNode(unitToMatch.getId(), optionalResource.getId());
                //now match the remaining requirements on these options and sort them after how many req they fulfill
                Set<RequirementsMatchingReport<Resource>> matchingReports = matchOptionalResourceConfiguration(
                        optionalResourceCapability.getOptionalDependencies(), resourceRequirements);
                if (!matchingReports.isEmpty()) {
                    serviceUnitOptions.addResourceOptions(optionalResourceCapability, matchingReports);

                    //remove the requirements matched by the LARGEST match
                    //get iterator next as the first in the matchingReports must be the BEST match (sorted in decreasing nr of matched policies)
                    List<Requirement> matched = matchingReports.iterator().next().matchedRequirements
                            .get(Metric.MetricType.RESOURCE);
                    serviceUnitOptions.addMatchedRequirements(matched);
                    resourceRequirements.removeAll(matched);
                }
            }
        }

        //2.2 match Quality requirements
        if (requirementsMapByType.containsKey(Metric.MetricType.QUALITY)) {
            List<Requirement> matchedRequirements = matchedRequirementsMap.get(Metric.MetricType.QUALITY);

            List<Requirement> qualityRequirements = requirementsMapByType.get(Metric.MetricType.QUALITY);
            //2.2.1 match requirements on fixed Quality
            for (Quality quality : unitToMatch.getQualityProperties()) {
                Map<Metric, MetricValue> properties = quality.getProperties();
                List<Requirement> requirementsMatchedForThisResource = matchRequirementsToProperties(properties,
                        qualityRequirements);
                qualityRequirements.removeAll(requirementsMatchedForThisResource);
                matchedRequirements.addAll(requirementsMatchedForThisResource);
                serviceUnitOptions.addMatchedRequirements(requirementsMatchedForThisResource);
            }

            //the rest of the unmatched requirements are matched on the optional resources, 
            //and the optional resource which matches the most requirements is selected
            //I need set cover here
            //2.2.2 match requirements on optional Quality
            //first on mandatory quality
            for (ElasticityCapability optionalQualityCapability : unitToMatch.getQualityAssociations()) {
                //now match the remaining requirements on these options and sort them after how many req they fulfill
                Set<RequirementsMatchingReport<Quality>> matchingReports = matchOptionalQualityConfiguration(
                        optionalQualityCapability.getMandatoryDependencies(), qualityRequirements);
                if (!matchingReports.isEmpty()) {
                    serviceUnitOptions.addQualityOptions(optionalQualityCapability, matchingReports);

                    //remove the requirements matched by the LARGEST match
                    List<Requirement> matched = matchingReports.iterator().next().matchedRequirements
                            .get(Metric.MetricType.QUALITY);
                    serviceUnitOptions.addMatchedRequirements(matched);
                    qualityRequirements.removeAll(matched);
                }
            }

            for (ElasticityCapability optionalQualityCapability : unitToMatch.getQualityAssociations()) {
                //now match the remaining requirements on these options and sort them after how many req they fulfill
                Set<RequirementsMatchingReport<Quality>> matchingReports = matchOptionalQualityConfiguration(
                        optionalQualityCapability.getOptionalDependencies(), qualityRequirements);
                if (!matchingReports.isEmpty()) {
                    serviceUnitOptions.addQualityOptions(optionalQualityCapability, matchingReports);

                    //remove the requirements matched by the LARGEST match
                    List<Requirement> matched = matchingReports.iterator().next().matchedRequirements
                            .get(Metric.MetricType.QUALITY);
                    serviceUnitOptions.addMatchedRequirements(matched);
                    qualityRequirements.removeAll(matched);
                }
            }
        }
        //2.3 Get all MANDATORY association ServiceUnits and check how much do they fill requirements.
        for (ElasticityCapability serviceUnitElasticityCapability : unitToMatch.getServiceUnitAssociations()) {
            Requirements r = new Requirements();
            r.setRequirements(serviceUnitOptions.getOverallUnMatched());
            for (Unit entity : serviceUnitElasticityCapability.getMandatoryDependencies()) {
                ServiceUnitOptions options = analyzeServiceUnitMatching((CloudOfferedService) entity, r);
                if (options != null) {
                    serviceUnitOptions.addMandatoryServiceUnitRaport(options);
                }
            }
        }
        //        2.4 The requirements left unmatched are matched with OptionalServiceUnit Associations
        //thus, for example, if one requires a VM with X resources, and Y IOperformance, 
        //it could get a VM which optionally could have EBS,
        if (!serviceUnitOptions.getOverallUnMatched().isEmpty()) {
            for (ElasticityCapability optionalServiceUnitElasticityCapability : unitToMatch
                    .getServiceUnitAssociations()) {
                Requirements r = new Requirements();
                r.setRequirements(serviceUnitOptions.getOverallUnMatched());
                //go and analyze each optional target from the elasticity stuff. not good though. I need to select one or the other? 
                //TODO: structure reports after ElasticityCapabilities. Example: for capability A we have Reports for units B,C,D
                for (Unit entity : optionalServiceUnitElasticityCapability.getOptionalDependencies()) {
                    ServiceUnitOptions options = analyzeServiceUnitMatching((CloudOfferedService) entity, r);
                    if (options != null) {
                        serviceUnitOptions.addOptionalServiceUnitRaport(options);
                    }
                }
            }
        }
        //        //2.5 match Cost requirements (cost needs to also include the cost of the MANDATORY associations
        //        //TODO: to be implemented (Continue)
        //        match to cost properties
        //        if (requirementsMapByType.containsKey(Metric.MetricType.COST)) {
        //            List<Requirement> matchedRequirements = matchedRequirementsMap.get(Metric.MetricType.COST);
        //            List<Requirement> costRequirements = requirementsMapByType.get(Metric.MetricType.COST);
        //
        //            List<CostFunction> costFunctions = unitToMatch.getCostFunctions();
        //
        //            for (CostFunction costFunction : unitToMatch.getCostFunctions()) {
        //                for (CostElement element : costFunction.getCostElements()) {
        //                    Metric costMetric = element.getCostMetric();
        //                    Map<MetricValue, Double> properties = element.getCostIntervalFunction();
        //
        //
        //                    List<Requirement> requirementsMatchedForThisResource = new ArrayList<Requirement>();
        //
        //                    Iterator<Requirement> requirementsIterator = costRequirements.iterator();
        //                    while (requirementsIterator.hasNext()) {
        //                        Requirement requirement = requirementsIterator.next();
        //
        //                        Metric requirementMetric = requirement.getMetric();
        //                        if (costMetric.equals(requirementMetric)) {
        //                            boolean respectsAllConditions = true;
        //
        //                            for (Condition condition : requirement.getConditions()) {
        //                                //consider we only evaluate cost, not interval
        //                                boolean conditionIsRespected = true;
        //                                for (Double d : properties.values()) {
        //                                    MetricValue costValue = new MetricValue(d);
        //                                    if (condition.isRespectedByValue(costValue)) {
        //                                        conditionIsRespected = true;
        //                                        break;
        //                                    }
        //                                }
        //                                if (!conditionIsRespected) {
        //                                    respectsAllConditions = false;
        //                                    break;
        //                                }
        //                            }
        //                            if (respectsAllConditions) {
        //                                //add requirement to matched requirements list
        //                                requirementsMatchedForThisResource.add(requirement);
        //                                //remove requirement so it is not matched again in the next searches
        //                                requirementsIterator.remove();
        //                            }
        //                        } else {
        //                            continue;
        //                        }
        //
        //                    }
        //
        //                    costRequirements.removeAll(requirementsMatchedForThisResource);
        //                    matchedRequirements.addAll(requirementsMatchedForThisResource);
        //                    serviceUnitOptions.addMatchedRequirements(requirementsMatchedForThisResource);
        //                }
        //            }
        //        }
        //
        //            //TODO: to process also cost to apply an utility in conjunction with another
        //            if (!serviceUnitOptions.getOverallUnMatched().isEmpty()) {
        //                //here I must check and apply it for quality, resource or ServiceUnit
        //
        //                for (CostFunction costFunction : unitToMatch.getCostFunctions()) {
        //                    for (Quality quality : costFunction.getAppliedInConjunctionWithQuality()) {
        //                        Map<Metric, MetricValue> properties = quality.getProperties();
        //                        List<Requirement> requirementsMatchedForThisResource = matchRequirementsToProperties(properties, qualityRequirements);
        //                        qualityRequirements.removeAll(requirementsMatchedForThisResource);
        //                        matchedRequirements.addAll(requirementsMatchedForThisResource);
        //                        serviceUnitOptions.addMatchedRequirements(requirementsMatchedForThisResource);
        //                    }
        //                }
        //
        //        }

        //2.6 match Elasticity requirements (also need to consider the MANDATORY associations, which reduce the elasticity)
        //TODO: to be implemented
        return serviceUnitOptions;
    }

    /**
     * Does set cover to match any optional configuration. Sorts the optional
     * elements after the number of matched properties
     *
     * @param unit
     * @param requirementsToMatch
     * @return
     */
    private Set<RequirementsMatchingReport<Resource>> matchOptionalResourceConfiguration(
            List<Unit> optionalConfiguration, List<Requirement> requirementsToMatch) {
        //the results will be sorted after the nr of matched stuff
        Set<RequirementsMatchingReport<Resource>> matchedReportSet = new TreeSet<RequirementsMatchingReport<Resource>>(
                new Comparator<RequirementsMatchingReport>() {
                    public int compare(RequirementsMatchingReport o1, RequirementsMatchingReport o2) {
                        Integer matched1 = o1.getMatchedResourceCountForMetricType(Metric.MetricType.RESOURCE);
                        Integer matched2 = o2.getMatchedResourceCountForMetricType(Metric.MetricType.RESOURCE);
                        return -1 * matched1.compareTo(matched2); //multiplied by -1 to have the largest number first
                    }
                });

        //1 go trough each optional Resource and match their requirements
        for (Unit entity : optionalConfiguration) {
            if (!(entity instanceof Resource)) {
                continue;
            } else {
                Resource resource = (Resource) entity;
                Map<Metric, MetricValue> resourceProperties = resource.getProperties();
                //match as many requirements to resource properties as possible
                List<Requirement> requirementsMatchedForThisResource = matchRequirementsToProperties(
                        resourceProperties, requirementsToMatch);
                //create the report entry 

                if (requirementsMatchedForThisResource.size() > 0) {
                    Map<Metric.MetricType, List<Requirement>> matchedRequirementsMap = new EnumMap<Metric.MetricType, List<Requirement>>(
                            Metric.MetricType.class);
                    matchedRequirementsMap.put(Metric.MetricType.RESOURCE, requirementsMatchedForThisResource);
                    RequirementsMatchingReport<Resource> matchingReport = new RequirementsMatchingReport<Resource>(
                            matchedRequirementsMap, resource);

                    //add report entry to the report
                    matchedReportSet.add(matchingReport);
                }
            }
        }

        return matchedReportSet;

    }

    private Set<RequirementsMatchingReport<Quality>> matchOptionalQualityConfiguration(
            List<Unit> optionalConfiguration, List<Requirement> requirementsToMatch) {
        //the results will be sorted after the nr of matched stuff
        Set<RequirementsMatchingReport<Quality>> matchedReportSet = new TreeSet<RequirementsMatchingReport<Quality>>(
                new Comparator<RequirementsMatchingReport>() {
                    public int compare(RequirementsMatchingReport o1, RequirementsMatchingReport o2) {
                        Integer matched1 = o1.getMatchedResourceCountForMetricType(Metric.MetricType.QUALITY);
                        Integer matched2 = o2.getMatchedResourceCountForMetricType(Metric.MetricType.QUALITY);
                        return -1 * matched1.compareTo(matched2); //multiplied by -1 to have the largest number first
                    }
                });

        //1 go trough each optional Resource and match their requirements
        for (Unit entity : optionalConfiguration) {
            if (!(entity instanceof Quality)) {
                continue;
            } else {
                Quality quality = (Quality) entity;
                Map<Metric, MetricValue> resourceProperties = quality.getProperties();
                //match as many requirements to resource properties as possible
                List<Requirement> requirementsMatchedForThisResource = matchRequirementsToProperties(
                        resourceProperties, requirementsToMatch);

                if (requirementsMatchedForThisResource.size() > 0) {
                    //create the report entry 
                    Map<Metric.MetricType, List<Requirement>> matchedRequirementsMap = new EnumMap<Metric.MetricType, List<Requirement>>(
                            Metric.MetricType.class);
                    matchedRequirementsMap.put(Metric.MetricType.QUALITY, requirementsMatchedForThisResource);
                    RequirementsMatchingReport<Quality> matchingReport = new RequirementsMatchingReport<Quality>(
                            matchedRequirementsMap, quality);

                    //add report entry to the report
                    matchedReportSet.add(matchingReport);
                }
            }
        }

        return matchedReportSet;

    }
    //
    //    /**
    //     * Evaluates the cost for each ServiceUnitOptions object, as it needs to
    //     * consider
    //     *
    //     * @param optionsToEvaluate
    //     * @param optionalConfiguration
    //     * @param requirementsToMatch
    //     * @return
    //     */
    //    private  Set<RequirementsMatchingReport<CostFunction>> matchOptionalCostFunctionConfiguration(ServiceUnitOptions optionsToEvaluate, List<CostFunction> optionalConfiguration, List<Requirement> requirementsToMatch) {
    ////        //the results will be sorted after the nr of matched stuff
    //        Set<RequirementsMatchingReport<CostFunction>> matchedReportSet = new TreeSet<RequirementsMatchingReport<CostFunction>>(new Comparator<RequirementsMatchingReport>() {
    //            public int compare(RequirementsMatchingReport o1, RequirementsMatchingReport o2) {
    //                Integer matched1 = o1.getMatchedResourceCountForMetricType(Metric.MetricType.COST);
    //                Integer matched2 = o2.getMatchedResourceCountForMetricType(Metric.MetricType.COST);
    //                return -1 * matched1.compareTo(matched2); //multiplied by -1 to have the largest number first
    //            }
    //        });
    //
    //
    //        //1 go trough each optional CostFunction and prune the options
    //        for (CostFunction costFunction : optionalConfiguration) {
    //            if
    //            
    //            List<Quality> appliedInConjunctionWithQuality = costFunction.getAppliedInConjunctionWithQuality();
    //            List<Resource> appliedInConjunctionWithResource = costFunction.getAppliedInConjunctionWithResource();
    //            List<ServiceUnit> appliedInConjunctionWithServiceUnit = costFunction.getAppliedInConjunctionWithServiceUnit();
    //            
    //            
    //            
    //            
    //            if () {
    //                for (CostElement costElement : costFunction.getCostElements()) {
    //                    costElement.
    //            
    //                }
    //            }
    //            Map<Metric, MetricValue> resourceProperties = resource.getProperties();
    //            //match as many requirements to resource properties as possible
    //            List<Requirement> requirementsMatchedForThisResource = matchRequirementsToProperties(resourceProperties, requirementsToMatch);
    //            //create the report entry 
    //            Map<Metric.MetricType, List<Requirement>> matchedRequirementsMap = new EnumMap<Metric.MetricType, List<Requirement>>(Metric.MetricType.class);
    //            matchedRequirementsMap.put(Metric.MetricType.RESOURCE, requirementsMatchedForThisResource);
    //            RequirementsMatchingReport<Resource> matchingReport = new RequirementsMatchingReport<Resource>(matchedRequirementsMap, resource);
    //
    //            //add report entry to the report
    //            matchedReportSet.add(matchingReport);
    //
    //        }
    //
    //        return matchedReportSet;
    //
    //
    //
    //    }

    /**
     *
     * @param propertiesToMatch
     * @param requirementsToMatch
     * @return list of matched requirements
     */
    private List<Requirement> matchRequirementsToProperties(Map<Metric, MetricValue> propertiesToMatch,
            List<Requirement> requirementsToMatch) {
        List<Requirement> matchedRequirements = new ArrayList<Requirement>();

        //used to tarverse the requirements list and remove the allready matched ones
        List<Requirement> requirements = new ArrayList<Requirement>(requirementsToMatch);

        Iterator<Requirement> requirementsIterator = requirements.iterator();
        while (requirementsIterator.hasNext()) {
            Requirement requirement = requirementsIterator.next();
            Metric requirementMetric = requirement.getMetric();

            if (propertiesToMatch.containsKey(requirementMetric)) {
                MetricValue resourcePropertyValue = propertiesToMatch.get(requirementMetric);
                boolean respectsAllConditions = true;

                for (Condition condition : requirement.getConditions()) {
                    if (!condition.isRespectedByValue(resourcePropertyValue)) {
                        respectsAllConditions = false;
                        break;
                    }
                }
                if (respectsAllConditions) {
                    //add requirement to matched requirements list
                    matchedRequirements.add(requirement);
                    //remove requirement so it is not matched again in the next searches
                    requirementsIterator.remove();
                }
            }
        }
        return matchedRequirements;

    }

    public static class RequirementsMatchingReport<T> {

        //requirements matched by type
        private Map<Metric.MetricType, List<Requirement>> matchedRequirements;
        private T matchedElement;

        public RequirementsMatchingReport() {
        }

        public RequirementsMatchingReport(Map<Metric.MetricType, List<Requirement>> matchedRequirements,
                T matchedElement) {
            this.matchedRequirements = matchedRequirements;
            this.matchedElement = matchedElement;
        }

        public Map<Metric.MetricType, List<Requirement>> getMatchedRequirements() {
            return matchedRequirements;
        }

        public T getConcreteConfiguration() {
            return matchedElement;
        }

        public Integer getMatchedResourceCountForMetricType(Metric.MetricType metricType) {
            if (this.matchedRequirements.containsKey(metricType)) {
                return this.matchedRequirements.get(metricType).size();
            } else {
                return 0;
            }
        }

        @Override
        public String toString() {
            String description = "RequirementsMatchingReport:\n";
            for (Metric.MetricType key : matchedRequirements.keySet()) {
                description += "For requirements: " + key + " matched " + matchedRequirements.get(key).size()
                        + "\n";
            }

            //apoi optional configs nu ai de unde sa stii
            description += matchedElement.toString();
            return description;
        }
    }
}