sim.model.entity.Category.java Source code

Java tutorial

Introduction

Here is the source code for sim.model.entity.Category.java

Source

/*
 * BehaviorSim - version 1.0 
 * 
 * Copyright (C) 2010 The BehaviorSim Development Team, fasheng@cs.gsu.edu.
 * 
 * 
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option) any later
 * version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 * Place, Suite 330, Boston, MA 02111-1307 USA
 * 
 * 
 * Info, Questions, Suggestions & Bugs Report to fasheng@cs.gsu.edu.
 *  
 */

package sim.model.entity;

import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.Toolkit;
import java.awt.image.FilteredImageSource;
import java.awt.image.ImageFilter;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JComponent;

import org.apache.commons.beanutils.BeanUtils;

import sim.util.MessageUtils;
import sim.util.MethodUtils;

/**
 * The entity category wrappers. It is the supper class of all categories in the
 * system.
 * 
 * <p>
 * Each category has two fixed properties: Category Name and Category Icon
 * </p>
 * 
 * <p>
 * The category name should be unique!!!
 * </p>
 * 
 * @author Fasheng Qiu
 * @version 1.0
 */
public class Category extends Entity {

    // Category name
    private String name;

    // Category properties, used in the navigation tree panel
    // The value of the properties can be changed by the user
    private List properties = null;

    // Category methods
    private List methods = null;

    /**
     * A deep copy of this category object to the specified category object.
     * 
     * <p>
     * The purpose of this method is to provide a state copy for the cooperative
     * action selection mechanism, where each action will produce a "new" state
     * of the category. To avoid the "new" state affects the original state, a
     * copied category is used to perform the action.
     * </p>
     * 
     * <p>
     * <strong>FIXME</strong> DO WE NEED TO COPY methods ? DOES THE EXCUTED
     * ACTION AT EACH TIME STEP AFFECT THESE TWO PROPERTIES?
     * </p>
     * 
     * @param category
     *            The category who gets the states of this category
     */
    public void copyTo(Category category) {
        if (category == null)
            return;
        super.copyTo(category);
        category.name = this.name;

        // Default: the methods are not copied, suppose that
        // it will never be changed after the execution of all behaviors.
        category.properties.clear();
        category.properties.addAll(this.getProperties());
        // category.methods.clear();
        // category.methods.addAll(this.properties);
    }

    /**
     * Initialize the category and register the category name and iconPath
     * 
     */
    public Category() {
        super();
        properties = new ArrayList();
        methods = new ArrayList();
    }

    /**
     * Register a property for further referenced
     * 
     * @param p
     *            The category property
     */
    public void registerPropertyName(Property p) {
        properties.add(p);
    }

    /**
     * Register a bunch of properties for further referenced
     * 
     * @param p
     *            The category property list
     */
    public void registerProperties(List p) {
        if (p != null && p.size() > 0) {
            properties.addAll(p);
        }
    }

    /**
     * Obtain all properties (not populated with property values)
     * 
     * @return All properties
     */
    public List getProperties() {
        List copy = new ArrayList(properties.size());
        for (int i = 0; i < properties.size(); i++) {
            copy.add(((Property) properties.get(i)).copy());
        }
        return copy;
    }

    /**
     * <p>
     * Determine the type of the specified property.
     * </p>
     * <p>
     * First, query the property list and find that property.
     * </p>
     * <p>
     * Then, return the type of the property.
     * </p>
     * 
     * <p>
     * If no property of the specified name is found, then -1 is returned to
     * indicate that the specified name does not exist as a category property.
     * </p>
     * 
     * @param name
     *            The property name
     * @return The type of the property
     */
    public int getPropertyType(String propertyName) {
        for (int i = 0; i < properties.size(); i++) {
            Property p = (Property) properties.get(i);
            if (p.name.equals(propertyName)) {
                return p.type;
            }
        }
        return -1;
    }

