Commit 7e0a91ce authored by Sven Gestegård Robertz's avatar Sven Gestegård Robertz
Browse files

started creating labcomm2006 for legacy interfaces

parent 36753c06
package se.lth.control.labcomm2006;
public class LabComm {
public static final String VERSION = "LabComm2006";
/*
* Predeclared aggregate type indices
*/
public static final int TYPEDEF = 0x01;
public static final int SAMPLE = 0x02;
public static final int ARRAY = 0x10;
public static final int STRUCT = 0x11;
/*
* Predeclared primitive type indices
*/
public static final int BOOLEAN = 0x20;
public static final int BYTE = 0x21;
public static final int SHORT = 0x22;
public static final int INT = 0x23;
public static final int LONG = 0x24;
public static final int FLOAT = 0x25;
public static final int DOUBLE = 0x26;
public static final int STRING = 0x27;
/*
* Start of user declared types
*/
public static final int FIRST_USER_INDEX = 0x40;
}
package se.lth.control.labcomm2006;
import java.io.IOException;
public interface LabCommDecoder {
public void register(LabCommDispatcher dispatcher,
LabCommHandler handler) throws IOException;
public boolean decodeBoolean() throws IOException;
public byte decodeByte() throws IOException;
public short decodeShort() throws IOException;
public int decodeInt() throws IOException;
public long decodeLong() throws IOException;
public float decodeFloat() throws IOException;
public double decodeDouble() throws IOException;
public String decodeString() throws IOException;
public int decodePacked32() throws IOException;
}
package se.lth.control.labcomm2006;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.InputStream;
import java.io.IOException;
public class LabCommDecoderChannel implements LabCommDecoder {
private DataInputStream in;
private LabCommDecoderRegistry registry;
public LabCommDecoderChannel(InputStream in) throws IOException {
this.in = new DataInputStream(in);
registry = new LabCommDecoderRegistry();
}
public void runOne() throws Exception {
boolean done = false;
while (!done) {
int tag = decodePacked32();
switch (tag) {
case LabComm.TYPEDEF:
case LabComm.SAMPLE: {
int index = decodePacked32();
String name = decodeString();
ByteArrayOutputStream signature = new ByteArrayOutputStream();
collectFlatSignature(new LabCommEncoderChannel(signature, false));
registry.add(index, name, signature.toByteArray());
} break;
default: {
LabCommDecoderRegistry.Entry e = registry.get(tag);
if (e == null) {
throw new IOException("Unhandled tag " + tag);
}
LabCommDispatcher d = e.getDispatcher();
if (d == null) {
throw new IOException("No dispatcher for '" + e.getName() + "'");
}
LabCommHandler h = e.getHandler();
if (h == null) {
throw new IOException("No handler for '" + e.getName() +"'");
}
d.decodeAndHandle(this, h);
done = true;
}
}
}
}
public void run() throws Exception {
while (true) {
runOne();
}
}
private void collectFlatSignature(LabCommEncoder out) throws IOException {
int type = decodePacked32();
out.encodePacked32(type);
switch (type) {
case LabComm.ARRAY: {
int dimensions = decodePacked32();
out.encodePacked32(dimensions);
for (int i = 0 ; i < dimensions ; i++) {
out.encodePacked32(decodePacked32());
}
collectFlatSignature(out);
} break;
case LabComm.STRUCT: {
int fields = decodePacked32();
out.encodePacked32(fields);
for (int i = 0 ; i < fields ; i++) {
out.encodeString(decodeString());
collectFlatSignature(out);
}
} break;
case LabComm.BOOLEAN:
case LabComm.BYTE:
case LabComm.SHORT:
case LabComm.INT:
case LabComm.LONG:
case LabComm.FLOAT:
case LabComm.DOUBLE:
case LabComm.STRING: {
} break;
default: {
throw new IOException("Unimplemented type=" + type);
}
}
out.end(null);
}
public void register(LabCommDispatcher dispatcher,
LabCommHandler handler) throws IOException {
registry.add(dispatcher, handler);
}
public boolean decodeBoolean() throws IOException {
return in.readBoolean();
}
public byte decodeByte() throws IOException {
return in.readByte();
}
public short decodeShort() throws IOException {
return in.readShort();
}
public int decodeInt() throws IOException {
return in.readInt();
}
public long decodeLong() throws IOException {
return in.readLong();
}
public float decodeFloat() throws IOException {
return in.readFloat();
}
public double decodeDouble() throws IOException {
return in.readDouble();
}
public String decodeString() throws IOException {
//in.readShort(); // HACK
//return in.readUTF();
int len = decodePacked32() & 0xffffffff;
byte[] chars = new byte[len];
for(int i=0; i<len; i++) {
chars[i] = in.readByte();
}
return new String(chars);
}
public int decodePacked32() throws IOException {
long res=0;
byte i=0;
boolean cont=true;
do {
byte c = in.readByte();
res = (res << 7) | (c & 0x7f);
cont = (c & 0x80) != 0;
i++;
} while(cont);
return (int) (res & 0xffffffff);
}
}
package se.lth.control.labcomm2006;
import java.io.IOException;
import java.util.HashMap;
public class LabCommDecoderRegistry {
public static class Entry {
private LabCommDispatcher dispatcher;
private LabCommHandler handler;
private int index;
private String name;
private byte[] signature;
public Entry(LabCommDispatcher dispatcher,
LabCommHandler handler) {
this.dispatcher = dispatcher;
this.name = dispatcher.getName();
this.signature = dispatcher.getSignature();
this.handler = handler;
}
public Entry(int index, String name, byte[] signature) {
this.index = index;
this.name = name;
this.signature = signature;
}
public LabCommDispatcher getDispatcher() {
return dispatcher;
}
public void setDispatcher(LabCommDispatcher dispatcher) {
this.dispatcher = dispatcher;
}
public LabCommHandler getHandler() {
return handler;
}
public void setHandler(LabCommHandler handler) {
this.handler = handler;
}
public String getName() {
return name;
}
public int getIndex() {
return index;
}
public void setIndex(int index) throws IOException {
if (this.index != 0 && this.index != index) {
throw new IOException("Index mismatch " +
this.index + " != " + index);
}
this.index = index;
}
public boolean matchName(String name) {
return this.name.equals(name);
}
public boolean matchSignature(byte[] signature) {
boolean result = this.signature.length == signature.length;
for (int i = 0 ; result && i < signature.length ; i++) {
result = this.signature[i] == signature[i];
}
return result;
}
public boolean match(String name, byte[] signature) {
return matchName(name) && matchSignature(signature);
}
public void check(String name, byte[] signature) throws IOException {
if (!matchName(name)) {
throw new IOException("Name mismatch '" +
this.name + "' != '" + name + "'");
}
if (!matchSignature(signature)) {
throw new IOException("Signature mismatch");
}
}
}
private HashMap<Class, Entry> byClass;
private HashMap<Integer, Entry> byIndex;
public LabCommDecoderRegistry() {
byClass = new HashMap<Class, Entry>();
byIndex = new HashMap<Integer, Entry>();
}
public synchronized void add(LabCommDispatcher dispatcher,
LabCommHandler handler) throws IOException{
Entry e = byClass.get(dispatcher.getSampleClass());
if (e != null) {
e.check(dispatcher.getName(), dispatcher.getSignature());
e.setHandler(handler);
} else {
for (Entry e2 : byIndex.values()) {
if (e2.match(dispatcher.getName(), dispatcher.getSignature())) {
e2.setDispatcher(dispatcher);
e2.setHandler(handler);
e = e2;
break;
}
}
if (e == null) {
e = new Entry(dispatcher, handler);
byClass.put(dispatcher.getSampleClass(), e);
}
}
}
public synchronized void add(int index,
String name,
byte[] signature) throws IOException {
Entry e = byIndex.get(Integer.valueOf(index));
if (e != null) {
e.check(name, signature);
} else {
for (Entry e2 : byClass.values()) {
if (e2.match(name, signature)) {
e2.setIndex(index);
e = e2;
break;
}
}
if (e == null) {
e = new Entry(index, name, signature);
}
byIndex.put(Integer.valueOf(index), e);
}
}
public synchronized Entry get(int index) {
return byIndex.get(Integer.valueOf(index));
}
}
\ No newline at end of file
package se.lth.control.labcomm2006;
public interface LabCommDispatcher {
public Class getSampleClass();
public String getName();
public byte[] getSignature();
public void decodeAndHandle(LabCommDecoder decoder,
LabCommHandler handler) throws Exception;
}
package se.lth.control.labcomm2006;
import java.io.IOException;
public interface LabCommEncoder {
public void register(LabCommDispatcher dispatcher) throws IOException;
public void begin(Class<? extends LabCommSample> c) throws IOException;
public void end(Class<? extends LabCommSample> c) throws IOException;
public void encodeBoolean(boolean value) throws IOException;
public void encodeByte(byte value) throws IOException;
public void encodeShort(short value) throws IOException;
public void encodeInt(int value) throws IOException;
public void encodeLong(long value) throws IOException;
public void encodeFloat(float value) throws IOException;
public void encodeDouble(double value) throws IOException;
public void encodeString(String value) throws IOException;
public void encodePacked32(long value) throws IOException;
}
package se.lth.control.labcomm2006;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class LabCommEncoderChannel implements LabCommEncoder {
private LabCommWriter writer;
private ByteArrayOutputStream bytes;
private DataOutputStream data;
private LabCommEncoderRegistry registry;
public LabCommEncoderChannel(LabCommWriter writer,
boolean emitVersion) throws IOException {
this.writer = writer;
bytes = new ByteArrayOutputStream();
data = new DataOutputStream(bytes);
registry = new LabCommEncoderRegistry();
if (emitVersion) {
throw new RuntimeError("Labcomm 2006 does not support emitVersion");
}
}
public LabCommEncoderChannel(LabCommWriter writer) throws IOException {
this(writer, true);
}
public LabCommEncoderChannel(OutputStream writer,
boolean emitVersion) throws IOException {
this(new WriterWrapper(writer), emitVersion);
}
public LabCommEncoderChannel(OutputStream writer) throws IOException {
this(new WriterWrapper(writer), true);
}
public void register(LabCommDispatcher dispatcher) throws IOException {
int index = registry.add(dispatcher);
encodePacked32(LabComm.SAMPLE);
encodePacked32(index);
encodeString(dispatcher.getName());
byte[] signature = dispatcher.getSignature();
for (int i = 0 ; i < signature.length ; i++) {
encodeByte(signature[i]);
}
end(null);
}
public void begin(Class<? extends LabCommSample> c) throws IOException {
encodePacked32(registry.getTag(c));
}
public void end(Class<? extends LabCommSample> c) throws IOException {
data.flush();
//XXX when writer was a stream, it was probably a bit more GC efficient:
//bytes.writeTo(writer);
writer.write(bytes.toByteArray());
bytes.reset();
}
public void encodeBoolean(boolean value) throws IOException{
data.writeBoolean(value);
}
public void encodeByte(byte value) throws IOException {
data.writeByte(value);
}
public void encodeShort(short value) throws IOException {
data.writeShort(value);
}
public void encodeInt(int value) throws IOException {
data.writeInt(value);
}
public void encodeLong(long value) throws IOException {
data.writeLong(value);
}
public void encodeFloat(float value) throws IOException {
data.writeFloat(value);
}
public void encodeDouble(double value) throws IOException {
data.writeDouble(value);
}
public void encodeString(String value) throws IOException {
data.writeShort(0); // HACK...
data.writeUTF(value);
//kludge, to replace above hack with packed length
ByteArrayOutputStream tmpb = new ByteArrayOutputStream();
DataOutputStream tmps = new DataOutputStream(tmpb);
tmps.writeUTF(value);
tmps.flush();
byte[] tmp = tmpb.toByteArray();
encodePacked32(tmp.length-2);
for (int i = 2 ; i < tmp.length ; i++) {
encodeByte(tmp[i]);
}
}
/**
method for API harmonization with labcomm2013.
Labcomm2006 encodes lengths etc as 32 bit ints.
*/
public inline void encodePacked32(long value) throws IOException {
encodeInt(value);
}
}
package se.lth.control.labcomm2006;
import java.io.IOException;
import java.util.HashMap;
public class LabCommEncoderRegistry {
public static class Entry {
private LabCommDispatcher dispatcher;
private int index;
public Entry(LabCommDispatcher dispatcher, int index) {
this.dispatcher = dispatcher;
this.index = index;
}
public LabCommDispatcher getDispatcher() {
return dispatcher;
}
public int getIndex() {
return index;
}
}
private int userIndex = LabComm.FIRST_USER_INDEX;
private HashMap<Class, Entry> byClass;
public LabCommEncoderRegistry() {
byClass = new HashMap<Class, Entry>();
}
public synchronized int add(LabCommDispatcher dispatcher) {
Entry e = byClass.get(dispatcher.getSampleClass());
if (e == null) {
e = new Entry(dispatcher, userIndex);
byClass.put(dispatcher.getSampleClass(), e);
userIndex++;
}
return e.getIndex();
}
public int getTag(Class<? extends LabCommSample> sample) throws IOException {
Entry e = byClass.get(sample);
if (e == null) {
throw new IOException("'" +
sample.getSimpleName() +
"' is not registered");
}
return e.index;
}
}
\ No newline at end of file
package se.lth.control.labcomm2006;
public interface LabCommHandler {
}
\ No newline at end of file
package se.lth.control.labcomm2006;
public interface LabCommReader {
public void handle(byte[] data, int begin, int end);
}
package se.lth.control.labcomm2006;
public interface LabCommSample {
}
\ No newline at end of file