]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.spreadsheet.graph/src/org/simantics/spreadsheet/graph/SpreadsheetGraphUtils.java
Spreadsheet changes
[simantics/platform.git] / bundles / org.simantics.spreadsheet.graph / src / org / simantics / spreadsheet / graph / SpreadsheetGraphUtils.java
1 package org.simantics.spreadsheet.graph;
2
3 import java.io.File;
4 import java.io.FileNotFoundException;
5 import java.io.FileOutputStream;
6 import java.io.IOException;
7 import java.io.ObjectOutputStream;
8 import java.util.ArrayList;
9 import java.util.Collection;
10 import java.util.HashMap;
11 import java.util.Iterator;
12 import java.util.List;
13 import java.util.Map;
14
15 import org.simantics.Simantics;
16 import org.simantics.databoard.Bindings;
17 import org.simantics.databoard.binding.mutable.Variant;
18 import org.simantics.databoard.util.binary.RandomAccessBinary;
19 import org.simantics.datatypes.DatatypeResource;
20 import org.simantics.datatypes.literal.Font;
21 import org.simantics.datatypes.literal.RGB;
22 import org.simantics.datatypes.utils.BTree;
23 import org.simantics.db.ReadGraph;
24 import org.simantics.db.Resource;
25 import org.simantics.db.WriteGraph;
26 import org.simantics.db.common.request.BinaryRead;
27 import org.simantics.db.common.request.ObjectsWithType;
28 import org.simantics.db.common.request.UnaryRead;
29 import org.simantics.db.common.utils.LiteralFileUtil;
30 import org.simantics.db.exception.DatabaseException;
31 import org.simantics.db.exception.ServiceException;
32 import org.simantics.db.layer0.util.Layer0Utils;
33 import org.simantics.db.layer0.variable.Variable;
34 import org.simantics.db.layer0.variable.Variables;
35 import org.simantics.db.procedure.Listener;
36 import org.simantics.db.service.ClusteringSupport;
37 import org.simantics.layer0.Layer0;
38 import org.simantics.scl.runtime.tuple.Tuple2;
39 import org.simantics.simulator.toolkit.StandardRealm;
40 import org.simantics.spreadsheet.ExternalRef;
41 import org.simantics.spreadsheet.Range;
42 import org.simantics.spreadsheet.Spreadsheets;
43 import org.simantics.spreadsheet.graph.synchronization.SpreadsheetSynchronizationEventHandler;
44 import org.simantics.spreadsheet.resource.SpreadsheetResource;
45 import org.simantics.spreadsheet.solver.SheetNode;
46 import org.simantics.spreadsheet.solver.SpreadsheetBook;
47 import org.simantics.spreadsheet.solver.SpreadsheetEngine;
48 import org.simantics.spreadsheet.solver.SpreadsheetLine;
49 import org.simantics.spreadsheet.solver.SpreadsheetStyle;
50 import org.simantics.spreadsheet.util.SpreadsheetUtils;
51 import org.simantics.structural.synchronization.client.Synchronizer;
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
54
55 import gnu.trove.iterator.TObjectIntIterator;
56 import gnu.trove.map.hash.TObjectIntHashMap;
57
58 public class SpreadsheetGraphUtils {
59
60     private static final Logger LOGGER = LoggerFactory.getLogger(SpreadsheetGraphUtils.class);
61
62     public static File extractInitialCondition(ReadGraph graph, Resource ic) throws DatabaseException, IOException {
63
64         SpreadsheetResource SR = SpreadsheetResource.getInstance(graph);
65
66         File temp = Simantics.getTempfile("excel","ic");
67
68         LiteralFileUtil.copyRandomAccessBinaryToFile(graph, ic, SR.InitialCondition_bytes, temp);
69         if (temp.length() == 0)
70             throw new FileNotFoundException("Snapshot file does not exist.\nThis seems to be a database bug that manifests as total loss of state file data.\nThis error prevents the program from crashing.");
71
72         return temp;
73         
74     }
75         
76     public static RandomAccessBinary getOrCreateRandomAccessBinary(WriteGraph graph, Resource initialCondition) throws DatabaseException, IOException {
77
78         SpreadsheetResource SR = SpreadsheetResource.getInstance(graph);
79         
80         // We put snapshot literals in their own clusters for now just to be safe
81         Resource literal = graph.getPossibleObject(initialCondition, SR.InitialCondition_bytes);
82         if (literal != null) {
83             RandomAccessBinary rab = graph.getRandomAccessBinary(literal);
84             rab.position(0);
85             rab.removeBytes(rab.length(), RandomAccessBinary.ByteSide.Right);
86             return rab;
87         } else {
88             Layer0 L0 = Layer0.getInstance(graph);
89             ClusteringSupport cs = graph.getService(ClusteringSupport.class);
90             literal = graph.newResource(cs.createCluster());
91             graph.claim(literal, L0.InstanceOf, null, L0.ByteArray);
92             graph.claim(initialCondition, SR.InitialCondition_bytes, SR.InitialCondition_bytes_Inverse, literal);
93             return graph.createRandomAccessBinary(literal, Bindings.BYTE_ARRAY.type(), null);
94         }
95     }
96
97     public static Resource saveInitialCondition(WriteGraph graph, Variable run, Resource container, String name) throws DatabaseException {
98
99                 String sessionName = run.getParent(graph).getURI(graph);
100
101                 Resource bookResource = run.getRepresents(graph);
102                 
103         StandardRealm<SheetNode, SpreadsheetBook> realm = SpreadsheetSessionManager.getInstance().getOrCreateRealm(graph, sessionName);
104         SpreadsheetBook book = realm.getEngine();
105
106         try {
107         
108                 File temp = Simantics.getTempfile("excel", "ic");
109                 System.err.println("Saving initial condition to " + temp.getAbsolutePath());
110                 
111                         FileOutputStream fileOut = new FileOutputStream(temp);
112                         ObjectOutputStream out = new ObjectOutputStream(fileOut);
113                         out.writeObject(book);
114                         out.close();
115                         fileOut.close();
116                         
117                         Layer0 L0 = Layer0.getInstance(graph);
118                 SpreadsheetResource SR = SpreadsheetResource.getInstance(graph);
119                         Resource ic = graph.newResource();
120                         graph.claim(ic, L0.InstanceOf, SR.InitialCondition);
121                         graph.addLiteral(ic, L0.HasName, L0.NameOf, L0.String, name, Bindings.STRING);
122                 
123                 RandomAccessBinary rab = getOrCreateRandomAccessBinary(graph, ic);
124                 LiteralFileUtil.copyRandomAccessBinaryFromFile(temp, rab);
125                 
126                         graph.claim(container, L0.ConsistsOf, L0.PartOf, ic);
127                         
128                         graph.deny(bookResource, SR.HasInitialCondition);
129                         graph.claim(bookResource, SR.HasInitialCondition, ic);
130                         graph.claim(ic, SR.InitialCondition_ConditionOf, bookResource);
131                         
132                         setDefaultInitialConditionForBook(graph, bookResource, ic);
133
134                 return ic;
135                 
136         } catch (IOException e) {
137                 
138                 throw new DatabaseException(e);
139                 
140         }
141     }
142     
143     public static void setDefaultInitialConditionForBook(WriteGraph graph, Resource book, Resource ic) throws ServiceException {
144         SpreadsheetResource SR = SpreadsheetResource.getInstance(graph);
145         graph.deny(book, SR.Book_HasDefaultInitialCondition);
146         graph.claim(ic, SR.InitialCondition_DefaultConditionOf, book);
147     }
148
149     public static void evaluateAll(ReadGraph graph, Variable run) throws DatabaseException {
150
151                 String sessionName = run.getParent(graph).getURI(graph);
152         StandardRealm<SheetNode, SpreadsheetBook> realm = SpreadsheetSessionManager.getInstance().getOrCreateRealm(graph, sessionName);
153         SpreadsheetBook book = realm.getEngine();
154         book.accept(new EvaluateAll(book));
155         
156     }
157
158     public static void invalidateAll(ReadGraph graph, Variable run) throws DatabaseException {
159
160                 String sessionName = run.getParent(graph).getURI(graph);
161         StandardRealm<SheetNode, SpreadsheetBook> realm = SpreadsheetSessionManager.getInstance().getOrCreateRealm(graph, sessionName);
162         SpreadsheetBook book = realm.getEngine();
163         book.accept(new InvalidateAll());
164         realm.getNodeManager().refreshVariables();
165         
166     }
167     
168     public static boolean fullSynchronization(ReadGraph graph, Variable run) throws DatabaseException {
169         return partialSynchronization(graph, run, null);
170     }
171
172     public static boolean partialSynchronization(ReadGraph graph, Variable run, TObjectIntHashMap<Variable> changeFlags) throws DatabaseException {
173
174         Synchronizer synchronizer = new Synchronizer(graph);
175                 String sessionName = run.getParent(graph).getURI(graph);
176                 
177         Resource bookResource = run.getRepresents(graph);
178         Variable configuration = Variables.getVariable(graph, bookResource);
179         
180         StandardRealm<SheetNode, SpreadsheetBook> realm = SpreadsheetSessionManager.getInstance().getOrCreateRealm(graph, sessionName);
181         SpreadsheetBook book = realm.getEngine();
182                         
183         SpreadsheetSynchronizationEventHandler handler = new SpreadsheetSynchronizationEventHandler(graph, book);
184         
185 //        System.err.println("sessionName : " + sessionName);
186 //        System.err.println("bookResource : " + graph.getURI(bookResource));
187 //        System.err.println("configuration : " + configuration.getURI(graph));
188 //        System.err.println("realm : " + realm);
189 //        System.err.println("book : " + book);
190         
191         if (changeFlags == null) {
192             synchronizer.fullSynchronization(configuration, handler);
193         } else {
194             
195             TObjectIntIterator<Variable> iter = changeFlags.iterator();
196             iter.advance();
197             Variable row = iter.key();
198             
199             Variable rowParent = row.getParent(graph);
200             while (!rowParent.equals(configuration)) {
201                 changeFlags.put(rowParent, 1);
202                 rowParent = rowParent.getParent(graph);
203             }
204             
205             changeFlags.put(configuration, 1);
206             
207             synchronizer.partialSynchronization(configuration, handler, changeFlags);
208         }
209         
210 //        book.accept(new InvalidateAll());
211 //        realm.getNodeManager().refreshVariables();
212 //        mapping.currentRevision = synchronizer.getHeadRevisionId();
213 //        mapping.setTrustUids(true);
214         // Clean up queries
215 //        QueryControl qc = g.getService(QueryControl.class);
216 //        qc.flush(g);
217 //        TimeLogger.log("Finished full synchronization");
218         realm.getNodeManager().fireNodeListeners();
219         return handler.getDidChanges();
220         
221     }
222
223     public static Variable findCell(ReadGraph graph, Variable run, String reference) throws DatabaseException {
224
225         int pos = reference.indexOf("!");
226         String sheetName = reference.substring(0, pos);
227         String cellName = reference.substring(pos+1);
228
229                 String sessionName = run.getParent(graph).getURI(graph);
230         StandardRealm<SheetNode, SpreadsheetBook> realm = SpreadsheetSessionManager.getInstance().getOrCreateRealm(graph, sessionName);
231         SpreadsheetBook book = realm.getEngine();
232         SpreadsheetEngine engine = book.getEngine(sheetName);
233         if(engine == null) return null;
234         
235         Range r = Spreadsheets.decodeCellAbsolute(cellName);
236         SpreadsheetLine line = engine.getLine(r.startRow);
237         if(line == null) return null;
238         
239         String path = line.getPath();
240         if(path == null) return null;
241         
242         Variable lineVariable = run.browse(graph, path);
243         if(lineVariable==null) return null;
244         
245         return lineVariable.getChild(graph, cellName);
246         
247     }
248
249     
250
251     public static List<Variable> possibleConfigurationCellVariables(ReadGraph graph, Variable sheet, Range range) throws DatabaseException {
252         List<Variable> rowVariables = possibleConfigurationLineVariables(graph, sheet, range);
253         List<Variable> result = new ArrayList<>();
254         for (Variable variable : rowVariables) {
255             Collection<Variable> children = variable.getChildren(graph);
256             for (Variable child : children) {
257                 if (variableInRange(graph, child, range)) {
258                     result.add(child);
259                 }
260             }
261         }
262         return result;
263     }
264     
265     public static Map<Integer, Resource> possibleConfigurationLineResources(ReadGraph graph, Variable sheet, Range range) throws DatabaseException {
266         Variable lines = sheet.getPossibleChild(graph, "Lines");
267         if (lines == null)
268             throw new DatabaseException("Invalid input variable " + sheet.getURI(graph));
269         Resource linesR = lines.getRepresents(graph);
270         BTree bt = new BTree(graph, linesR);
271         List<Tuple2> tuples = bt.searchRangeBTree(graph, Variant.ofInstance(range.startRow), Variant.ofInstance(range.endRow));
272         Map<Integer, Resource> result = new HashMap<>(tuples.size());
273         for (Tuple2 tuple : tuples) {
274             Integer lineNumber = (Integer)((Variant)tuple.c0).getValue();
275             Resource resource = (Resource)tuple.c1;
276             result.put(lineNumber, resource);
277         }
278         return result; 
279     }
280     
281     public static List<Variable> possibleConfigurationLineVariables(ReadGraph graph, Variable sheet, Range range) throws DatabaseException {
282         Map<Integer, Resource> rows = possibleConfigurationLineResources(graph, sheet, range);
283         List<Variable> result = new ArrayList<>(rows.size());
284         for (Resource row: rows.values()) {
285             Variable lineVar = Variables.getPossibleVariable(graph, row);
286             if (lineVar != null)
287                 result.add(lineVar);
288         }
289         return result;
290     }
291     
292     public static List<Variable> possibleRunLineVariables(ReadGraph graph, Variable sheetRun, Range range) throws DatabaseException {
293         
294         Variable run = sheetRun.getParent(graph);
295         
296         String sheetName = sheetRun.getName(graph);
297         String sessionName = run.getParent(graph).getURI(graph);
298         
299         StandardRealm<SheetNode, SpreadsheetBook> realm = SpreadsheetSessionManager.getInstance().getOrCreateRealm(graph, sessionName);
300         SpreadsheetBook book = realm.getEngine();
301         
302         SpreadsheetEngine engine = book.getEngine(sheetName);
303         if(engine == null) return null;
304         
305         List<Variable> result = new ArrayList<>();
306         
307         int end = range.endRow < engine.lines.getMaxRow() ? range.endRow : engine.lines.getMaxRow();
308         for (int i = range.startRow; i <= end; i++) {
309                 SpreadsheetLine line = engine.getLine(i);
310                 if(line == null)
311                         continue;
312                 
313                 String path = line.getPath();
314                 path = line.getPath();
315                 if(path == null)
316                         continue;
317                 
318                 Variable lineVariable = run.browse(graph, path);
319                 if(lineVariable==null)
320                         continue;
321                 result.add(lineVariable);
322         }
323     
324         return result;
325     }
326     
327     public static List<Variable> possibleRunCellVariables(ReadGraph graph, Variable sheetRun, Range range) throws DatabaseException {
328         List<Variable> runLineVariable = possibleRunLineVariables(graph, sheetRun, range);
329         List<Variable> result = new ArrayList<>();
330         for (Variable variable : runLineVariable) {
331 //              System.out.println("line: " + variable.getURI(graph));
332             for (Variable child : variable.getChildren(graph)) {
333 //              System.out.print("cell : " + child.getURI(graph));
334                 if (variableInRange(graph, child, range)) {
335                     result.add(child);
336                 }
337             }
338         }
339         return result;
340     }
341     
342     private static boolean variableInRange(ReadGraph graph, Variable child, Range range) throws DatabaseException {
343         String name = child.getName(graph);
344         Range childRange = Spreadsheets.decodeCellAbsolute(name);
345 //        System.out.print(" and range " + childRange);
346         if (childRange != null && range.contains(childRange)) {
347 //              System.out.println(" => range.contains(childRange) = true");
348             return true;
349         }
350 //        System.out.println();
351         return false;
352     }
353     
354     public static Map<Integer, Resource> createConfigurationLineResources(WriteGraph graph, Variable sheet, Range range) throws DatabaseException {
355         Layer0 L0 = Layer0.getInstance(graph);
356         SpreadsheetResource SHEET = SpreadsheetResource.getInstance(graph);
357         
358         Variable lines = sheet.getPossibleChild(graph, "Lines");
359         if (lines == null)
360             throw new DatabaseException("Invalid input variable " + sheet.getURI(graph));
361         Resource linesR = lines.getRepresents(graph);
362         BTree bt = new BTree(graph, linesR);
363         
364         Map<Integer, Resource> result = new HashMap<>();
365         for (int lineNumber = range.startRow; lineNumber <= range.endRow; lineNumber++) {
366             Resource line = graph.newResource();
367             graph.claim(line, L0.InstanceOf, null, SHEET.Line);
368             graph.claimLiteral(line, L0.HasName, L0.NameOf, L0.String, "Row" + lineNumber, Bindings.STRING);
369             bt.insertBTree(graph, Variant.ofInstance(lineNumber), line);
370             result.put(lineNumber, line);
371         }
372         return result;
373     }
374
375     public static List<Variable> getOrCreateConfigurationCellVariables(WriteGraph graph, Variable sheet, Range range) throws DatabaseException {
376         
377         List<Variable> rows = possibleConfigurationLineVariables(graph, sheet, range);
378         if (rows.isEmpty()) {
379             createConfigurationLineResources(graph, sheet, range);
380             rows = possibleConfigurationLineVariables(graph, sheet, range);
381         }
382         
383         List<Variable> cells = possibleConfigurationCellVariables(graph, sheet, range);
384         if (cells.isEmpty()) {
385             Iterator<Variable> rowIterator = rows.iterator();
386             for (int rowNumber = range.startRow; rowNumber <= range.endRow; rowNumber++) {
387                 Variable row = rowIterator.next();
388                 for (int colNumber = range.startColumn; colNumber <= range.endColumn; colNumber++) {
389                     String location = Spreadsheets.cellName(rowNumber, colNumber);
390                     defaultCreateCell(graph, row, location, new Variant(Bindings.STRING, ""));
391                 }
392             }
393         }
394         
395         cells = possibleConfigurationCellVariables(graph, sheet, range);
396         if(cells.isEmpty())
397             throw new DatabaseException("Unexpected problem while creating spreadsheet cell at '" + range + "'");
398         
399         return cells;
400     }
401     
402     private static void defaultCreateCell(WriteGraph graph, Variable parent, String location, Variant value) throws DatabaseException {
403
404         Layer0 L0 = Layer0.getInstance(graph);
405         SpreadsheetResource SHEET = SpreadsheetResource.getInstance(graph);
406         Resource container = parent.getRepresents(graph);
407         
408         Resource cell = graph.newResource();
409         graph.claim(cell, L0.InstanceOf, null, SHEET.TextCell);
410         graph.addLiteral(cell, L0.HasName, L0.NameOf, L0.String, location, Bindings.STRING);
411         graph.addLiteral(cell, SHEET.Cell_content, SHEET.Cell_content_Inverse, L0.Variant, value, Bindings.VARIANT);
412         graph.claim(cell, L0.PartOf, container);
413         
414         Resource book = Variables.getContext(graph, parent).getRepresents(graph);
415         
416         
417         Collection<Resource> objects = graph.sync(new ObjectsWithType(book, L0.ConsistsOf, SHEET.Style));
418         
419         int styleId = SpreadsheetStyle.empty().getStyleId();
420         Resource style = null;
421         for (Resource possibleStyle : objects) {
422             int possibleStyleId = graph.getRelatedValue2(possibleStyle, SHEET.Style_id, Bindings.INTEGER);
423             if (possibleStyleId == styleId) {
424                 style = possibleStyle;
425                 break;
426             }
427         }
428         
429         if (style == null) {
430             style = graph.newResource();
431             graph.claim(style, L0.InstanceOf, null, SHEET.Style);
432             graph.claim(style, L0.PartOf, book);
433             
434             int id = objects.size();
435             graph.claimLiteral(style, L0.HasName, "Style_" + id);
436             graph.claimLiteral(style, SHEET.Style_id, styleId, Bindings.INTEGER);
437         }
438         graph.claim(cell, SHEET.Cell_HasStyle, style);
439         Layer0Utils.addCommentMetadata(graph, "Created cell on location " + location + " with value " + value.toString());
440     }
441
442     public static Resource createStyle(WriteGraph graph, Resource book, SpreadsheetStyle sstyle) throws DatabaseException {
443         Layer0 L0 = Layer0.getInstance(graph);
444         SpreadsheetResource SR = SpreadsheetResource.getInstance(graph);
445         Resource style = graph.newResource();
446         graph.claim(style, L0.InstanceOf, null, SR.Style);
447         graph.claim(style, L0.PartOf, book);
448         
449         int styleId = sstyle.getStyleId();
450         String styleName = sstyle.name;
451         
452         graph.claimLiteral(style, L0.HasName, styleName);
453         //System.err.println("CREATING STYLE " + styleName + " WITH ID: " + styleId);
454         graph.claimLiteral(style, SR.Style_id, styleId, Bindings.INTEGER);
455         
456         DatatypeResource DATATYPES = DatatypeResource.getInstance(graph);
457         if (sstyle.foreground != null)
458             graph.claimLiteral(style, SR.Cell_foreground, DATATYPES.RGB_Integer, sstyle.foreground, RGB.Integer.BINDING);
459         if (sstyle.background != null)
460             graph.claimLiteral(style, SR.Cell_background, DATATYPES.RGB_Integer, sstyle.background, RGB.Integer.BINDING);
461         if (sstyle.align != -1)
462             graph.claimLiteral(style, SR.Cell_align, sstyle.align, Bindings.INTEGER);
463         if (sstyle.font != null)
464             graph.claimLiteral(style, SR.Cell_font, DATATYPES.Font, sstyle.font, Font.BINDING);
465         if (sstyle.border != -1)
466             graph.claimLiteral(style, SR.Cell_border, sstyle.border);
467         if (sstyle.formatString != null && !sstyle.formatString.isEmpty())
468             graph.claimLiteral(style, SR.Cell_formatString, sstyle.formatString, Bindings.STRING);
469         if (sstyle.formatIndex != -1)
470             graph.claimLiteral(style, SR.Cell_formatIndex, sstyle.formatIndex, Bindings.INTEGER);
471         
472         return style;
473     }
474     
475     public static Resource createBook(WriteGraph graph, Resource parent, String name) throws DatabaseException {
476         Layer0 L0 = Layer0.getInstance(graph);
477         SpreadsheetResource SR = SpreadsheetResource.getInstance(graph);
478         Resource book = graph.newResource();
479         graph.claim(book, L0.InstanceOf, SR.Book);
480         graph.claimLiteral(book, L0.HasName, L0.NameOf, L0.String, name, Bindings.STRING);
481         graph.claim(parent, L0.ConsistsOf, book);
482         
483         return book;
484     }
485     
486     public static Variable constructAndInitializeRunVariable(WriteGraph graph, Resource root) throws DatabaseException {
487         Variable run = SpreadsheetUtils.getBookVariable(graph, root);
488         SpreadsheetGraphUtils.fullSynchronization(graph, run);
489         SpreadsheetGraphUtils.evaluateAll(graph, run);
490         SpreadsheetGraphUtils.saveInitialCondition(graph, run, root, "Initial");
491         return run;
492     }
493     
494     public static Variant extRefVariable(ReadGraph graph, Variable var) throws DatabaseException {
495         System.err.println("extRefVariable " + var.getURI(graph));
496         return new Variant(Bindings.VOID, new ExternalRefVariable(graph, var));
497     }
498     
499     static class ExternalRefVariable implements ExternalRef {
500
501         final private String uri;
502         
503         public ExternalRefVariable(ReadGraph graph, Variable variable) throws DatabaseException {
504             this.uri = variable.getURI(graph);
505         }
506         
507         @Override
508         public void listen(Object context, ExternalRefListener listener) {
509             System.err.println("listen " + listener);
510             Simantics.getSession().asyncRequest(new UnaryRead<String, Variant>(uri) {
511
512                 @Override
513                 public Variant perform(ReadGraph graph) throws DatabaseException {
514                     Variable variable = Variables.getVariable(graph, parameter);
515                     System.err.println("ExternalRef value for " + variable.getURI(graph));
516                     return variable.getVariantValue(graph);
517                 }
518                 
519             }, new Listener<Variant>() {
520
521                 @Override
522                 public void execute(Variant result) {
523                     System.err.println("execute " + result);
524                     listener.newValue(result);
525                 }
526
527                 @Override
528                 public void exception(Throwable t) {
529                     LOGGER.error("Error while evaluating variable value", t);
530                 }
531
532                 @Override
533                 public boolean isDisposed() {
534                     return listener.isDisposed();
535                 }
536                 
537             });
538         }
539         
540     }
541
542     public static Variant extRefActiveVariable(ReadGraph graph, Variable var) throws DatabaseException {
543         System.err.println("extRefActiveVariable " + var.getURI(graph));
544         return new Variant(Bindings.VOID, new ExternalRefActiveVariable(graph, var));
545     }
546     
547     static class ExternalRefActiveVariable implements ExternalRef {
548
549         final private String uri;
550         
551         public ExternalRefActiveVariable(ReadGraph graph, Variable variable) throws DatabaseException {
552             this.uri = variable.getURI(graph);
553         }
554         
555         @Override
556         public void listen(Object context, ExternalRefListener listener) {
557             System.err.println("listen " + context + " " + listener);
558             Simantics.getSession().asyncRequest(new BinaryRead<String, String, Variant>((String)context, uri) {
559
560                 @Override
561                 public Variant perform(ReadGraph graph) throws DatabaseException {
562                     Variable contextVariable = Variables.getVariable(graph, parameter);
563                     System.err.println("extref1 " + contextVariable.getURI(graph));
564                     Variable configVariable = Variables.getVariable(graph, parameter2);
565                     System.err.println("extref2 " + configVariable.getURI(graph));
566                     Variable activeVariable = Variables.switchPossibleContext(graph, configVariable, contextVariable.getRepresents(graph));
567                     System.err.println("ExternalRef value for " + activeVariable.getURI(graph));
568                     return activeVariable.getVariantValue(graph);
569                 }
570             }, new Listener<Variant>() {
571
572                 @Override
573                 public void execute(Variant result) {
574                     System.err.println("execute " + result);
575                     listener.newValue(result);
576                 }
577
578                 @Override
579                 public void exception(Throwable t) {
580                     LOGGER.error("Error while evaluating variable value", t);
581                 }
582
583                 @Override
584                 public boolean isDisposed() {
585                     return listener.isDisposed();
586                 }
587                 
588             });
589         }
590         
591     }
592     
593 }