/*
* Copyright (C) 2003-2014, C. Ramakrishnan / Illposed Software.
* All rights reserved.
*
* This code is licensed under the BSD 3-Clause license.
* See file LICENSE (or LICENSE.html) for more information.
*/
package com.illposed.osc;
import com.illposed.osc.utility.OSCJavaToByteArrayConverter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Pattern;
/**
* An simple (non-bundle) OSC message.
*
* An OSC <i>Message</i> is made up of
* an <i>Address Pattern</i> (the receiver of the message)
* and <i>Arguments</i> (the content of the message).
*
* @author Chandrasekhar Ramakrishnan
*/
public class OSCMessage extends AbstractOSCPacket {
/**
* Java regular expression pattern matching a single invalid character.
* The invalid characters are:
* ' ', '#', '*', ',', '?', '[', ']', '{', '}'
*/
private static final Pattern ILLEGAL_ADDRESS_CHAR
= Pattern.compile("[ \\#\\*\\,\\?\\[\\]\\{\\}]");
private String address;
private List<Object> arguments;
/**
* Creates an empty OSC Message.
* In order to send this OSC message,
* you need to set the address and optionally some arguments.
*/
public OSCMessage() {
this(null);
}
/**
* Creates an OSCMessage with an address already initialized.
* @param address the recipient of this OSC message
*/
public OSCMessage(String address) {
this(address, null);
}
/**
* Creates an OSCMessage with an address
* and arguments already initialized.
* @param address the recipient of this OSC message
* @param arguments the data sent to the receiver
*/
public OSCMessage(String address, Collection<Object> arguments) {
checkAddress(address);
this.address = address;
if (arguments == null) {
this.arguments = new LinkedList<Object>();
} else {
this.arguments = new ArrayList<Object>(arguments);
}
init();
}
/**
* The receiver of this message.
* @return the receiver of this OSC Message
*/
public String getAddress() {
return address;
}
/**
* Set the address of this message.
* @param address the receiver of the message
*/
public void setAddress(String address) {
checkAddress(address);
this.address = address;
contentChanged();
}
/**
* Add an argument to the list of arguments.
* @param argument a Float, Double, String, Character, Integer, Long, Boolean, null
* or an array of these
*/
public void addArgument(Object argument) {
arguments.add(argument);
contentChanged();
}
/**
* The arguments of this message.
* @return the arguments to this message
*/
public List<Object> getArguments() {
return Collections.unmodifiableList(arguments);
}
/**
* Convert the address into a byte array.
* Used internally only.
* @param stream where to write the address to
*/
private void computeAddressByteArray(OSCJavaToByteArrayConverter stream) {
stream.write(address);
}
/**
* Convert the arguments into a byte array.
* Used internally only.
* @param stream where to write the arguments to
*/
private void computeArgumentsByteArray(OSCJavaToByteArrayConverter stream) {
stream.write(',');
stream.writeTypes(arguments);
for (Object argument : arguments) {
stream.write(argument);
}
}
@Override
byte[] computeByteArray(OSCJavaToByteArrayConverter stream) {
computeAddressByteArray(stream);
computeArgumentsByteArray(stream);
return stream.toByteArray();
}
/**
* Throws an exception if the given address is invalid.
* We explicitly allow <code>null</code> here,
* because we want to allow to set the address in a lazy fashion.
* @param address to be checked for validity
*/
private static void checkAddress(String address) {
// NOTE We explicitly allow <code>null</code> here,
// because we want to allow to set in a lazy fashion.
if ((address != null) && !isValidAddress(address)) {
throw new IllegalArgumentException("Not a valid OSC address: "
+ address);
}
}
/**
* Checks whether a given string is a valid OSC <i>Address Pattern</i>.
* @param address to be checked for validity
* @return true if the supplied string constitutes a valid OSC address
*/
public static boolean isValidAddress(String address) {
return (address != null)
&& address.startsWith("/")
&& !address.contains("//")
&& !ILLEGAL_ADDRESS_CHAR.matcher(address).find();
}
}