KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > buchuki > ensmer > input > command > CommandMap


1 /*
2  * Copyright 2004 Dusty Phillips
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package com.buchuki.ensmer.input.command;
17
18 import java.util.*;
19 import com.buchuki.ensmer.input.event.*;
20 import groovy.lang.Closure;
21
22 /**
23  * Class to map events to commands based on the owner of the command. Contains
24  * methods to add command/event mappings, and to retrieve them. Commands can
25  * either be implementations of the Command interface, or extensions of Groovy
26  * Closures (To allow commands to be added from frontend scripts).
27  *
28  * A general guideline: It should be ok to associate more than one event with
29  * the same command, but it is not wise to associate multiple commands with
30  * the same event for any one owner. It is up to the calling class to manage
31  * this; if multiple commands are associated with one event, only one
32  * (undefined) command will be fired.
33  *
34  * @author Dusty Phillips [dusty@buchuki.com]
35  */

36 public class CommandMap {
37
38     /**
39      * Add a command to the map of commands
40      *
41      * @param owner an object representing the owner of the command. This
42      * object is passed into retrieval functions so the CommandMap can manage
43      * commands for multiple objects.
44      * @param command an implementation of the <code>Command</code> interface
45      * that should be executed whenever the command is activated
46      * @param event an EnsmerInputEvent that can occur. Events are compared to
47      * this based on <code>.equals()</code> comparison to determine if they
48      * exist.
49      */

50     public void addCommand(Object JavaDoc owner, Command command, EnsmerInputEvent event) {
51         removeCommand(owner, event); //in case its being reset
52
List<CommandEvent> ownerList = owners.get(owner);
53         if (ownerList == null) {
54             ownerList = new ArrayList<CommandEvent>();
55             owners.put(owner, ownerList);
56         }
57         CommandEvent cmdevt = new CommandEvent(command, event);
58         ownerList.add(cmdevt);
59     }
60
61     /**
62      * Add a closure to the map of commands. The Closure is wrapped in a Command
63      * so it can be executed by the Commandmap. Used so Groovy scripts can add
64      * commands.
65      *
66      * @param owner an object representing the owner of the command.
67      * @param command a groovy <code>Closure</code> that is executed when the
68      * command is activated
69      * @param event an EnsmerInputEvent that can occur. Events are compared to
70      * this based on <code>.equals()</code> comparison.
71      */

72     public void addCommand(Object JavaDoc owner, Closure command, EnsmerInputEvent event) {
73         addCommand(owner, new ClosureCommand(command), event);
74     }
75     
76     /**
77      * Retrieve a command from the map of commands, given an event.
78      *
79      * @param owner an object representing the owner of the command to
80      * differentiate it from possible other objects assocated with the command
81      * @param event an event that has occured. A command is looked up as
82      * interacting with this event and is returned
83      * @return the command associated with the event for the given owner, or
84      * null if no command is associated with that event
85      */

86     public Command getCommand(Object JavaDoc owner, EnsmerInputEvent event) {
87         List<CommandEvent> ownerList = owners.get(owner);
88         if (ownerList == null) {
89             return null;
90         }
91         for (CommandEvent cmd: ownerList) {
92             if (cmd.getEvent().equals(event)) {
93                 return cmd.getCommand();
94             }
95         }
96         return null;
97     }
98     
99     /**
100      * Remove a command/event mapping from the map of commands, given an event.
101      * @param owner an object representing the owner of the command to differentiate
102      * it from possible other objects associated with the event
103      * @param event an event to compare to the list of command mappings; the
104      * associated command is removed
105      * @return the command that was removed
106      */

107     public Command removeCommand(Object JavaDoc owner, EnsmerInputEvent event) {
108         List <CommandEvent> ownerList = owners.get(owner);
109         if (ownerList == null) {
110             return null;
111         }
112         Command command = null;
113         Iterator<CommandEvent> i = ownerList.iterator();
114         while (i.hasNext()) {
115             CommandEvent cmd = i.next();
116             if (cmd.getEvent().equals(event)) {
117                 if (command == null) { //only return first match, remove all
118
command = cmd.getCommand();
119                 }
120                 i.remove();
121             }
122         }
123         return command;
124     }
125     
126     /**
127      * Remove all command/event mappings associated with a particular owner.
128      * @param owner an object representing the owner of the command to be
129      * removed. All commands associated with this owner are removed.
130      */

131     public void removeAllCommands(Object JavaDoc owner) {
132         owners.remove(owner);
133     }
134     
135     /**
136      * Interpret an event for the object. If the event exists for the given
137      * owner, the command associated with it is executed.
138      *
139      * @param owner an object representing the owner of the command to
140      * differentiate it from possible other objects associated with the
141      * command
142      * @param event an event that has occured. A command is looked up as
143      * interacting with this event and is executed
144      * @return true if a command was executed, false otherwise
145      */

146     public boolean interpretEvent(Object JavaDoc owner, EnsmerInputEvent event) {
147         Command cmd = getCommand(owner, event);
148         if (cmd != null) {
149             return cmd.execute(event);
150         }
151         return false;
152     }
153
154     /**
155      * Map linking object owners to a list of CommandEvent objects.
156      */

157     private Map<Object JavaDoc, List<CommandEvent>> owners =
158             new HashMap<Object JavaDoc, List<CommandEvent>>();
159
160     /**
161      * Class representing a command and event together. These are stored in
162      * lists that are sequentially searched for now; eventually a more
163      * scalable solution, perhaps based on hashing should be used.
164      *
165      * @author Dusty Phillips [dusty@buchuki.com]
166      */

167     private class CommandEvent {
168
169         /**
170          * Create a CommandEvent
171          *
172          * @param command the command executed
173          * @param event the event associated
174          */

175         public CommandEvent(Command command, EnsmerInputEvent event) {
176             this.command = command;
177             this.event = event;
178         }
179
180         /**
181          * Get the command to be executed
182          *
183          * @return the command to be executed
184          */

185         public Command getCommand() {
186             return command;
187         }
188
189         /**
190          * Get the event to be associated
191          *
192          * @return the event to be associated
193          */

194         public EnsmerInputEvent getEvent() {
195             return event;
196         }
197
198         /**
199          * The command to be executed
200          */

201         private Command command;
202
203         /**
204          * The event to be associated
205          */

206         private EnsmerInputEvent event;
207     }
208 }
209
210 /**
211  * Class to wrap a Groovy closure in a Command so it can be easily called. The
212  * Closure must accept one argument (An EnsmerInputEvent) and return a Boolean
213  * That is, it must indirectly implement the Command interface
214  *
215  * @author Dusty Phillips [dusty@buchuki.com]
216  */

217 class ClosureCommand implements Command {
218     /**
219      * The Closure to delegate to.
220      */

221     private Closure closure;
222     
223     /**
224      * Construct the ClosureCommand with a reference to the Closure that it must
225      * interact with.
226      */

227     public ClosureCommand(Closure closure) {
228         this.closure = closure;
229     }
230     
231     /**
232      * Execute the command. Call the closure and return its value. No error
233      * checking is done.
234      */

235     public boolean execute(EnsmerInputEvent event) {
236         return (Boolean JavaDoc) closure.call(event);
237     }
238 }
239
Popular Tags