Package org.drools.planner.core.domain.solution

Source Code of org.drools.planner.core.domain.solution.SolutionDescriptor

/*
* 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.domain.variable.PlanningVariableDescriptor;
import org.drools.planner.core.solution.Solution;

public class SolutionDescriptor {

    private final Class<? extends Solution> solutionClass;
    private final BeanInfo solutionBeanInfo;
   
    private final Map<String, PropertyDescriptor> propertyDescriptorMap;
    private final Map<String, PropertyDescriptor> entityPropertyDescriptorMap;
    private final Map<String, PropertyDescriptor> entityCollectionPropertyDescriptorMap;

    private final Map<Class<?>, PlanningEntityDescriptor> planningEntityDescriptorMap;

    public SolutionDescriptor(Class<? extends Solution> 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<String, PropertyDescriptor>(mapSize);
        entityPropertyDescriptorMap = new HashMap<String, PropertyDescriptor>(mapSize);
        entityCollectionPropertyDescriptorMap = new HashMap<String, PropertyDescriptor>(mapSize);
        planningEntityDescriptorMap = new HashMap<Class<?>, 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 void addPlanningEntityDescriptor(PlanningEntityDescriptor planningEntityDescriptor) {
        planningEntityDescriptorMap.put(planningEntityDescriptor.getPlanningEntityClass(), planningEntityDescriptor);
    }

    public Class<? extends Solution> getSolutionClass() {
        return solutionClass;
    }

    // ************************************************************************
    // Model methods
    // ************************************************************************

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

    public Set<Class<?>> getPlanningEntityClassSet() {
        return planningEntityDescriptorMap.keySet();
    }

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

    public boolean hasPlanningEntityDescriptorStrict(Class<?> planningEntityClass) {
        return planningEntityDescriptorMap.containsKey(planningEntityClass);
    }

    public PlanningEntityDescriptor getPlanningEntityDescriptorStrict(Class<?> planningEntityClass) {
        return planningEntityDescriptorMap.get(planningEntityClass);
    }

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

    public PlanningEntityDescriptor getPlanningEntityDescriptor(Class<?> planningEntitySubclass) {
        PlanningEntityDescriptor planningEntityDescriptor = null;
        Class<?> planningEntityClass = planningEntitySubclass;
        while (planningEntityClass != null) {
            planningEntityDescriptor = planningEntityDescriptorMap.get(planningEntityClass);
            if (planningEntityDescriptor != null) {
                return planningEntityDescriptor;
            }
            planningEntityClass = planningEntityClass.getSuperclass();
        }
        // TODO move this into the client methods
        throw new IllegalArgumentException("A planningEntity is an instance of a planningEntitySubclass ("
                + planningEntitySubclass + ") that is not configured as a planningEntity.\n" +
                "If that class (" + planningEntitySubclass.getSimpleName() + ") (or superclass thereof) is not a " +
                "planningEntityClass (" + getPlanningEntityClassSet()
                + "), check your Solution implementation's annotated methods.\n" +
                "If it is, check your solver configuration.");
    }
   
    public Collection<PlanningVariableDescriptor> getChainedVariableDescriptors() {
        Collection<PlanningVariableDescriptor> chainedVariableDescriptors
                = new ArrayList<PlanningVariableDescriptor>();
        for (PlanningEntityDescriptor entityDescriptor : planningEntityDescriptorMap.values()) {
            for (PlanningVariableDescriptor variableDescriptor : entityDescriptor.getPlanningVariableDescriptors()) {
                if (variableDescriptor.isChained()) {
                    chainedVariableDescriptors.add(variableDescriptor);
                }
            }
        }
        return chainedVariableDescriptors;
    }

    // ************************************************************************
    // Extraction methods
    // ************************************************************************

    public Collection<Object> getAllFacts(Solution solution) {
        Collection<Object> facts = new ArrayList<Object>();
        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<Object> getPlanningEntityList(Solution solution) {
        List<Object> planningEntityList = new ArrayList<Object>();
        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<Object> getPlanningEntityListByPlanningEntityClass(Solution solution, Class<?> planningEntityClass) {
        List<Object> planningEntityList = new ArrayList<Object>();
        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) {
                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;
    }

    @Override
    public String toString() {
        return getClass().getSimpleName() + "(" + solutionClass.getName() + ")";
    }

}
TOP

Related Classes of org.drools.planner.core.domain.solution.SolutionDescriptor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.