    /**
     * Return all properties, including property name, property type and
     * property value.
     * 
     * @return All registered properties
     */
    public List getAllProperties() {
        List p = new ArrayList(properties.size());
        for (int i = 0; i < properties.size(); i++) {
            Property temp = ((Property) properties.get(i)).copy();
            try {
                temp.value = MethodUtils.invokeExactField(this, temp.name);
            } catch (Exception e) {
                e.printStackTrace();
            }
            p.add(temp);
        }
        return p;
    }

    /**
     * Return a copy of all properties, values of which are those defined in
     * CategoryDefinePanel.
     * 
     * @return A copy of all properties.
     */
    public List getOriginalProperties() {
        return getProperties();

    }

    /**
     * System called initialization.It is called before the simulation
     * calculation. It is supposed to be only used internally.
     * 
     * <p>
     * Here the values of user-defined properties are reset to the initial
     * values.
     * </p>
     */
    public void _initInternal() {
        for (int i = 0; i < properties.size(); i++) {
            Property property = (Property) properties.get(i);
            try {
                MethodUtils.invokeSetField(this, property.name, property.value);
            } catch (Exception e) {
            }
        }
    }

    /**
     * <p>
     * Invoke the category and set the specified property to its new value.
     * <p>
     * 
     * <p>
     * This method uses java reflect to set the property value. It assumes that
     * except the properties "name", all the other properties are declared in
     * the subclass, and thus they can be set by the direct field access.
     * <p>
     * 
     * <p>
     * This method also set the value by different types, see
     * {@link #getPropertyType(String propertyName)}.
     * </p>
     * 
     * @param propertyName
     *            The property name to be set
     * @param propertyValue
     *            The property value
     * @throws Exception
     *             If the property value can not be set properly.
     */
    public void updateProperty(String propertyName, String propertyValue) throws Exception {
        if (propertyName.equals("name")) {
            this.setEntityType(propertyValue);
        } else {
            Object propertyV = propertyValue;
            int type = this.getPropertyType(propertyName);
            if (type == PropertyType.NUMBER) {
                try {
                    propertyV = new Double(propertyValue);
                } catch (Exception e) {
                    MessageUtils.debug(this, "updateProperty", e);
                    MessageUtils.displayError("The property value: " + propertyV
                            + " is incorrect according to the pre-set property type!");
                    return;
                }
            }
            MethodUtils.invokeSetField(this, propertyName, propertyV);
        }
    }

    /**
     * Update the initial value for the specified property. The initial value is
     * reset before each simulation iteration.
     * 
     * @param propertyName
     *            The name of the property to set the initial value
     * @param propertyValue
     *            The new initial value of the property
     */
    public void updatePropertyInitial(String propertyName, Object propertyValue) {
        for (int i = 0; i < properties.size(); i++) {
            Property property = (Property) properties.get(i);
            if (property.name.equals(propertyName))
                property.value = propertyValue;
        }
    }

    /**
     * Register a method for further reference.
     * 
     * <p>
     * This method can only be called after the method is compiled successfully.
     * It is generally called by the <code>DynamicManager</code> {@link #sim.configure.dclass.DynamicManager}.
     * </p>
     * 
     * @param m
     *            The method to register
     * @throws IllegalStateException
     *             When the method to add is not compiled successfully
     */
    public void registerMethod(CMethod m) {
        if (m != null && m.transSuccess) {
            this.methods.add(m);
            return;
        }
        throw new IllegalStateException("The method '" + m.name + "' is not compiled successfully!");
    }

    /**
     * Update the method definition. The name of the old method and the new
     * method is the same.
     * 
     * @param newMethod
     *            The new method instance
     */
    public void updateMethod(CMethod newMethod) {
        if (newMethod == null)
            return;
        for (int i = 0; i < methods.size(); i++) {
            if (((CMethod) methods.get(i)).name.equals(newMethod.name.trim())) {
                methods.set(i, newMethod);
                break;
            }
        }
    }

