-package org.simantics.db.procore.cluster;\r
-\r
-import org.simantics.db.exception.RuntimeDatabaseException;\r
-import org.simantics.db.procore.cluster.ClusterChangeSetI.Operation;\r
-import org.simantics.db.procore.cluster.ClusterChangeSetI.OperationEnum;\r
-import org.simantics.db.service.ClusterUID;\r
-\r
-class CCSParser {\r
- private static boolean DEBUG = false;\r
- enum StmEnum {\r
- Add,\r
- Remove\r
- };\r
- enum ReferenceType {\r
- Local,\r
- ForeignShort,\r
- ForeignLong\r
- };\r
- static class Args {\r
- ClusterUID clusterUID;\r
- ForeignTable rft;\r
- Operation rop;\r
- Args(ClusterUID clusterUID, ForeignTable rft, Operation rop) {\r
- this.clusterUID = clusterUID;\r
- this.rft = rft;\r
- this.rop = rop;\r
- }\r
- void createResource(short aRI) {\r
- rop.type = OperationEnum.CreateResource;\r
- rop.count = 1;\r
- rop.resourceIndex = aRI;\r
- }\r
- void addRelation(short aRI, short aPI, ClusterUID aPC, short aOI, ClusterUID aOC) {\r
- rop.type = OperationEnum.AddRelation;\r
- rop.count = 5;\r
- rop.resourceIndex = aRI;\r
- rop.predicateIndex = aPI;\r
- rop.predicateCluster = aPC;\r
- rop.objectIndex = aOI;\r
- rop.objectCluster = aOC;\r
- }\r
- void removeRelation(short aRI, short aPI, ClusterUID aPC, short aOI, ClusterUID aOC) {\r
- rop.type = OperationEnum.RemoveRelation;\r
- rop.count = 5;\r
- rop.resourceIndex = aRI;\r
- rop.predicateIndex = aPI;\r
- rop.predicateCluster = aPC;\r
- rop.objectIndex = aOI;\r
- rop.objectCluster = aOC;\r
- }\r
- void setValue(short aRI, byte[] apValueData, int valueStart, int aValueSize) {\r
- rop.type = OperationEnum.SetValue;\r
- rop.count = 4;\r
- rop.resourceIndex = aRI;\r
- rop.valueSize = aValueSize;\r
- rop.valueData = apValueData;\r
- rop.valueStart = valueStart;\r
- }\r
- void deleteValue(short aRI) {\r
- rop.type = OperationEnum.DeleteValue;\r
- rop.count = 1;\r
- rop.resourceIndex = aRI;\r
- }\r
- void modifyValue(short aRI, long aOffset, int aSize, byte[] apValue, int valueStart) {\r
- rop.type = OperationEnum.ModifyValue;\r
- rop.count = 5;\r
- rop.resourceIndex = aRI;\r
- rop.valueOffset = aOffset;\r
- rop.valueSize = aSize;\r
- rop.valueData = apValue;\r
- rop.valueStart = valueStart;\r
- }\r
- }\r
- private static class Data {\r
- short resource;\r
- ClusterUID clusterUID;\r
- boolean left;\r
- Data() {\r
- resource = 0;\r
- clusterUID = ClusterUID.Null;\r
- left = false;\r
- }\r
- }\r
- static class ForeignTable {\r
- ForeignTable() {\r
- init();\r
- }\r
- void init() {\r
- mSize = 0;\r
- }\r
- boolean get(short key, Data data) {\r
- if (key < mSize) {\r
- data.resource = mTable[key].resource;\r
- data.clusterUID = mTable[key].clusterUID;\r
- data.left = mTable[key].left;\r
- return true;\r
- }\r
- return false;\r
- }\r
- void getOrThrow(short key, Data data) {\r
- if (key < mSize) {\r
- data.resource = mTable[key].resource;\r
- data.clusterUID = mTable[key].clusterUID;\r
- data.left = mTable[key].left;\r
- } else\r
- new IllegalArgumentException("Missing foreign table entry for key=" + key + ".");\r
- }\r
- // cid is just for debugging\r
- void put(ClusterUID clusterUID, final Data data) {\r
- if (mSize <256) {\r
- if (DEBUG)\r
- System.out.println("ft put c=" + clusterUID + " i=" + mSize + " r=" + data.resource\r
- + " rc=" + data.clusterUID);\r
- if (data.resource == 0)\r
- throw new RuntimeDatabaseException("Resource can not be zero.");\r
- if (data.clusterUID.equals(ClusterUID.Null))\r
- throw new RuntimeDatabaseException("Cluster can not be zero.");\r
- mTable[mSize++] = data;\r
- }\r
- }\r
- private Data[] mTable = new Data[256];\r
- private int mSize;\r
- }\r
- static int parseStm(StmEnum stmEnum, Args args, byte[] bytes, int ap,\r
- int aBits, // number of bits used from operation code\r
- ReferenceType aPredicate, ReferenceType aObject) {\r
- assert(aBits <= 6);\r
- byte left = (byte)(6 - aBits);\r
- short ri = (short)((bytes[ap] & (1<<aBits)-1) << (8+left)); // top reference bits\r
- Data pdata = new Data();\r
- ap = getData(args.clusterUID, args.rft, bytes, ++ap, aPredicate, pdata);\r
- Data odata = new Data();\r
- ap = getData(args.clusterUID, args.rft, bytes, ap, aObject, odata);\r
- ri |= bytes[ap++] & 0xFF;\r
- short b = 0;\r
- byte l = 0;\r
- if (left > 0) { // middle index bits\r
- b = (short)(bytes[ap++] & 0xFF);\r
- l = 8;\r
- byte t = (byte)b;\r
- t &= (1<<left)-1;\r
- ri |= t << 8;\r
- l -= left;\r
- b >>= left; // skip used\r
- }\r
- GetLeftArgs a = new GetLeftArgs(ap, b, l);\r
- getLeft(args.clusterUID, args.rft, bytes, pdata, a);\r
- getLeft(args.clusterUID, args.rft, bytes, odata, a);\r
- ap = a.p;\r
- if (DEBUG)\r
- System.out.println("" + stmEnum + " r=" + ri + " rc=" + args.clusterUID +\r
- " p=" + pdata.resource + " pc=" + pdata.clusterUID +\r
- " o=" + odata.resource + " oc=" + odata.clusterUID);\r
- if (ClusterUID.Null.equals(args.clusterUID) || ClusterUID.Null.equals(pdata.clusterUID) || ClusterUID.Null.equals(odata.clusterUID))\r
- throw new RuntimeDatabaseException("Illegal cluster uid. args=" + args);\r
- switch (stmEnum) {\r
- case Add:\r
- args.addRelation(ri,\r
- pdata.resource, pdata.clusterUID,\r
- odata.resource, odata.clusterUID);\r
- break;\r
- case Remove:\r
- args.removeRelation(ri, pdata.resource, pdata.clusterUID, odata.resource, odata.clusterUID);\r
- break;\r
- default:\r
- new RuntimeException("Internal error. Contact application support.");\r
- }\r
- return ap;\r
- }\r
- private static class GetLeftArgs {\r
- GetLeftArgs(int p, short b, byte l) {\r
- this.p = p;\r
- this.b = b;\r
- this.l = l;\r
- }\r
- int p;\r
- short b;\r
- byte l;\r
- }\r
- private static void getLeft(ClusterUID aClusterUID, ForeignTable rft, byte[] bytes,\r
- Data rdata, GetLeftArgs a) {\r
- if (rdata.left) {\r
- if (a.l < 6) {\r
- a.b |= ((bytes[a.p] & 0xFF) << a.l); // next 8 bits\r
- ++a.p;\r
- a.l += 8;\r
- }\r
- byte t = (byte)a.b;\r
- t &= 0x3F;\r
- rdata.resource |= t << 8; // top bits\r
- rdata.left = false; // just for debugging\r
- if (rdata.clusterUID != aClusterUID)\r
- rft.put(aClusterUID, rdata);\r
- a.b >>>= 6; // skip used bits\r
- a.l -= 6;\r
- } else // ForeignShort\r
- rft.getOrThrow(rdata.resource, rdata);\r
- }\r
- private static int getData(ClusterUID aClusterUID, ForeignTable ft, byte[] bytes, int rp, ReferenceType a, Data rdata) {\r
- switch (a) {\r
- default: \r
- throw new IllegalArgumentException("Illegal enumeration value=" + a + ".");\r
- case Local:\r
- rdata.resource = (short)(bytes[rp] & 0xFF); // low byte\r
- rdata.clusterUID = aClusterUID;\r
- rdata.left = true;\r
- rp += 1;\r
- break;\r
- case ForeignShort:\r
- rdata.resource = (short)(bytes[rp] & 0xFF); // index to foreign table\r
- rdata.left = false;\r
- rp += 1;\r
- break;\r
- case ForeignLong:\r
- rdata.clusterUID = ClusterUID.make(bytes, rp);\r
- rp += ClusterUID.getLongLength() * 8;\r
- rdata.resource = (short)(bytes[rp] & 0xFF); // low byte\r
- rdata.left = true;\r
- rp += 1;\r
- break;\r
- }\r
- return rp;\r
- }\r
- static long getLongN(byte[] bytes, int offset, int size) {\r
- long l = 0;\r
- for (int i=0, shift=0; i<size; ++i, ++offset, shift+=8) {\r
- l |= (bytes[offset] & 0xFF) << shift;\r
- }\r
- return l;\r
- }\r
- static short getShort(byte[] bytes, int offset) {\r
- return (short)getLongN(bytes, offset, 2);\r
- }\r
- static int getInt(byte[] bytes, int offset) {\r
- return (int)getLongN(bytes, offset, 4);\r
- }\r
-}\r
+package org.simantics.db.procore.cluster;
+
+import org.simantics.db.exception.RuntimeDatabaseException;
+import org.simantics.db.procore.cluster.ClusterChangeSetI.Operation;
+import org.simantics.db.procore.cluster.ClusterChangeSetI.OperationEnum;
+import org.simantics.db.service.ClusterUID;
+
+class CCSParser {
+ private static boolean DEBUG = false;
+ enum StmEnum {
+ Add,
+ Remove
+ };
+ enum ReferenceType {
+ Local,
+ ForeignShort,
+ ForeignLong
+ };
+ static class Args {
+ ClusterUID clusterUID;
+ ForeignTable rft;
+ Operation rop;
+ Args(ClusterUID clusterUID, ForeignTable rft, Operation rop) {
+ this.clusterUID = clusterUID;
+ this.rft = rft;
+ this.rop = rop;
+ }
+ void createResource(short aRI) {
+ rop.type = OperationEnum.CreateResource;
+ rop.count = 1;
+ rop.resourceIndex = aRI;
+ }
+ void addRelation(short aRI, short aPI, ClusterUID aPC, short aOI, ClusterUID aOC) {
+ rop.type = OperationEnum.AddRelation;
+ rop.count = 5;
+ rop.resourceIndex = aRI;
+ rop.predicateIndex = aPI;
+ rop.predicateCluster = aPC;
+ rop.objectIndex = aOI;
+ rop.objectCluster = aOC;
+ }
+ void removeRelation(short aRI, short aPI, ClusterUID aPC, short aOI, ClusterUID aOC) {
+ rop.type = OperationEnum.RemoveRelation;
+ rop.count = 5;
+ rop.resourceIndex = aRI;
+ rop.predicateIndex = aPI;
+ rop.predicateCluster = aPC;
+ rop.objectIndex = aOI;
+ rop.objectCluster = aOC;
+ }
+ void setValue(short aRI, byte[] apValueData, int valueStart, int aValueSize) {
+ rop.type = OperationEnum.SetValue;
+ rop.count = 4;
+ rop.resourceIndex = aRI;
+ rop.valueSize = aValueSize;
+ rop.valueData = apValueData;
+ rop.valueStart = valueStart;
+ }
+ void deleteValue(short aRI) {
+ rop.type = OperationEnum.DeleteValue;
+ rop.count = 1;
+ rop.resourceIndex = aRI;
+ }
+ void modifyValue(short aRI, long aOffset, int aSize, byte[] apValue, int valueStart) {
+ rop.type = OperationEnum.ModifyValue;
+ rop.count = 5;
+ rop.resourceIndex = aRI;
+ rop.valueOffset = aOffset;
+ rop.valueSize = aSize;
+ rop.valueData = apValue;
+ rop.valueStart = valueStart;
+ }
+ }
+ private static class Data {
+ short resource;
+ ClusterUID clusterUID;
+ boolean left;
+ Data() {
+ resource = 0;
+ clusterUID = ClusterUID.Null;
+ left = false;
+ }
+ }
+ static class ForeignTable {
+ ForeignTable() {
+ init();
+ }
+ void init() {
+ mSize = 0;
+ }
+ boolean get(short key, Data data) {
+ if (key < mSize) {
+ data.resource = mTable[key].resource;
+ data.clusterUID = mTable[key].clusterUID;
+ data.left = mTable[key].left;
+ return true;
+ }
+ return false;
+ }
+ void getOrThrow(short key, Data data) {
+ if (key < mSize) {
+ data.resource = mTable[key].resource;
+ data.clusterUID = mTable[key].clusterUID;
+ data.left = mTable[key].left;
+ } else
+ new IllegalArgumentException("Missing foreign table entry for key=" + key + ".");
+ }
+ // cid is just for debugging
+ void put(ClusterUID clusterUID, final Data data) {
+ if (mSize <256) {
+ if (DEBUG)
+ System.out.println("ft put c=" + clusterUID + " i=" + mSize + " r=" + data.resource
+ + " rc=" + data.clusterUID);
+ if (data.resource == 0)
+ throw new RuntimeDatabaseException("Resource can not be zero.");
+ if (data.clusterUID.equals(ClusterUID.Null))
+ throw new RuntimeDatabaseException("Cluster can not be zero.");
+ mTable[mSize++] = data;
+ }
+ }
+ private Data[] mTable = new Data[256];
+ private int mSize;
+ }
+ static int parseStm(StmEnum stmEnum, Args args, byte[] bytes, int ap,
+ int aBits, // number of bits used from operation code
+ ReferenceType aPredicate, ReferenceType aObject) {
+ assert(aBits <= 6);
+ byte left = (byte)(6 - aBits);
+ short ri = (short)((bytes[ap] & (1<<aBits)-1) << (8+left)); // top reference bits
+ Data pdata = new Data();
+ ap = getData(args.clusterUID, args.rft, bytes, ++ap, aPredicate, pdata);
+ Data odata = new Data();
+ ap = getData(args.clusterUID, args.rft, bytes, ap, aObject, odata);
+ ri |= bytes[ap++] & 0xFF;
+ short b = 0;
+ byte l = 0;
+ if (left > 0) { // middle index bits
+ b = (short)(bytes[ap++] & 0xFF);
+ l = 8;
+ byte t = (byte)b;
+ t &= (1<<left)-1;
+ ri |= t << 8;
+ l -= left;
+ b >>= left; // skip used
+ }
+ GetLeftArgs a = new GetLeftArgs(ap, b, l);
+ getLeft(args.clusterUID, args.rft, bytes, pdata, a);
+ getLeft(args.clusterUID, args.rft, bytes, odata, a);
+ ap = a.p;
+ if (DEBUG)
+ System.out.println("" + stmEnum + " r=" + ri + " rc=" + args.clusterUID +
+ " p=" + pdata.resource + " pc=" + pdata.clusterUID +
+ " o=" + odata.resource + " oc=" + odata.clusterUID);
+ if (ClusterUID.Null.equals(args.clusterUID) || ClusterUID.Null.equals(pdata.clusterUID) || ClusterUID.Null.equals(odata.clusterUID))
+ throw new RuntimeDatabaseException("Illegal cluster uid. args=" + args);
+ switch (stmEnum) {
+ case Add:
+ args.addRelation(ri,
+ pdata.resource, pdata.clusterUID,
+ odata.resource, odata.clusterUID);
+ break;
+ case Remove:
+ args.removeRelation(ri, pdata.resource, pdata.clusterUID, odata.resource, odata.clusterUID);
+ break;
+ default:
+ new RuntimeException("Internal error, unrecognized StmEnum value encountered: " + stmEnum);
+ }
+ return ap;
+ }
+ private static class GetLeftArgs {
+ GetLeftArgs(int p, short b, byte l) {
+ this.p = p;
+ this.b = b;
+ this.l = l;
+ }
+ int p;
+ short b;
+ byte l;
+ }
+ private static void getLeft(ClusterUID aClusterUID, ForeignTable rft, byte[] bytes,
+ Data rdata, GetLeftArgs a) {
+ if (rdata.left) {
+ if (a.l < 6) {
+ a.b |= ((bytes[a.p] & 0xFF) << a.l); // next 8 bits
+ ++a.p;
+ a.l += 8;
+ }
+ byte t = (byte)a.b;
+ t &= 0x3F;
+ rdata.resource |= t << 8; // top bits
+ rdata.left = false; // just for debugging
+ if (rdata.clusterUID != aClusterUID)
+ rft.put(aClusterUID, rdata);
+ a.b >>>= 6; // skip used bits
+ a.l -= 6;
+ } else // ForeignShort
+ rft.getOrThrow(rdata.resource, rdata);
+ }
+ private static int getData(ClusterUID aClusterUID, ForeignTable ft, byte[] bytes, int rp, ReferenceType a, Data rdata) {
+ switch (a) {
+ default:
+ throw new IllegalArgumentException("Illegal enumeration value=" + a + ".");
+ case Local:
+ rdata.resource = (short)(bytes[rp] & 0xFF); // low byte
+ rdata.clusterUID = aClusterUID;
+ rdata.left = true;
+ rp += 1;
+ break;
+ case ForeignShort:
+ rdata.resource = (short)(bytes[rp] & 0xFF); // index to foreign table
+ rdata.left = false;
+ rp += 1;
+ break;
+ case ForeignLong:
+ rdata.clusterUID = ClusterUID.make(bytes, rp);
+ rp += ClusterUID.getLongLength() * 8;
+ rdata.resource = (short)(bytes[rp] & 0xFF); // low byte
+ rdata.left = true;
+ rp += 1;
+ break;
+ }
+ return rp;
+ }
+ static long getLongN(byte[] bytes, int offset, int size) {
+ long l = 0;
+ for (int i=0, shift=0; i<size; ++i, ++offset, shift+=8) {
+ l |= (bytes[offset] & 0xFF) << shift;
+ }
+ return l;
+ }
+ static short getShort(byte[] bytes, int offset) {
+ return (short)getLongN(bytes, offset, 2);
+ }
+ static int getInt(byte[] bytes, int offset) {
+ return (int)getLongN(bytes, offset, 4);
+ }
+}