package tr.gov.ulakbim.jDenetX.streams;
import tr.gov.ulakbim.jDenetX.core.InputStreamProgressMonitor;
import tr.gov.ulakbim.jDenetX.core.InstancesHeader;
import tr.gov.ulakbim.jDenetX.core.ObjectRepository;
import tr.gov.ulakbim.jDenetX.options.*;
import tr.gov.ulakbim.jDenetX.streams.net.UDPStreamReceiver;
import tr.gov.ulakbim.jDenetX.tasks.TaskMonitor;
import weka.core.Attribute;
import weka.core.DenseInstance;
import weka.core.Instance;
import weka.core.Instances;
import weka.core.converters.ArffLoader.ArffReader;
import java.io.*;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Created by IntelliJ IDEA.
* User: caglar
* Date: Sep 20, 2010
* Time: 3:08:54 PM
* To change this template use File | Settings | File Templates.
*/
public class UDPStream extends AbstractOptionHandler implements
InstanceStream {
@Override
public String getPurposeString() {
return "A stream read from UDP.";
}
private static final long serialVersionUID = 1L;
public FileOption arffFileOption = new FileOption("arffFileHeader", 'f',
"ARFF file header to load.", null, "arff", false);
public IntOption portOption = new IntOption(
"portNumber",
'p',
"Port number that the socket will be created at and will be bind",
2500, 1, 65555);
public IntOption packetSizeOption = new IntOption(
"packetSizeOption",
'a',
"Size of each packet in bytes",
1024, 8, Integer.MAX_VALUE); //Min length is 8, since this is the size of header
public FlagOption checkHostOption = new FlagOption(
"checkHost",
't',
"Do you want to match the host that the packets coming from the host you specify.");
public StringOption hostOption = new StringOption(
"host",
'h',
"host name or ip that the socket will be created at",
"-1");
public IntOption classIndexOption = new IntOption(
"classIndex",
'c',
"Class index of data. 0 for none or -1 for last attribute in file.",
-1, -1, Integer.MAX_VALUE);
public IntOption socketTimeoutOption = new IntOption(
"socketTimeout",
's',
"socket timeout in ms (Enter 0 for no timeout)",
5000, 0, Integer.MAX_VALUE);
public IntOption windowSizeOption = new IntOption(
"windowSize",
'w',
"Size of the window that the instances will be stored before processing",
1000, 1, Integer.MAX_VALUE);
public IntOption maxInstancesOption = new IntOption(
"maxInstances",
'm',
"limit in max number of instances (Enter 0 for no limit)",
1000000, 0, Integer.MAX_VALUE);
protected Instances instances; //Queue of instances
protected Instances activeInstances; //Active Queue of instances
protected Reader fileReader;
protected boolean endOfStream;
protected Instance lastInstanceRead;
protected int numInstancesRead;
protected InputStreamProgressMonitor fileProgressMonitor;
protected UDPStreamReceiver uStreamReceiver;
public UDPStream() {
}
public UDPStream(String arffFileName, int classIndex) {
this.arffFileOption.setValue(arffFileName);
this.classIndexOption.setValue(classIndex);
restart();
}
@Override
public void prepareForUseImpl(TaskMonitor monitor,
ObjectRepository repository) {
restart();
}
public InstancesHeader getHeader() {
return new InstancesHeader(this.instances);
}
public long estimatedRemainingInstances() {
double progressFraction = 0.0;
try {
if (this.fileProgressMonitor != null || this.fileProgressMonitor.available() > 0) {
progressFraction = this.fileProgressMonitor
.getProgressFraction();
}
} catch (IOException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
if ((progressFraction > 0.0) && (this.numInstancesRead > 0)) {
return (long) ((this.numInstancesRead / progressFraction) - this.numInstancesRead);
}
return -1;
}
public boolean hasMoreInstances() {
if (this.endOfStream) {
uStreamReceiver.closeSocket();
}
return !this.endOfStream;
}
public Instance nextInstance() {
Instance prevInstance = this.lastInstanceRead;
this.endOfStream = !recieveNextInstanceFromStream();
return prevInstance;
}
public boolean isRestartable() {
return true;
}
public void restart() {
try {
if (this.fileReader != null) {
this.fileReader.close();
}
if (this.uStreamReceiver != null) {
if (this.uStreamReceiver.isSockBound()) {
this.uStreamReceiver.closeSocket();
}
}
InputStream fileStream = new FileInputStream(this.arffFileOption
.getFile());
this.fileProgressMonitor = new InputStreamProgressMonitor(
fileStream);
this.fileReader = new BufferedReader(new InputStreamReader(
this.fileProgressMonitor));
ArffReader arff = new ArffReader(fileReader, 0);
this.instances = arff.getStructure();
this.activeInstances = arff.getStructure();
if (this.classIndexOption.getValue() < 0) {
this.instances
.setClassIndex(this.instances.numAttributes() - 1);
this.activeInstances
.setClassIndex(this.activeInstances.numAttributes() - 1);
} else if (this.classIndexOption.getValue() > 0) {
this.instances
.setClassIndex(this.classIndexOption.getValue() - 1);
this.activeInstances
.setClassIndex(this.classIndexOption.getValue() - 1);
}
this.numInstancesRead = 0;
this.lastInstanceRead = null;
uStreamReceiver = new UDPStreamReceiver(portOption.getValue(), packetSizeOption.getValue());
uStreamReceiver.openSocket(socketTimeoutOption.getValue());
if (checkHostOption.isSet()) {
if (hostOption.getValue() != null && hostOption.getValue().length() > 7) {
InetAddress address = InetAddress.getByName(hostOption.getValue());
uStreamReceiver.putHostConstraint(address);
} else {
InetAddress address = InetAddress.getByName(hostOption.getValue());
uStreamReceiver.putHostConstraint(address);
}
}
this.endOfStream = !recieveNextInstanceFromStream();
} catch (IOException ioe) {
throw new RuntimeException("UDPStream restart failed.", ioe);
}
}
protected boolean recieveNextInstanceFromStream() {
if (uStreamReceiver == null) {
throw new NullPointerException("recieveNextInstanceFromStream: UDP Data Receiver object should not be empty");
}
if ((this.maxInstancesOption.getValue() == 0) || (this.numInstancesRead < maxInstancesOption.getValue())) {
if (uStreamReceiver.isSockBound()) {
try {
String message = uStreamReceiver.getPacketData();
if (message != null && message.length() > 0) {
addInstance(message);
}
} catch (IOException e) {
e.printStackTrace();
Logger.getAnonymousLogger().log(Level.WARNING, "An IOException occured!");
}
}
if (activeInstances.size() > 0) {
this.lastInstanceRead = this.activeInstances.instance(0);
this.activeInstances.delete(); //keep instances clean
this.numInstancesRead++;
} else if (instances.size() > 0) {
this.lastInstanceRead = this.instances.instance(0);
this.instances.delete(); // keep instances clean
this.numInstancesRead++;
}
if (uStreamReceiver.isSockBound()) {
return true;
}
}
return false;
}
protected void addInstance(String mess) {
if (!mess.toLowerCase().startsWith("@data") || !mess.toLowerCase().startsWith("@relation") || !mess.toLowerCase().startsWith("%")) {
if (instances != null) {
if (instances.size() < windowSizeOption.getValue()) {
addInstanceToInstances(mess, instances);
} else {
activeInstances = instances;
instances.clear();
addInstanceToInstances(mess, instances);
}
} else {
throw new NullPointerException("instances can't be null.");
}
}
}
protected void addInstanceToInstances(String mess, Instances insts) {
String[] tokens = mess.split(",");
Instance inst = new DenseInstance(insts.numAttributes());
inst.setDataset(insts);
ArrayList<Attribute> attList = new ArrayList<Attribute>();
attList = Collections.list(inst.enumerateAttributes());
for (Attribute attr : attList) {
if (attr.isNumeric()) {
inst.setValue(attr, Double.parseDouble(tokens[attr.index()].trim()));
} else {
inst.setValue(attr, tokens[attr.index()].trim());
}
}
if (mess.length() == attList.size() + 1) {
inst.setClassValue(tokens[attList.size()].trim());
}
insts.add(inst);
}
public void getDescription(StringBuilder sb, int indent) {
// TODO Auto-generated method stub
}
}