1 package org.simantics.db.procore.cluster;
\r
3 import org.simantics.db.exception.RuntimeDatabaseException;
\r
4 import org.simantics.db.procore.cluster.ClusterChangeSetI.Operation;
\r
5 import org.simantics.db.procore.cluster.ClusterChangeSetI.OperationEnum;
\r
6 import org.simantics.db.service.ClusterUID;
\r
9 private static boolean DEBUG = false;
\r
14 enum ReferenceType {
\r
20 ClusterUID clusterUID;
\r
23 Args(ClusterUID clusterUID, ForeignTable rft, Operation rop) {
\r
24 this.clusterUID = clusterUID;
\r
28 void createResource(short aRI) {
\r
29 rop.type = OperationEnum.CreateResource;
\r
31 rop.resourceIndex = aRI;
\r
33 void addRelation(short aRI, short aPI, ClusterUID aPC, short aOI, ClusterUID aOC) {
\r
34 rop.type = OperationEnum.AddRelation;
\r
36 rop.resourceIndex = aRI;
\r
37 rop.predicateIndex = aPI;
\r
38 rop.predicateCluster = aPC;
\r
39 rop.objectIndex = aOI;
\r
40 rop.objectCluster = aOC;
\r
42 void removeRelation(short aRI, short aPI, ClusterUID aPC, short aOI, ClusterUID aOC) {
\r
43 rop.type = OperationEnum.RemoveRelation;
\r
45 rop.resourceIndex = aRI;
\r
46 rop.predicateIndex = aPI;
\r
47 rop.predicateCluster = aPC;
\r
48 rop.objectIndex = aOI;
\r
49 rop.objectCluster = aOC;
\r
51 void setValue(short aRI, byte[] apValueData, int valueStart, int aValueSize) {
\r
52 rop.type = OperationEnum.SetValue;
\r
54 rop.resourceIndex = aRI;
\r
55 rop.valueSize = aValueSize;
\r
56 rop.valueData = apValueData;
\r
57 rop.valueStart = valueStart;
\r
59 void deleteValue(short aRI) {
\r
60 rop.type = OperationEnum.DeleteValue;
\r
62 rop.resourceIndex = aRI;
\r
64 void modifyValue(short aRI, long aOffset, int aSize, byte[] apValue, int valueStart) {
\r
65 rop.type = OperationEnum.ModifyValue;
\r
67 rop.resourceIndex = aRI;
\r
68 rop.valueOffset = aOffset;
\r
69 rop.valueSize = aSize;
\r
70 rop.valueData = apValue;
\r
71 rop.valueStart = valueStart;
\r
74 private static class Data {
\r
76 ClusterUID clusterUID;
\r
80 clusterUID = ClusterUID.Null;
\r
84 static class ForeignTable {
\r
91 boolean get(short key, Data data) {
\r
93 data.resource = mTable[key].resource;
\r
94 data.clusterUID = mTable[key].clusterUID;
\r
95 data.left = mTable[key].left;
\r
100 void getOrThrow(short key, Data data) {
\r
102 data.resource = mTable[key].resource;
\r
103 data.clusterUID = mTable[key].clusterUID;
\r
104 data.left = mTable[key].left;
\r
106 new IllegalArgumentException("Missing foreign table entry for key=" + key + ".");
\r
108 // cid is just for debugging
\r
109 void put(ClusterUID clusterUID, final Data data) {
\r
112 System.out.println("ft put c=" + clusterUID + " i=" + mSize + " r=" + data.resource
\r
113 + " rc=" + data.clusterUID);
\r
114 if (data.resource == 0)
\r
115 throw new RuntimeDatabaseException("Resource can not be zero.");
\r
116 if (data.clusterUID.equals(ClusterUID.Null))
\r
117 throw new RuntimeDatabaseException("Cluster can not be zero.");
\r
118 mTable[mSize++] = data;
\r
121 private Data[] mTable = new Data[256];
\r
124 static int parseStm(StmEnum stmEnum, Args args, byte[] bytes, int ap,
\r
125 int aBits, // number of bits used from operation code
\r
126 ReferenceType aPredicate, ReferenceType aObject) {
\r
127 assert(aBits <= 6);
\r
128 byte left = (byte)(6 - aBits);
\r
129 short ri = (short)((bytes[ap] & (1<<aBits)-1) << (8+left)); // top reference bits
\r
130 Data pdata = new Data();
\r
131 ap = getData(args.clusterUID, args.rft, bytes, ++ap, aPredicate, pdata);
\r
132 Data odata = new Data();
\r
133 ap = getData(args.clusterUID, args.rft, bytes, ap, aObject, odata);
\r
134 ri |= bytes[ap++] & 0xFF;
\r
137 if (left > 0) { // middle index bits
\r
138 b = (short)(bytes[ap++] & 0xFF);
\r
144 b >>= left; // skip used
\r
146 GetLeftArgs a = new GetLeftArgs(ap, b, l);
\r
147 getLeft(args.clusterUID, args.rft, bytes, pdata, a);
\r
148 getLeft(args.clusterUID, args.rft, bytes, odata, a);
\r
151 System.out.println("" + stmEnum + " r=" + ri + " rc=" + args.clusterUID +
\r
152 " p=" + pdata.resource + " pc=" + pdata.clusterUID +
\r
153 " o=" + odata.resource + " oc=" + odata.clusterUID);
\r
154 if (ClusterUID.Null.equals(args.clusterUID) || ClusterUID.Null.equals(pdata.clusterUID) || ClusterUID.Null.equals(odata.clusterUID))
\r
155 throw new RuntimeDatabaseException("Illegal cluster uid. args=" + args);
\r
158 args.addRelation(ri,
\r
159 pdata.resource, pdata.clusterUID,
\r
160 odata.resource, odata.clusterUID);
\r
163 args.removeRelation(ri, pdata.resource, pdata.clusterUID, odata.resource, odata.clusterUID);
\r
166 new RuntimeException("Internal error. Contact application support.");
\r
170 private static class GetLeftArgs {
\r
171 GetLeftArgs(int p, short b, byte l) {
\r
180 private static void getLeft(ClusterUID aClusterUID, ForeignTable rft, byte[] bytes,
\r
181 Data rdata, GetLeftArgs a) {
\r
184 a.b |= ((bytes[a.p] & 0xFF) << a.l); // next 8 bits
\r
188 byte t = (byte)a.b;
\r
190 rdata.resource |= t << 8; // top bits
\r
191 rdata.left = false; // just for debugging
\r
192 if (rdata.clusterUID != aClusterUID)
\r
193 rft.put(aClusterUID, rdata);
\r
194 a.b >>>= 6; // skip used bits
\r
196 } else // ForeignShort
\r
197 rft.getOrThrow(rdata.resource, rdata);
\r
199 private static int getData(ClusterUID aClusterUID, ForeignTable ft, byte[] bytes, int rp, ReferenceType a, Data rdata) {
\r
202 throw new IllegalArgumentException("Illegal enumeration value=" + a + ".");
\r
204 rdata.resource = (short)(bytes[rp] & 0xFF); // low byte
\r
205 rdata.clusterUID = aClusterUID;
\r
210 rdata.resource = (short)(bytes[rp] & 0xFF); // index to foreign table
\r
211 rdata.left = false;
\r
215 rdata.clusterUID = ClusterUID.make(bytes, rp);
\r
216 rp += ClusterUID.getLongLength() * 8;
\r
217 rdata.resource = (short)(bytes[rp] & 0xFF); // low byte
\r
224 static long getLongN(byte[] bytes, int offset, int size) {
\r
226 for (int i=0, shift=0; i<size; ++i, ++offset, shift+=8) {
\r
227 l |= (bytes[offset] & 0xFF) << shift;
\r
231 static short getShort(byte[] bytes, int offset) {
\r
232 return (short)getLongN(bytes, offset, 2);
\r
234 static int getInt(byte[] bytes, int offset) {
\r
235 return (int)getLongN(bytes, offset, 4);
\r