ca.sfu.federation.model.InputTable.java Source code

Java tutorial

Introduction

Here is the source code for ca.sfu.federation.model.InputTable.java

Source

/**
 * 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
 */

package ca.sfu.federation.model;

import ca.sfu.federation.ApplicationContext;
import ca.sfu.federation.model.annotations.Update;
import ca.sfu.federation.model.exception.DuplicatePropertyException;
import ca.sfu.federation.model.exception.ParameterCountMismatchException;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.lang.exception.ExceptionUtils;

/**
 * A table to hold input arguments for an update method. Arguments are stored
 * and retrieved in the same order they appear in the update method signature.
 * @author Davis Marques
 */
public class InputTable extends Observable implements Serializable {

    private static final Logger logger = Logger.getLogger(InputTable.class.getName());

    private ArrayList inputs = new ArrayList(); // the inputs, in order
    private String description; // description of the update method
    private INamed parent; // the parent object
    private boolean primed; // all inputs have the required user input values

    //--------------------------------------------------------------------------

    /**
     * InputTable constructor.
     * @param Parent The parent object.
     */
    public InputTable(INamed Parent) {
        this.description = "";
        this.parent = Parent;
    }

    //--------------------------------------------------------------------------

    /**
     * Add a property to the table.
     * @param Name Input name.
     * @param Description Input description.
     * @param Clazz Input class.
     * @throws DuplicatePropertyException A property with the same name already exists in the table.
     */
    private void addInput(String Name, String Description, Class Clazz) throws DuplicatePropertyException {
        // create the new input
        Input myInput = new Input(Name, Description, Clazz, this.parent.getContext());
        // add the input to the list and index
        String name = myInput.getName();
        LinkedHashMap index = this.getInputIndex();
        if (!index.containsKey(name)) {
            this.inputs.add(myInput);
        } else {
            throw new DuplicatePropertyException();
        }
    }

    /**
     * Clear all automatically generated inputs.
     */
    public void clearInputs() {
        this.inputs.clear();
    }

    /**
     * Generate inputs for the UpdateMethod.
     * TODO: need to add a description field in the update annotation to describe each method parameter
     * @param UpdateMethod The update method.
     * @throws ParameterCountMismatchException The number of parameters in the Update annotation does not correspond with the number of parameters in the Update method signature.
     */
    public void generateInputs(Method UpdateMethod) throws ParameterCountMismatchException {
        // clear the current inputs
        this.inputs.clear();
        // get method properties
        Update updateAnnotation = UpdateMethod.getAnnotation(Update.class);
        this.description = updateAnnotation.description();
        String[] param = updateAnnotation.parameter();
        Class[] type = UpdateMethod.getParameterTypes();
        // if the number of parameters in the method signature matches the number of parameters in the annotation
        if (param.length == type.length) {
            // for each parameter, add an input to the table
            for (int i = 0; i < param.length; i++) {
                try {
                    this.addInput(param[i], "Input description pulled from Update method annotation.", type[i]);
                } catch (DuplicatePropertyException ex) {
                    String stack = ExceptionUtils.getFullStackTrace(ex);
                    logger.log(Level.WARNING, "{0}", stack);
                }
            }
        } else {
            // the number of parameters in the user's Update annotation does not correspond with the method signature
            throw new ParameterCountMismatchException();
        }
    }

    /**
     * Get all dependancies for the Inputs in this InputTable.
     * @return SystolicArrayElements upon which this InputTable is dependant.
     * TODO: need to think about caching the dependancy list and how updates on the user input on Inputs can propagate dependancy updates to the SAE
     * TODO: need to think about whether order of dep list is significant, and therefore should be changed to a List output
     */
    public Map getDependancies() {
        // init
        HashSet dep = new HashSet();
        // add dependancies for each input to the set
        Iterator e = this.inputs.iterator();
        while (e.hasNext()) {
            Input input = (Input) e.next();
            dep.addAll((HashSet) input.getDependancies());
        }
        // convert to map
        // should revisit this at some point .. doesn't make sense any more
        LinkedHashMap result = new LinkedHashMap();
        Iterator iter = dep.iterator();
        while (iter.hasNext()) {
            INamed named = (INamed) iter.next();
            result.put(named.getName(), named);
        }
        // return result
        return (Map) result;
    }

    /**
     * Get dep for a particular named input.
     * @param InputName The input name.
     */
    public List getDependancies(String InputName) {
        ArrayList deps = new ArrayList();
        LinkedHashMap index = this.getInputIndex();
        Input input = (Input) index.get(InputName);
        if (input != null) {
            deps.addAll(input.getDependancies());
        }
        return (List) deps;
    }

