Line: 1 to 1 | ||||||||
---|---|---|---|---|---|---|---|---|
Using Aspects to build GUIsSukesh Chopra, Kaitlin Duck Sherwood, and Sebastian Streg | ||||||||
Line: 72 to 72 | ||||||||
| ||||||||
Changed: | ||||||||
< < |
| |||||||
> > |
| |||||||
| ||||||||
Changed: | ||||||||
< < | After careful evaluation, we decided to use Swix as our XML translator. | |||||||
> > | After careful thought we decided to use Swix as our XML translator. | |||||||
Out of the box, Swix takes two input files: an XML file which describes the GUI, and a Java class that does some initialization, defines actions used by the GUI (as methods in the class, not in the widgets' class) , and starts Swix. | ||||||||
Line: 97 to 97 | ||||||||
Similarly, we considered inserting a dummy method in the wrapper class(es) to correspond to each instance. The only function of the dummy methods would be to give the developer something unique to the instance that they could then exploit with a pointcut. | ||||||||
Changed: | ||||||||
< < | Instead, we realized that since we had to use a wrapper anyway, we could pass an instance identifier to a wrapper's constructor and use that id in advice to determine whether it was the correct instance for that advice. | |||||||
> > | Instead, we theorized that since we had to use a wrapper anyway, we could pass an instance identifier to a wrapper's constructor and use that id in advice to determine whether it was the correct instance for that advice. Unfortunately, modifying Swix to allow inserting the instance ID to the constructor is very complicated. Instead, immediately after object creation, we pass the ID to a dummy method: dummyParserMethod(obj, object_id); We then key advice on the dummyParserMethod: | |||||||
Changed: | ||||||||
< < | public aspect AddListener { private XTextField countField; private XLabel pressCount; | |||||||
> > | after(Object obj, String id): call(* Parser.dummyParserMethod(Object, String)) && args(obj, id) | |||||||
Deleted: | ||||||||
< < | after(String aName, String aLabel): execution(XButton.new(String, String)) && args(aName, aLabel) { if(aName == "buttonOne") | |||||||
{ | ||||||||
Changed: | ||||||||
< < | XButton xb = (XButton)(thisJoinPoint.getThis()); xb.addActionListener(new ActionListener() | |||||||
> > | if(id == "FlowLayout1") | |||||||
{ | ||||||||
Added: | ||||||||
> > | XButton xbutton = (XButton)obj; xbutton.addActionListener(new ActionListener() { | |||||||
public void actionPerformed(ActionEvent e) | ||||||||
Added: | ||||||||
> > | ||||||||
{ | ||||||||
Changed: | ||||||||
< < | button1 action; }); } | |||||||
> > | // TODO: add in behaviour for FlowLayout1 here System.out.println("Behaviour for FlowLayout1 not yet implemented.\n"); | |||||||
} | ||||||||
Deleted: | ||||||||
< < | after(String aName, String aLabel): execution(XButton.new(String, String)) && args(aName, aLabel) { if(aName == "buttonTwo") { XButton xb = (XButton)(thisJoinPoint.getThis()); xb.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { button2 action; | |||||||
}); | ||||||||
Changed: | ||||||||
< < | } | |||||||
> > | ||||||||
} } | ||||||||
Changed: | ||||||||
< < | Broadly speaking, there are two important characteristics of widgets: actions (e.g. button pushes) and state (e.g. text fields, labels). Actions can be attached to widgets once, in advice after() the widget is created. Widgets with state need to have a pointer to them kept in the state. This structure is so regular that a skeleton can be generated automatically. Note that we can take advantage of being able to define identical pointcuts to separate advice for different buttons. We could have made one advice with if statements to figure out which instance it was, but that would jumble different instances' actions together. In the case of widgets with behaviour, the behaviour is attached to the widget once, right after construction of the widget. In cases where the widget has state that needs to be maintained, a pointer to the widget can be grabbed once, right after construction of the widget. | |||||||
> > | Skeleton generation | |||||||
Unmodified, Swix takes as inputs
| ||||||||
Changed: | ||||||||
< < | We add an aspect file to the above, but the Java starter class file is now simple enough to make with a preprocessing utility. We also have a pre-processing utility that creates a "skeleton" aspect that the users would flesh out with behavioural code. | |||||||
> > | We add an aspect file to the above, but the Java starter class file is now simple enough to make with a preprocessing utility. The auxilliary Java class is now much simpler: it has only one string that ever changes, so it can be made automatically. Broadly speaking, there are two important characteristics of widgets: actions (e.g. button pushes) and state (e.g. text fields, labels). Actions can be attached to widgets once, in advice after() the widget is created. Widgets with state need to have a pointer to them kept in the aspect so that they can be used by advice. | |||||||
StatusWe lost a huge amount of time trying to configure Eclipse to get load time weaving to work, so are a bit behind. (We are not the only group bitten by configuration issues; Arjun also spent a lot of time configuring Eclipse.) | ||||||||
Changed: | ||||||||
< < | We have modified Swix so that instead of creating JComponent instances, it creates instances of our wrapper classes. At this point, it makes XButton, XTextField, and XLabel instances instead of JButton, JTextField, and JLabel instances. | |||||||
> > | We have modified Swix so that instead of creating JComponent instances, it creates instances of our wrapper classes. At this point, it makes XButton, XTextField, XPanel, and XLabel instances instead of JButton, JTextField, JPanel, and JLabel instances. | |||||||
Changed: | ||||||||
< < | We have extended the format of the Swix input XML format slightly. It already had a slot to define which action should be used for a widget (although the code for those actions needed to be placed in the auxilliary Java class); we now recognize a | |||||||
> > | We have written XSLT that translates the XML (including the actions) into an aspect file. We also create the starter Java file -- it is trivial to create. The Swix input XML format already had a slot to define an id; we currently make that mandatory. We hope to remove that restriction in the future. | |||||||
At this point, we have a two-step process: we create the aspect and the auxilliary Java class statically and then start Swix using those files as input; we do not expect significant problems combining those steps. | ||||||||
Changed: | ||||||||
< < | @@@ we probably need to hack out the bits where the action is called -- it will try to go to the aux Java class.
@@@ do we need to ignore the | |||||||
> > | At this point, we have not demonstrated that the advice and Parser code work well together. There is some configuration bug that is preventing even the simplest of pointcuts/advice from being recognized. Even this will not fire:
public aspect SwixAspect { after(): call(* SwixClass.moo(int)) { System.out.println("....................................................."); } } | |||||||
Added: | ||||||||
> > | We feel reasonably certain that we will be able to figure out the configuration issue (or get help on it), just not tonight. | |||||||