1 package org.simantics.db.impl.query;
4 import java.io.IOException;
5 import java.io.UnsupportedEncodingException;
6 import java.net.MalformedURLException;
8 import java.net.URLDecoder;
10 import org.simantics.utils.FileUtils;
12 public class CodeGen {
16 class GenerationInfo {
21 boolean useNeedsToBlock;
22 String entryCreationArguments;
23 GenerationInfo(String p1, String keyName, String keyToId, String p4, String procedure, String entryCreationArguments, boolean useNeedsToBlock) {
25 this.keyName = keyName;
26 this.keyToId = keyToId;
27 this.procedure = procedure;
28 this.useNeedsToBlock = useNeedsToBlock;
29 this.entryCreationArguments = entryCreationArguments;
33 GenerationInfo signatureR1RelationInfo = new GenerationInfo ( "int r", "r", "keyR", "long", "InternalProcedure<RelationInfo>", "", false );
34 GenerationInfo signatureR1Bytes = new GenerationInfo ( "int r", "r", "keyR", "long", "InternalProcedure<byte[]>", "", false );
35 GenerationInfo signatureR1IntSet = new GenerationInfo ( "int r", "r", "keyR", "long", "InternalProcedure<IntSet>", "", false );
36 GenerationInfo signatureR1IP = new GenerationInfo ( "int r", "r", "keyR", "long", "IntProcedure", "", false );
37 GenerationInfo signatureR2IP = new GenerationInfo ( "int r1, int r2", "r1,r2", "keyR2", "long", "IntProcedure", "", false );
38 GenerationInfo signatureR2TIP = new GenerationInfo ( "int r1, int r2", "r1,r2", "keyR2", "long", "TripleIntProcedure", "", false );
39 GenerationInfo signatureID1 = new GenerationInfo ( "String id", "id", "keyID", "String", "InternalProcedure<Integer>", "", false );
40 GenerationInfo signatureID2 = new GenerationInfo ( "String id", "id", "keyID", "String", "InternalProcedure<TObjectIntHashMap<String>>", "", false );
41 GenerationInfo signatureChildMap = new GenerationInfo ( "int r", "r", "keyR", "long", "InternalProcedure<ObjectResourceIdMap<String>>", "", false );
42 GenerationInfo signatureRead = new GenerationInfo ( "Read<?> r", "r", "id", "long", "AsyncProcedure", "", true );
43 GenerationInfo signatureAsyncRead = new GenerationInfo ( "AsyncRead<?> r", "r", "id", "long", "AsyncProcedure", "", true );
44 GenerationInfo signatureMultiRead = new GenerationInfo ( "MultiRead<?> r", "r", "id", "long", "SyncMultiProcedure", "", false );
45 GenerationInfo signatureAsyncMultiRead = new GenerationInfo ( "AsyncMultiRead<?> r", "r", "id", "long", "AsyncMultiProcedure", "", false );
46 GenerationInfo signatureExternalRead = new GenerationInfo ( "ExternalRead<?> r", "r", "id", "long", "AsyncProcedure", ", graph", false );
48 private void line(StringBuilder content, String line) {
49 for(int i=0;i<indent;i++)
55 public void generateQuery(StringBuilder content, String clazz, GenerationInfo signature, boolean runnerShortcut, boolean genReturn) {
56 generateGetOrCreate(content, clazz, signature);
57 generateRemove(content, clazz, signature);
58 generateRunner(content, clazz, signature, runnerShortcut, genReturn);
61 public void generateRunner(StringBuilder content, String clazz, GenerationInfo signature, boolean shortcut, boolean genReturn) {
63 line(content, "public static " + (genReturn ? "Object" : "void") + " runner" + clazz + "(ReadGraphImpl graph, " + signature.p1 + ", CacheEntry parent, ListenerBase listener, final " + signature.procedure + " procedure" + (signature.useNeedsToBlock ? ", boolean needsToBlock" : "") + ") throws DatabaseException {");
64 line(content, " QueryCache cache = graph.processor.cache;");
66 line(content, " if(parent == null && listener == null && !cache.shouldCache(graph.processor, " + signature.keyName + ")) {");
67 line(content, " if (SINGLE) {");
68 line(content, " " + clazz + " e = cache.peek" + clazz + "(" + signature.keyName + ");");
69 line(content, " if (e != null && e.isReady()) {");
70 line(content, " " + (genReturn ? "return " : "") + "e.performFromCache(graph, procedure);");
71 if(!genReturn) line(content, " return;");
74 line(content, " " + (genReturn ? "return " : "") + clazz + ".computeForEach(graph, " + signature.keyName + ", null, procedure" + (signature.useNeedsToBlock ? ", needsToBlock" : "") + ");");
75 if(!genReturn) line(content, " return;");
78 if(signature.useNeedsToBlock) {
79 line(content, " " + clazz + " entry = (" + clazz + ")cache.getOrCreate" + clazz + "(graph, " + signature.keyName + ", needsToBlock);");
80 line(content, " if(entry == null) {");
81 line(content, " graph.processor.schedule(new SessionTask(graph) {");
82 line(content, " @Override");
83 line(content, " public void run0(int thread) {");
84 line(content, " try {");
85 line(content, " runner" + clazz + "(graph, r, parent, listener, procedure, needsToBlock);");
86 line(content, " } catch (DatabaseException e) {");
87 line(content, " Logger.defaultLogError(e);");
90 line(content, " });");
91 line(content, " return null;");
94 line(content, " " + clazz + " entry = (" + clazz + ")cache.getOrCreate" + clazz + "(graph, " + signature.keyName + ");");
96 line(content, " " + signature.procedure + " procedure_ = procedure != null ? procedure : emptyProcedure" + clazz + ";");
97 line(content, " if(entry.isReady()) {");
98 line(content, " graph.processor.listening.registerDependencies(graph, entry, parent, listener, procedure_, false);");
100 line(content, " Object result = entry.performFromCache(graph, procedure_);");
101 line(content, " graph.processor.listening.registerFirstKnown(listener, result);");
102 line(content, " return result;");
104 line(content, " entry.performFromCache(graph, procedure_);");
107 line(content, " else {");
108 line(content, " assert(entry.isPending());");
110 line(content, " graph.processor.listening.registerDependencies(graph, entry, parent, listener, procedure_, false);");
111 if(shortcut) line(content, " Object result = " + clazz + ".computeForEach(graph, " + signature.keyName + ", entry, procedure_" + (signature.useNeedsToBlock ? ", needsToBlock" : "") + ");");
112 else line(content, " entry.compute(graph, procedure_);");
113 line(content, " graph.processor.listening.registerFirstKnown(listener, result);");
114 line(content, " return result;");
116 line(content, " graph.processor.listening.registerDependencies(graph, entry, parent, listener, procedure_, false);");
117 if(shortcut) line(content, " " + clazz + ".computeForEach(graph, " + signature.keyName + ", entry, procedure_" + (signature.useNeedsToBlock ? ", needsToBlock" : "") + ");");
118 else line(content, " entry.compute(graph, procedure_);");
124 String lower = Character.toLowerCase(clazz.charAt(0)) + clazz.substring(1);
126 line(content, "private " + clazz + " peek" + clazz + "(" + signature.p1 + ") {");
127 line(content, " synchronized(" + lower +"Map) {");
128 line(content, " return (" + clazz + ") " + lower + "Map.get(" + signature.keyName + ");");
134 public void generateRemove(StringBuilder content, String clazz, GenerationInfo signature) {
136 String lower = Character.toLowerCase(clazz.charAt(0)) + clazz.substring(1);
138 line(content, "void remove(" + clazz + " entry) {");
139 line(content, " synchronized(" + lower + "Map) {");
140 line(content, " " + lower + "Map.remove(entry.id);");
147 public void generateGetOrCreate(StringBuilder content, String clazz, GenerationInfo signature) {
149 String lower = Character.toLowerCase(clazz.charAt(0)) + clazz.substring(1);
151 line(content, "" + clazz + " getOrCreate" + clazz + "(ReadGraphImpl graph, " + signature.p1 + (signature.useNeedsToBlock ? ", boolean needsToBlock" : "") + ") throws DatabaseException {");
152 line(content, " " + clazz + " existing = null;");
153 line(content, " synchronized(" + lower + "Map) {");
154 line(content, " existing = (" + clazz + ")" + lower + "Map.get(" + signature.keyName + ");");
155 line(content, " if(existing == null) {");
156 line(content, " existing = new " + clazz + "(" + signature.keyName + signature.entryCreationArguments + ");");
157 line(content, " existing.setPending(querySupport);");
158 line(content, " " + lower + "Map.put(" + signature.keyToId + "(" + signature.keyName + "), existing);");
159 line(content, " size++;");
160 line(content, " return existing;");
162 line(content, " if(existing.requiresComputation()) {");
163 line(content, " existing.setPending(querySupport);");
164 line(content, " return existing;");
167 line(content, " if(existing.isPending()) {");
168 if(signature.useNeedsToBlock) {
169 line(content, " if(needsToBlock)");
170 line(content, " waitPending(graph, existing);");
171 line(content, " else {");
172 line(content, " return null;");
175 line(content, " waitPending(graph, existing);");
178 line(content, " return existing;");
184 public void generate() {
186 URL classLocation = CodeGen.class.getResource(".");
187 if (classLocation != null) {
188 if (classLocation.getProtocol().equals("file")) {
190 URL resource = new URL(classLocation, ".");
191 File path = new File(URLDecoder.decode(resource.getPath(), "UTF-8"));
192 String target = path.getAbsolutePath().replace("\\", "/");
193 target = target.replace("/bin/", "/src/") + "/QueryCache.java";
194 System.err.println("target=" + target);
195 File source = new File(target);
196 StringBuilder content = new StringBuilder();
197 content.append("package org.simantics.db.impl.query;\n");
198 content.append("\n");
200 content.append("import org.simantics.db.ObjectResourceIdMap;\n");
201 content.append("import org.simantics.db.RelationInfo;\n");
202 content.append("import org.simantics.db.common.utils.Logger;\n");
203 content.append("import org.simantics.db.exception.DatabaseException;\n");
204 content.append("import org.simantics.db.impl.graph.ReadGraphImpl;\n");
205 content.append("import org.simantics.db.impl.procedure.InternalProcedure;\n");
206 content.append("import org.simantics.db.impl.query.QueryProcessor.SessionTask;\n");
207 content.append("import org.simantics.db.procedure.AsyncMultiProcedure;\n");
208 content.append("import org.simantics.db.procedure.AsyncProcedure;\n");
209 content.append("import org.simantics.db.procedure.ListenerBase;\n");
210 content.append("import org.simantics.db.procedure.SyncMultiProcedure;\n");
211 content.append("import org.simantics.db.request.AsyncMultiRead;\n");
212 content.append("import org.simantics.db.request.AsyncRead;\n");
213 content.append("import org.simantics.db.request.ExternalRead;\n");
214 content.append("import org.simantics.db.request.MultiRead;\n");
215 content.append("import org.simantics.db.request.Read;\n");
216 content.append("\n");
218 content.append("public class QueryCache extends QueryCacheBase {\n");
219 content.append("\n");
221 line(content, "private static final boolean SINGLE = true;");
222 content.append("\n");
224 line(content,"public QueryCache(QuerySupport querySupport, int threads) {");
225 line(content," super(querySupport, threads);");
227 content.append("\n");
229 generateQuery(content, "Objects", signatureR2IP, true, false);
230 generateQuery(content, "Statements", signatureR2TIP, true, false);
231 generateQuery(content, "DirectObjects", signatureR2IP, true, false);
232 generateQuery(content, "RelationInfoQuery", signatureR1RelationInfo, true, false);
233 generateQuery(content, "URIToResource", signatureID1, true, false);
234 generateQuery(content, "ValueQuery", signatureR1Bytes, true, false);
235 generateQuery(content, "OrderedSet", signatureR1IP, true, false);
236 generateQuery(content, "PrincipalTypes", signatureR1IP, true, false);
237 generateQuery(content, "DirectPredicates", signatureR1IntSet, true, false);
238 generateQuery(content, "Predicates", signatureR1IntSet, true, false);
239 generateQuery(content, "ReadEntry", signatureRead, true, true);
240 generateQuery(content, "AsyncReadEntry", signatureAsyncRead, true, true);
241 generateQuery(content, "Types", signatureR1IntSet, true, false);
242 generateQuery(content, "ChildMap", signatureChildMap, true, false);
243 generateQuery(content, "TypeHierarchy", signatureR1IntSet, true, false);
244 generateQuery(content, "SuperTypes", signatureR1IntSet, true, false);
245 generateQuery(content, "SuperRelations", signatureR1IntSet, true, false);
247 generateQuery(content, "AssertedPredicates", signatureR1IP, false, false);
248 generateQuery(content, "AssertedStatements", signatureR2TIP, false, false);
249 generateQuery(content, "DirectSuperRelations", signatureR1IP, false, false);
250 generateQuery(content, "MultiReadEntry", signatureMultiRead, false, false);
251 generateQuery(content, "AsyncMultiReadEntry", signatureAsyncMultiRead, false, false);
252 generateQuery(content, "ExternalReadEntry", signatureExternalRead, false, false);
253 content.append("}\n");
254 FileUtils.writeFile(source, content.toString().getBytes());
255 } catch (MalformedURLException e) {
257 } catch (UnsupportedEncodingException e) {
259 } catch (IOException e) {
267 public static void main(String[] args) {
268 new CodeGen().generate();