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 ids = new HashMap(); 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 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; } }