    /**
     * Return all user-defined methods for further reference
     * 
     * @return all user-defined methods for further reference
     */
    public List getAllMethods() {
        return new ArrayList(this.methods);
    }

    /**
     * Register a bunch of methods for this category
     * 
     * @param methods
     *            The method list to register
     */
    public void registerMethods(List methods) {
        if (methods == null)
            return;
        for (int i = 0; i < methods.size(); i++) {
            this.registerMethod((CMethod) methods.get(i));
        }
    }

    /**
     * Remove all property definitions
     */
    public void removeProperties() {
        this.properties.clear();
    }

    /**
     * Remove all method definitions
     */
    public void removeMethods() {
        this.methods.clear();
    }

    /**
     * The initialization method, should be called before the category can
     * function
     * 
     * @param c
     *            The component used to load the image, usually it is
     *            SystemEditorPanel
     * @param name
     *            The name of the category
     * @param iconPath
     *            The icon image path of the category
     */
    public void init(JComponent c, String name, String iconPath) {
        /** Set the name and icon path */
        this.name = name;
        /** Initialize internal states if any */
        init();
        /** Prepare entity image */
        prepareEntityImage(c, iconPath);
    }

    /**
     * Prepare the entity image
     */
    protected void prepareEntityImage(JComponent c, String path) {
        // Prepare the entity image
        super.prepareEntityImage(c, path);
        // Adjust the image
        ImageFilter filter = new WhiteFilter();
        FilteredImageSource filteredImage = new FilteredImageSource(display.getImage().getSource(), filter);
        Image image = Toolkit.getDefaultToolkit().createImage(filteredImage);
        MediaTracker tracker = new MediaTracker(c);
        try {
            tracker.addImage(image, 0);
            tracker.waitForAll();
        } catch (InterruptedException e) {
        }
        display.setImage(image);
        display.setImagePath(path);
    }

    /**
     * To setup the current action to be executed and/or prepare other
     * pre-requirements (such as setting variable).
     * 
     * <p>
     * The user should implement this method to implement the choice mechanism
     * of current action to be executed.
     * </p>
     * 
     * <p>
     * An example would be: if (some conditions) {
     * setAction(getAction("categoryName", "actionName")); } else if (...) { ...
     * ... ... ... } where categoryName is the name of the category when it is
     * defined and actionName is the name of the action when it is defined.
     * </p>
     */
    protected void preprocess() {
    }

    /**
     * Copy the internal states from this entity to the specified entity.
     * 
     * <p>
     * All fields and user-defined properties are copied. The fields are copied
     * using <code>org.apache.commons.beanutils.BeanUtils.</code> and the
     * user-defined properties are copied using <code>MethodUtils</code>
     * </p>
     * 
     * @param toEntity
     *            The entity which gets the states of this entity
     * @throws Exception
     *             if copy is not successfully.
     */
    public void copyState(Entity toEntity) throws Exception {
        try {
            BeanUtils.copyProperties(toEntity, this);
        } catch (Exception e) {
            e.printStackTrace();
            MessageUtils.debug(this, "copyState", e);
            throw new RuntimeException(
                    "The internal states of the two-version entities can not be copied from one to the other.");
        }
        // The initial values of user-defined properties
        ((Category) toEntity).properties.clear();
        ((Category) toEntity).registerProperties(getProperties());
        // Set the current value of each property on the target entity
        for (int i = 0; i < properties.size(); i++) {
            Property temp = (Property) properties.get(i);
            try {
                Object value = MethodUtils.invokeExactField(this, temp.name);
                MethodUtils.invokeSetField(toEntity, temp.name, value);
            } catch (NoSuchFieldException e) {
                ;// MessageUtils.debug(this, "copyState", e);
            }
        }
    }

    /**
     * return type of this entity
     */
    public String getEntityType() {
        return this.name;
    }

    /**
     * Set the name of this entity
     * 
     * @param name
     *            The name of this entity
     */
    public void setEntityType(String name) {
        this.name = name;
    }

}