summaryrefslogtreecommitdiffstats
path: root/docs/dist/doc/examples/spacewar/Debug.java
blob: a3afb1ddac2a06e9f5bc0a7dcd97ad5b20b17c42 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
/*

Copyright (c) Xerox Corporation 1998-2002.  All rights reserved.

Use and copying of this software and preparation of derivative works based
upon this software are permitted.  Any distribution of this software or
derivative works must comply with all applicable United States export control
laws.

This software is made available AS IS, and Xerox Corporation makes no warranty
about the software, its performance or its conformity to any specification.

|<---            this code is formatted to fit into 80 columns             --->|
|<---            this code is formatted to fit into 80 columns             --->|
|<---            this code is formatted to fit into 80 columns             --->|

Debug.java
Part of the Spacewar system.

*/

package spacewar;

import java.awt.Menu;
import java.awt.CheckboxMenuItem;
import java.awt.Frame;
import java.awt.TextArea;
import java.awt.Dimension;

/**
 * This aspect specifies debugging information to be output to the
 * information window.
 *
 * When the debug aspect is compiled in the Frame menu has several checkbox
 * items that can be used to control the amount of tracing information
 * displayed.  (By default the first three are off, because they generate
 * so much information.)
 *
 * There are two reasons to gather all this debugging code into an aspect
 * like this:
 *
 *   (1) It makes it easier to understand when it is all in one place.
 *
 *   (2) It means that we can "plug and debug".  We can enable/disable
 *       the debugging code simply by weaving or not weaving this
 *       aspect in.
 *
 * All in all, this is a lot better than the usual practice of writing
 * complex debugging code and then deleting it when the bug is found,
 * only to regret it a month later when a related bug surfaces.  (Or even
 * the same bug!)
 *
 * This file also defines a class InfoWin, which it uses to display all the
 * debugging information.
 */
aspect Debug {

    private static InfoWin infoWin = new InfoWin();

    private static Menu menu = new Menu("Debug");

    private static CheckboxMenuItem traceConstructors =
        new CheckboxMenuItem("trace constructors", false);
    private static CheckboxMenuItem traceInitializations =
        new CheckboxMenuItem("trace initializations", false);
    private static CheckboxMenuItem traceMethods =
        new CheckboxMenuItem("trace methods", false);
    private static CheckboxMenuItem traceClockTick =
        new CheckboxMenuItem("trace clock tick", false);
    private static CheckboxMenuItem traceRegistry =
        new CheckboxMenuItem("trace registry", true);
    private static CheckboxMenuItem traceFireCollideDamage =
        new CheckboxMenuItem("trace fire, collide, damage", true);

    after() returning (SWFrame frame): call(SWFrame+.new(..)) {
        menu.add(traceConstructors);
        menu.add(traceInitializations);
        menu.add(traceMethods);
        menu.add(traceClockTick);
        menu.add(traceRegistry);
        menu.add(traceFireCollideDamage);
        frame.getMenuBar().add(menu);
    }

    /*
     * all constructors
     */
    pointcut allConstructorsCut(): 
	call((spacewar.* && !(Debug+ || InfoWin+)).new(..));

    before(): allConstructorsCut() {
        if (traceConstructors.getState()) {
            infoWin.println("begin constructing " + thisJoinPoint.getSignature());
        }
    }

    after() returning: allConstructorsCut() {
        if (traceConstructors.getState()) {
            infoWin.println("done constructing " + thisJoinPoint.getSignature());
        }
    }

    /*
     * All dynamic initializations
     */
    pointcut allInitializationsCut(): 
	initialization((spacewar.* && !(Debug+ || InfoWin+)).new(..));

    before(): allInitializationsCut() {
        if (traceConstructors.getState()) {
            infoWin.println("begin initializing " + thisJoinPoint.getSignature());
        }
    }
    after() returning : allInitializationsCut() {
        if (traceConstructors.getState()) {
            infoWin.println("done initializing " + thisJoinPoint.getSignature());
        }
    }

    /*
     * all methods
     */
    pointcut allMethodsCut(): 
        execution(* (spacewar.* && !(Debug+ || InfoWin+)).*(..));

    before(): allMethodsCut() {
        if (traceMethods.getState()) {
            infoWin.println("entering " + thisJoinPoint.getSignature());
        }
    }
    after() returning : allMethodsCut() {
        if (traceMethods.getState()) {
            infoWin.println("exiting " + thisJoinPoint.getSignature());
        }
    }

    /*
     * clock ticks
     */
    after(Object obj) returning :
        (target(obj) && (target(Game) ||
			 target(Registry) ||
			 target(SpaceObject)))
        && call(void clockTick()) {
        if (traceClockTick.getState())
            infoWin.println("ticking " + obj);
    }

    /*
     * registry contents
     */
    after(Registry registry) returning :
        target(registry) && (call(void register(..)) ||
			     call(void unregister(..))) {
        if (traceRegistry.getState())
            infoWin.println(registry.getTable().size() +
                            " space objects in the registry.");
    }

    /*
     * fire, collide, damage
     */
    after() returning : call(void Ship.fire()) {
        if (traceFireCollideDamage.getState())
            infoWin.println("firing");
    }

    after(Ship ship, SpaceObject obj) returning :
	call(void handleCollision(SpaceObject)) && target(ship) && args(obj) {
        if (traceFireCollideDamage.getState())
            infoWin.println(ship + " collides with " + obj);
    }

    after(Ship shipA, Ship shipB) returning :
        execution(void Ship.bounce(Ship, Ship)) && args(shipA, shipB) {
        if (traceFireCollideDamage.getState())
            infoWin.println(shipA + " bounces with " + shipB);
    }

    before(Ship ship, double amount):
	call(void Ship.inflictDamage(double)) && target(ship) && args(amount) {
        if (traceFireCollideDamage.getState())
            if (amount > 0)
                infoWin.println(ship + "gets " +
                                amount + " damage (" +
                                ship.getDamage() + ")");
    }

}

class InfoWin {
    private Frame    frame;
    private TextArea info;

    InfoWin() {
        frame = new Frame("debugging info for spacewar game");
        info = new TextArea();
        info.setEditable(false);

        Dimension screenSize = frame.getToolkit().getScreenSize();
        frame.setSize(250, 600);
        frame.setLocation(screenSize.width - 250, 0);
        frame.add(info);
        frame.show();
        frame.toFront();
    }

    void clear() {
        info.setText("");
    }

    void println(String line) {
        info.append(line + "\n");
    }

    void print(String line) {
        info.append(line);
    }
}