]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.browsing.ui.graph.impl/src/org/simantics/browsing/ui/graph/impl/LazyViewpoint.java
Merge "Multiple reader thread support for db client"
[simantics/platform.git] / bundles / org.simantics.browsing.ui.graph.impl / src / org / simantics / browsing / ui / graph / impl / LazyViewpoint.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2010 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.browsing.ui.graph.impl;
13
14 import org.simantics.browsing.ui.BuiltinKeys;
15 import org.simantics.browsing.ui.DataSource;
16 import org.simantics.browsing.ui.NodeContext;
17 import org.simantics.browsing.ui.PrimitiveQueryUpdater;
18 import org.simantics.browsing.ui.common.viewpoints.ViewpointStub;
19 import org.simantics.browsing.ui.content.Viewpoint;
20 import org.simantics.browsing.ui.graph.impl.request.ResourceQuery;
21 import org.simantics.db.AsyncReadGraph;
22 import org.simantics.db.ReadGraph;
23 import org.simantics.db.exception.DatabaseException;
24 import org.simantics.db.procedure.Listener;
25 import org.simantics.utils.datastructures.Pair;
26
27 /**
28  * Implement {@link #children(ReadGraph)} and {@link #hasChildren(ReadGraph)}.
29  * 
30  * @author Tuukka Lehtonen
31  */
32 public abstract class LazyViewpoint extends ViewpointStub {
33
34     /**
35      * Needed for separating childQuery and hasChildQuery from each other in the
36      * equals sense.
37      */
38     private static final Object                 CHILDREN     = new Object();
39
40     final private ResourceQuery<NodeContext[]> childQuery;
41
42     final protected PrimitiveQueryUpdater       updater;
43     final protected NodeContext                context;
44     final protected BuiltinKeys.ViewpointKey    key;
45
46     /**
47      * @param graph
48      * @return
49      */
50     public abstract NodeContext[] children(ReadGraph graph) throws DatabaseException;
51
52     /**
53      * @param graph
54      * @return
55      */
56     public abstract Boolean hasChildren(ReadGraph graph) throws DatabaseException;
57
58     /**
59      * This identity is used to give the back-end graph requests a
60      * <em>properly unique</em> identity that so that the graph back-end caching
61      * and graph explorer node context caching work together properly.
62      * 
63      * Consider having two graph explorer instances that have the same
64      * configuration (same evaluators) and are showing the same resource from
65      * the graph database. In this case the requests are actually meant to have
66      * an identical identity and performing the graph request will simply bind a
67      * new listener for the one and same request.
68      * 
69      * @return an additional identity for graph back-end requests to make them
70      *         properly unique
71      */
72     public Object getIdentity() {
73         return key;
74     }
75
76     public LazyViewpoint(final PrimitiveQueryUpdater updater, NodeContext context, BuiltinKeys.ViewpointKey key) {
77
78         assert updater != null;
79         assert context != null;
80         assert key != null;
81
82         this.updater = updater;
83         this.context = context;
84         this.key = key;
85
86         this.childQuery = new ResourceQuery<NodeContext[]>(Pair.make(getIdentity(), CHILDREN), context) {
87
88             @Override
89             public NodeContext[] perform(ReadGraph graph) throws DatabaseException {
90                 return children(graph);
91             }
92
93             @Override
94             public String toString() {
95                 return LazyViewpoint.this.toString() + "[CHILDREN]";
96             }
97
98         };
99
100     }
101
102     private Listener<NodeContext[]> createListener() {
103         
104         return new Listener<NodeContext[]>() {
105
106                 boolean executed = false;
107                 boolean disposed = false;
108                 
109             @Override
110             public void execute(NodeContext[] result) {
111                 replaceChildrenResult(result);
112                 executed = true;
113             }
114
115             @Override
116             public boolean isDisposed() {
117                 if(disposed) return true;
118
119                 if((updater.isDisposed() || !updater.isShown(context)) && executed) {
120                         children = Viewpoint.PENDING_CHILDREN;
121                         disposed = true;
122                         return true;
123                 } else {
124                         return false;
125                 }
126                 
127             }
128
129             public void exception(Throwable t) {
130                 System.out.print("LazyViewpoint.childQuery failed: ");
131                 t.printStackTrace();
132             }
133
134             @Override
135             public String toString() {
136                 return "LazyViewpoint[" + System.identityHashCode(LazyViewpoint.this) + "].childProcedure";
137             }
138
139         };
140         
141     }
142     
143     public NodeContext getContext() {
144         return context;
145     }
146
147     @Override
148     public NodeContext[] getChildren() {
149
150         if (children == Viewpoint.PENDING_CHILDREN) {
151             DataSource<AsyncReadGraph> source = updater.getDataSource(AsyncReadGraph.class);
152             final Listener<NodeContext[]> childProcedure = createListener();
153             source.schedule(graph -> graph.asyncRequest(childQuery, childProcedure));
154         }
155
156         return children;
157
158     }
159
160     @Override
161     public Boolean getHasChildren() {
162         return getChildren().length > 0;
163     }
164
165     protected void replaceChildrenResult(NodeContext[] result) {
166         setChildren(updater, result);
167         updater.scheduleReplace(context, key, this);
168     }
169
170     /**
171      * @param <T>
172      * @param clazz
173      * @return input of the specified class
174      * @throws ClassCastException if the input class does not match the
175      *         specified class
176      * @throws NullPointerException if the input is null
177      */
178     @SuppressWarnings("unchecked")
179     protected <T> T getInput(Class<T> clazz) throws ClassCastException {
180         Object o = context.getConstant(BuiltinKeys.INPUT);
181         if (o == null)
182             throw new NullPointerException("null input");
183         return (T) o;
184     }
185
186     /**
187      * @param <T>
188      * @param clazz
189      * @return <code>null</code> if input is <code>null</code> or if the class does not match
190      */
191     @SuppressWarnings("unchecked")
192     protected <T> T tryGetInput(Class<T> clazz) {
193         Object o = context.getConstant(BuiltinKeys.INPUT);
194         if (o != null && clazz.isInstance(o))
195             return (T) o;
196         return null;
197     }
198
199 }