]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.procore/src/org/simantics/db/procore/cluster/CCSParser.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.db.procore / src / org / simantics / db / procore / cluster / CCSParser.java
1 package org.simantics.db.procore.cluster;\r
2 \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
7 \r
8 class CCSParser {\r
9     private static boolean DEBUG = false;\r
10     enum StmEnum {\r
11         Add,\r
12         Remove\r
13     };\r
14     enum ReferenceType {\r
15         Local,\r
16         ForeignShort,\r
17         ForeignLong\r
18     };\r
19     static class Args {\r
20         ClusterUID clusterUID;\r
21         ForeignTable rft;\r
22         Operation rop;\r
23         Args(ClusterUID clusterUID, ForeignTable rft, Operation rop) {\r
24             this.clusterUID = clusterUID;\r
25             this.rft = rft;\r
26             this.rop = rop;\r
27         }\r
28         void createResource(short aRI) {\r
29             rop.type = OperationEnum.CreateResource;\r
30             rop.count = 1;\r
31             rop.resourceIndex = aRI;\r
32         }\r
33         void addRelation(short aRI, short aPI, ClusterUID aPC, short aOI, ClusterUID aOC) {\r
34             rop.type = OperationEnum.AddRelation;\r
35             rop.count = 5;\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
41         }\r
42         void removeRelation(short aRI, short aPI, ClusterUID aPC, short aOI, ClusterUID aOC) {\r
43             rop.type = OperationEnum.RemoveRelation;\r
44             rop.count = 5;\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
50         }\r
51         void setValue(short aRI, byte[] apValueData, int valueStart, int aValueSize) {\r
52             rop.type = OperationEnum.SetValue;\r
53             rop.count = 4;\r
54             rop.resourceIndex = aRI;\r
55             rop.valueSize = aValueSize;\r
56             rop.valueData = apValueData;\r
57             rop.valueStart = valueStart;\r
58         }\r
59         void deleteValue(short aRI) {\r
60             rop.type = OperationEnum.DeleteValue;\r
61             rop.count = 1;\r
62             rop.resourceIndex = aRI;\r
63         }\r
64         void modifyValue(short aRI, long aOffset, int aSize, byte[] apValue, int valueStart) {\r
65             rop.type = OperationEnum.ModifyValue;\r
66             rop.count = 5;\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
72         }\r
73     }\r
74     private static class Data {\r
75         short resource;\r
76         ClusterUID clusterUID;\r
77         boolean left;\r
78         Data() {\r
79             resource = 0;\r
80             clusterUID = ClusterUID.Null;\r
81             left = false;\r
82         }\r
83     }\r
84     static class ForeignTable {\r
85         ForeignTable() {\r
86             init();\r
87         }\r
88         void init() {\r
89             mSize = 0;\r
90         }\r
91         boolean get(short key, Data data) {\r
92             if (key < mSize) {\r
93                 data.resource = mTable[key].resource;\r
94                 data.clusterUID = mTable[key].clusterUID;\r
95                 data.left = mTable[key].left;\r
96                 return true;\r
97             }\r
98             return false;\r
99         }\r
100         void getOrThrow(short key, Data data) {\r
101             if (key < mSize) {\r
102                 data.resource = mTable[key].resource;\r
103                 data.clusterUID = mTable[key].clusterUID;\r
104                 data.left = mTable[key].left;\r
105             } else\r
106                 new IllegalArgumentException("Missing foreign table entry for key=" + key + ".");\r
107         }\r
108         // cid is just for debugging\r
109         void put(ClusterUID clusterUID, final Data data) {\r
110             if (mSize <256) {\r
111                 if (DEBUG)\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
119             }\r
120         }\r
121         private Data[] mTable = new Data[256];\r
122         private int mSize;\r
123     }\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
135         short b = 0;\r
136         byte l = 0;\r
137         if (left > 0) { // middle index bits\r
138             b = (short)(bytes[ap++] & 0xFF);\r
139             l = 8;\r
140             byte t = (byte)b;\r
141             t &= (1<<left)-1;\r
142             ri |= t << 8;\r
143             l -= left;\r
144             b >>= left; // skip used\r
145         }\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
149         ap = a.p;\r
150         if (DEBUG)\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
156         switch (stmEnum) {\r
157             case Add:\r
158                 args.addRelation(ri,\r
159                         pdata.resource, pdata.clusterUID,\r
160                         odata.resource, odata.clusterUID);\r
161                 break;\r
162             case Remove:\r
163                 args.removeRelation(ri, pdata.resource, pdata.clusterUID, odata.resource, odata.clusterUID);\r
164                 break;\r
165             default:\r
166                 new RuntimeException("Internal error. Contact application support.");\r
167         }\r
168         return ap;\r
169     }\r
170     private static class GetLeftArgs {\r
171         GetLeftArgs(int p, short b, byte l) {\r
172             this.p = p;\r
173             this.b = b;\r
174             this.l = l;\r
175         }\r
176         int p;\r
177         short b;\r
178         byte l;\r
179     }\r
180     private static void getLeft(ClusterUID aClusterUID, ForeignTable rft, byte[] bytes,\r
181         Data rdata, GetLeftArgs a) {\r
182         if (rdata.left) {\r
183             if (a.l < 6) {\r
184                 a.b |= ((bytes[a.p] & 0xFF) << a.l); // next 8 bits\r
185                 ++a.p;\r
186                 a.l += 8;\r
187             }\r
188             byte t = (byte)a.b;\r
189             t &= 0x3F;\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
195             a.l -= 6;\r
196         } else // ForeignShort\r
197             rft.getOrThrow(rdata.resource, rdata);\r
198     }\r
199     private static int getData(ClusterUID aClusterUID, ForeignTable ft, byte[] bytes, int rp, ReferenceType a, Data rdata) {\r
200         switch (a) {\r
201             default: \r
202                 throw new IllegalArgumentException("Illegal enumeration value=" + a + ".");\r
203             case Local:\r
204                 rdata.resource = (short)(bytes[rp] & 0xFF); // low byte\r
205                 rdata.clusterUID = aClusterUID;\r
206                 rdata.left = true;\r
207                 rp += 1;\r
208                 break;\r
209             case ForeignShort:\r
210                 rdata.resource = (short)(bytes[rp] & 0xFF); // index to foreign table\r
211                 rdata.left = false;\r
212                 rp += 1;\r
213                 break;\r
214             case ForeignLong:\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
218                 rdata.left = true;\r
219                 rp += 1;\r
220                 break;\r
221         }\r
222         return rp;\r
223     }\r
224     static long getLongN(byte[] bytes, int offset, int size) {\r
225         long l = 0;\r
226         for (int i=0, shift=0; i<size; ++i, ++offset, shift+=8) {\r
227             l |= (bytes[offset] & 0xFF) << shift;\r
228         }\r
229         return l;\r
230     }\r
231     static short getShort(byte[] bytes, int offset) {\r
232         return (short)getLongN(bytes, offset, 2);\r
233     }\r
234     static int getInt(byte[] bytes, int offset) {\r
235         return (int)getLongN(bytes, offset, 4);\r
236     }\r
237 }\r