annotate java/src/uk/ac/qmul/eecs/ccmi/network/OscProtocol.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.io.IOException;
f@0 23 import java.net.SocketException;
f@0 24 import java.nio.ByteBuffer;
f@0 25 import java.nio.channels.SocketChannel;
f@0 26 import java.util.ResourceBundle;
f@0 27
f@0 28 import uk.ac.qmul.eecs.ccmi.gui.DiagramEventSource;
f@0 29
f@0 30 import de.sciss.net.OSCBundle;
f@0 31 import de.sciss.net.OSCMessage;
f@0 32
f@0 33 /*
f@0 34 * An implementation of the Protocol interface which uses OSC messages
f@0 35 * streamed on a TCP connection.
f@0 36 *
f@0 37 */
f@0 38 class OscProtocol implements Protocol {
f@0 39
f@0 40 OscProtocol(){
f@0 41 buffer = ByteBuffer.allocate(DEFAULT_CAPACITY);
f@0 42 codec = new CCmIOSCPacketCodec();
f@0 43 }
f@0 44
f@0 45 @Override
f@0 46 public void send(SocketChannel channel, Command cmd) throws IOException {
f@0 47 /* OSC message args = [diagram, cmd.arg1, cmd.arg2, amd.arg2, ... , cmd.argN ] */
f@0 48 bundle = new CCmIOSCBundle(cmd.getTimestamp());
f@0 49 Object[] args = new Object[2+cmd.getArgNum()];
f@0 50 args[0] = cmd.getDiagram();
f@0 51 args[1] = cmd.getSource().toString();
f@0 52 for(int i=0; i<cmd.getArgNum();i++)
f@0 53 args[i+2] = cmd.getArgAt(i);
f@0 54
f@0 55 bundle.addPacket(new OSCMessage(OSC_NAME_PREFIX+cmd.getName().toString(),args));
f@0 56 try{
f@0 57 writeBundle(channel);
f@0 58 }catch(IOException u){
f@0 59 throw new IOException(
f@0 60 /* give a more user friendly message */
f@0 61 ResourceBundle.getBundle(Server.class.getName()).getString("dialog.error.no_send"),u);
f@0 62 }
f@0 63 }
f@0 64
f@0 65 @Override
f@0 66 public void send(SocketChannel channel, Reply reply) throws IOException {
f@0 67 /* OSC message args = [messageLen, diagram, message ] */
f@0 68 bundle = new CCmIOSCBundle(reply.getTimestamp());
f@0 69 bundle.addPacket(new OSCMessage(
f@0 70 OSC_NAME_PREFIX+reply.getName().toString(),
f@0 71 new Object[] {reply.getMessageLen(), reply.getDiagram() ,reply.getMessage(),reply.getSource().toString()}
f@0 72 ));
f@0 73 try{
f@0 74 writeBundle(channel);
f@0 75 }catch(IOException u){
f@0 76 throw new IOException(
f@0 77 /* give a more user friendly message */
f@0 78 ResourceBundle.getBundle(Server.class.getName()).getString("dialog.error.no_send"),u);
f@0 79 }
f@0 80 }
f@0 81
f@0 82 @Override
f@0 83 public void send(SocketChannel channel, LockMessage lockMessage) throws IOException {
f@0 84 /* OSC message args = [diagram, source, lock.arg1, lock.arg2, lock.arg2, ... , lock.argN ] */
f@0 85 bundle = new CCmIOSCBundle(lockMessage.getTimestamp());
f@0 86 Object[] args = new Object[2+lockMessage.getArgNum()];
f@0 87 args[0] = lockMessage.getDiagram();
f@0 88 args[1] = lockMessage.getSource().toString();
f@0 89 for(int i=0; i<lockMessage.getArgNum();i++)
f@0 90 args[i+2] = lockMessage.getArgAt(i);
f@0 91
f@0 92 bundle.addPacket(new OSCMessage(
f@0 93 OSC_NAME_PREFIX+lockMessage.getName().toString(),
f@0 94 args));
f@0 95 try{
f@0 96 writeBundle(channel);
f@0 97 }catch(IOException u){
f@0 98 throw new IOException(
f@0 99 /* give a more user friendly message */
f@0 100 ResourceBundle.getBundle(Server.class.getName()).getString("dialog.error.no_send"),u);
f@0 101 }
f@0 102 }
f@0 103
f@0 104 @Override
f@0 105 public void send(SocketChannel channel, AwarenessMessage awareMsg) throws IOException {
f@0 106 /* OSC message args = [diagram name, siagram event action source]*/
f@0 107 bundle = new CCmIOSCBundle(awareMsg.getTimestamp());
f@0 108 Object[] args = new Object[2];
f@0 109 args[0] = awareMsg.getDiagram();
f@0 110 args[1] = awareMsg.getSource().toString();
f@0 111
f@0 112 bundle.addPacket(new OSCMessage(
f@0 113 OSC_NAME_PREFIX+awareMsg.getName().toString(),
f@0 114 args));
f@0 115 try{
f@0 116 writeBundle(channel);
f@0 117 }catch(IOException u){
f@0 118 throw new IOException(
f@0 119 /* give a more user friendly message */
f@0 120 ResourceBundle.getBundle(Server.class.getName()).getString("dialog.error.no_send"),u);
f@0 121 }
f@0 122 }
f@0 123
f@0 124 // @Override
f@0 125 // public Command receiveCommand(SocketChannel channel) throws IOException {
f@0 126 // OSCBundle bundle = readBundle(channel);
f@0 127 // OSCMessage oscMessage = (OSCMessage)bundle.getPacket(0);
f@0 128 // String name = oscMessage.getName();
f@0 129 // assert(name.startsWith(""+OSC_NAME_PREFIX));
f@0 130 // name = name.substring(1); // chop off the trailing '/'
f@0 131 // Object args[] = new Object[oscMessage.getArgCount()-CMD_OFFSET];
f@0 132 // for(int i=0; i< args.length;i++)
f@0 133 // args[i] = oscMessage.getArg(i+CMD_OFFSET);
f@0 134 // return new Command(
f@0 135 // Command.valueOf(name),
f@0 136 // (String)oscMessage.getArg(CMD_DIAGRAM_INDEX),
f@0 137 // args,
f@0 138 // bundle.getTimeTag(),
f@0 139 // DiagramEventSource.valueOf((String)oscMessage.getArg(CMD_SOURCE_INDEX))
f@0 140 // );
f@0 141 // }
f@0 142
f@0 143 @Override
f@0 144 public Reply receiveReply(SocketChannel channel) throws IOException {
f@0 145 OSCBundle bundle = readBundle(channel);
f@0 146 OSCMessage oscMessage = (OSCMessage)bundle.getPacket(0);
f@0 147 String name = oscMessage.getName();
f@0 148 assert(name.startsWith(""+OSC_NAME_PREFIX));
f@0 149 name = name.substring(1); // chop off the trailing '/'
f@0 150 @SuppressWarnings("unused")
f@0 151 Integer len = (Integer)oscMessage.getArg(REPLY_LEN_INDEX); // of no use at the moment
f@0 152 return new Reply(
f@0 153 Reply.valueOf(name),
f@0 154 (String)oscMessage.getArg(REPLY_DIAGRAM_INDEX),
f@0 155 (String)oscMessage.getArg(REPLY_MESSAGE_INDEX),
f@0 156 bundle.getTimeTag(),
f@0 157 DiagramEventSource.valueOf((String)oscMessage.getArg(REPLY_SOURCE_INDEX)));
f@0 158 }
f@0 159
f@0 160 @Override
f@0 161 public LockMessage receiveLockMessage(SocketChannel channel) throws IOException {
f@0 162 OSCBundle bundle = readBundle(channel);
f@0 163 OSCMessage oscMessage = (OSCMessage)bundle.getPacket(0);
f@0 164 String name = oscMessage.getName();
f@0 165 name = name.substring(1); // chop off the trailing '/'
f@0 166 Object args[] = new Object[oscMessage.getArgCount()-LOCK_OFFSET];
f@0 167 for(int i=0; i< args.length;i++)
f@0 168 args[i] = oscMessage.getArg(i+LOCK_OFFSET);
f@0 169 return new LockMessage(
f@0 170 LockMessage.valueOf(name),
f@0 171 bundle.getTimeTag(),
f@0 172 (String)oscMessage.getArg(LOCK_DIAGRAM_INDEX),
f@0 173 args,
f@0 174 DiagramEventActionSource.valueOf((String)oscMessage.getArg(LOCK_SOURCE_INDEX))
f@0 175 );
f@0 176 }
f@0 177
f@0 178 public Message receiveMessage(SocketChannel channel) throws IOException {
f@0 179 OSCBundle bundle = readBundle(channel);
f@0 180 OSCMessage oscMessage = (OSCMessage)bundle.getPacket(0);
f@0 181 String name = oscMessage.getName();
f@0 182 assert(name.startsWith(""+OSC_NAME_PREFIX));
f@0 183 name = name.substring(1); // chop off the trailing '/'
f@0 184 if(name.endsWith(Reply.NAME_POSTFIX)){ // it's a reply
f@0 185 @SuppressWarnings("unused")
f@0 186 Integer len = (Integer)oscMessage.getArg(REPLY_LEN_INDEX); // of no use at the moment
f@0 187 Reply reply = new Reply(
f@0 188 Reply.valueOf(name),
f@0 189 (String)oscMessage.getArg(REPLY_DIAGRAM_INDEX),
f@0 190 (String)oscMessage.getArg(REPLY_MESSAGE_INDEX),
f@0 191 bundle.getTimeTag(),
f@0 192 DiagramEventSource.valueOf((String)oscMessage.getArg(REPLY_SOURCE_INDEX)));
f@0 193 return reply;
f@0 194 }else if (name.endsWith(LockMessage.NAME_POSTFIX)){
f@0 195 Object args[] = new Object[oscMessage.getArgCount()-LOCK_OFFSET];
f@0 196 for(int i=0; i< args.length;i++)
f@0 197 args[i] = oscMessage.getArg(i+LOCK_OFFSET);
f@0 198 return new LockMessage(
f@0 199 LockMessage.valueOf(name),
f@0 200 bundle.getTimeTag(),
f@0 201 (String)oscMessage.getArg(LOCK_DIAGRAM_INDEX),
f@0 202 args,
f@0 203 DiagramEventActionSource.valueOf((String)oscMessage.getArg(LOCK_SOURCE_INDEX))
f@0 204 );
f@0 205 }else if(name.endsWith(AwarenessMessage.NAME_POSTFIX)){ // it's an awareness message
f@0 206 AwarenessMessage.Name awName = AwarenessMessage.valueOf(name);
f@0 207 if(awName == AwarenessMessage.Name.USERNAME_A || awName == AwarenessMessage.Name.ERROR_A){
f@0 208 return new AwarenessMessage(awName,
f@0 209 (String)oscMessage.getArg(AWAR_DIAGRAM_INDEX),
f@0 210 (String)oscMessage.getArg(AWAR_SOURCE_INDEX)
f@0 211 );
f@0 212 }else {
f@0 213 return new AwarenessMessage(awName,
f@0 214 (String)oscMessage.getArg(AWAR_DIAGRAM_INDEX),
f@0 215 DiagramEventActionSource.valueOf((String)oscMessage.getArg(AWAR_SOURCE_INDEX))
f@0 216 );
f@0 217 }
f@0 218 }else{ // it's a command
f@0 219 Object args[] = new Object[oscMessage.getArgCount()-CMD_OFFSET];
f@0 220 for(int i=0; i< args.length;i++)
f@0 221 args[i] = oscMessage.getArg(i+CMD_OFFSET);
f@0 222 return new Command(
f@0 223 Command.valueOf(name),
f@0 224 (String)oscMessage.getArg(CMD_DIAGRAM_INDEX),
f@0 225 args,
f@0 226 bundle.getTimeTag(),
f@0 227 DiagramEventSource.valueOf((String)oscMessage.getArg(CMD_SOURCE_INDEX))
f@0 228 );
f@0 229 }
f@0 230 }
f@0 231
f@0 232 private OSCBundle readBundle(SocketChannel channel) throws IOException{
f@0 233 /* read the size of the OSC packet, first 4 bytes according to OSC specs */
f@0 234 buffer.rewind().limit(4);
f@0 235 while( buffer.hasRemaining() )
f@0 236 if( channel.read( buffer ) == -1 )
f@0 237 throw new SocketException(ResourceBundle.getBundle(Server.class.getName()).getString("error.connection_close"));
f@0 238
f@0 239 buffer.rewind();
f@0 240 int packetSize = buffer.getInt();
f@0 241 assert(packetSize > 0 );
f@0 242 ByteBuffer b = buffer;
f@0 243 /* if the packet is very big we must allocate an ad hoc temporary big big buffer */
f@0 244 if(packetSize <= DEFAULT_CAPACITY)
f@0 245 b.rewind().limit(packetSize);
f@0 246 else
f@0 247 b = ByteBuffer.allocate(packetSize);
f@0 248 /* read the packet, it must be a bundle containing only one message */
f@0 249 while( b.hasRemaining() )
f@0 250 if( channel.read( b ) == -1 )
f@0 251 throw new SocketException(ResourceBundle.getBundle(Server.class.getName()).getString("error.connection_close"));
f@0 252 b.rewind();
f@0 253 return (OSCBundle)codec.decode(b);
f@0 254 }
f@0 255
f@0 256 private void writeBundle(SocketChannel channel) throws IOException{
f@0 257 ByteBuffer b = buffer;
f@0 258 buffer.clear();
f@0 259 if(bundle.getSize() + 4 > DEFAULT_CAPACITY){
f@0 260 b = ByteBuffer.allocate(bundle.getSize() + 4);
f@0 261 }
f@0 262 b.position(4);
f@0 263 bundle.encode(codec,b);
f@0 264 int len = b.position() - 4;
f@0 265 b.putInt(0, len);
f@0 266 b.flip();
f@0 267 channel.write(b);
f@0 268 }
f@0 269
f@0 270 ByteBuffer buffer;
f@0 271 CCmIOSCBundle bundle;
f@0 272 CCmIOSCPacketCodec codec;
f@0 273
f@0 274 private static final int DEFAULT_CAPACITY = 1024;
f@0 275 private static final char OSC_NAME_PREFIX = '/';
f@0 276
f@0 277
f@0 278 private static final int REPLY_LEN_INDEX = 0;
f@0 279 /* position of the diagram Name in the OSC message */
f@0 280 private static final int REPLY_DIAGRAM_INDEX = 1;
f@0 281 private static final int REPLY_SOURCE_INDEX = 3;
f@0 282 private static final int CMD_DIAGRAM_INDEX = 0;
f@0 283 private static final int CMD_SOURCE_INDEX = 1;
f@0 284 private static final int CMD_OFFSET = 2;
f@0 285 private static final int LOCK_DIAGRAM_INDEX = 0;
f@0 286 private static final int LOCK_SOURCE_INDEX = 1;
f@0 287 private static final int LOCK_OFFSET = 2;
f@0 288 private static final int AWAR_DIAGRAM_INDEX = 0;
f@0 289 private static final int AWAR_SOURCE_INDEX = 1;
f@0 290 /* ------------------------------------------------*/
f@0 291 private static final int REPLY_MESSAGE_INDEX = 2;
f@0 292 }