    /**
     * Get Input by name.
     * @return Input
     */
    public Input getInput(String Name) {
        // init
        Input result = null;
        // if the named Input exists in the table
        LinkedHashMap index = this.getInputIndex();
        if (index.containsKey(Name)) {
            result = (Input) index.get(Name);
        }
        // return result
        return result;
    }

    /**
     * Create an index by name for the current inputs.
     * @return Map.
     */
    private LinkedHashMap getInputIndex() {
        // init
        LinkedHashMap index = new LinkedHashMap();
        // add all inputs to the index
        Iterator e = this.inputs.iterator();
        while (e.hasNext()) {
            Input input = (Input) e.next();
            index.put(input.getName(), input);
        }
        // return result
        return index;
    }

    /**
     * Get input keys.
     * @return List of keys.
     */
    public List getInputKeys() {
        ArrayList keys = new ArrayList();
        Iterator e = this.inputs.iterator();
        while (e.hasNext()) {
            Input input = (Input) e.next();
            keys.add(input.getName());
        }
        return keys;
    }

    /**
     * Get Inputs in order.
     * @return An array of Inputs.
     */
    public Input[] getInputs() {
        // init
        Input[] theinputs = new Input[this.inputs.size()];
        // copy inputs into array
        Iterator e = this.inputs.iterator();
        int count = 0;
        while (e.hasNext()) {
            theinputs[count] = (Input) e.next();
            count++;
        }
        // return result
        return theinputs;
    }

    /**
     * Get named input value.
     * @param Name
     */
    public Object getInputValue(String Name) {
        Iterator e = this.inputs.iterator();
        boolean found = false;
        while (e.hasNext()) {
            Input input = (Input) e.next();
            if (Name.equals(input.getName())) {
                return input.getUserInput();
            }
        }
        return null;
    }

    /**
     * Get Input values in order, cast to their proper types.
     * @return Array of property values.
     */
    public Object[] getInputValues() {
        // init
        ArrayList values = new ArrayList();
        // put Input result values in vector
        Iterator e = this.inputs.iterator();
        while (e.hasNext()) {
            Input myInput = (Input) e.next();
            values.add(myInput.getResult());
        }
        // copy result values into an array
        Object[] result = new Object[values.size()];
        values.addAll(Arrays.asList(result));
        // return result
        return result;
    }

    /**
     * Get Input classes.
     * @return Array of Input classes.
     */
    public Class[] getInputClass() {
        // init
        ArrayList inputclass = new ArrayList();
        Class[] result = null;
        // add class for each input to the list
        Iterator e = this.inputs.iterator();
        while (e.hasNext()) {
            Input input = (Input) e.next();
            inputclass.add(input.getInputClass());
        }
        // copy results into a class array
        result = new Class[inputclass.size()];
        inputclass.addAll(Arrays.asList(result));
        // return results
        return result;
    }

    /**
     * Get update method description.
     * @return Description
     */
    public String getUpdateMethodDescription() {
        return this.description;
    }

    /**
     * Determine if the InputTable contains the named Input.
     * @return True if the input table contains the named property, false otherwise.
     */
    public boolean hasInput(String PropertyName) {
        // init
        boolean result = false;
        // check if index contains propertyname
        LinkedHashMap index = this.getInputIndex();
        if (index.containsKey(PropertyName)) {
            result = true;
        }
        // return result
        return result;
    }

    /**
     * Check to see if each Input in the InputTable has the required values to
     * proceed with Expression resolution.
     * @return True if primed, false otherwise.
     */
    public boolean isPrimed() {
        boolean inputIsPrimed = true;
        Iterator e = this.inputs.iterator();
        while (e.hasNext()) {
            Input input = (Input) e.next();
            if (!input.isPrimed()) {
                return false;
            }
        }
        return inputIsPrimed;
    }

    public void setContext(INamed Named) {
        this.parent = Named;
    }

    /**
     * Set the Input user value.
     * @param InputName The Input name.
     * @param UserInputValue The user specified input value.
     */
    public void setInput(String InputName, String UserInputValue) {
        LinkedHashMap index = this.getInputIndex();
        Input myInput = (Input) index.get(InputName);
        try {
            myInput.setUserInput(UserInputValue);
        } catch (Exception ex) {
            String stack = ExceptionUtils.getFullStackTrace(ex);
            logger.log(Level.WARNING, "{0}", stack);
        }
        // notify parent object of change
        this.setChanged();
        this.notifyObservers(Integer.valueOf(ApplicationContext.EVENT_INPUT_CHANGE));
    }

}