package edu.calpoly.cpe205.fetter; import java.lang.reflect.*; import javax.swing.*; import java.util.*; import java.io.*; import java.lang.reflect.*; import java.lang.*; import java.awt.*; import javax.swing.event.*; import java.awt.event.*; /** * ETAMainModel stores the references to all the data of the ETA program. * This data includes the reference to the Main Test Object as well as * the Main Test Class. It will store a Collection of all the methods * and fields of the Main Test Class. It will also store a Collection of * of all the Test Object Items created by the user. It will store a * Collection of returned Objects that are returned from method calls * issued by the user * @see MethodData * @see FieldData * @see ParameterData * @see ReturnedData */ // Author: Mike Power // Version History: // Nov 19, 2000 - comments/pseudocode added // Nov 30, 2000 - (Michael Hebron) fixed class description so it shows up // in javadocs // Jan 17, 2001 - (Wes Strickland) added stubs for Stage One release // Jan 31, 2001 - (Apel Yahinian) implemented InstantiateClass() method // Feb 28, 2001 - (Wes Strickland) added code for Stage Three (code already complete) public class ETAMainModel { /** * Constructs a new ETAMainModel. *

* Pre-conditions: none
* Post-conditions: listeners is non-null
* methods is non-null
* fields is non-null
* returnedObjects is non-null
* parameterObjects is non-null
*/ public ETAMainModel() { //SET listeners to NEW LinkedList //listeners = new LinkedList(); //SET methods to NEW LinkedList methods = new LinkedList(); //SET fields to NEW LinkedList fields = new LinkedList(); pool.addParameterListener(new ParameterPoolListener()); pool.addReturnListener(new ReturnedPoolListener()); } /** * Removes from parameter Collection and informs all listeners that data * has been removed * Post-conditions: data has been removed from Collection parameters */ public void removeParameterData(ParameterData data) { //CALL removeParameterData of pool with data pool.removeParameterData(data); } /** * Removes from parameter collection and informs all listeners that data * has been removed *

* Post-conditions: data has been removed from Collection returnedListeners */ public void removeReturnedData(ReturnedData data) { //CALL removeReturnedData of pool with data pool.removeReturnedData(data); } /** * Displays the fields of the object *

* Pre-condition: none
* Post-condition: none * @param obj object to be inspected * @param description description of object being inpected * @param editable boolean stating whether the user will be able to edit the object or not */ public void inspect(Object obj, String description, boolean editable) { //CALL inspect of inspect with obj and editable //CALL setVisible on inspect with true Assert.preCondition(obj != null, "Can't inspect null"); inspect = new ObjectInspector(view); inspect.inspect(obj, description, editable); inspect.setVisible(true); } /** *Sets the class that the user wants to test *

*Pre-conditions: none
*Post-conditions: none
*@param classToLoad the fully quallified class name that the user wants *to test *@return indicates if the classToLoaded loaded without error */ public boolean setMainTestClass(String classToLoad) { //CALL getClass on this returns thisClass //CALL getClassLoader on thisClass returns loader ClassLoader load = null; //A classloader that will be used to load classes with strings boolean result; //indicates the result of the call to the class loader load = this.getClass().getClassLoader(); result = false; //TRY //CALL loadClass on loader with parameter classToLoad returns //loadedClass throws ClassNotFoundException //CALL setMainTestClass with parameter loadedClass //set result to true //ENDTRY try { Class newWorkingClass = null; //the class that is to be loaded in by the class loader newWorkingClass = load.loadClass(classToLoad); setMainTestClass(newWorkingClass); result = true; //CATCH ClassNotFoundException //set result to false //ENDCATCH } catch(ClassNotFoundException exc) { ETA.out.println(classToLoad + " not found in classpath"); result = false; } //RETURN result return result; } /** *Sets the class that the user wants to test *

*Pre-conditions: the view has been set
*Post-conditions: mainTestObject is null
*

*@param the class that the user wants to load and test */ public void setMainTestClass(Class classToLoad) { //SET workingClass to classToLoad mainTestClass = classToLoad; //CALL clearFields on view view.clearFields(); //CALL clearMethods on view view.clearMethods(); //CALL clearPreview on view view.clearPreview(); //CALL populateView with classToLoad populateView(classToLoad); //CALL enableMainTest on view with false view.enableMainTest(false); //SET mainTestObject to null mainTestObject = null; //RETURN true return; } /** * Populates the View with all the methods and fields declared in * declaredClass. Determines the super class and super interfaces of * declaredClass and class popluateView for each. *

* Pre-conditions: the view has been set * Post-conditions: the view is updated with all declared methods and
* fields of declaredClass * @param declaredClass the Class that parsed to populate the view with
* methods and fields */ protected void populateView(Class declaredClass) { Method[] methods = null; //All the declared methods of "declaredClass" Field[] fields = null; //All the declared fields of "declaredClass" Class[] interfaces = null; //All the declared interfaces of "declaredClass" MethodData method = null; //A temporary reference to a MethodData while it is being constructed. FieldData field = null; //A temporary reference to a FieldData while it is being constructed. //CALL getDeclaredMethods on declaredClass returns methods //CALL setAccessible of AccessibleObject with methods and true methods = declaredClass.getDeclaredMethods(); AccessibleObject.setAccessible(methods, true); //FOR ndx = 1 to length of methods // CONSTRUCT MethodData method from methods INDEX ndx // CALL addMethodRow on view with method returns row // CALL setMethodRowInterface on method with row //ENDFOR for (int ndx = 0; ndx < methods.length; ndx++) { method = new MethodData(methods[ndx], this); method.setMethodRowInterface(view.addMethodRow(method)); this.methods.add(method); } //CALL getDeclaredFields on declaredClass returns fields //CALL setAccessible of AccessibleObject with methods and true fields = declaredClass.getDeclaredFields(); AccessibleObject.setAccessible(fields, true); //FOR ndx = 1 to length of fields //CONSTRUCT FieldData field from methods INDEX ndx //CALL addFieldRow on view with field returns row //ENDFOR for (int ndx = 0; ndx < fields.length; ndx++) { field = new FieldData(fields[ndx], this); view.addFieldRow(field); this.fields.add(field); } //CALL getInterfaces on declaredClass returns interfaces interfaces = declaredClass.getInterfaces(); //FOR ndx = 1 to length of interfaces //CALL populateView with interfaces INDEX ndx //ENDFOR for (int ndx = 0; ndx < interfaces.length; ndx++) { populateView(interfaces[ndx]); } //CALL getSuperclass on declaredClass returns superClass Class superClass = declaredClass.getSuperclass(); //IF superClass not null //THEN //CALL populateView with superClass //ENDIF if(superClass != null) { populateView(superClass); } } /** * Sets the view that will display the models information. *

* @param viewAbs the view that will be used by the model to display
* its information. */ public void setView(ETAViewAbstract viewAbs) { //SET view to viewAbs view = viewAbs; //CONSTRUCT ObjectInspector insp with view //SET inspect to insp //inspect = new ObjectInspector(view); } /** * Sets the mainTestObject to be obj, repopulates the view with the * methods and fields declared in obj *

* Pre-conditions: the view has been set
* Post-conditions: view is enable
* mainTestObject set to obj * @param the Object that the user wants to test, sets mainTest to obj */ public void loadObject(Object obj) { //CALL addParameterData with obj and "Main Test Object" //addParameterData(obj, "Main Test Object"); //CALL getClass on obj returns cls //CALL setMainTestClass with cls setMainTestClass(obj.getClass()); //SET mainTestObject to obj Assert.preCondition(obj != null, "Can't load null object"); mainTestObject = obj; //CALL enableMainTest on view with true view.enableMainTest(true); //CALL forName with "Component" returns compClass //IF CALL isAssignableFrom on class of Component with mainTestClass //CALL setPreviewComponent with obj //ENDIF if(Component.class.isAssignableFrom(mainTestClass)) { view.setPreviewComponent((Component)obj); } } /** * Constructs the main test class from the Constructor object con with the * with the parameters stored in datas. *

* Pre-conditions: view is not null
* con is constructor for Main Test Class
* Post-conditions: mainTestObject is not null
* @param con the constructor that will be used to construct the Main
* Test Object
* @param datas The parameters that will be used to construct the Main
* Test Object
* @param name The name that will be used to describe and refer to the Main Test Object
*/ public void instantiateClass(Constructor con, ParameterDataInterface[] datas, String name) { Object[] tempData = null; // An array to store all the contents of datas as Objects //CONSTRUCT parameters array of Object with length equal to data length //FOR ndx = 1 to parameters length //CALL getValueObject on datas INDEX ndx returns obj //SET parameters INDEX ndx to obj //ENDFOR //TRY //CALL newInstance on con with parameters return instance //SET mainTestObject to instance //CALL addParameterData with mainTestObject and name //CALL forName with "Component" returns compClass //IF CALL isAssignableFrom on compClass with mainTestClass //CALL setPreviewComponent with mainTestObject //ENDIF //CALL enableThis on view with true //ENDTRY con.setAccessible(true); tempData = new Object[datas.length]; for (int ndx = 0; ndx < datas.length; ndx++) { tempData[ndx] = ( ( ParameterData ) datas[ndx]).getValueObject(); } try { mainTestObject = con.newInstance( tempData ); addParameterData( mainTestObject, name); if(Component.class.isAssignableFrom(mainTestClass)) { view.setPreviewComponent((Component)mainTestObject); } view.enableMainTest(true); //CATCH InstantiationException //CALL getDeclaringClass on con returns abstractClass //CALL getName on abstractClass returns abstractName //CONCAT "Can not create objects of abstract types. " with abstractName //returns abstractError //CONCAT abstractError with " is an abstract type" returns //abstractFullMessage //CALL println of err in ETA with abstractFullMessage //CALL printStackTrace of InstantiationException with err in ETA //ENDCATCH } catch (InstantiationException ins) { ETA.err.println("Can not create objects of asbtract types. " + con.getDeclaringClass().getName() + " is an abstract type."); ins.printStackTrace(ETA.err); //CATCH IllegalAccessException //CONSTRUCT String msg with "The ETA was not allowed to access this //constructor." //CALL println of err in ETA with msg //CALL printStackTrace of IllegalAccessException with err in ETA //ENDCATCH } catch(IllegalAccessException acc) { ETA.err.println("The ETA was not allowed to access this constructor."); acc.printStackTrace(ETA.err); //CATCH IllegalArgumentException //CONSTRUCT String msg with "An error has caused a value of the wrong //type to be passed to the constructor, please constact ETA support" //CALL println of err in ETA with msg //CALL printStackTrace of IllegalArgumentException with err in ETA //ENDCATCH } catch (IllegalArgumentException exe) { ETA.err.println("An error has caused a value of the wrong type to be passed " + "to the constructor, please contact ETA support"); exe.printStackTrace(ETA.err); //CATCH InvocationTargetException //CALL printStackTrace of InvocationTargetException //ENDCATCH } catch (InvocationTargetException inv) { inv.printStackTrace(); } //CONSTRUCT String msg "Main Test Class Constructor " String msg = "Main Test Class Constructor "; //CONSTRUCT String msg2 " called" String msg2 = " called"; //CONSTRUCT String with "with " String with = "with "; //CALL println on log of ETAMainModel with msg name of con msg2 //FOR ndx = 1 to parameters length //CALL println on log of ETAMainModel with toString of //parameters INDEX ndx //ENDFOR } /** * Adds the specified ParameterDataListener to recieve events for the model * when ParameterData is added removed or changed *

* Pre-conditions: listeners is not null
* Post-conditions: none
* * @param list a listener that wants to be informed when a ParameterData is
* is added changed or removed
*/ public void addParameterDataListener(ParameterDataListener list) { //CALL add on listeners with list //listeners.add(list); pool.addParameterListener(list); } /** * Removes the specified ParameterDataListener from recieving events for the model * when ParameterData is added removed or changed *

* Pre-conditions: listeners is not null
* Post-conditions:
* * @param list the listener that is no longer interested in listening to
* added removed and changed ParameterData */ public void removeParameterDataListener(ParameterDataListener list) { //CALL remove on listeners with list //listeners.remove(list); pool.removeParameterListener(list); } /** * Used to determin if the specified ParameterDataListener is registered
* to recieve events from the model for added removed and changed
* ParameterData.
*

* Pre-conditions: listeners is not null
* Post-conditions:
* * @param list the listener that is tested to see if it is listening to
* added removed changed ParameterData * @return true if list is listening to added removed or changed
* false otherwise
*/ public boolean isParameterDataListener(ParameterDataListener list) { //CALL constains on listerers with list returns b //RETURN b return false; } /** * Returns the Main Test Class that the user is testing *

* @return the Main Test Class of this Model
*/ public Class getMainTestClass() { //RETURN mainTestClass return mainTestClass; } /** * Constructs and added a new ParameterData for the newItem Object and the
* name and adds it to the pool *

* Pre-conditions: pool is not null * Post-conditions:
* * @param newItem the value of the item that is being added to the pool
* @param name a String describing the source of the value, what method
* it was returned from or what field it represents. */ public void addParameterData(Constructor con, ParameterDataInterface[] params, String name) { Object[] conParams = null; //To contain all the contents of params with object references // CONSTUCT Object[] conParams from params // CALL setAccessible on con with true // CALL newInstance on con with conParams returns data // CALL addParameterData on this with data and name conParams = new Object[params.length]; for (int ndx = 0; ndx < params.length; ndx++) { conParams[ndx] = ((ParameterData) params[ndx]).getValueObject(); } con.setAccessible(true); try { addParameterData(con.newInstance(conParams), name); // CATCH InstantiationException // CALL getDeclaringClass on con returns abstractClass // CALL getName on abstractClass returns abstractName // CONCAT "Can not create objects of abstract types. " with abstractName // returns abstractError // CONCAT abstractError with " is an abstract type" returns // abstractFullMessage // CALL println of err in ETA with abstractFullMessage // CALL printStackTrace of InstantiationException with err in ETA // ENDCATCH } catch(InstantiationException exc) { ETA.err.println("Can not create object of abstact types. "); ETA.err.println(con.getDeclaringClass().getName() + " is an abstract type."); exc.printStackTrace(ETA.err); // CATCH IllegalAccessException // CONSTRUCT String msg with "The ETA was not allowed to access this // constructor." // CALL println of err in ETA with msg // CALL printStackTrace of IllegalAccessException with err in ETA // ENDCATCH } catch(IllegalAccessException exc) { ETA.err.println("The ETA was not allowed to access this constructor."); exc.printStackTrace(ETA.err); // CATCH IllegalArgumentException // CONSTRUCT String msg with "An error has caused a value of the wrong // type to be passed to the constructor, please constact ETA support" // CALL println of err in ETA with msg // CALL printStackTrace of IllegalArgumentException with err in ETA // ENDCATCH } catch(IllegalArgumentException exc) { ETA.err.println("The constuctor was passed an invalid parameter, " + "constuction failed"); exc.printStackTrace(ETA.err); // CATCH InvocationTargetException // CALL printStackTrace of InvocationTargetException // ENDCATCH } catch(InvocationTargetException exc) { exc.printStackTrace(ETA.err); } } /** * Constructs and added a new ParameterData for the newItem Object and the
* name and adds it to the pool *

* Pre-conditions: pool is not null * Post-conditions:
* * @param newItem the value of the item that is being added to the pool
* @param name a String describing the source of the value, what method
* it was returned from or what field it represents. */ public void addParameterData(Object newItem, String name) { //CONSTRUCT ParameterData param from newItem and name //CALL addParameterData on pool with param pool.addParameterData(new ParameterData(newItem, name, this)); } /** * Constructs and addds a new ReturnedData from the newItem Object and the
* name and adds it to the pool *

* Pre-conditions: pool is not null * Post-conditions:
* * @param newItem is the value of the item that is being added to the pool
* @param name is a String describing the source of the value, what method
* it was returned from or what field it represents. */ public void addReturnedData(Object value, String from) { //CONSTRUCT ReturnedData data from value and from //CALL addReturnedData on pool with data pool.addReturnedData(new ReturnedData(value, from, this)); } /** *Returns the reference to the Main Test Object *

*@return the reference to the Main Test Object */ public Object getMainTestObject() { //RETURN mainTestObject Assert.preCondition(mainTestObject != null, "Main Test Object is null"); return mainTestObject; } /** *This method will be used to convert the strings generated by className back to * the class objects that className used to create them. * Such as the string "java.lang.Byte[]" can be passed into this method * and it will return the Class class for arrays of java.lang.Bytes * Pre-conditions:
* Post-conditions:
*@param classToMake the class object that the caller wants a class for. *@return a Class object that is named by the param string. */ public static Class nameToClass(String nameOfClass) { //IF CALL endsWith on nameOfClass with "[]" //CALL length on nameOfClass returns lengthOfClassToMake //CALL substring on nameOfClass with 0 and lengthOfClassToMake -2 returns componentClassName //CALL nameToClass of ETAMainModel with nextClass returns componentClass //CALL newInstance of Array with componentClass and 0 returns arrayObject //CALL getClass on arrayObject returns classMade //RETURN classMade //ENDIF if(nameOfClass.endsWith("[]")) { return Array.newInstance(ETAMainModel.nameToClass(nameOfClass. substring(0, nameOfClass.length() -2)), 0).getClass(); //ELSE //TRY //CALL forName of Class with nameOfClass returns classMade //RETURN classMade //ENDTRY //CATCH ClassNotFoundException //CALL println of System.out with "If the class is not found, we are in trouble" //ENDCATCH //ENDELSE } else { try { return Class.forName(nameOfClass); } catch(ClassNotFoundException exc) { System.err.println("An error has occured in ETA, please reboot"); } } throw new RuntimeException("Statement should not be reached"); } /** *This method will be used to convert array names and primitive names *of classes to a name that is more appropreiate. Such as changing [B *for a byte array to java.lang.Byte[] * Pre-conditions:
* Post-conditions:
*@param nameToMake the class object that the caller wants a name for. *@return a formated name representing the name of nameToMake. */ public static String classToName(Class nameToMake) { // CALL isArray on nameToMake returns classIsArray // IF classIsArray // CONSTUCT String brackets as "[]" // CALL getComponentType on nameToMake returns arrayType // CALL nameToMake of ETAMainModel on arrayType returns arrayTypeName // RETURN arrayTypeName + brackets Assert.assert(nameToMake != null, "nameToMake cannot be null!"); if (nameToMake.isArray()) { Assert.assert(nameToMake.isArray(), "nameToMake.isArray() must be true!"); return ETAMainModel.classToName(nameToMake.getComponentType()) + "[]"; // ELSE // CALL isPrimitive on nameTomake returns classIsPrimitive // IF classIsPrimitive // IF CALL equals on nameToMake with Boolean.TYPE // RETURN java.lang.Boolean // ELSEIF CALL equals on nameToMake with Byte.TYPE // RETURN java.lang.Byte // ELSEIF CALL equals on nameToMake with Character.TYPE // RETURN java.lang.Character // ELSEIF CALL equals on nameToMake with Double.TYPE // RETURN java.lang.Double // ELSEIF CALL equals on nameToMake with Float.TYPE // RETURN java.lang.Float // ELSEIF CALL equals on nameToMake with Integer.TYPE // RETURN java.lang.Integer // ELSEIF CALL equals on nameToMake with Long.TYPE // RETURN java.lang.Long // ELSEIF CALL equals on nameToMake with Short.TYPE // RETURN java.lang.Short // ELSE // RETURN void // ENDIF } else if (nameToMake.isPrimitive()) { Assert.assert(nameToMake.isPrimitive(), "nameToMake must be primitive here!"); if (nameToMake.equals(Boolean.TYPE)) { Assert.assert(nameToMake.equals(Boolean.TYPE), "nameToMake must be boolean here!"); return "java.lang.Boolean"; } else if (nameToMake.equals(Byte.TYPE)) { Assert.assert(nameToMake.equals(Byte.TYPE), "nameToMake must be of type Byte here!"); return "java.lang.Byte"; } else if (nameToMake.equals(Character.TYPE)) { Assert.assert(nameToMake.equals(Character.TYPE), "nameToMake must be Character here!"); return "java.lang.Character"; } else if (nameToMake.equals(Double.TYPE)) { Assert.assert(nameToMake.equals(Double.TYPE), "nameToMake must be Double here!"); return "java.lang.Double"; } else if (nameToMake.equals(Float.TYPE)) { Assert.assert(nameToMake.equals(Float.TYPE), "nameToMake must be Float here!"); return "java.lang.Float"; } else if (nameToMake.equals(Integer.TYPE)) { Assert.assert(nameToMake.equals(Integer.TYPE), "nameToMake must be integer here!"); return "java.lang.Integer"; } else if (nameToMake.equals(Long.TYPE)) { Assert.assert(nameToMake.equals(Long.TYPE), "nameToMake must be long here!"); return "java.lang.Long"; } else if (nameToMake.equals(Short.TYPE)) { Assert.assert(nameToMake.equals(Short.TYPE), "nameToMake must be short here!"); return "java.lang.Short"; } else { return "void"; } // ELSE // CALL getName on nameToMake returns name // RETURN name // ENDIF } else { Assert.assert(!nameToMake.isPrimitive(), "nameToMake cannot be primitive here!"); Assert.assert(!nameToMake.isArray(), "nameToMake cannot be an array here!"); return nameToMake.getName(); } } /** * Returns the current value of descNum and increments descNum by one, this
* will be used to create names for primitive ParameterDatas that were created
* from a ParameterObjectComboBox *

* Pre-conditions:
* Post-conditions:
* * @return the current value of descNum to be concatenated on to the name of a
* user created primitive from ParameterObjectComboBox */ public static int getNumber() { //COPY descNum to num //INCREMENT descNum //RETURN num return 0; } /** *Will store all the references to ParameterData and ReturnedData Objects,
*and will also inform the ETAMainModel when a ParameterData or ReturnedData
*has been added or removed
*/ protected static ObjectPool pool = new ObjectPool(); /** *A count that will be used to defferentiate one user created primitive from
*ParameterObjectComboBox from another */ protected static int descNum = 1; /** *The reference to the object that the user has created to test with the ETA,
*commonly referred to as the "THIS" */ protected Object mainTestObject; /** *The view that will be used to display the ETAMainModels informations */ protected ETAViewAbstract view; /** *The user selected Class that is going to be tested by the ETA */ protected Class mainTestClass; /** *Will be used to display the contents of an Object so that the user can
*edit and change the Object */ protected ObjectInspector inspect; /** *@link aggregation * @associates <{FieldData}> * *A Collection of all the FieldData associated to the MainTestClass */ protected Collection fields; /** *@link aggregation * @associates <{MethodData}> * *A Collection of all the MethodData associated to the MainTestClass */ protected Collection methods; /** *Listens to the ObjectPool for added ParameterData and removed ParameterData *the ETAMainModel will then have the view add or remove ParameterData *and also inform the ParameterObjectComboBox */ protected class ParameterPoolListener implements ParameterDataListener { /** *Returns an empty string indicating that this ParameterDataListener is *to everything */ public String getTypeName() { return ""; } /** * Does nothing */ public void parameterDataChanged(ParameterDataInterface changed) { } /** * Changes the view to reflect the added ParameterData in the pool *

* Pre-conditions: the view has been set * Post-conditions: */ public void parameterDataAdded(ParameterDataInterface added) { //CALL addParameterRow on view with added if (view != null) view.addParameterRow(added); } /** * Changes the view to reflect the removed ParameterData in the pool *

* Pre-conditions: the view has been set * Post-conditions: */ public void parameterDataRemoved(ParameterDataInterface removed) { //CALL removeParameterRow on view with removed view.removeParameterRow(removed); } } /** *Listens to the ObjectPool for added ReturnedData and removed ReturnedData *The ETAMainModel will then have the view add or remove the ReturnedData */ protected class ReturnedPoolListener implements ObjectPool.ReturnedPoolListener { /** * Changes the view to reflect the addeded ReturnedData in the pool *

* Pre-conditions: the view has been set * Post-conditions: none */ public void returnedAdded(ReturnedData added) { //CALL addReturnedRow on view with added if (view != null) view.addReturnedRow(added); } /** * Changes the view to reflect the removed ReturnedData in the pool *

* Pre-conditions: the view has been set * Post-conditions: none */ public void returnedRemoved(ReturnedData removed) { //CALL removeReturnedRow on view with removed view.removeReturnedRow(removed); } } }