annotate java/src/uk/ac/qmul/eecs/ccmi/network/ClientConnectionManager.java @ 1:e3935c01cde2 tip

moved license of PdPersistenceManager to the beginning of the file
author Fiore Martin <f.martin@qmul.ac.uk>
date Tue, 08 Jul 2014 19:52:03 +0100
parents 78b7fc5391a2
children
rev   line source
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 }