f@0
|
1 /*
|
f@0
|
2 CCmI Editor - A Collaborative Cross-Modal Diagram Editing Tool
|
f@0
|
3
|
f@0
|
4 Copyright (C) 2011 Queen Mary University of London (http://ccmi.eecs.qmul.ac.uk/)
|
f@0
|
5
|
f@0
|
6 This program is free software: you can redistribute it and/or modify
|
f@0
|
7 it under the terms of the GNU General Public License as published by
|
f@0
|
8 the Free Software Foundation, either version 3 of the License, or
|
f@0
|
9 (at your option) any later version.
|
f@0
|
10
|
f@0
|
11 This program is distributed in the hope that it will be useful,
|
f@0
|
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
f@0
|
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
f@0
|
14 GNU General Public License for more details.
|
f@0
|
15
|
f@0
|
16 You should have received a copy of the GNU General Public License
|
f@0
|
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
|
f@0
|
18 */
|
f@0
|
19
|
f@0
|
20 package uk.ac.qmul.eecs.ccmi.network;
|
f@0
|
21
|
f@0
|
22 import java.awt.geom.Point2D;
|
f@0
|
23 import java.awt.geom.Rectangle2D;
|
f@0
|
24 import java.io.IOException;
|
f@0
|
25 import java.nio.channels.SelectionKey;
|
f@0
|
26 import java.nio.channels.Selector;
|
f@0
|
27 import java.nio.channels.SocketChannel;
|
f@0
|
28 import java.text.MessageFormat;
|
f@0
|
29 import java.util.HashMap;
|
f@0
|
30 import java.util.HashSet;
|
f@0
|
31 import java.util.Iterator;
|
f@0
|
32 import java.util.LinkedList;
|
f@0
|
33 import java.util.Map;
|
f@0
|
34 import java.util.ResourceBundle;
|
f@0
|
35 import java.util.Set;
|
f@0
|
36 import java.util.concurrent.BlockingQueue;
|
f@0
|
37 import java.util.concurrent.ConcurrentLinkedQueue;
|
f@0
|
38 import java.util.concurrent.LinkedBlockingQueue;
|
f@0
|
39
|
f@0
|
40 import javax.swing.SwingUtilities;
|
f@0
|
41
|
f@0
|
42 import uk.ac.qmul.eecs.ccmi.diagrammodel.DiagramElement;
|
f@0
|
43 import uk.ac.qmul.eecs.ccmi.diagrammodel.DiagramTreeNode;
|
f@0
|
44 import uk.ac.qmul.eecs.ccmi.gui.Diagram;
|
f@0
|
45 import uk.ac.qmul.eecs.ccmi.gui.DiagramEventSource;
|
f@0
|
46 import uk.ac.qmul.eecs.ccmi.gui.DiagramPanel;
|
f@0
|
47 import uk.ac.qmul.eecs.ccmi.gui.Edge;
|
f@0
|
48 import uk.ac.qmul.eecs.ccmi.gui.EditorTabbedPane;
|
f@0
|
49 import uk.ac.qmul.eecs.ccmi.gui.Finder;
|
f@0
|
50 import uk.ac.qmul.eecs.ccmi.gui.Node;
|
f@0
|
51 import uk.ac.qmul.eecs.ccmi.gui.SpeechOptionPane;
|
f@0
|
52 import uk.ac.qmul.eecs.ccmi.gui.awareness.DisplayFilter;
|
f@0
|
53 import uk.ac.qmul.eecs.ccmi.speech.Narrator;
|
f@0
|
54 import uk.ac.qmul.eecs.ccmi.speech.NarratorFactory;
|
f@0
|
55 import uk.ac.qmul.eecs.ccmi.utils.InteractionLog;
|
f@0
|
56
|
f@0
|
57 /**
|
f@0
|
58 * This is the class that manages the connection with the server. When a diagram is shared
|
f@0
|
59 * this class becomes responsible for actually operating the model (trough the EVT tough, by calling SwingUtilities.invokeLater ).
|
f@0
|
60 * If the operation is issued by the local user, than it performs the local action with local data only after
|
f@0
|
61 * being acknowledged by the server, else it creates the data on demand. For example upon an insert
|
f@0
|
62 * issued by the server, the element is created from scratch, according to the message of the server.
|
f@0
|
63 *
|
f@0
|
64 */
|
f@0
|
65 public class ClientConnectionManager extends NetworkThread {
|
f@0
|
66
|
f@0
|
67 public ClientConnectionManager(EditorTabbedPane tabbedPane) throws IOException{
|
f@0
|
68 super("Network Client Thread");
|
f@0
|
69 channels = new HashMap<SocketChannel, Diagram>();
|
f@0
|
70 requests = new ConcurrentLinkedQueue<Request>();
|
f@0
|
71 answers = new LinkedBlockingQueue<Answer>();
|
f@0
|
72 pendingCommands = new LinkedList<SendCmdRequest>();
|
f@0
|
73 selector = Selector.open();
|
f@0
|
74 this.tabbedPane = tabbedPane;
|
f@0
|
75 protocol = ProtocolFactory.newInstance();
|
f@0
|
76 mustSayGoodbye = false;
|
f@0
|
77 waitingAnswer = false;
|
f@0
|
78 }
|
f@0
|
79
|
f@0
|
80 /**
|
f@0
|
81 * The Event Dispatching Thread communicates with this thread through a concurrent queue.
|
f@0
|
82 * This is the method to add requests to the queue.
|
f@0
|
83 * @param r the request for this thread
|
f@0
|
84 */
|
f@0
|
85 public void addRequest(Request r){
|
f@0
|
86 requests.add(r);
|
f@0
|
87 if(r instanceof SendLockRequest){
|
f@0
|
88 SendLockRequest slr = (SendLockRequest) r;
|
f@0
|
89 if(slr.lock.getName().toString().startsWith(LockMessage.GET_LOCK_PREFIX))
|
f@0
|
90 waitingAnswer = true;
|
f@0
|
91 }
|
f@0
|
92 selector.wakeup();
|
f@0
|
93 }
|
f@0
|
94
|
f@0
|
95 public Answer getAnswer(){
|
f@0
|
96 try {
|
f@0
|
97 Answer answer = answers.take();
|
f@0
|
98 waitingAnswer = false;
|
f@0
|
99 return answer;
|
f@0
|
100 } catch (InterruptedException e) {
|
f@0
|
101 throw new RuntimeException(e);// must never happen
|
f@0
|
102 }
|
f@0
|
103 }
|
f@0
|
104
|
f@0
|
105 @Override
|
f@0
|
106 public void run(){
|
f@0
|
107 while(!mustSayGoodbye){
|
f@0
|
108 try {
|
f@0
|
109 selector.select();
|
f@0
|
110 } catch (IOException e) {
|
f@0
|
111 revertAllDiagrams();
|
f@0
|
112 }
|
f@0
|
113
|
f@0
|
114 if(mustSayGoodbye)
|
f@0
|
115 break;
|
f@0
|
116
|
f@0
|
117 /* handle the requests for the remote server from the local users */
|
f@0
|
118 handleRequests();
|
f@0
|
119
|
f@0
|
120 for (Iterator<SelectionKey> itr = selector.selectedKeys().iterator(); itr.hasNext();){
|
f@0
|
121 SelectionKey key = itr.next();
|
f@0
|
122 itr.remove();
|
f@0
|
123
|
f@0
|
124 if(!key.isValid())
|
f@0
|
125 continue;
|
f@0
|
126
|
f@0
|
127 if(key.isReadable()){
|
f@0
|
128 SocketChannel channel = (SocketChannel)key.channel();
|
f@0
|
129 Message msg = null;
|
f@0
|
130 try {
|
f@0
|
131 msg = protocol.receiveMessage(channel);
|
f@0
|
132 } catch (IOException e) {
|
f@0
|
133 revertDiagram(channel,false);
|
f@0
|
134 /* signal the event dispatching thread, otherwise blocked */
|
f@0
|
135 try {
|
f@0
|
136 /* RevertedDiagramAnswer is to prevent the Event dispatching Thread from blocking if the *
|
f@0
|
137 * server goes down and the client is still waiting for an answer. If the thread *
|
f@0
|
138 * was not waiting for an answers the RevertedDiagramAnswer will not be put in the queue */
|
f@0
|
139 if(waitingAnswer)
|
f@0
|
140 answers.put(new RevertedDiagramAnswer());
|
f@0
|
141 } catch (InterruptedException ie) {
|
f@0
|
142 throw new RuntimeException(ie);
|
f@0
|
143 }
|
f@0
|
144 continue;
|
f@0
|
145 }
|
f@0
|
146 //System.out.println("ClientConnaectionManager: read message " + msg.getName());
|
f@0
|
147 /* retrieve the diagram */
|
f@0
|
148 String diagramName = msg.getDiagram();
|
f@0
|
149 final Diagram diagram = channels.get(channel);
|
f@0
|
150 node = null;
|
f@0
|
151 edge = null;
|
f@0
|
152 if(msg instanceof Command){
|
f@0
|
153 final Command cmd = (Command)msg;
|
f@0
|
154 cmd.getSource().setDiagramName(diagram.getName());
|
f@0
|
155 /* log the command through the interaction log, if any */
|
f@0
|
156 Command.log(cmd, "remote command received");
|
f@0
|
157 switch(cmd.getName()){
|
f@0
|
158 case INSERT_NODE :
|
f@0
|
159 double dx = (Double)cmd.getArgAt(1);
|
f@0
|
160 double dy = (Double)cmd.getArgAt(2);
|
f@0
|
161 node = Finder.findNode((String)cmd.getArgAt(0), diagram.getNodePrototypes());
|
f@0
|
162 node = (Node)node.clone();
|
f@0
|
163 /* Place the top left corner of the bounds at the origin. It might be different from *
|
f@0
|
164 * the origin, as it depends on how the clonation is implemented internally. These calls *
|
f@0
|
165 * to translate are not notified to any listener as the node is not n the model yet */
|
f@0
|
166 Rectangle2D bounds = node.getBounds();
|
f@0
|
167 node.translate(new Point2D.Double(),-bounds.getX(),-bounds.getY(), DiagramEventSource.NONE);
|
f@0
|
168 /* perform the actual translation from the origin */
|
f@0
|
169 node.translate(new Point2D.Double(),dx,dy,DiagramEventSource.NONE);
|
f@0
|
170 SwingUtilities.invokeLater(new CommandExecutor.Insert(diagram.getCollectionModel(), node, null, cmd.getSource()));
|
f@0
|
171 break;
|
f@0
|
172 case INSERT_EDGE :
|
f@0
|
173 diagram.getCollectionModel().getMonitor().lock();
|
f@0
|
174 edge = Finder.findEdge((String)cmd.getArgAt(0), diagram.getEdgePrototypes());
|
f@0
|
175 edge = (Edge)edge.clone();
|
f@0
|
176 long[] nodesToConnect = new long[cmd.getArgNum()-1];
|
f@0
|
177 for(int i=0;i<nodesToConnect.length;i++)
|
f@0
|
178 nodesToConnect[i] = (Long)cmd.getArgAt(i+1);
|
f@0
|
179 SwingUtilities.invokeLater(new CommandExecutor.Insert(diagram.getCollectionModel(), edge, nodesToConnect, cmd.getSource()));
|
f@0
|
180 diagram.getCollectionModel().getMonitor().unlock();
|
f@0
|
181 break;
|
f@0
|
182 case REMOVE_NODE :
|
f@0
|
183 diagram.getCollectionModel().getMonitor().lock();
|
f@0
|
184 node = Finder.findNode((Long)cmd.getArgAt(0), diagram.getCollectionModel().getNodes());
|
f@0
|
185 diagram.getCollectionModel().getMonitor().unlock();
|
f@0
|
186 SwingUtilities.invokeLater(new CommandExecutor.Remove(diagram.getCollectionModel(),node,cmd.getSource()));
|
f@0
|
187 break;
|
f@0
|
188 case REMOVE_EDGE :
|
f@0
|
189 diagram.getCollectionModel().getMonitor().lock();
|
f@0
|
190 edge = Finder.findEdge((Long)cmd.getArgAt(0), diagram.getCollectionModel().getEdges());
|
f@0
|
191 diagram.getCollectionModel().getMonitor().unlock();
|
f@0
|
192 SwingUtilities.invokeLater(new CommandExecutor.Remove(diagram.getCollectionModel(),edge,cmd.getSource()));
|
f@0
|
193 break;
|
f@0
|
194 case SET_EDGE_NAME :
|
f@0
|
195 diagram.getCollectionModel().getMonitor().lock();
|
f@0
|
196 edge = Finder.findEdge((Long)cmd.getArgAt(0), diagram.getCollectionModel().getEdges());
|
f@0
|
197 diagram.getCollectionModel().getMonitor().unlock();
|
f@0
|
198 SwingUtilities.invokeLater(new CommandExecutor.SetName(edge, (String)cmd.getArgAt(1),cmd.getSource()));
|
f@0
|
199 break;
|
f@0
|
200 case SET_NODE_NAME :
|
f@0
|
201 diagram.getCollectionModel().getMonitor().lock();
|
f@0
|
202 node = Finder.findNode((Long)cmd.getArgAt(0), diagram.getCollectionModel().getNodes());
|
f@0
|
203 diagram.getCollectionModel().getMonitor().unlock();
|
f@0
|
204 SwingUtilities.invokeLater(new CommandExecutor.SetName(node, (String)cmd.getArgAt(1),cmd.getSource()));
|
f@0
|
205 break;
|
f@0
|
206 case SET_PROPERTY :
|
f@0
|
207 diagram.getCollectionModel().getMonitor().lock();
|
f@0
|
208 node = Finder.findNode((Long)cmd.getArgAt(0),diagram.getCollectionModel().getNodes());
|
f@0
|
209 diagram.getCollectionModel().getMonitor().unlock();
|
f@0
|
210 SwingUtilities.invokeLater(new CommandExecutor.SetProperty(
|
f@0
|
211 node,
|
f@0
|
212 (String)cmd.getArgAt(1),
|
f@0
|
213 (Integer)cmd.getArgAt(2),
|
f@0
|
214 (String)cmd.getArgAt(3),
|
f@0
|
215 cmd.getSource()
|
f@0
|
216 ));
|
f@0
|
217 break;
|
f@0
|
218 case SET_PROPERTIES :
|
f@0
|
219 diagram.getCollectionModel().getMonitor().lock();
|
f@0
|
220 node = Finder.findNode((Long)cmd.getArgAt(0),diagram.getCollectionModel().getNodes());
|
f@0
|
221 diagram.getCollectionModel().getMonitor().unlock();
|
f@0
|
222 SwingUtilities.invokeLater(new CommandExecutor.SetProperties(
|
f@0
|
223 node,
|
f@0
|
224 (String)cmd.getArgAt(1),
|
f@0
|
225 cmd.getSource()
|
f@0
|
226 ));
|
f@0
|
227 break;
|
f@0
|
228 case CLEAR_PROPERTIES :
|
f@0
|
229 diagram.getCollectionModel().getMonitor().lock();
|
f@0
|
230 node = Finder.findNode((Long)cmd.getArgAt(0),diagram.getCollectionModel().getNodes());
|
f@0
|
231 diagram.getCollectionModel().getMonitor().unlock();
|
f@0
|
232 SwingUtilities.invokeLater(new CommandExecutor.ClearProperties(node,cmd.getSource()));
|
f@0
|
233 break;
|
f@0
|
234 case SET_NOTES :
|
f@0
|
235 int[] path = new int[cmd.getArgNum()-1];
|
f@0
|
236 for(int i = 0; i< cmd.getArgNum()-1;i++){
|
f@0
|
237 path[i] = (Integer)cmd.getArgAt(i);
|
f@0
|
238 }
|
f@0
|
239 final String notes = (String)cmd.getArgAt(cmd.getArgNum()-1);
|
f@0
|
240 diagram.getCollectionModel().getMonitor().lock();
|
f@0
|
241 treeNode = Finder.findTreeNode(path, (DiagramTreeNode)diagram.getTreeModel().getRoot());
|
f@0
|
242 diagram.getCollectionModel().getMonitor().unlock();;
|
f@0
|
243 SwingUtilities.invokeLater(new CommandExecutor.SetNotes(diagram.getTreeModel(),treeNode, notes,cmd.getSource()));
|
f@0
|
244 break;
|
f@0
|
245 case ADD_PROPERTY :
|
f@0
|
246 diagram.getCollectionModel().getMonitor().lock();
|
f@0
|
247 node = Finder.findNode((Long)cmd.getArgAt(0),diagram.getCollectionModel().getNodes());
|
f@0
|
248 diagram.getCollectionModel().getMonitor().unlock();
|
f@0
|
249 SwingUtilities.invokeLater(new CommandExecutor.AddProperty(
|
f@0
|
250 node,
|
f@0
|
251 (String)cmd.getArgAt(1),
|
f@0
|
252 (String)cmd.getArgAt(2),
|
f@0
|
253 cmd.getSource()
|
f@0
|
254 ));
|
f@0
|
255 break;
|
f@0
|
256 case REMOVE_PROPERTY :
|
f@0
|
257 diagram.getCollectionModel().getMonitor().lock();
|
f@0
|
258 node = Finder.findNode((Long)cmd.getArgAt(0),diagram.getCollectionModel().getNodes());
|
f@0
|
259 diagram.getCollectionModel().getMonitor().unlock();
|
f@0
|
260 SwingUtilities.invokeLater(new CommandExecutor.RemoveProperty(
|
f@0
|
261 node,
|
f@0
|
262 (String)cmd.getArgAt(1),
|
f@0
|
263 (Integer)cmd.getArgAt(2),
|
f@0
|
264 cmd.getSource()));
|
f@0
|
265 break;
|
f@0
|
266 case SET_MODIFIERS :
|
f@0
|
267 diagram.getCollectionModel().getMonitor().lock();
|
f@0
|
268 node = Finder.findNode((Long)cmd.getArgAt(0),diagram.getCollectionModel().getNodes());
|
f@0
|
269 indexes = new HashSet<Integer>(cmd.getArgNum()-3);
|
f@0
|
270 for(int i=3;i<cmd.getArgNum();i++){
|
f@0
|
271 indexes.add((Integer)cmd.getArgAt(i));
|
f@0
|
272 }
|
f@0
|
273 diagram.getCollectionModel().getMonitor().unlock();
|
f@0
|
274 SwingUtilities.invokeLater(new CommandExecutor.SetModifiers(
|
f@0
|
275 node,
|
f@0
|
276 (String)cmd.getArgAt(1),
|
f@0
|
277 (Integer)cmd.getArgAt(2),
|
f@0
|
278 indexes,
|
f@0
|
279 cmd.getSource()));
|
f@0
|
280 break;
|
f@0
|
281 case SET_ENDLABEL :
|
f@0
|
282 diagram.getCollectionModel().getMonitor().lock();
|
f@0
|
283 edge = Finder.findEdge((Long)cmd.getArgAt(0),diagram.getCollectionModel().getEdges());
|
f@0
|
284 node = Finder.findNode((Long)cmd.getArgAt(1),diagram.getCollectionModel().getNodes());
|
f@0
|
285 diagram.getCollectionModel().getMonitor().unlock();
|
f@0
|
286 SwingUtilities.invokeLater(new CommandExecutor.SetEndLabel(edge, node,(String)cmd.getArgAt(2),cmd.getSource()));
|
f@0
|
287 break;
|
f@0
|
288 case SET_ENDDESCRIPTION :
|
f@0
|
289 diagram.getCollectionModel().getMonitor().lock();
|
f@0
|
290 edge = Finder.findEdge((Long)cmd.getArgAt(0),diagram.getCollectionModel().getEdges());
|
f@0
|
291 node = Finder.findNode((Long)cmd.getArgAt(1),diagram.getCollectionModel().getNodes());
|
f@0
|
292 diagram.getCollectionModel().getMonitor().unlock();
|
f@0
|
293 SwingUtilities.invokeLater(new CommandExecutor.SetEndDescription(
|
f@0
|
294 edge,
|
f@0
|
295 node,
|
f@0
|
296 (Integer)cmd.getArgAt(2),
|
f@0
|
297 cmd.getSource()
|
f@0
|
298 ));
|
f@0
|
299 break;
|
f@0
|
300 case TRANSLATE_NODE :
|
f@0
|
301 diagram.getCollectionModel().getMonitor().lock();
|
f@0
|
302 node = Finder.findNode((Long)cmd.getArgAt(0),diagram.getCollectionModel().getNodes());
|
f@0
|
303 diagram.getCollectionModel().getMonitor().unlock();
|
f@0
|
304 SwingUtilities.invokeLater(new CommandExecutor.Translate(
|
f@0
|
305 node,
|
f@0
|
306 new Point2D.Double((Double)cmd.getArgAt(1),(Double)cmd.getArgAt(2)),
|
f@0
|
307 (Double)cmd.getArgAt(3),
|
f@0
|
308 (Double)cmd.getArgAt(4),
|
f@0
|
309 cmd.getSource()));
|
f@0
|
310 break;
|
f@0
|
311 case TRANSLATE_EDGE :
|
f@0
|
312 diagram.getCollectionModel().getMonitor().lock();
|
f@0
|
313 edge = Finder.findEdge((Long)cmd.getArgAt(0),diagram.getCollectionModel().getEdges());
|
f@0
|
314 diagram.getCollectionModel().getMonitor().unlock();
|
f@0
|
315 SwingUtilities.invokeLater(new CommandExecutor.Translate(
|
f@0
|
316 edge,
|
f@0
|
317 new Point2D.Double((Double)cmd.getArgAt(1),(Double)cmd.getArgAt(2)),
|
f@0
|
318 (Double)cmd.getArgAt(3),
|
f@0
|
319 (Double)cmd.getArgAt(4),
|
f@0
|
320 cmd.getSource()));
|
f@0
|
321 break;
|
f@0
|
322 case BEND :
|
f@0
|
323 diagram.getCollectionModel().getMonitor().lock();
|
f@0
|
324 edge = Finder.findEdge((Long)cmd.getArgAt(0),diagram.getCollectionModel().getEdges());
|
f@0
|
325 diagram.getCollectionModel().getMonitor().unlock();
|
f@0
|
326 Point2D bendStart = null;
|
f@0
|
327 if(cmd.getArgNum() == 5){
|
f@0
|
328 bendStart = new Point2D.Double((Double)cmd.getArgAt(3),(Double)cmd.getArgAt(4));
|
f@0
|
329 }
|
f@0
|
330 SwingUtilities.invokeLater(new CommandExecutor.Bend(
|
f@0
|
331 edge,
|
f@0
|
332 new Point2D.Double((Double)cmd.getArgAt(1),(Double)cmd.getArgAt(2)),
|
f@0
|
333 bendStart,
|
f@0
|
334 cmd.getSource()));
|
f@0
|
335 break;
|
f@0
|
336 case STOP_EDGE_MOVE :
|
f@0
|
337 diagram.getCollectionModel().getMonitor().lock();
|
f@0
|
338 edge = Finder.findEdge((Long)cmd.getArgAt(0),diagram.getCollectionModel().getEdges());
|
f@0
|
339 diagram.getCollectionModel().getMonitor().unlock();
|
f@0
|
340 SwingUtilities.invokeLater(new CommandExecutor.StopMove(edge,cmd.getSource()));
|
f@0
|
341 break;
|
f@0
|
342 case STOP_NODE_MOVE :
|
f@0
|
343 node = Finder.findNode((Long)cmd.getArgAt(0), diagram.getCollectionModel().getNodes());
|
f@0
|
344 SwingUtilities.invokeLater(new CommandExecutor.StopMove(node,cmd.getSource()));
|
f@0
|
345 break;
|
f@0
|
346 }
|
f@0
|
347 }else if(msg instanceof Reply){
|
f@0
|
348 Reply reply = (Reply)msg;
|
f@0
|
349 /* log the reply through the interaction logger, if any */
|
f@0
|
350 Reply.log(reply);
|
f@0
|
351 sendCmdRequest = null;
|
f@0
|
352 for(SendCmdRequest scr : pendingCommands){
|
f@0
|
353 if(scr.matches(channel, reply.getDiagram())){
|
f@0
|
354 sendCmdRequest = scr;
|
f@0
|
355 break;
|
f@0
|
356 }
|
f@0
|
357 }
|
f@0
|
358 assert(sendCmdRequest != null);
|
f@0
|
359 pendingCommands.remove(sendCmdRequest);
|
f@0
|
360 switch(reply.getName()){
|
f@0
|
361 case INSERT_NODE_R :
|
f@0
|
362 case INSERT_EDGE_R :
|
f@0
|
363 SwingUtilities.invokeLater(new CommandExecutor.Insert(diagram.getCollectionModel(), sendCmdRequest.element, null, reply.getSource()));
|
f@0
|
364 break;
|
f@0
|
365 case REMOVE_EDGE_R :
|
f@0
|
366 case REMOVE_NODE_R :
|
f@0
|
367 SwingUtilities.invokeLater(new CommandExecutor.Remove(diagram.getCollectionModel(), sendCmdRequest.element,reply.getSource()));
|
f@0
|
368 break;
|
f@0
|
369 case SET_EDGE_NAME_R :
|
f@0
|
370 case SET_NODE_NAME_R :
|
f@0
|
371 SwingUtilities.invokeLater(new CommandExecutor.SetName(sendCmdRequest.element, (String)sendCmdRequest.cmd.getArgAt(1),reply.getSource()));
|
f@0
|
372 break;
|
f@0
|
373 case SET_PROPERTY_R :
|
f@0
|
374 SwingUtilities.invokeLater(new CommandExecutor.SetProperty(
|
f@0
|
375 (Node)sendCmdRequest.element,
|
f@0
|
376 (String)sendCmdRequest.cmd.getArgAt(1),
|
f@0
|
377 (Integer)sendCmdRequest.cmd.getArgAt(2),
|
f@0
|
378 (String)sendCmdRequest.cmd.getArgAt(3),
|
f@0
|
379 reply.getSource()
|
f@0
|
380 ));
|
f@0
|
381 break;
|
f@0
|
382 case SET_PROPERTIES_R :
|
f@0
|
383 Node n = (Node)sendCmdRequest.element;
|
f@0
|
384 SwingUtilities.invokeLater(new CommandExecutor.SetProperties(
|
f@0
|
385 n,
|
f@0
|
386 (String)sendCmdRequest.cmd.getArgAt(1),
|
f@0
|
387 reply.getSource()));
|
f@0
|
388 break;
|
f@0
|
389 case CLEAR_PROPERTIES_R :
|
f@0
|
390 SwingUtilities.invokeLater(new CommandExecutor.ClearProperties((Node)sendCmdRequest.element,reply.getSource()));
|
f@0
|
391 break;
|
f@0
|
392 case SET_NOTES_R :
|
f@0
|
393 SwingUtilities.invokeLater(new CommandExecutor.SetNotes(
|
f@0
|
394 diagram.getTreeModel(),
|
f@0
|
395 ((SendTreeCmdRequest)sendCmdRequest).treeNode,
|
f@0
|
396 (String)sendCmdRequest.cmd.getArgAt(sendCmdRequest.cmd.getArgNum()-1),
|
f@0
|
397 reply.getSource()));
|
f@0
|
398 break;
|
f@0
|
399 case ADD_PROPERTY_R :
|
f@0
|
400 SwingUtilities.invokeLater(new CommandExecutor.AddProperty(
|
f@0
|
401 (Node)sendCmdRequest.element,
|
f@0
|
402 (String)sendCmdRequest.cmd.getArgAt(1),
|
f@0
|
403 (String)sendCmdRequest.cmd.getArgAt(2),
|
f@0
|
404 reply.getSource()));
|
f@0
|
405 break;
|
f@0
|
406 case REMOVE_PROPERTY_R :
|
f@0
|
407 SwingUtilities.invokeLater(new CommandExecutor.RemoveProperty(
|
f@0
|
408 (Node)sendCmdRequest.element,
|
f@0
|
409 (String)sendCmdRequest.cmd.getArgAt(1),
|
f@0
|
410 (Integer)sendCmdRequest.cmd.getArgAt(2),
|
f@0
|
411 reply.getSource()));
|
f@0
|
412 break;
|
f@0
|
413 case SET_MODIFIERS_R :
|
f@0
|
414 indexes = new HashSet<Integer>(sendCmdRequest.cmd.getArgNum()-3);
|
f@0
|
415 for(int i=3;i<sendCmdRequest.cmd.getArgNum();i++){
|
f@0
|
416 indexes.add((Integer)sendCmdRequest.cmd.getArgAt(i));
|
f@0
|
417 }
|
f@0
|
418 SwingUtilities.invokeLater(new CommandExecutor.SetModifiers(
|
f@0
|
419 (Node)sendCmdRequest.element,
|
f@0
|
420 (String)sendCmdRequest.cmd.getArgAt(1),
|
f@0
|
421 (Integer)sendCmdRequest.cmd.getArgAt(2),
|
f@0
|
422 indexes,
|
f@0
|
423 reply.getSource()));
|
f@0
|
424 break;
|
f@0
|
425 case SET_ENDLABEL_R :
|
f@0
|
426 synchronized(diagram.getCollectionModel().getMonitor()){
|
f@0
|
427 node = Finder.findNode((Long)sendCmdRequest.cmd.getArgAt(1),diagram.getCollectionModel().getNodes());
|
f@0
|
428 }
|
f@0
|
429 SwingUtilities.invokeLater(new CommandExecutor.SetEndLabel(
|
f@0
|
430 (Edge)sendCmdRequest.element,
|
f@0
|
431 node,
|
f@0
|
432 (String)sendCmdRequest.cmd.getArgAt(2),
|
f@0
|
433 reply.getSource()));
|
f@0
|
434 break;
|
f@0
|
435 case SET_ENDDESCRIPTION_R :
|
f@0
|
436 synchronized(diagram.getCollectionModel().getMonitor()){
|
f@0
|
437 node = Finder.findNode((Long)sendCmdRequest.cmd.getArgAt(1),diagram.getCollectionModel().getNodes());
|
f@0
|
438 }
|
f@0
|
439 SwingUtilities.invokeLater(new CommandExecutor.SetEndDescription(
|
f@0
|
440 (Edge)sendCmdRequest.element,
|
f@0
|
441 node,
|
f@0
|
442 /* if the endDescription ain't included then we have to set it to null ( = NONE )*/
|
f@0
|
443 sendCmdRequest.cmd.getArgNum() == 3 ? (Integer)sendCmdRequest.cmd.getArgAt(2): -1,
|
f@0
|
444 reply.getSource()));
|
f@0
|
445 break;
|
f@0
|
446 case TRANSLATE_NODE_R :
|
f@0
|
447 node = (Node)sendCmdRequest.element;
|
f@0
|
448 SwingUtilities.invokeLater(new CommandExecutor.Translate(
|
f@0
|
449 node,
|
f@0
|
450 new Point2D.Double((Double)sendCmdRequest.cmd.getArgAt(1),(Double)sendCmdRequest.cmd.getArgAt(2)),
|
f@0
|
451 (Double)sendCmdRequest.cmd.getArgAt(3),
|
f@0
|
452 (Double)sendCmdRequest.cmd.getArgAt(4),
|
f@0
|
453 reply.getSource()));
|
f@0
|
454 break;
|
f@0
|
455 case TRANSLATE_EDGE_R :
|
f@0
|
456 edge = (Edge)sendCmdRequest.element;
|
f@0
|
457 SwingUtilities.invokeLater(new CommandExecutor.Translate(
|
f@0
|
458 edge,
|
f@0
|
459 new Point2D.Double((Double)sendCmdRequest.cmd.getArgAt(1),(Double)sendCmdRequest.cmd.getArgAt(2)),
|
f@0
|
460 (Double)sendCmdRequest.cmd.getArgAt(3),
|
f@0
|
461 (Double)sendCmdRequest.cmd.getArgAt(4),
|
f@0
|
462 reply.getSource()
|
f@0
|
463 ));
|
f@0
|
464 break;
|
f@0
|
465 case BEND_R :
|
f@0
|
466 edge = (Edge)sendCmdRequest.element;
|
f@0
|
467 Point2D bendStart = null;
|
f@0
|
468 if(sendCmdRequest.cmd.getArgNum() == 5){
|
f@0
|
469 bendStart = new Point2D.Double((Double)sendCmdRequest.cmd.getArgAt(3),(Double)sendCmdRequest.cmd.getArgAt(4));
|
f@0
|
470 }
|
f@0
|
471 SwingUtilities.invokeLater(new CommandExecutor.Bend(
|
f@0
|
472 edge,
|
f@0
|
473 new Point2D.Double((Double)sendCmdRequest.cmd.getArgAt(1),(Double)sendCmdRequest.cmd.getArgAt(2)),
|
f@0
|
474 bendStart,
|
f@0
|
475 reply.getSource()
|
f@0
|
476 ));
|
f@0
|
477 break;
|
f@0
|
478 case STOP_EDGE_MOVE_R :
|
f@0
|
479 edge = (Edge)sendCmdRequest.element;
|
f@0
|
480 SwingUtilities.invokeLater(new CommandExecutor.StopMove(edge,reply.getSource()));
|
f@0
|
481 break;
|
f@0
|
482 case STOP_NODE_MOVE_R :
|
f@0
|
483 node = (Node)sendCmdRequest.element;
|
f@0
|
484 SwingUtilities.invokeLater(new CommandExecutor.StopMove(node,reply.getSource()));
|
f@0
|
485 break;
|
f@0
|
486 case ERROR_R :
|
f@0
|
487 SwingUtilities.invokeLater(new CommandExecutor.ShowErrorMessageDialog(tabbedPane, "Error for command on "+ sendCmdRequest.element.getName()+ ". " +reply.getMessage(),reply.getSource()));
|
f@0
|
488 InteractionLog.log("SERVER", "error:reply from server", DiagramElement.toLogString(sendCmdRequest.element) + " " +reply.getMessage());
|
f@0
|
489 break;
|
f@0
|
490 default : throw new RuntimeException("Reply message not recognized: "+reply.getName());
|
f@0
|
491 }
|
f@0
|
492 }else if(msg instanceof LockMessage){ // lock message from the server
|
f@0
|
493 try {
|
f@0
|
494 answers.put(new LockAnswer((LockMessage)msg));
|
f@0
|
495 } catch (InterruptedException e) {
|
f@0
|
496 throw new RuntimeException(e); // must never happen
|
f@0
|
497 }
|
f@0
|
498 }else{ // awareness message
|
f@0
|
499 AwarenessMessage awMsg = (AwarenessMessage)msg;
|
f@0
|
500 DisplayFilter filter = DisplayFilter.getInstance();
|
f@0
|
501 if(filter != null){// if awareness panel ain't open, drop the packet
|
f@0
|
502 switch(awMsg.getName()){
|
f@0
|
503 case START_A :{
|
f@0
|
504 if(filter.configurationHasChanged()){
|
f@0
|
505 for(Diagram d : channels.values())
|
f@0
|
506 getAwarenessPanelEditor().clearRecords(d.getName());
|
f@0
|
507 }
|
f@0
|
508 DiagramEventActionSource actionSource = (DiagramEventActionSource)awMsg.getSource();
|
f@0
|
509 if(actionSource.getCmd() == Command.Name.INSERT_NODE || actionSource.getCmd() == Command.Name.INSERT_EDGE || actionSource.getCmd() == Command.Name.SELECT_NODE_FOR_EDGE_CREATION)
|
f@0
|
510 getAwarenessPanelEditor().addTimedRecord(diagramName, filter.processForText(actionSource));
|
f@0
|
511 else
|
f@0
|
512 getAwarenessPanelEditor().addRecord(diagramName, filter.processForText(actionSource));
|
f@0
|
513 /* announce the just received awareness message via the second voice */
|
f@0
|
514 NarratorFactory.getInstance().speakWholeText(filter.processForSpeech(actionSource), Narrator.SECOND_VOICE);
|
f@0
|
515 }break;
|
f@0
|
516 case STOP_A : {
|
f@0
|
517 if(filter.configurationHasChanged()){
|
f@0
|
518 for(Diagram d : channels.values())
|
f@0
|
519 getAwarenessPanelEditor().clearRecords(d.getName());
|
f@0
|
520 }
|
f@0
|
521 DiagramEventActionSource actionSource = (DiagramEventActionSource)awMsg.getSource();
|
f@0
|
522 /* unselect node for edge creation is announced and put temporarily on the text panel *
|
f@0
|
523 * (select node for edge creation is temporary as well so we don't need to clean the panel) */
|
f@0
|
524 if(actionSource.getCmd() == Command.Name.UNSELECT_NODE_FOR_EDGE_CREATION){
|
f@0
|
525 getAwarenessPanelEditor().addTimedRecord(diagramName, filter.processForText(actionSource));
|
f@0
|
526 NarratorFactory.getInstance().speakWholeText(filter.processForSpeech(actionSource));
|
f@0
|
527 }else{
|
f@0
|
528 getAwarenessPanelEditor().removeRecord(diagramName,filter.processForText(actionSource));
|
f@0
|
529 }
|
f@0
|
530 }break;
|
f@0
|
531 case USERNAME_A : {
|
f@0
|
532 String userNames = (String)awMsg.getSource();
|
f@0
|
533 getAwarenessPanelEditor().replaceUserName(diagramName,userNames);
|
f@0
|
534 }break;
|
f@0
|
535 case ERROR_A : {
|
f@0
|
536 SpeechOptionPane.showMessageDialog(tabbedPane, (String)awMsg.getSource());
|
f@0
|
537 }break;
|
f@0
|
538 }
|
f@0
|
539 }
|
f@0
|
540 }
|
f@0
|
541 }
|
f@0
|
542 }
|
f@0
|
543 }
|
f@0
|
544 /* this part is never reached out unless the thread is shut down */
|
f@0
|
545 for(SocketChannel channel : channels.keySet()){
|
f@0
|
546 try{channel.close();}catch(IOException ioe){ioe.printStackTrace();}
|
f@0
|
547 }
|
f@0
|
548 }
|
f@0
|
549
|
f@0
|
550 public void shutdown(){
|
f@0
|
551 mustSayGoodbye = true;
|
f@0
|
552 selector.wakeup();
|
f@0
|
553 }
|
f@0
|
554
|
f@0
|
555 private void handleRequests() {
|
f@0
|
556 while(!requests.isEmpty()){
|
f@0
|
557 Request request = requests.poll();
|
f@0
|
558 if(request instanceof AddDiagramRequest){
|
f@0
|
559 AddDiagramRequest adr = (AddDiagramRequest)request;
|
f@0
|
560 try {
|
f@0
|
561 adr.channel.configureBlocking(false);
|
f@0
|
562 adr.channel.register(selector, SelectionKey.OP_READ);
|
f@0
|
563 channels.put(adr.channel, adr.diagram);
|
f@0
|
564 } catch (IOException ioe) {
|
f@0
|
565 /* something went wrong, turn the diagram back into a local one */
|
f@0
|
566 /* put the entry in channels just for a moment as it will be used in revertDiagram */
|
f@0
|
567 channels.put(adr.channel, adr.diagram);
|
f@0
|
568 revertDiagram(adr.channel,false);
|
f@0
|
569 }
|
f@0
|
570 }else if(request instanceof RmDiagramRequest){ // user un-shared a diagram
|
f@0
|
571 RmDiagramRequest rdr = (RmDiagramRequest)request;
|
f@0
|
572 Set<Map.Entry<SocketChannel, Diagram>> entryset = channels.entrySet();
|
f@0
|
573 SocketChannel channel = null;
|
f@0
|
574 for(Map.Entry<SocketChannel, Diagram> entry : entryset){
|
f@0
|
575 if(entry.getValue().getName().equals(rdr.diagramName)){
|
f@0
|
576 channel = entry.getKey();
|
f@0
|
577 }
|
f@0
|
578 }
|
f@0
|
579 if(channel != null)
|
f@0
|
580 revertDiagram(channel,true);
|
f@0
|
581 }else if(request instanceof SendCmdRequest||request instanceof SendTreeCmdRequest){
|
f@0
|
582 SendCmdRequest scr = (SendCmdRequest)request;
|
f@0
|
583 //System.out.println("ClientConnectionManager:handling request "+scr.cmd.getName());
|
f@0
|
584 if(!channels.containsKey(scr.channel))
|
f@0
|
585 continue; // commands issued after reverting a diagram are dropped
|
f@0
|
586 pendingCommands.add(scr);
|
f@0
|
587 try{
|
f@0
|
588 protocol.send(scr.channel, scr.cmd);
|
f@0
|
589 }catch(IOException e){
|
f@0
|
590 /* the pending commands is normally removed upon reply receive */
|
f@0
|
591 pendingCommands.remove(scr);
|
f@0
|
592 revertDiagram(scr.channel,false);
|
f@0
|
593 }
|
f@0
|
594 }else if(request instanceof SendLockRequest){
|
f@0
|
595 SendLockRequest slr = (SendLockRequest)request;
|
f@0
|
596 try {
|
f@0
|
597 protocol.send(slr.channel,slr.lock);
|
f@0
|
598 } catch (IOException e) {
|
f@0
|
599 revertDiagram(slr.channel,false);
|
f@0
|
600 try {
|
f@0
|
601 /* RevertedDiagramAnswer is to prevent the Event dispatching Thread from blocking if the *
|
f@0
|
602 * server goes down and the client is still waiting for an answer. If the thread *
|
f@0
|
603 * was not waiting for an answers the RevertedDiagramAnswer will not be put in the queue */
|
f@0
|
604 if(waitingAnswer)
|
f@0
|
605 answers.put(new RevertedDiagramAnswer());
|
f@0
|
606 } catch (InterruptedException ie) {
|
f@0
|
607 throw new RuntimeException(ie); //must never happen
|
f@0
|
608 }
|
f@0
|
609 }
|
f@0
|
610 }else if(request instanceof SendAwarenessRequest){
|
f@0
|
611 SendAwarenessRequest awr = (SendAwarenessRequest)request;
|
f@0
|
612 try{
|
f@0
|
613 protocol.send(awr.channel, awr.awMsg);
|
f@0
|
614 }catch (IOException e) {
|
f@0
|
615 revertDiagram(awr.channel,false);
|
f@0
|
616 }
|
f@0
|
617 }
|
f@0
|
618 }
|
f@0
|
619 }
|
f@0
|
620
|
f@0
|
621 private void revertDiagram(SocketChannel c,final boolean userRequest){
|
f@0
|
622 /* from now on all the commands using this channel will be dropped */
|
f@0
|
623 final Diagram diagram = channels.remove(c);
|
f@0
|
624 if(diagram == null)
|
f@0
|
625 return;
|
f@0
|
626 try{c.close();}catch(IOException ioe){ioe.printStackTrace();}
|
f@0
|
627 SwingUtilities.invokeLater(new Runnable(){
|
f@0
|
628 @Override
|
f@0
|
629 public void run() {
|
f@0
|
630 for(int i=0; i< tabbedPane.getTabCount();i++){
|
f@0
|
631 DiagramPanel dPanel = (DiagramPanel)tabbedPane.getComponentAt(i);
|
f@0
|
632 if(dPanel.getDiagram() instanceof NetDiagram){
|
f@0
|
633 NetDiagram netDiagram = (NetDiagram)dPanel.getDiagram();
|
f@0
|
634 if( netDiagram.getDelegate().equals(diagram)){
|
f@0
|
635 /* set the old (unwrapped) diagram as the current one */
|
f@0
|
636 dPanel.setAwarenessPanelEnabled(false);
|
f@0
|
637 dPanel.setDiagram(diagram);
|
f@0
|
638 break;
|
f@0
|
639 }
|
f@0
|
640 }
|
f@0
|
641 }
|
f@0
|
642 if(!userRequest)// show the message only if the revert is due to an error
|
f@0
|
643 SpeechOptionPane.showMessageDialog(tabbedPane, MessageFormat.format(
|
f@0
|
644 ResourceBundle.getBundle(Server.class.getName()).getString("dialog.error.connection"),
|
f@0
|
645 diagram.getName())
|
f@0
|
646 );
|
f@0
|
647 }
|
f@0
|
648 });
|
f@0
|
649
|
f@0
|
650 }
|
f@0
|
651
|
f@0
|
652 private void revertAllDiagrams(){
|
f@0
|
653 for(SocketChannel c : channels.keySet())
|
f@0
|
654 try{c.close();}catch(IOException ioe){ioe.printStackTrace();}
|
f@0
|
655 channels.clear();
|
f@0
|
656
|
f@0
|
657 SwingUtilities.invokeLater(new Runnable(){
|
f@0
|
658 @Override
|
f@0
|
659 public void run() {
|
f@0
|
660 for(int i=0; i< tabbedPane.getTabCount();i++){
|
f@0
|
661 DiagramPanel dPanel = (DiagramPanel)tabbedPane.getComponentAt(i);
|
f@0
|
662 if(dPanel.getDiagram() instanceof NetDiagram){
|
f@0
|
663 NetDiagram netDiagram = (NetDiagram)dPanel.getDiagram();
|
f@0
|
664 /* set the old (unwrapped) diagram as the current one */
|
f@0
|
665 dPanel.setAwarenessPanelEnabled(false);
|
f@0
|
666 dPanel.setDiagram(netDiagram.getDelegate());
|
f@0
|
667 }
|
f@0
|
668 }
|
f@0
|
669 SpeechOptionPane.showMessageDialog(
|
f@0
|
670 tabbedPane,
|
f@0
|
671 ResourceBundle.getBundle(Server.class.getName()).getString("dialog.error.connections"));
|
f@0
|
672 }
|
f@0
|
673 });
|
f@0
|
674 }
|
f@0
|
675
|
f@0
|
676 public interface Request {};
|
f@0
|
677
|
f@0
|
678 public interface DiagramRequest extends Request {};
|
f@0
|
679
|
f@0
|
680 public static class AddDiagramRequest implements DiagramRequest {
|
f@0
|
681 public AddDiagramRequest(SocketChannel channel, Diagram diagram){
|
f@0
|
682 this.channel = channel; this.diagram = diagram;
|
f@0
|
683 }
|
f@0
|
684 public SocketChannel channel;
|
f@0
|
685 public Diagram diagram;
|
f@0
|
686 }
|
f@0
|
687
|
f@0
|
688 public static class RmDiagramRequest implements DiagramRequest {
|
f@0
|
689 public RmDiagramRequest(String diagramName){
|
f@0
|
690 this.diagramName = diagramName;
|
f@0
|
691 }
|
f@0
|
692 public String diagramName;
|
f@0
|
693 }
|
f@0
|
694
|
f@0
|
695 public static class SendCmdRequest implements Request {
|
f@0
|
696 public SendCmdRequest(Command cmd, SocketChannel channel, DiagramElement element ){
|
f@0
|
697 this.cmd = cmd; this.element = element;this.channel = channel;
|
f@0
|
698 }
|
f@0
|
699
|
f@0
|
700 public boolean matches(SocketChannel c,String diagramName){
|
f@0
|
701 return(diagramName.equals(cmd.getDiagram())&&c.socket().getInetAddress().equals(channel.socket().getInetAddress()));
|
f@0
|
702 }
|
f@0
|
703 public DiagramElement element;
|
f@0
|
704 public SocketChannel channel;
|
f@0
|
705 public Command cmd;
|
f@0
|
706 }
|
f@0
|
707
|
f@0
|
708 public static class SendTreeCmdRequest extends SendCmdRequest{
|
f@0
|
709 public SendTreeCmdRequest( Command cmd,SocketChannel channel,DiagramTreeNode treeNode) {
|
f@0
|
710 super(cmd,channel,null);
|
f@0
|
711 this.treeNode = treeNode;
|
f@0
|
712 }
|
f@0
|
713 public DiagramTreeNode treeNode;
|
f@0
|
714 public SocketChannel channel;
|
f@0
|
715 public Command cmd;
|
f@0
|
716 }
|
f@0
|
717
|
f@0
|
718 public static class SendLockRequest implements Request {
|
f@0
|
719 public SendLockRequest (SocketChannel channel, LockMessage lock){
|
f@0
|
720 this.channel = channel;
|
f@0
|
721 this.lock = lock;
|
f@0
|
722 }
|
f@0
|
723 public SocketChannel channel;
|
f@0
|
724 public LockMessage lock;
|
f@0
|
725 }
|
f@0
|
726
|
f@0
|
727 public static class SendAwarenessRequest implements Request {
|
f@0
|
728 public SendAwarenessRequest(SocketChannel channel, AwarenessMessage awMsg){
|
f@0
|
729 this.awMsg = awMsg;
|
f@0
|
730 this.channel = channel;
|
f@0
|
731 }
|
f@0
|
732 public SocketChannel channel;
|
f@0
|
733 public AwarenessMessage awMsg;
|
f@0
|
734 }
|
f@0
|
735
|
f@0
|
736 public interface Answer {};
|
f@0
|
737 public static class LockAnswer implements Answer {
|
f@0
|
738 public LockAnswer(LockMessage answer){
|
f@0
|
739 this.message = answer;
|
f@0
|
740 }
|
f@0
|
741 public LockMessage message;
|
f@0
|
742 }
|
f@0
|
743
|
f@0
|
744 public static class RevertedDiagramAnswer implements Answer{}
|
f@0
|
745
|
f@0
|
746 private Node node;
|
f@0
|
747 private Edge edge;
|
f@0
|
748 private DiagramTreeNode treeNode;
|
f@0
|
749 private Set<Integer> indexes;
|
f@0
|
750 private SendCmdRequest sendCmdRequest;
|
f@0
|
751 /* for each server hold the diagram it shares with it */
|
f@0
|
752 private Map<SocketChannel, Diagram> channels;
|
f@0
|
753 private ConcurrentLinkedQueue<Request> requests;
|
f@0
|
754 private BlockingQueue<Answer> answers;
|
f@0
|
755 private LinkedList<SendCmdRequest> pendingCommands;
|
f@0
|
756 private Selector selector;
|
f@0
|
757 private EditorTabbedPane tabbedPane;
|
f@0
|
758 private Protocol protocol;
|
f@0
|
759 private volatile boolean waitingAnswer;
|
f@0
|
760 private volatile boolean mustSayGoodbye;
|
f@0
|
761 }
|