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
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
|
package ca.ubc.cs.spl.aspectPatterns.patternLibrary;
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This file is part of the design patterns project at UBC
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* either https://www.mozilla.org/MPL/ or https://aspectj.org/MPL/.
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is ca.ubc.cs.spl.aspectPatterns.
*
* For more details and the latest version of this code, please see:
* https://www.cs.ubc.ca/labs/spl/projects/aodps.html
*
* Contributor(s):
*/
import java.util.WeakHashMap;
import java.util.Collection;
import java.util.LinkedList;
import java.util.Iterator;
import ca.ubc.cs.spl.aspectPatterns.patternLibrary.Command;
import ca.ubc.cs.spl.aspectPatterns.patternLibrary.CommandInvoker;
import ca.ubc.cs.spl.aspectPatterns.patternLibrary.CommandReceiver;
/**
* This is the abstract <i>Command</i> protocol.
*
* Note that this implementation allows only for exactly one command per
* invoker. That is usually sufficient, but alternate implementations
* could account for multiple commands by using composite
* (macro) commands (either with or without defined order).
*
* To allow for some flexibility, commands can either be explicitly
* set or removed by <i>Client</i>s, or this can be done via
* pointcuts.
*
* @author Jan Hannemann
* @author Gregor Kiczales
* @version 1.1, 02/17/04
*/
public abstract aspect CommandProtocol {
////////////////////////////////
// Invoker -> Command mapping //
////////////////////////////////
/**
* stores the mapping between CommandInvokers and Commands
*/
private WeakHashMap mappingInvokerToCommand = new WeakHashMap();
/**
* Sets a new command for an invoker
*
* @param invoker the object which will invoke the command
* @param command the command to be set
* @return the former command
*/
public Object setCommand(CommandInvoker invoker, Command command) {
return mappingInvokerToCommand.put(invoker, command);
}
/**
* Removes a command from an invoker
*
* @param invoker the object which will no longer invoke the command
* @param command the command to be removed
* @return the former command
*/
public Object removeCommand(CommandInvoker invoker) {
return setCommand(invoker, null);
}
/**
* Returns the command for an invoker
*
* @param invoker the object for which to return the command
* @return the current command for the invoker
*/
public Command getCommand(CommandInvoker invoker) {
return (Command) mappingInvokerToCommand.get(invoker);
}
/////////////////////////////////
// Command -> Receiver mapping //
/////////////////////////////////
/**
* stores the mapping between Coammnds and Receivers
*/
private WeakHashMap mappingCommandToReceiver = new WeakHashMap();
/**
* Sets a new receiver for a command
*
* @param command the command to be set
* @param receiver the object to be manipulated by the command's
* execute() method
* @return the former receiver
*/
public Object setReceiver(Command command, CommandReceiver receiver) {
return mappingCommandToReceiver.put(command, receiver);
}
/**
* Returns the receiver for a particular command
*
* @param invoker the object for which to return the command
* @returns the current command for the invoker
*/
public CommandReceiver getReceiver(Command command) {
return (CommandReceiver) mappingCommandToReceiver.get(command);
}
///////////////////////////////////////
// Command Execution via PC & advice //
///////////////////////////////////////
/**
* The join points after which to execute the command.
* This replaces the normally scattered <i>Command.execute()</i> calls.
*
* @param invoker the object invoking the command
*/
protected abstract pointcut commandTrigger(CommandInvoker invoker);
/**
* Calls <code>executeCommand()</code> when the command is triggered.
*
* @param invoker the object invoking the command
*/
after(CommandInvoker invoker): commandTrigger(invoker) {
Command command = getCommand(invoker);
if (command != null) {
CommandReceiver receiver = getReceiver(command);
command.executeCommand(receiver);
} else {
// Do nothing: This Invoker has no associated command
}
}
//////////////////////////////////
// setCommand() via PC & advice //
//////////////////////////////////
/**
* The join points after which to set a command for an invoker.
* This replaces the normally scattered <i>Invoker.add(Command)</i> calls.
* The pointcut is provided in addition to the setCommand() method above,
* to allow all pattern code to be removed from concrete invokers.
*
* This PC is non-abstract, to make it optional for sub-aspcects to define
* it.
*
* @param invoker the invoker to attach the command to
* @param command the command to be attached to the invoker
*/
protected pointcut setCommandTrigger(CommandInvoker invoker, Command command);
/**
* Calls <code>addCommand()</code> when a command should be set.
*
* @param invoker the invoker to attach the command to
* @param command the command to be attached to the invoker
*/
after (CommandInvoker invoker, Command command):
setCommandTrigger(invoker, command) {
if (invoker != null) {
setCommand(invoker, command);
} else {
// If the invoker is null, the command cannot be set.
// Either ignore this case or throw an exception
}
}
/////////////////////////////////////
// removeCommand() via PC & advice //
/////////////////////////////////////
/**
* The join points after which to remove a command from an invoker.
* This replaces the normally scattered <code>Invoker.remove(Command)
* </code> calls.
*
* The pointcut is provided in addition to the <code>removeCommand()
* </code> method above, to allow all pattern code to be removed from
* concrete invokers.
*
* This PC is non-abstract, to make it optional for sub-aspcects to define
* it.
*
* @param invoker the invoker to remove the command from
*/
protected pointcut removeCommandTrigger(CommandInvoker invoker);
/**
* Calls <code>removeCommand()</code> when a command should be removed.
*
* @param invoker the invoker to remove the command from
*/
after(CommandInvoker invoker): removeCommandTrigger(invoker) {
if (invoker != null) {
removeCommand(invoker);
} else {
// If the invoker is null, the command cannot be removed.
// Either ignore this case or throw an exception
}
}
////////////////////////////////////////////
// Command default method implementations //
////////////////////////////////////////////
/**
* Provides a deault implementation for the isExecutable method defined
* in the Command interface.
*
* @return true (default implementation). Can be overwritten by concrete
* aspects or even concrete commands.
*/
public boolean Command.isExecutable() {
return true;
}
}
|