c491fb377464e366f5b34e8e8eac2e0e205840c5
[simantics/platform.git] / bundles / org.simantics.db.impl / src / org / simantics / db / impl / BlockingAsyncProcedure.java
1 /*******************************************************************************
2  * Copyright (c) 2018 Association for Decentralized Information Management
3  * in Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     Semantum Oy - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.db.impl;
13
14 import org.simantics.db.AsyncReadGraph;
15 import org.simantics.db.exception.DatabaseException;
16 import org.simantics.db.impl.graph.BarrierTracing;
17 import org.simantics.db.impl.graph.ReadGraphImpl;
18 import org.simantics.db.impl.query.AsyncReadEntry;
19 import org.simantics.db.impl.query.PendingTaskSupport;
20 import org.simantics.db.procedure.AsyncProcedure;
21
22 public class BlockingAsyncProcedure<Result> implements AsyncProcedure<Result> {
23
24     private static final Object NO_RESULT = new Object();
25
26     public final Object key;
27     public final ReadGraphImpl queryGraph;
28     public final ReadGraphImpl callerGraph;
29     public final AsyncProcedure<Result> procedure;
30     public PendingTaskSupport pendingTaskSupport;
31     public Object result = NO_RESULT;
32     public Throwable exception = null;
33
34     private ReadGraphImpl queryGraph() {
35         return queryGraph;
36     }
37     
38     public BlockingAsyncProcedure(ReadGraphImpl callerGraph, AsyncReadEntry<Result> entry, AsyncProcedure<Result> procedure, Object key, boolean needsToBlock) {
39
40         // A new graph for evaluating the query with correct parent and asyncBarrier
41         queryGraph = callerGraph.withParent(entry, () -> {
42
43             dispatchProcedure(queryGraph(), callerGraph, entry, procedure, needsToBlock);
44             
45         });
46         
47         queryGraph.asyncBarrier.inc();
48
49         this.procedure = procedure;
50         this.key = key;
51         this.queryGraph.asyncBarrier.inc();
52         this.callerGraph = callerGraph;
53         if (BarrierTracing.BOOKKEEPING) {
54             BarrierTracing.registerBAP(this);
55         }
56     }
57
58     @Override
59     public void execute(AsyncReadGraph graph_, Result result) {
60         
61         this.result = result;
62         queryGraph.asyncBarrier.dec();
63         
64     }
65
66     @Override
67     public void exception(AsyncReadGraph graph_, Throwable t) {
68
69         this.exception = t;
70         queryGraph.asyncBarrier.dec();
71         
72     }
73     
74     public void waitBarrier() {
75         queryGraph.asyncBarrier.waitBarrier(key, queryGraph);
76     }
77     
78     public void dec() {
79
80         queryGraph.asyncBarrier.dec();
81         
82     }
83
84     @SuppressWarnings("unchecked")
85     public Result get() throws DatabaseException {
86
87         queryGraph.asyncBarrier.waitBarrier(key, queryGraph);
88
89         if(exception != null) {
90             if(exception instanceof DatabaseException) throw (DatabaseException)exception;
91             throw new DatabaseException(exception);
92         } else {
93             return (Result)result;
94         }
95
96     }
97
98     @SuppressWarnings("unchecked")
99     public Result getResult() {
100         return (Result)result;
101     }
102
103     public Throwable getException() {
104         return exception;
105     }
106
107     @Override
108     public String toString() {
109         return "." + procedure; 
110     }
111     
112     private void dispatchProcedure(ReadGraphImpl queryGraph, ReadGraphImpl parentGraph, AsyncReadEntry<Result> entry, AsyncProcedure<Result> procedure_, boolean needsToBlock) {
113         
114         AsyncProcedure<Result> procedure = entry != null ? entry : procedure_;
115
116         ReadGraphImpl executeGraph = parentGraph.withParent(parentGraph.parent);
117         executeGraph.asyncBarrier.inc();
118         try {
119             if(procedure != null) {
120                 procedure.execute(executeGraph, get());
121             }
122         } catch (DatabaseException e) {
123             if(procedure != null) procedure.exception(executeGraph, e);
124             exception = e;
125         } catch (Throwable t) {
126             DatabaseException dbe = new DatabaseException(t);
127             if(procedure != null) procedure.exception(executeGraph, dbe);
128             exception = dbe;
129         } finally {
130
131             if (entry != null) {
132                 assert(entry.isReady());
133                 // This does not throw
134                 entry.performFromCache(executeGraph, procedure_);
135             }
136
137             executeGraph.asyncBarrier.dec();
138             if(needsToBlock)
139                 executeGraph.asyncBarrier.waitBarrier(procedure, executeGraph);
140         }
141
142         if (BarrierTracing.BOOKKEEPING) {
143             BarrierTracing.unregisterBAP(this);
144         }
145
146     }
147
148 }