/**
* Squidy Interaction Library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* Squidy Interaction Library is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Squidy Interaction Library. If not, see
* <http://www.gnu.org/licenses/>.
*
* 2009 Human-Computer Interaction Group, University of Konstanz.
* <http://hci.uni-konstanz.de>
*
* Please contact info@squidy-lib.de or visit our website
* <http://www.squidy-lib.de> for further information.
*/
package org.squidy.nodes;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlType;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.squidy.common.util.ReflectionUtil;
import org.squidy.manager.ProcessException;
import org.squidy.manager.controls.CheckBox;
import org.squidy.manager.controls.ComboBox;
import org.squidy.manager.controls.TextField;
import org.squidy.manager.data.IData;
import org.squidy.manager.data.IDataContainer;
import org.squidy.manager.data.Processor;
import org.squidy.manager.data.Property;
import org.squidy.manager.data.domainprovider.impl.EndianDomainProvider;
import org.squidy.manager.model.AbstractNode;
import org.squidy.manager.protocol.osc.OSCListener;
import org.squidy.manager.protocol.osc.OSCServer;
import org.squidy.nodes.optitrack.utils.TrackingConstant;
import org.squidy.nodes.optitrack.utils.TrackingUtility;
import com.illposed.osc.Endian;
import com.illposed.osc.OSCBundle;
import com.illposed.osc.OSCMessage;
/**
* <code>SquidyRemote</code>.
*
* <pre>
* Date: Nov 29, 2008
* Time: 7:25:32 PM
* </pre>
*
* @author Roman Rädle, <a
* href="mailto:Roman.Raedle@uni-konstanz.de">Roman.Raedle@uni-konstanz.de</a>,
* University of Konstanz
* @version $Id: SquidyRemote.java 772 2011-09-16 15:39:44Z raedle $
* @since 1.1.0
*/
@XmlType(name = "Squidy Remote")
@Processor(
name = "Squidy Remote",
icon = "/org/squidy/nodes/image/48x48/squidy-remote.png",
description = "/org/squidy/nodes/html/SquidyRemote.html",
types = { Processor.Type.INPUT, Processor.Type.OUTPUT },
tags = { "squidy", "remote", "distributed", "computing", "multi", "OSC", "network" }
)
public class SquidyRemote extends AbstractNode {
// Log to log info, error, debug,... messages.
private static final Log LOG = LogFactory.getLog(SquidyRemote.class);
// ################################################################################
// BEGIN OF ADJUSTABLES
// ################################################################################
@XmlAttribute(name = "host")
@Property(
name = "Host",
description = "The host which should receive Squidy Remote data.",
group = "Connection Settings"
)
@TextField
private String host = "127.0.0.1";
/**
* @return the host
*/
public final String getHost() {
return host;
}
/**
* @param host the host to set
*/
public final void setHost(String host) {
this.host = host;
if (serverMap != null && host != "") {
stopOSCServer();
startOSCServer(host, port);
}
}
// ################################################################################
@XmlAttribute(name = "port")
@Property(
name = "Port",
description = "The port which should receive Squidy Remote data.",
group = "Connection Settings"
)
@TextField
private int port = 1919;
/**
* @return the port
*/
public final int getPort() {
return port;
}
/**
* @param port the port to set
*/
public final void setPort(int port) {
this.port = port;
if (serverMap != null) {
stopOSCServer();
startOSCServer(host, port);
}
}
// ################################################################################
@XmlAttribute(name = "receiver")
@Property(
name = "Receiver",
description = "Whether the Squidy Remote acts as a receiver or not.",
group = "Options"
)
@CheckBox
public boolean receiver;
/**
* @return the receiver
*/
public final boolean isReceiver() {
return receiver;
}
/**
* @param receiver the receiver to set
*/
public final void setReceiver(boolean receiver) {
this.receiver = receiver;
if (serverMap != null && host != "") {
OSCServer server = serverMap.get(host);
if (server != null)
{
if (receiver && !server.isListening()) {
server.startListening();
}
else if (!receiver && server.isListening()) {
server.stopListening();
}
}
}
}
// ################################################################################
@XmlAttribute(name = "sender")
@Property(
name = "Sender",
description = "Whether the Squidy Remote acts as a sender or not.",
group = "Options"
)
@CheckBox
public boolean sender = true;
/**
* @return the sender
*/
public final boolean isSender() {
return sender;
}
/**
* @param sender the sender to set
*/
public final void setSender(boolean sender) {
this.sender = sender;
}
@XmlAttribute(name = "endian")
@Property(
name = "Endian",
description = "Indicates which endian strategy will be used to identify bytes or not.",
group = "Options"
)
@ComboBox(
domainProvider = EndianDomainProvider.class
)
private Endian endian = Endian.LITTLE_ENDIAN;
/**
* @return the endian
*/
public final Endian getEndian() {
return endian;
}
/**
* @param endian
* the endian to set
*/
public final void setEndian(Endian endian) {
this.endian = endian;
if (isProcessing() && host != "") {
// Restart the osc server with new endian strategy.
stopOSCServer();
startOSCServer(host, port);
}
}
// ################################################################################
// END OF ADJUSTABLES
// ################################################################################
//private OSCServer server;
private HashMap<String, OSCServer> serverMap;
private ArrayList<String> hostList;
/* (non-Javadoc)
* @see org.squidy.manager.ReflectionProcessable#onStart()
*/
@Override
public void onStart() throws ProcessException {
serverMap = new HashMap<String, OSCServer>();
hostList = new ArrayList<String>();
startOSCServer(host, port);
}
/* (non-Javadoc)
* @see org.squidy.manager.ReflectionProcessable#onStop()
*/
@Override
public void onStop() throws ProcessException {
stopOSCServer();
}
/**
*
*/
private OSCServer startOSCServer(String variableHost, int variablePort) {
OSCServer server = serverMap.get(host);
if (server == null && variableHost != "" && variablePort > 0)
{
server = new OSCServer(variableHost, variablePort, variablePort, endian);
serverMap.put(variableHost, server);
hostList.add(variableHost);
server.addOSCListener("/squidy/remote", new OSCListener() {
/* (non-Javadoc)
* @see org.squidy.manager.protocol.osc.OSCListener#handleMessages(com.illposed.osc.OSCMessage[])
*/
public void handleMessages(OSCMessage[] messages) {
List<IData> datas = new ArrayList<IData>();
for (OSCMessage message : messages) {
Object[] arguments = message.getArguments();
IData data = ReflectionUtil.createInstance((String) arguments[0]);
Object[] rawData = new Object[arguments.length - 1];
System.arraycopy(arguments, 1, rawData, 0, rawData.length);
data.deserialize(rawData);
datas.add(data);
}
// Publish received data.
publish(datas);
}
});
if (receiver) {
server.startListening();
}
}
return server;
}
/**
*
*/
private void stopOSCServer() {
for (String iHost : hostList)
{
OSCServer server = serverMap.get(iHost);
if (server != null) {
server.close();
server = null;
}
serverMap.remove(iHost);
}
hostList.clear();
}
/* (non-Javadoc)
* @see org.squidy.manager.data.logic.ReflectionProcessable#beforeDataContainerProcessing(org.squidy.manager.data.IDataContainer)
*/
@Override
public IDataContainer preProcess(IDataContainer dataContainer) {
if (sender) {
OSCBundle bundle = new OSCBundle(new Date(dataContainer.getTimestamp()));
OSCServer server = null;
int i = 0;
for (IData data : dataContainer.getData()) {
i++;
String type = data.getClass().getName();
Object[] serializedData = data.serialize();
OSCMessage dataMessage = new OSCMessage("/squidy/remote");
dataMessage.addArgument(type);
for (Object o : serializedData) {
dataMessage.addArgument(o);
}
bundle.addPacket(dataMessage);
String remoteHost = TrackingUtility.getAttributesAlpha(data, TrackingConstant.REMOTEHOST);
if(remoteHost != "")
{
server = serverMap.get(remoteHost);
if (server == null)
{
server = startOSCServer(remoteHost, TrackingUtility.getAttributesInteger(data, TrackingConstant.REMOTEPORT));
}
}
else if (this.host != "")
{
server = serverMap.get(this.host);
}
if (server != null)
{
if (i == 2) {
server.send(bundle);
bundle = new OSCBundle(new Date(dataContainer.getTimestamp()));
i = 0;
}
}
}
if (server != null)
server.send(bundle);
}
return super.preProcess(dataContainer);
}
}