6253744bb05e26d012ff3b86906e465fc9911e95
[simantics/platform.git] / bundles / org.simantics.db.impl / src / org / simantics / db / impl / query / ExternalReadEntry.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 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  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.db.impl.query;
13
14 import java.util.LinkedList;
15
16 import org.simantics.databoard.Bindings;
17 import org.simantics.db.DevelopmentKeys;
18 import org.simantics.db.exception.DatabaseException;
19 import org.simantics.db.impl.graph.ReadGraphImpl;
20 import org.simantics.db.procedure.AsyncProcedure;
21 import org.simantics.db.procedure.Listener;
22 import org.simantics.db.request.ExternalRead;
23 import org.simantics.db.request.RequestFlags;
24 import org.simantics.utils.Development;
25
26 final public class ExternalReadEntry<T> extends CacheEntryBase<AsyncProcedure<T>> implements Listener<T> {
27
28     final LinkedList<T> items = new LinkedList<T>();
29
30     protected ExternalRead<T> id;
31     protected ReadGraphImpl graph;
32     protected boolean registered = false;
33
34     @Override
35     int makeHash() {
36         return id.hashCode();
37     }
38     
39     @Override
40     public Object getOriginalRequest() {
41         return id;
42     }
43     
44     @Override
45     public void clearResult(QuerySupport support) {
46     }
47     
48     @Override
49     public void discard() {
50         id.unregistered();
51         id = null;
52         graph = null;
53         super.discard();
54     }
55
56     @Override
57     public void setPending(QuerySupport querySupport) {
58         //if(result != NO_RESULT) {
59             //new Exception("result = " + result).printStackTrace();
60         //}
61         statusOrException = PENDING;
62         result = REQUIRES_COMPUTATION;
63     }
64     
65     public ExternalReadEntry(ExternalRead<T> request, ReadGraphImpl graph) {
66         assert request != null;
67         this.id = request;
68         this.graph = graph;
69     }
70     
71     @Override
72     public void except(Throwable t) {
73         
74                 if (Development.DEVELOPMENT) {
75                         if(Development.<Boolean>getProperty(DevelopmentKeys.CACHE_ENTRY_STATE, Bindings.BOOLEAN)) {
76                                 System.err.println("[QUERY STATE]: excepted " + this);
77                         }
78                 }
79
80         if(statusOrException != DISCARDED) {
81             statusOrException = EXCEPTED;
82             result = t;
83         } else {
84             result = t;
85         }
86         
87         assert(isExcepted());
88         
89     }
90     
91     @Override
92     public void setResult(Object result) {
93
94         super.setResult(result);
95         assert(!(result instanceof Throwable));
96         assert(!isExcepted());
97         
98     }
99     
100     @Override
101     public void setReady() {
102         super.setReady();
103     }
104
105     @Override
106     final public Query getQuery() {
107         
108         return new Query() {
109
110                         @Override
111                         public void recompute(ReadGraphImpl graph) {
112
113                                 synchronized(items) {
114
115                                         // Update
116                                         if(!items.isEmpty()) {
117                                             setReady();
118                                                 setResult(items.removeFirst());
119                                         }
120                                         // Reschedule
121                                         if(!items.isEmpty()) {
122                                                 graph.processor.updatePrimitive(id);
123                                         }
124
125                                 }
126                                 
127                         }
128
129                         @Override
130                         public void removeEntry(QueryProcessor processor) {
131                                 processor.cache.remove(ExternalReadEntry.this);
132                         }
133
134                         @Override
135                         public int type() {
136                                 return RequestFlags.IMMEDIATE_UPDATE;
137                         }
138                         
139                         @Override
140                         public String toString() {
141                                 if(id == null) return "DISCARDED ExternalRead";
142                                 else return id.toString();
143                         }
144                 
145         };
146         
147     }
148
149         @Override
150         public String toString() {
151                 if(id == null) return "DISCARDED ExternalRead " + System.identityHashCode(this);
152                 else return id.toString() + " " + + System.identityHashCode(this);
153         }
154
155     @Override
156     public Object performFromCache(ReadGraphImpl graph, AsyncProcedure<T> procedure) {
157         
158         AsyncProcedure<T> proc = (AsyncProcedure<T>)procedure;
159
160             if(isExcepted()) {
161             
162             proc.exception(graph, (Throwable)getResult());
163             
164         } else {
165             
166             proc.execute(graph, (T)getResult());
167
168         }
169             
170             return getResult();
171         
172     }
173     
174     @Override
175     void prepareRecompute(QuerySupport querySupport) {
176         // Do nothing - the state is already set and cannot be recomputed on demand
177     }
178
179     public Object compute(ReadGraphImpl graph, AsyncProcedure<T> procedure) throws DatabaseException {
180         
181                 try {
182                         
183                         ReadGraphImpl queryGraph = graph.withParent(this, null, true);
184
185                         if(!registered) {
186                                 id.register(graph, this);
187                                 registered = true;
188                         }
189                         
190                         queryGraph.asyncBarrier.waitBarrier(id, graph);
191
192                 } catch (Throwable t) {
193
194                         except(t);
195
196                 }
197
198                 performFromCache(graph, procedure);
199                 
200                 return getResult();
201
202     }
203
204         @Override
205         public void execute(T result) {
206
207         if(this.result == REQUIRES_COMPUTATION) {
208                 
209                         setResult(result);
210                         setReady();
211
212         } else {
213
214                 synchronized(items) {
215                         items.addLast(result);
216                                 graph.processor.updatePrimitive(id);
217                         // TODO: implement flags/logic in ExternalRead to state that all but the latest request result can be evaporated
218                         // In some cases where data is produced really fast this might be necessary but currently this queueing will do.
219                 }
220                 
221         }
222                 
223         }
224
225         @Override
226         public void exception(Throwable t) {
227                 except(t);
228         }
229
230         @Override
231         public boolean isDisposed() {
232                 return registered && (isDiscarded() || !graph.processor.isBound(this));
233         }
234
235     @Override
236     public String classId() {
237         return null;
238     }
239
240 }