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