Repository for our CSSE 374 Software Design project.
These are Scary Stories in 5 words from the Facebook group I Love Programming:
- Does it work in IE8?
- The client wants more changes
- That should not take long
- It works on my machine
- Just one more small change
- What happened to the database?
- Diagrams (Pictures below in same order):
- Auto-Generated UML of Project
- Manually Generated UML of Project
- Pictures
To run the program, run the PatternDetectorApp and there will be an instructions button that will explain everything to the user.
Code remained about the same, most of GUI did not requiring knowing about ASM parsing.
We improved code by using a common interface, IPhase, which allowed us to easily add new phases and the configuration file recognize these new phases with only small changes to the code. To add a new phase, please refer to instructions in the application.
Please refer to the following link: GUI Package to see all the classes used in creating the GUI.
Input-Folder: C:\Users\mercieal\Documents\School\csse374\374BlueShells\BlueShells374\bin\problem\client
Input-Classes: problem.lib.LinearTransformer,java.util.Enumeration,java.util.Iterator
Output-Directory: input_output
Dot-Path: C:\\Program Files (x86)\\Graphviz2.38\\bin\\dot.exe
Phases: Class-Loading,Adapter-Detection,UML-Generation
Adapter-MethodDelegation: 1
For this half-milestone, we added further detection to the Adapter Pattern. We also made all detectors implement one interface, the Invoker interface. This was in place for brute force detection or visitor detection, allowing either to be called without changing core code.
We are planning to do a GUI. We plan to make further progress during the weekend, once we all finish the exam and other homework. General framework started.
-
Diagrams (Pictures below in same order):
-
Pictures
We continued to use the visitor pattern. Left code the same in the framework/library unless bug was found or additional functionality that was not there in the first place.
We also made a brute force Adapter Pattern Detector. To see it in work, there are lines that can be uncommented. When GUI is made, an option could be made to see it separate.
Instructions are still similar to previous milestone.
To test the program, there is a console available for use.
The client would input the desired classes, such as classes in a package, in as the initial arguments. Once that object is finished loading, a console type structure is loaded. From there, follow the prompts for desired inputs.
To the see the brute force Adapter Pattern finder, code must be changed for the current console implementation.
Supported operations: Generator, Help, Quit
Input command:> Generator
Generators: Supported generators - UML, Sequence
Input generator:> UML
Generated graph, please refresh the input_output folder
Supported operations: Generator, Help, Quit
Input command:> quit
CompositeVisitor compositeVisitor = new CompositeVisitor();
compositeVisitor.write(model);
// BruteForceAdapterDetector adapterVisitor = new BruteForceAdapterDetector(model);
// adapterVisitor.adapterDetect();
package problem.visitor;
import java.util.ArrayList;
import java.util.List;
import problem.interfaces.IClass;
import problem.interfaces.IField;
import problem.interfaces.IModel;
import problem.interfaces.IRelation;
import problem.patterns.AdapterPattern;
public class BruteForceAdapterDetector {
IModel model;
private List<IClass> classList;
public BruteForceAdapterDetector(IModel m){
this.model = m;
this.classList = new ArrayList<>();
}
public void adapterDetect(){
for(IClass c: this.model.getClasses()){
if (c.getInterface().size() == 1) {
// Detecting adapter
if (c.getExtension().equals("java/lang/Object")
|| c.getExtension().equals("")) {
// Doesn't have an extension
if (c.getIField().size() == 1) {
// Only 1 field
this.classList.add(c);
// Adds it when all three parts exist
}
}
}
}
for (IClass c0 : this.classList) {
boolean isAdaptee = false;
IClass adaptee = null;
boolean isTarget = false;
IClass target = null;
String fieldType = ((List<IField>) c0.getIField())
.get(0).getDesc();
String interfaceName = ((List<String>) c0
.getInterface()).get(0);
for (IClass c1 : this.model.getClasses()) {
if (c1.getClassName().equals(fieldType)
|| c1.getClassName().replace("/", ".")
.equals(fieldType)) {
isAdaptee = true;
adaptee = c1;
continue; // If this one, not the interface
}
if (c1.getClassName().equals(interfaceName)) {
isTarget = true;
target = c1;
}
if (target != null && adaptee != null) {
break;
}
}
if (isAdaptee && isTarget) {
adaptee.addPattern(
new AdapterPattern(adaptee.getClassName(),
"\\<\\<adaptee\\>\\>"));
target.addPattern(
new AdapterPattern(target.getClassName(),
"\\<\\<target\\>\\>"));
c0.addPattern(new AdapterPattern(c0.getClassName(),
"\\<\\<adapter\\>\\>"));
}
for (IRelation r : this.model.getRelations()) {
if (r.getFromObject()
.equals(c0.getClassName().replace("/", ""))
&& r.getToObject().equals(
fieldType.replace(".", ""))) {
r.addProperty("xlabel=\"\\<\\<adapts\\>\\>\"");
}
}
}
}
}
package problem.visitor;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import problem.interfaces.IClass;
import problem.interfaces.IField;
import problem.interfaces.IModel;
import problem.patterns.CompositePattern;
public class CompositeVisitor implements IInvoker {
private IVisitor visitor;
private Map<String, String> abstractToInterface; // extension, interface
private List<IClass> possibleComposites;
private List<String> possibleComponents;
private boolean notPossibleComposite;
private IClass currentClass;
public CompositeVisitor() {
this.visitor = new Visitor();
this.abstractToInterface = new HashMap<>();
this.possibleComposites = new ArrayList<>();
this.possibleComponents = new ArrayList<>();
this.preVisitModel();
this.preVisitClass();
this.visitField();
this.postVisitModel();
}
private void preVisitModel() {
this.visitor.addVisit(VisitType.PreVisit, IModel.class,
(ITraverser t) -> {
IModel m = (IModel) t;
for (IClass c : m.getClasses()) {
if (c.getAccessLevel() == 1057) {
if (c.getInterface().size() == 1) {
String inter = "";
for (String interfaze : c.getInterface()) {
inter = interfaze;
}
this.abstractToInterface.put(c.getClassName(),
inter);
} else {
this.abstractToInterface.put(c.getClassName(),
"");
}
}
}
});
}
private void preVisitClass() {
this.visitor.addVisit(VisitType.PreVisit, IClass.class,
(ITraverser t) -> {
IClass c = (IClass) t;
this.notPossibleComposite = false;
if (c.getInterface().size() == 0
&& c.getExtension().equals(null)) {
this.notPossibleComposite = true;
}
this.currentClass = c;
});
}
private void visitField() {
this.visitor.addVisit(VisitType.Visit, IField.class, (ITraverser t) -> {
IField f = (IField) t;
if (this.notPossibleComposite) {
return;
}
if (f.getSignature().equals("")) {
return;
}
String[] sig = f.getSignature().split("<");
String sigCheck = sig[sig.length - 1];
sigCheck = sigCheck.replace(".", "/");
sigCheck = sigCheck.substring(1);
for (String s : this.currentClass.getInterface()) {
if (s.equals(sigCheck)) {
this.possibleComposites.add(this.currentClass);
this.possibleComponents.add(sigCheck);
}
}
if (this.currentClass.getExtension().equals(sigCheck)) {
this.possibleComposites.add(this.currentClass);
this.possibleComponents.add(sigCheck);
}
if (this.abstractToInterface
.containsKey(this.currentClass.getExtension())
&& this.abstractToInterface.containsValue(sigCheck)) {
this.possibleComposites.add(this.currentClass);
this.possibleComponents.add(sigCheck);
}
});
}
private void postVisitModel() {
this.visitor.addVisit(VisitType.PostVisit, IModel.class,
(ITraverser t) -> {
IModel m = (IModel) t;
List<String> comfComp = new ArrayList<>();
List<String> comfComposite = new ArrayList<>();
for (IClass c : m.getClasses()) {
for (String s : this.possibleComponents) {
if (c.getInterface().size() > 1
|| c.getAccessLevel() == 1057) {
break;
}
List<String> classInterface = (List<String>) c
.getInterface();
int iSize = classInterface.size();
String cExt = c.getExtension();
if ((iSize != 0 && classInterface.get(0).equals(s))
|| cExt.equals(s)
|| (this.abstractToInterface
.get(cExt) != null
&& this.abstractToInterface
.get(cExt).equals(s))) {
// detect maybe leaf check fields
boolean hasComField = false;
for (IField f : c.getIField()) {
if (hasComField) {
break;
}
String sigCheck = f.getSignature();
if (!sigCheck.equals("")) {
String[] sig = f.getSignature()
.split("<");
sigCheck = sig[sig.length - 1];
sigCheck = sigCheck.replace(".", "/");
sigCheck = sigCheck.substring(1);
}
if (sigCheck.equals(s)) {
hasComField = true;
}
}
if (!hasComField) {
if (!comfComp.contains(s)) {
comfComp.add(s);
}
c.addPattern(new CompositePattern(
c.getClassName(),
"\\<\\<Leaf\\>\\>"));
}
}
}
}
for (String s : comfComp) {
for (IClass c : m.getClasses()) {
if (c.getClassName().equals(s)) {
c.addPattern(
new CompositePattern(c.getClassName(),
"\\<\\<Component\\>\\>"));
}
if (this.abstractToInterface
.get(c.getClassName()) != null
&& this.abstractToInterface
.get(c.getClassName()).equals(s)) {
c.addPattern(
new CompositePattern(c.getClassName(),
"\\<\\<Component\\>\\>"));
}
}
}
for (IClass s2 : this.possibleComposites) {
List<IField> classFields = (List<IField>) s2
.getIField();
for (IField f : classFields) {
String sigCheck = f.getSignature();
if (!sigCheck.equals("")) {
String[] sig = f.getSignature().split("<");
sigCheck = sig[sig.length - 1];
sigCheck = sigCheck.replace(".", "/");
sigCheck = sigCheck.substring(1);
}
if (comfComp.contains(sigCheck)) {
s2.addPattern(
new CompositePattern(s2.getClassName(),
"\\<\\<Composite\\>\\>"));
comfComposite.add(s2.getClassName());
}
}
}
for (IClass c2 : m.getClasses()) {
for (String s3 : comfComposite) {
if (c2.getExtension().equals(s3)) {
c2.addPattern(
new CompositePattern(c2.getClassName(),
"\\<\\<Composite\\>\\>"));
}
}
}
});
}
@Override
public void write(IModel model) {
ITraverser traverser = (ITraverser) model;
traverser.accept(this.visitor);
}
}
package problem.patterns;
import problem.interfaces.IPattern;
public class CompositePattern implements IPattern {
private String className;
private String UMLProperty;
private String UMLlabel;
/**
* Container class for holding information about creating representation of
* the Component Pattern
*
* @param className
* - name of class the pattern is being added to
* @param type
* - The label for the class name: Component (interface for all
* objects in the composition), Composite (Behavior of the
* components having children and to store child component), Leaf
* (Behavior for the elements in the composition)
*/
public CompositePattern(String className, String type) {
this.className = className;
this.UMLProperty = "fillcolor=yellow, style=filled, ";
this.UMLlabel = type;
}
@Override
public String getProperty() {
return this.UMLProperty;
}
@Override
public String getLabel() {
return this.UMLlabel;
}
@Override
public String getClassName() {
return this.className;
}
}
Luke Danielson
- Worked on Composite Visitor Pattern
- Found the java.awt and java.swing arguments
- Added additional tests to previous milestone
Larry Gates
- Started the Composite Visitor Pattern
- Created the Composite Pattern Object
- Cleaned up code and README
Aaron Mercier
- Worked on Composite Visitor Pattern
- Tests for current milestone
- Brute force for previous milestone
After feedback from Chandan's review:
- : Add additional testing to the integration testing, four or more additional testing
- : Brute force version as we he had earlier
-
Diagrams (Pictures below in same order):
-
Pictures:
We continued to use the visitor pattern. Left code the same in the framework/library unless bug was found. Add to add additional methods to the IRelation objects, as a way to add label descriptions to be used.
Instructions are still similar to previous milestone.
To test the program, there is a console available for use.
The client would input the desired classes, such as classes in a package, in as the initial arguments. Once that object is finished loading, a console type structure is loaded. From there, follow the prompts for desired inputs.
Supported operations: Generator, Help, Quit
Input command:> Generator
Generators: Supported generators - UML, Sequence
Input generator:> UML
Generated graph, please refresh the input_output folder
Supported operations: Generator, Help, Quit
Input command:> quit
public class DecoratorPattern implements IPattern{
private String className;
private String UMLproperty;
private String UMLlabel;
//need something with relations
public DecoratorPattern(String className, String type) {
this.className = className;
this.UMLproperty = "fillcolor=green, style=filled,";
this.UMLlabel = type; //type means decorator or component and will be provided from the visitor
}
@Override
public String getProperty() {
return this.UMLproperty;
}
@Override
public String getLabel() {
return this.UMLlabel;
}
public String getClassName(){
return this.className;
}
}
public class DecoratorVisitor implements IInvoker {
private IVisitor visitor;
private List<String> decoratorList;
private List<String> concreteDecorators;
private Collection<String> tempInterfaces;
private List<String> componentList;
private String tempExtension;
private IClass tempClass;
private boolean notAbstract;
private boolean isDecorator;
public DecoratorVisitor() {
this.visitor = new Visitor();
this.decoratorList = new ArrayList<>();
this.concreteDecorators = new ArrayList<>();
this.componentList = new ArrayList<>();
this.setupPreVisitClass();
this.visitField();
this.visitExtensionRelation();
this.postVisitModel();
}
@Override
public void write(IModel model) {
ITraverser traverser = (ITraverser) model;
traverser.accept(this.visitor);
}
private void setupPreVisitClass() { // search for a class that could
// potentially be the decorator and add
// it to a list
this.visitor.addVisit(VisitType.PreVisit, ConcreteClass.class,
(ITraverser t) -> {
this.tempClass = (IClass) t;
this.tempInterfaces = new ArrayList<>();
this.tempExtension = "";
this.notAbstract = false;
this.isDecorator = false;
// if (this.tempClass.getAcessLevel() != 1057){ //if the
// class is not abstract it cannot be a decorator
// this.notAbstract = true;
// return;
// }
this.tempInterfaces = this.tempClass.getInterface();
this.tempExtension = this.tempClass.getExtension();
});
}
private void visitField() {
this.visitor.addVisit(VisitType.Visit, Field.class, (ITraverser t) -> {
if (this.notAbstract) // if already determined to be a decorator or
// not return to avoid wasted computation
return;
IField f = (IField) t;
String desc = f.getDesc().replace(".", "/");
if (desc.equals("java/lang/Object")) {
return;
}
if (desc.equals(this.tempExtension)
|| this.tempInterfaces.contains(desc)) {
this.componentList.add(desc);
if (!this.isDecorator) {
this.decoratorList.add(this.tempClass.getClassName());
this.tempClass.addPattern(
new DecoratorPattern(this.tempClass.getClassName(),
"\\<\\<decorator\\>\\>"));
this.isDecorator = true;
}
}
});
}
private void visitExtensionRelation() {
this.visitor.addVisit(VisitType.Visit, ExtensionRelation.class,
(ITraverser t) -> {
IRelation ext = (IRelation) t;
for (int i = 0; i < this.decoratorList.size(); i++) {
String decorator = this.decoratorList.get(i);
decorator = decorator.replace("/", "");
if (ext.getToObject().equals(decorator)) {
// once the concrete decorator is found add its
// name to a list of concrete decorators
this.concreteDecorators.add(ext.getFromObject());
break;
}
}
});
}
private void postVisitModel() {
this.visitor.addVisit(VisitType.PostVisit, IModel.class,
(ITraverser t) -> {
IModel m = (IModel) t;
List<IClass> classList = m.getClasses();
for (String tempComponent : this.componentList) {
// find all component classes and add a decorator pattern object to it
for (IClass tempClass : classList) {
if (tempClass.getClassName()
.equals(tempComponent)) {
tempClass.addPattern(new DecoratorPattern(
tempClass.getClassName(),
"\\<\\<component\\>\\>"));
}
}
}
for (String tempConcrete : this.concreteDecorators) {
// find all concrete decorators and add a decorator pattern object
for (IClass tempClass : classList) {
if (tempClass.getClassName().replace("/", "")
.equals(tempConcrete)) {
tempClass.addPattern(new DecoratorPattern(
tempClass.getClassName(),
"\\<\\<decorator\\>\\>"));
}
}
}
List<IRelation> relations = m.getRelations();
for (String s : this.decoratorList) {
for (IRelation r : relations) {
if (r.getClass().equals(HasRelation.class)) {
if (s.replace("/", "")
.equals(r.getFromObject())) {
r.addProperty("xlabel=\"<<decorates>>\"");
}
}
}
}
});
}
}
DecoratorVisitor decoratorVisitor = new DecoratorVisitor();
decoratorVisitor.write(model);
public class AdapterPattern implements IPattern{
private String className;
private String UMLproperty;
private String UMLlabel;
public AdapterPattern(String className, String type) {
this.className = className;
this.UMLproperty = "fillcolor=red, style=filled,";
this.UMLlabel = type; //type means target, adapter, or adaptee and will be provided from the visitor
}
@Override
public String getProperty() {
return UMLproperty;
}
@Override
public String getLabel() {
return UMLlabel;
}
public String getClassName(){
return this.className;
}
}
public class AdapterVisitor implements IInvoker {
private IVisitor visitor;
private List<IClass> classList;
public AdapterVisitor() {
this.visitor = new Visitor();
this.classList = new ArrayList<>();
this.setupPreVisitClass();
this.visitHasRelation();
this.postVisitModel();
}
@Override
public void write(IModel model) {
ITraverser traverser = (ITraverser) model;
traverser.accept(this.visitor);
}
private void visitHasRelation() {
this.visitor.addVisit(VisitType.Visit, ConcreteClass.class,
(ITraverser t) -> {
});
}
private void setupPreVisitClass() {
this.visitor.addVisit(VisitType.PreVisit, ConcreteClass.class,
(ITraverser t) -> {
IClass c = (IClass) t;
if (c.getInterface().size() == 1) {
// Detecting adapter
if (c.getExtension().equals("java/lang/Object")) {
// Doesn't have an extension
if (c.getIField().size() == 1) {
// Only 1 field
this.classList.add(c);
// Adds it when all three parts exist
}
}
}
});
}
private void postVisitModel() {
this.visitor.addVisit(VisitType.PostVisit, IModel.class,
(ITraverser t) -> {
IModel m = (IModel) t;
for (IClass c0 : this.classList) {
boolean isAdaptee = false;
IClass adaptee = null;
boolean isTarget = false;
IClass target = null;
String fieldType = ((List<IField>) c0.getIField())
.get(0).getDesc();
String interfaceName = ((List<String>) c0
.getInterface()).get(0);
for (IClass c1 : m.getClasses()) {
if (c1.getClassName().equals(fieldType)
|| c1.getClassName().replace("/", ".")
.equals(fieldType)) {
isAdaptee = true;
adaptee = c1;
continue; // If this one, not the interface
}
if (c1.getClassName().equals(interfaceName)) {
isTarget = true;
target = c1;
}
if (target != null && adaptee != null) {
break;
}
}
if (isAdaptee && isTarget) {
adaptee.addPattern(
new AdapterPattern(adaptee.getClassName(),
"\\<\\<adaptee\\>\\>"));
target.addPattern(
new AdapterPattern(target.getClassName(),
"\\<\\<target\\>\\>"));
c0.addPattern(new AdapterPattern(c0.getClassName(),
"\\<\\<adapter\\>\\>"));
}
for (IRelation r : m.getRelations()) {
if (r.getFromObject()
.equals(c0.getClassName().replace("/", ""))
&& r.getToObject().equals(
fieldType.replace(".", ""))) {
r.addProperty("label=\"\\<\\<adapts\\>\\>\"");
}
}
}
});
}
}
AdapterVisitor adapterVisitor = new AdapterVisitor();
adapterVisitor.write(model);
Luke Danielson
- Worked on Decorator Visitor
- Helped on Adapter Visitor
Larry Gates
- Worked on Adapter Visitor
- Cleaned up code
Aaron Mercier
- Started Integration testing
- Helped with Decorator Visitor
- Helped with Adapter Visitor
After feedback from Chandan's review:
- : Make UML Diagram easier to read
- : Fix integration testing
As we progressed through the project, and also following Chandan's suggestion, the design of the project is overall in Visitor Pattern. Keeping most of the structure the same from the previous milestones, the visitor pattern is used for traversing through the model object and collecting information needed, then writing the output in a desired class that follows the output needed.
The Singleton tool is designed to be a Visitor Pattern. This way, all design patterns follow an interface and will allow future design patterns to use this. Inside of the IClass object, there is a list of IPattern objects that are effected by a pattern. The pattern then can bre used to print out specific values. Singleton code is in code section of this README. The IInvoker inferface will allow different files to write with information from the IVisitor object.
Instructions are still similar to previous milestone.
To test the program, there is a console available for use.
The client would input the desired classes, such as classes in a package, in as the initial arguments. Once that object is finished loading, a console type structure is loaded. From there, follow the prompts for desired inputs.
Supported operations: Generator, Help, Quit
Input command:> Generator
Generators: Supported generators - UML, Sequence
Input generator:> UML
Generated graph, please refresh the input_output folder
Supported operations: Generator, Help, Quit
Input command:> quit
public class SingletonPattern implements IPattern {
private String className;
private String UMLproperty;
private String UMLlabel;
public SingletonPattern(String className) {
this.className = className;
this.UMLproperty = "color=blue,";
this.UMLlabel = "\\<\\<Singleton\\>\\>";
}
@Override
public String UMLproperty() {
return this.UMLproperty;
}
public String getClassName(){
return this.className;
}
@Override
public String UMLlabel() {
return this.UMLlabel;
}
}
public class SingletonVisitor implements IInvoker {
private Visitor visitor;
private IClass currentClass;
private boolean hasFieldInstance;
private boolean hasMethodInstance;
public SingletonVisitor(){
this.visitor = new Visitor();
setupPreVisitClass();
visitField();
visitMethod();
postVisitClass();
}
private void setupPreVisitClass(){
this.visitor.addVisit(VisitType.PreVisit, ConcreteClass.class, (ITraverser t) ->{
this.currentClass = (IClass) t;
this.hasFieldInstance = false;
this.hasMethodInstance = false;
});
}
private void visitField(){
this.visitor.addVisit(VisitType.Visit, Field.class, (ITraverser t) -> {
IField f = (IField) t;
String desc = f.getDesc().replace(".", "/");
if (desc.equals(currentClass.getClassName())){
hasFieldInstance = true;
}
});
}
private void visitMethod(){
this.visitor.addVisit(VisitType.Visit, Method.class, (ITraverser t) -> {
IMethod m = (IMethod) t;
Type arg = Type.getReturnType(m.getDesc());
String arg2 = arg.toString().substring(1).replace(";", "");
if (arg2.equals(currentClass.getClassName())){
hasMethodInstance = true;
}
});
}
private void postVisitClass(){
this.visitor.addVisit(VisitType.PostVisit, ConcreteClass.class, (ITraverser t) -> {
IClass c = (IClass) t;
if (this.hasFieldInstance && this.hasMethodInstance){
c.addPattern(new SingletonPattern(c.getClassName()));
}
});
}
@Override
public void write(IModel model) {
ITraverser traverser = (ITraverser) model;
traverser.accept(this.visitor);
}
}
public interface IInvoker {
public void write(IModel model);
}
Added tests into the document
Luke Danielson
- Got Singleton pattern working
Larry Gates
- Unit test cases
Aaron Mercier
- Converted Sequence Generator to Visitor Pattern
After feedback from Chandan's review:
- Refactor the code so that the IArrow objects are outside of the IClass objects. Move them into hte IModel object.
- Handle relation objects in IModel
- Change the IGenerate class to become a visitor. Work with visitor models
- Method Container needs some refactoring
- Improve testing by creating an IModel object and testing the output with that
- Use a ByteArrayStream for testing instead of reading from files
- Fix the Sequence Diagrams for both the project and the shuffle method
A programmer and a business analyst are sitting in the break room one day eating lunch when suddenly the microwave catches fire. Thinking quickly, the analyst leaps up, unplugs the microwave, grabs the trash can, fills it with water from sink, and dumps the water on the microwave to put out the flames.
A few weeks later the two are again having lunch in the break room when suddenly the coffee maker bursts into flames. The programmer leaps up, grabs the coffee maker, shoves it into the microwave oven, and then hands the trash can to the business analyst, thus re-using the solution developed for the previous project.
- Test code:
- Testing Folder
- Project's New Tool
- Generated Sequence Diagram
- Manually Created Diagram
- Collections
- Generated Sequence Diagram
- Manually Created Diagram
The design patterns stayed mostly the same. Visitor Pattern used for ASM and Strategy Pattern used for the rest. We created an IGenerator object, which took the UML generator code and became an IGenerator object. Doing this allowed to implement future output files without making changes to our exisiting code.
Due to the improvement in running the program, the instructions are different from previous milestones.
To test the program, there is a console available for use.
The client would input the desired classes, such as classes in a package, in as the initial arguments. Once that object is finished loading, a console type structure is loaded. From there, follow the prompts for desired inputs.
For this milestone, the instructions would involve the shuffle method in Collections. Load java.util.Collections
into arguments, as in Eclipse and the run configuration.
Supported operations: Generator, Help, Quit
Input command:> Generator
Generators: Supported generators - UML, Sequence
Input generator:> Sequence
Input Class Name:>java.util.Collections
Input Method Name:>shuffle
Input Parameters (split by commas):>java.util.List
Input CallDepth (optional enter skip for default, default is 5)
class: java.util.Collections
method: shuffle
params: [java.util.List]
depth: 5
generating sequence diagram file
ERROR: The provided arguments do match any existing arguments
generating for method shuffle
generating for method swap
generating for method swap
Generated graph, please refresh the input_output folder
Supported operations: Generator, Help, Quit
Input command:> Quit
Aaron Mercier
- Created Sequence Diagram Generator object
- Started unit testing
- Completed Sequence Diagram Generator
Luke Danielson (Commit log is low due to fact he was capped. Worked with us, we forgot to include him in commit messages)
- Helped create Sequence Diagram Generator object
- Fixed Has Arrow dominance and duplicate arrow
- Made a console layout to allow easy running by any type of user
- Completed integrated testing
Larry Gates
- Created the container class to be used within methods.
- Finished unit testing
- Updated README
After feedback from Chandan's review:
- Create test classes for each class and appropriate method in the class
- Move the generate from IModel object and into its own class
- Ignore uses arrows when there is an association arrow (has)
- Add pictures to the Design sections of milestones
- Talk more about the type of Design Pattern(s) and other design implementations
- Continue to do integration testing
- Test code:
- Test File
- Abstract Factory PizzaStore
- Generated UML picture
- Project Code
- Designed UML Picture
- Generated UML Picture
While working on Milestone 2, it was important to use the information suggested by Dr. Rupakheti in lecture. Such as: visitMethodInsn and visitFieldInsn. The arrow objects were changed from just if statements and string to being a Strategy Pattern, which turned out to to be useful in the long run.
From reading the specifications and searching the given code, the team could not figure out how to find the inner types for arguments and return type of methods, such as for lists or collections.
The design pattern stayed the same, using Visitor Pattern for ASM and Strategy Pattern for the rest of it.
To run the program, run designParser (where the main method is located) with the classes you wish to have the UML generated for as arguments. If running the program from the command line, separate each argument with a space. If running the program through eclipse, right click on designParser, click on run configurations, go to the arguments tab, and fill in the classes in the "program arguments", separated by a space or a newline.
Luke Danielson
- Worked on testcases for Milestone 2
- Helped rewrite generateArrows(IClass obj) for Model.java with Larry
Larry Gates
- Constructed the Strategy Pattern for the 4 arrows for the classes.
- Helped rewrite generateArrows(IClass obj) for Model.java with Luke
Aaron Mercier
- Worked on visitors to create arrows
- Original design of handling arrows and values need for GraphViz to show the arrows.
The program is designed to create a coded model of the classes given as arguments. The model contains a list of classes, each class has it's info and a list of fields/methods, and each field/method has it's info. When ASM has finished visiting all of the given classes with the decorated visitors, the model's generateGraph method is called, which writes all of the stored information from the model into a graph.gv file. When the graph.gv file is finished, GraphViz generates a .PNG file using it.
The design patterns we used were: Visitor Pattern (ASM), and Strategy Pattern (remain parts)
To run the program, run designParser (where the main method is located) with the classes you wish to have the UML generated for as arguments. If running the program from the command line, separate each argument with a space. If running the program through eclipse, right click on designParser, click on run configurations, go to the arguments tab, and fill in the classes in the "program arguments", separated by a space or a newline.
The graph.gv and graph.png files are saved in the input_output folder.
There are example argument text files that can be copied and pasted into the argument box. AaronArguments.txt is the list of arguments for the generated UML for AaronsLab1-3 and MilestoneArguments.txt is the list of arguments for the generated UML for the project in project.asm package.
Aaron Mercier
- Set up the git repository
- implemented the method, field, and declaration visitors to create and fill in our model
- implemented/added the arrows to the .gv file
Luke Danielson
- Implemented the IClass and interface and the three subclasses ConcreteClass, AbstractClass, and InterfaceClass along with testing for each one.
- Implented/added fields to the .gv file.
Larry Gates
- Implemented the Field class and Method class.
- Implemented corresponding tests for the created classes.
- Implemented/added methods to the .gv file
- Made the .gv file more human readable.
Team Blue Shells:
- Luke Danielson
- Larry Gates
- Aaron Mercier