--- /dev/null
+package org.simantics.db.impl.query;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.simantics.db.impl.ClusterTraitsBase;
+
+import gnu.trove.list.array.TByteArrayList;
+import gnu.trove.map.hash.TLongIntHashMap;
+import gnu.trove.procedure.TLongIntProcedure;
+
+public class QuerySerializer {
+
+ private QueryProcessor processor;
+ private QuerySupport querySupport;
+ private TByteArrayList bytes = new TByteArrayList();
+ private TLongIntHashMap clusterKeys = new TLongIntHashMap();
+ private Map<String,Integer> ids = new HashMap<String,Integer>();
+
+ public QuerySerializer(QueryProcessor processor) {
+ this.processor = processor;
+ this.querySupport = processor.querySupport;
+ }
+
+ public int writeUnknownSize() {
+ int pos = bytes.size();
+ bytes.add((byte)0);
+ bytes.add((byte)0);
+ bytes.add((byte)0);
+ bytes.add((byte)0);
+ return pos;
+ }
+
+ public void setUnknownSize(int pos, int value) {
+ bytes.set(pos, (byte) (value & 0xFF));
+ bytes.set(pos+1, (byte) ((value >>> 8) & 0xFF));
+ bytes.set(pos+2, (byte) ((value >>> 16) & 0xFF));
+ bytes.set(pos+3, (byte) ((value >>> 24) & 0xFF));
+ }
+
+ public void serializeId(String classId) {
+ Integer id = ids.get(classId);
+ if(id == null) {
+ id = ids.size() + 1;
+ ids.put(classId, id);
+ }
+ writeLE(id);
+ }
+
+ public void addResource(int r) {
+ if(r < 0) {
+ writeLE(r);
+ } else {
+ long clusterId = querySupport.getClusterId(r);
+ int clusterKey = clusterKeys.get(clusterId);
+ if(clusterKey == 0) {
+ clusterKey = clusterKeys.size() + 1;
+ clusterKeys.put(clusterId, clusterKey);
+ }
+ int i = ClusterTraitsBase.createResourceKeyNoThrow(clusterKey, ClusterTraitsBase.getResourceIndexFromResourceKeyNoThrow(r));
+ writeLE(i);
+ }
+ }
+
+ public void addString(String s) {
+ byte[] b = s.getBytes();
+ writeLE(b.length);
+ bytes.add(b);
+ }
+
+ public void add(byte b) {
+ bytes.add(b);
+ }
+
+ public void add(byte[] bs) {
+ bytes.add(bs);
+ }
+
+ public byte[] bytes() {
+ TByteArrayList header = new TByteArrayList();
+ writeLE(header, ids.size());
+ for(Entry<String,Integer> entry : ids.entrySet()) {
+ String id = entry.getKey();
+ writeLE(header, id.length());
+ header.add(id.getBytes());
+ writeLE(header, entry.getValue());
+ }
+
+ writeLE(header, clusterKeys.size());
+ clusterKeys.forEachEntry(new TLongIntProcedure() {
+
+ @Override
+ public boolean execute(long a, int b) {
+ writeLE(header, a);
+ writeLE(header, b);
+ return true;
+ }
+
+ });
+
+ header.add(bytes.toArray());
+ return header.toArray();
+ }
+
+ public void writeLE(int value) {
+ writeLE(bytes, value);
+ }
+
+ public static void writeLE(TByteArrayList bytes, int value) {
+ bytes.add((byte) (value & 0xFF));
+ bytes.add((byte) ((value >>> 8) & 0xFF));
+ bytes.add((byte) ((value >>> 16) & 0xFF));
+ bytes.add((byte) ((value >>> 24) & 0xFF));
+ }
+
+ public void writeLE(long value) {
+ writeLE(bytes, value);
+ }
+
+ public static void writeLE(TByteArrayList bytes, long value) {
+ bytes.add((byte) (value & 0xFF));
+ bytes.add((byte) ((value >>> 8) & 0xFF));
+ bytes.add((byte) ((value >>> 16) & 0xFF));
+ bytes.add((byte) ((value >>> 24) & 0xFF));
+ bytes.add((byte) ((value >>> 32) & 0xFF));
+ bytes.add((byte) ((value >>> 40) & 0xFF));
+ bytes.add((byte) ((value >>> 48) & 0xFF));
+ bytes.add((byte) ((value >>> 56) & 0xFF));
+ }
+
+ public QueryProcessor getQueryProcessor() {
+ return processor;
+ }
+
+}