All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.drools.planner.core.domain.solution.SolutionDescriptor Maven / Gradle / Ivy

Go to download

Drools Planner optimizes automated planning by combining metaheuristic search algorithms with rule engine powered score calculation. This is the drools-planner-core module which contains metaheuristic algorithms.

There is a newer version: 6.0.0.Alpha9
Show newest version
/*
 * Copyright 2011 JBoss Inc
 *
 * 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 org.drools.planner.core.domain.solution;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.drools.planner.api.domain.solution.PlanningEntityCollectionProperty;
import org.drools.planner.api.domain.solution.PlanningEntityProperty;
import org.drools.planner.core.domain.common.DescriptorUtils;
import org.drools.planner.core.domain.entity.PlanningEntityDescriptor;
import org.drools.planner.core.solution.Solution;

public class SolutionDescriptor {

    private final Class solutionClass;
    private final BeanInfo solutionBeanInfo;
    
    private final Map propertyDescriptorMap;
    private final Map entityPropertyDescriptorMap;
    private final Map entityCollectionPropertyDescriptorMap;

    private final Map, PlanningEntityDescriptor> planningEntityDescriptorMap;

    public SolutionDescriptor(Class solutionClass) {
        this.solutionClass = solutionClass;
        try {
            solutionBeanInfo = Introspector.getBeanInfo(solutionClass);
        } catch (IntrospectionException e) {
            throw new IllegalStateException("The solutionClass (" + solutionClass + ") is not a valid java bean.", e);
        }
        int mapSize = solutionBeanInfo.getPropertyDescriptors().length;
        propertyDescriptorMap = new HashMap(mapSize);
        entityPropertyDescriptorMap = new HashMap(mapSize);
        entityCollectionPropertyDescriptorMap = new HashMap(mapSize);
        planningEntityDescriptorMap = new HashMap, PlanningEntityDescriptor>(mapSize);
    }

    public void processAnnotations() {
        processPropertyAnnotations();
    }

    private void processPropertyAnnotations() {
        boolean noPlanningEntityPropertyAnnotation = true;
        for (PropertyDescriptor propertyDescriptor : solutionBeanInfo.getPropertyDescriptors()) {
            propertyDescriptorMap.put(propertyDescriptor.getName(), propertyDescriptor);
            Method propertyGetter = propertyDescriptor.getReadMethod();
            if (propertyGetter != null) {
                if (propertyGetter.isAnnotationPresent(PlanningEntityProperty.class)) {
                    noPlanningEntityPropertyAnnotation = false;
                    entityPropertyDescriptorMap.put(propertyDescriptor.getName(), propertyDescriptor);
                } else if (propertyGetter.isAnnotationPresent(PlanningEntityCollectionProperty.class)) {
                    noPlanningEntityPropertyAnnotation = false;
                    if (!Collection.class.isAssignableFrom(propertyDescriptor.getPropertyType())) {
                        throw new IllegalStateException("The solutionClass (" + solutionClass
                                + ") has a PlanningEntityCollection annotated property ("
                                + propertyDescriptor.getName() + ") that does not return a Collection.");
                    }
                    entityCollectionPropertyDescriptorMap.put(propertyDescriptor.getName(), propertyDescriptor);
                }
            }
        }
        if (noPlanningEntityPropertyAnnotation) {
            throw new IllegalStateException("The solutionClass (" + solutionClass
                    + ") should have at least 1 getter with a PlanningEntityCollection or PlanningEntityProperty"
                    + " annotation.");
        }
    }

    public Class getSolutionClass() {
        return solutionClass;
    }

    public PropertyDescriptor getPropertyDescriptor(String propertyName) {
        return propertyDescriptorMap.get(propertyName);
    }

    public void addPlanningEntityDescriptor(PlanningEntityDescriptor planningEntityDescriptor) {
        planningEntityDescriptorMap.put(planningEntityDescriptor.getPlanningEntityClass(), planningEntityDescriptor);
    }

    public Set> getPlanningEntityImplementationClassSet() {
        return planningEntityDescriptorMap.keySet();
    }

    public Collection getPlanningEntityDescriptors() {
        return planningEntityDescriptorMap.values();
    }

    public boolean hasPlanningEntityDescriptor(Class planningEntityImplementationClass) {
        PlanningEntityDescriptor planningEntityDescriptor = null;
        Class planningEntityClass = planningEntityImplementationClass;
        while (planningEntityClass != null) {
            planningEntityDescriptor = planningEntityDescriptorMap.get(planningEntityClass);
            if (planningEntityDescriptor != null) {
                return true;
            }
            planningEntityClass = planningEntityClass.getSuperclass();
        }
        return false;
    }

    public PlanningEntityDescriptor getPlanningEntityDescriptor(Class planningEntityImplementationClass) {
        PlanningEntityDescriptor planningEntityDescriptor = null;
        Class planningEntityClass = planningEntityImplementationClass;
        while (planningEntityClass != null) {
            planningEntityDescriptor = planningEntityDescriptorMap.get(planningEntityClass);
            if (planningEntityDescriptor != null) {
                return planningEntityDescriptor;
            }
            planningEntityClass = planningEntityClass.getSuperclass();
        }
        throw new IllegalArgumentException("A planningEntity is an instance of a planningEntityImplementationClass ("
                + planningEntityImplementationClass + ") that is not configured as a planningEntity.\n" +
                "If that class (" + planningEntityImplementationClass.getSimpleName() + ") is not a " +
                "planningEntityClass (or subclass thereof), check your Solution implementation's annotated methods.\n" +
                "If it is, check your solver configuration.");
    }

    public Collection getAllFacts(Solution solution) {
        Collection facts = new ArrayList();
        facts.addAll(solution.getProblemFacts());
        for (PropertyDescriptor entityPropertyDescriptor : entityPropertyDescriptorMap.values()) {
            Object entity = extractPlanningEntity(entityPropertyDescriptor, solution);
            if (entity != null) {
                PlanningEntityDescriptor planningEntityDescriptor = getPlanningEntityDescriptor(entity.getClass());
                if (planningEntityDescriptor.isInitialized(entity)) {
                    facts.add(entity);
                }
            }
        }
        for (PropertyDescriptor entityCollectionPropertyDescriptor : entityCollectionPropertyDescriptorMap.values()) {
            Collection entityCollection = extractPlanningEntityCollection(
                    entityCollectionPropertyDescriptor, solution);
            for (Object entity : entityCollection) {
                PlanningEntityDescriptor planningEntityDescriptor = getPlanningEntityDescriptor(entity.getClass());
                if (planningEntityDescriptor.isInitialized(entity)) {
                    facts.add(entity);
                }
            }
        }
        return facts;
    }

    public List getPlanningEntityList(Solution solution) {
        List planningEntityList = new ArrayList();
        for (PropertyDescriptor entityPropertyDescriptor : entityPropertyDescriptorMap.values()) {
            Object entity = extractPlanningEntity(entityPropertyDescriptor, solution);
            if (entity != null) {
                planningEntityList.add(entity);
            }
        }
        for (PropertyDescriptor entityCollectionPropertyDescriptor : entityCollectionPropertyDescriptorMap.values()) {
            Collection entityCollection = extractPlanningEntityCollection(
                    entityCollectionPropertyDescriptor, solution);
            planningEntityList.addAll(entityCollection);
        }
        return planningEntityList;
    }

    public List getPlanningEntityListByPlanningEntityClass(Solution solution, Class planningEntityClass) {
        List planningEntityList = new ArrayList();
        for (PropertyDescriptor entityPropertyDescriptor : entityPropertyDescriptorMap.values()) {
            if (entityPropertyDescriptor.getPropertyType().isAssignableFrom(planningEntityClass)) {
                Object entity = extractPlanningEntity(entityPropertyDescriptor, solution);
                if (entity != null && planningEntityClass.isInstance(entity)) {
                    planningEntityList.add(entity);
                }
            }
        }
        for (PropertyDescriptor entityCollectionPropertyDescriptor : entityCollectionPropertyDescriptorMap.values()) {
            // TODO if (entityCollectionPropertyDescriptor.getPropertyType().getElementType().isAssignableFrom(planningEntityClass)) {
            Collection entityCollection = extractPlanningEntityCollection(
                    entityCollectionPropertyDescriptor, solution);
            for (Object entity : entityCollection) {
                if (planningEntityClass.isInstance(entity)) {
                    planningEntityList.add(entity);
                }
            }
        }
        return planningEntityList;
    }

    /**
     * @param solution never null
     * @return >= 0
     */
    public int getPlanningEntityCount(Solution solution) {
        return getPlanningEntityList(solution).size();
    }

    /**
     * Calculates an indication on how big this problem instance is.
     * This is intentionally very loosely defined for now.
     * @param solution never null
     * @return >= 0
     */
    public long getProblemScale(Solution solution) {
        long problemScale = 0L;
        for (PropertyDescriptor entityPropertyDescriptor : entityPropertyDescriptorMap.values()) {
            Object entity = extractPlanningEntity(entityPropertyDescriptor, solution);
            if (entity != null) {
                PlanningEntityDescriptor planningEntityDescriptor = getPlanningEntityDescriptor(entity.getClass());
                problemScale += planningEntityDescriptor.getProblemScale(solution, entity);
            }
        }
        for (PropertyDescriptor entityCollectionPropertyDescriptor : entityCollectionPropertyDescriptorMap.values()) {
            Collection entityCollection = extractPlanningEntityCollection(
                    entityCollectionPropertyDescriptor, solution);
            for (Object entity : entityCollection) {
                PlanningEntityDescriptor planningEntityDescriptor = getPlanningEntityDescriptor(entity.getClass());
                problemScale += planningEntityDescriptor.getProblemScale(solution, entity);
            }
        }
        return problemScale;
    }

    /**
     * @param solution never null
     * @return true if all the planning entities are initialized
     */
    public boolean isInitialized(Solution solution) {
        for (PropertyDescriptor entityPropertyDescriptor : entityPropertyDescriptorMap.values()) {
            Object entity = extractPlanningEntity(entityPropertyDescriptor, solution);
            if (entity == null) {
                return false;
            }
            PlanningEntityDescriptor planningEntityDescriptor = getPlanningEntityDescriptor(entity.getClass());
            if (!planningEntityDescriptor.isInitialized(entity)) {
                return false;
            }
        }
        for (PropertyDescriptor entityCollectionPropertyDescriptor : entityCollectionPropertyDescriptorMap.values()) {
            Collection entityCollection = extractPlanningEntityCollection(
                    entityCollectionPropertyDescriptor, solution);
            for (Object entity : entityCollection) {
                PlanningEntityDescriptor planningEntityDescriptor = getPlanningEntityDescriptor(entity.getClass());
                if (!planningEntityDescriptor.isInitialized(entity)) {
                    return false;
                }
            }
        }
        return true;
    }

    private Object extractPlanningEntity(PropertyDescriptor entityPropertyDescriptor, Solution solution) {
        return DescriptorUtils.executeGetter(entityPropertyDescriptor, solution);
    }

    private Collection extractPlanningEntityCollection(
            PropertyDescriptor entityCollectionPropertyDescriptor, Solution solution) {
        Collection entityCollection = (Collection)
                DescriptorUtils.executeGetter(entityCollectionPropertyDescriptor, solution);
        if (entityCollection == null) {
            throw new IllegalArgumentException("The solutionClass (" + solutionClass
                    + ")'s entityCollectionProperty ("
                    + entityCollectionPropertyDescriptor.getName() + ") should never return null.");
        }
        return entityCollection;
    }

}