]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.structural2/src/org/simantics/structural2/Functions.java
More SCL functions for experiment and run handling
[simantics/platform.git] / bundles / org.simantics.structural2 / src / org / simantics / structural2 / Functions.java
1 package org.simantics.structural2;
2
3
4 import java.util.ArrayList;
5 import java.util.Collection;
6 import java.util.Collections;
7 import java.util.HashSet;
8 import java.util.List;
9 import java.util.Map;
10 import java.util.Set;
11
12 import org.simantics.databoard.Bindings;
13 import org.simantics.databoard.Datatypes;
14 import org.simantics.databoard.adapter.AdaptException;
15 import org.simantics.databoard.binding.Binding;
16 import org.simantics.databoard.binding.error.BindingException;
17 import org.simantics.databoard.binding.error.DatatypeConstructionException;
18 import org.simantics.databoard.type.Datatype;
19 import org.simantics.databoard.util.URIStringUtils;
20 import org.simantics.db.Issue;
21 import org.simantics.db.ReadGraph;
22 import org.simantics.db.Resource;
23 import org.simantics.db.Statement;
24 import org.simantics.db.WriteGraph;
25 import org.simantics.db.common.issue.StandardIssue;
26 import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener;
27 import org.simantics.db.common.procedure.adapter.TransientCacheListener;
28 import org.simantics.db.common.request.ObjectsWithType;
29 import org.simantics.db.common.request.PossibleIndexRoot;
30 import org.simantics.db.common.request.ResourceRead;
31 import org.simantics.db.common.uri.UnescapedChildMapOfResource;
32 import org.simantics.db.exception.DatabaseException;
33 import org.simantics.db.layer0.function.All;
34 import org.simantics.db.layer0.function.StandardChildDomainChildren;
35 import org.simantics.db.layer0.request.PropertyInfo;
36 import org.simantics.db.layer0.request.PropertyInfoRequest;
37 import org.simantics.db.layer0.request.VariableRead;
38 import org.simantics.db.layer0.variable.AbstractChildVariable;
39 import org.simantics.db.layer0.variable.AbstractPropertyVariable;
40 import org.simantics.db.layer0.variable.LazyPropertyVariable;
41 import org.simantics.db.layer0.variable.NodeSupport;
42 import org.simantics.db.layer0.variable.StandardGraphChildVariable;
43 import org.simantics.db.layer0.variable.StandardGraphPropertyVariable;
44 import org.simantics.db.layer0.variable.ValueAccessor;
45 import org.simantics.db.layer0.variable.ValueAccessorWithBinding;
46 import org.simantics.db.layer0.variable.Variable;
47 import org.simantics.db.layer0.variable.VariableMap;
48 import org.simantics.db.layer0.variable.VariableMapImpl;
49 import org.simantics.db.layer0.variable.VariableNode;
50 import org.simantics.issues.common.IssueUtils;
51 import org.simantics.layer0.Layer0;
52 import org.simantics.scl.reflection.annotations.SCLValue;
53 import org.simantics.scl.runtime.SCLContext;
54 import org.simantics.scl.runtime.function.Function1;
55 import org.simantics.simulation.ontology.SimulationResource;
56 import org.simantics.simulator.variable.NodeManager;
57 import org.simantics.structural.stubs.StructuralResource2;
58 import org.simantics.structural2.procedural.Component;
59 import org.simantics.structural2.procedural.ConnectionPoint;
60 import org.simantics.structural2.procedural.Interface;
61 import org.simantics.structural2.procedural.SubstructureElement;
62 import org.simantics.structural2.procedural.Terminal;
63 import org.simantics.structural2.queries.ConnectionComponents;
64 import org.simantics.structural2.queries.ConnectionJoinComponents;
65 import org.simantics.structural2.queries.ConnectionPointMapOfResource;
66 import org.simantics.structural2.queries.PossibleConnectionPointInfo;
67 import org.simantics.structural2.scl.CompileStructuralValueRequest;
68 import org.simantics.structural2.scl.procedural.CompileProceduralComponentTypeRequest;
69 import org.simantics.structural2.variables.Connection;
70 import org.simantics.structural2.variables.ConnectionBrowser;
71 import org.simantics.structural2.variables.StandardProceduralChildVariable;
72 import org.simantics.structural2.variables.VariableConnectionPointDescriptor;
73 import org.simantics.utils.datastructures.MapList;
74
75 import gnu.trove.map.hash.THashMap;
76 import gnu.trove.set.hash.THashSet;
77
78 public class Functions {
79         
80         @SCLValue(type="ValueAccessor")
81         public static final ValueAccessor expressionValueAccessor = new ValueAccessorWithBinding() {
82
83                 public Binding getBinding() {
84                         return Bindings.STRING;
85                 }
86                 
87                 @Override
88                 public void setValue(WriteGraph graph, Variable context, Object value)
89                                 throws DatabaseException {
90                         if(value == null) {
91                                 if(getValue(graph, context) != null)
92                                         clearExpression(graph, context);
93                                 return;
94                         }
95                         
96                         // Get all necessary data
97                         String expression = (String)value;
98                         Variable parent = context.getParent(graph);
99                         if(!(parent instanceof AbstractPropertyVariable)) return;
100                         AbstractPropertyVariable property = (AbstractPropertyVariable)parent;                   
101                         Resource propertyResource = property.getRepresents(graph);
102                         if(propertyResource == null) return;
103                         Resource container = property.getContainerResource(graph);
104                         if(container == null) return;
105                         Resource predicate = property.getPossiblePredicateResource(graph);
106                         if(predicate == null) return;                   
107                         Statement stat = graph.getPossibleStatement(container, predicate);                      
108                         StructuralResource2 STR = StructuralResource2.getInstance(graph);
109                         
110                         // Write                        
111                         boolean createNew = false;
112                         if(stat.isAsserted(container))
113                                 createNew = true;
114                         else if(!graph.isInstanceOf(propertyResource, STR.SCLValue)) {
115                                 graph.deny(propertyResource);
116                                 createNew = true;
117                         }
118             Layer0 L0 = Layer0.getInstance(graph);
119                         if(createNew) {
120                                 propertyResource = graph.newResource();
121                                 graph.claim(container, predicate, propertyResource);
122                                 graph.claim(propertyResource, L0.InstanceOf, STR.SCLValue);                             
123                         }
124                         graph.claimLiteral(propertyResource, L0.SCLValue_expression, expression, Bindings.STRING);
125                 }
126
127                 private void clearExpression(WriteGraph graph, Variable context) throws DatabaseException {
128                         Variable parent = context.getParent(graph);
129                         if(!(parent instanceof AbstractPropertyVariable)) return;
130                         AbstractPropertyVariable property = (AbstractPropertyVariable)parent;
131                         Resource container = property.getContainerResource(graph);
132                         if(container == null) return;
133                         Resource predicate = property.getPossiblePredicateResource(graph);
134                         if(predicate == null) return;                   
135                         graph.deny(container, predicate);               
136                 }
137
138                 @Override
139                 public Object getValue(ReadGraph graph, Variable context)
140                                 throws DatabaseException {
141                         Variable parent = context.getParent(graph);
142                         if(!(parent instanceof AbstractPropertyVariable))
143                                 return null;
144                         AbstractPropertyVariable property = (AbstractPropertyVariable)parent;
145                         Resource propertyResource = property.getPossibleRepresents(graph);
146                         if(propertyResource == null) return null;
147                         StructuralResource2 STR = StructuralResource2.getInstance(graph);
148                         if(!graph.isInstanceOf(propertyResource, STR.SCLValue))
149                                 return null;
150             Layer0 L0 = Layer0.getInstance(graph);
151                         return graph.getPossibleRelatedValue(propertyResource, L0.SCLValue_expression);
152                 }
153                 
154         };
155         
156         static class ConnectionImpl implements Connection {
157
158                 final private StandardGraphPropertyVariable connectionPoint;
159                 
160                 public ConnectionImpl(StandardGraphPropertyVariable connectionPoint) {
161                         this.connectionPoint = connectionPoint;
162                 }
163                 
164                 @Override
165                 public Collection<Variable> getConnectionPoints(ReadGraph graph, Resource relationType) throws DatabaseException {
166                     Set<Variable> result = new THashSet<Variable>();
167                     for(VariableConnectionPointDescriptor desc : ConnectionBrowser.flatten(graph, connectionPoint.parent, connectionPoint.property.predicate, relationType)) {
168                         result.add(desc.getVariable(graph));
169                     }
170                     return result;
171                 }
172                 
173                 @Override
174                 public Collection<String> getConnectionPointURIs(ReadGraph graph, Resource relationType) throws DatabaseException {
175                     Set<String> result = new THashSet<String>();
176                     for(VariableConnectionPointDescriptor desc : ConnectionBrowser.flatten(graph, connectionPoint.parent, connectionPoint.property.predicate, relationType)) {
177                         result.add(desc.getURI(graph));
178                     }
179                     return result;
180                 }
181
182                 @Override
183                 public Collection<VariableConnectionPointDescriptor> getConnectionPointDescriptors(ReadGraph graph, Resource relationType) throws DatabaseException {
184                     return ConnectionBrowser.flatten(graph, connectionPoint.parent, connectionPoint.property.predicate, relationType);
185                 }
186
187         }
188         
189         @SCLValue(type="ValueAccessor")
190         public static final ValueAccessor connectionValueAccessor = new ValueAccessor() {
191
192                 @Override
193                 public void setValue(WriteGraph graph, Variable context, Object value) throws DatabaseException {
194                         throw new UnsupportedOperationException();
195                 }
196                 
197                 public void setValue(WriteGraph graph, Variable context, Object value, Binding binding) throws DatabaseException {
198                         throw new UnsupportedOperationException();
199                 }
200
201                 public Object getValue(ReadGraph graph, Variable context, Binding binding) throws DatabaseException {
202             try {
203                 Object value = getValue(graph, context);
204                 Binding srcBinding = Bindings.OBJECT.getContentBinding(value);
205                                 return Bindings.adapt(value, srcBinding, binding);
206                         } catch (AdaptException e) {
207                                 throw new DatabaseException(e);
208                         } catch (BindingException e) {
209                                 throw new DatabaseException(e);
210                         }
211                 }
212
213                 @Override
214                 public Object getValue(ReadGraph graph, Variable context) throws DatabaseException {
215                         StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context; 
216                         return new ConnectionImpl(variable);
217                 }
218
219                 @Override
220                 public Datatype getDatatype(ReadGraph graph, Variable context) throws DatabaseException {
221                         try {
222                                 return Datatypes.getDatatype(Connection.class);
223                         } catch (DatatypeConstructionException e) {
224                                 throw new DatabaseException(e);
225                         }
226                 }
227                 
228         };      
229
230
231         @SCLValue(type = "VariableMap")
232         public static VariableMap structuralChildDomainProperties = new VariableMapImpl() {
233         
234                 public Variable getPossibleConnectionPointFromContext(ReadGraph graph, Variable variable, Resource context, String name) throws DatabaseException {
235
236                         Map<String, Resource> connectionPoints = graph.syncRequest(new ConnectionPointMapOfResource(graph, context), TransientCacheAsyncListener.<Map<String,Resource>>instance());
237                         Resource cp = connectionPoints.get(name);
238                         if(cp == null) return null;
239                         else return new StandardGraphPropertyVariable(graph, variable, cp);
240                         
241                 }
242                 
243                 public Map<String, Variable> collectConnectionPointsFromContext(ReadGraph graph, StructuralResource2 STR, Variable variable, Resource context, Map<String, Variable> map, boolean needSynchronized) throws DatabaseException {
244                         
245                         if(graph.isImmutable(context)) {
246
247                                 Map<String, Resource> cps = graph.syncRequest(new ConnectionPointMapOfResource(graph, context), TransientCacheAsyncListener.<Map<String,Resource>>instance());
248                                 if(cps.size() == 0) return map;
249                                 
250                                 if(map == null) map = new THashMap<String,Variable>(cps.size());
251                                 
252                                 for(Map.Entry<String, Resource> entry : cps.entrySet()) {
253                                         String name = entry.getKey();
254                                         Resource cp = entry.getValue();
255                                         if(needSynchronized && !graph.isInstanceOf(cp, STR.SynchronizedConnectionRelation)) continue;
256                                         map.put(name, new StandardGraphPropertyVariable(graph, variable, cp));
257                                 }
258                                 
259                                 return map;
260
261                         } else {
262                                 
263                                 Collection<Resource> predicates = graph.getPredicates(context);
264                                 
265                                 for(Resource predicate : predicates) {
266                                         
267                                         PropertyInfo info = graph.isImmutable(predicate) ?
268                                                         graph.syncRequest(new PossibleConnectionPointInfo(predicate), TransientCacheAsyncListener.<PropertyInfo>instance()) :
269                                                                 graph.syncRequest(new PossibleConnectionPointInfo(predicate));
270                                                         
271                                         if(info != null) {
272                                                 if(map == null) map = new THashMap<String,Variable>(4);
273                                                 if(needSynchronized && !graph.isInstanceOf(predicate, STR.SynchronizedConnectionRelation)) continue;
274                                                 map.put(info.name, new StandardGraphPropertyVariable(graph, variable, predicate));
275                                         }
276                                         
277                                 }
278
279                                 return map;
280
281                         }
282                         
283                 }
284
285                 @Override
286                 public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
287                 final StandardGraphChildVariable variable = (StandardGraphChildVariable)context;
288                 Variable cp = getPossibleConnectionPointFromContext(graph, variable, variable.resource, name);
289                 if(cp != null) return cp;
290             return All.getStandardChildDomainPropertyVariable(graph, context, name);
291                 }
292
293                 @Override
294                 public Map<String, Variable> getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
295                 StandardGraphChildVariable variable = (StandardGraphChildVariable)context;
296                 StructuralResource2 STR = StructuralResource2.getInstance(graph);
297                 map = collectConnectionPointsFromContext(graph, STR, variable, variable.resource, map, false);
298             return All.getStandardChildDomainPropertyVariables(graph, context, map);
299                 }
300                 
301                 public Map<String,Variable> getVariables(ReadGraph graph, Variable context, String classification, Map<String,Variable> map) throws DatabaseException {
302                         if (StructuralResource2.URIs.SynchronizedRelation.equals(classification)) {
303                                 return All.getStandardChildDomainPropertyVariables(graph, context, classification, map);
304                         } else if (StructuralResource2.URIs.SynchronizedConnectionRelation.equals(classification)) {
305                         StandardGraphChildVariable variable = (StandardGraphChildVariable)context;
306                         return collectConnectionPointsFromContext(graph, StructuralResource2.getInstance(graph), variable, variable.resource, map, true);
307                         } else if(StructuralResource2.URIs.ConnectionRelation.equals(classification)) {
308                         StandardGraphChildVariable variable = (StandardGraphChildVariable)context;
309                         return collectConnectionPointsFromContext(graph, StructuralResource2.getInstance(graph), variable, variable.resource, map, false);
310                         }
311                         return super.getVariables(graph, context, classification, map);
312                 }
313                 
314         };
315
316         static class StructuralChildMapOfResource extends ResourceRead<Map<String, Resource>> {
317
318                 public StructuralChildMapOfResource(Resource resource) {
319                         super(resource);
320                 }
321
322                 @Override
323                 public Map<String, Resource> perform(ReadGraph graph) throws DatabaseException {
324                         StructuralResource2 STR = StructuralResource2.getInstance(graph);
325                         Resource type = graph.getPossibleType(resource, STR.Component);
326                         if(type != null) {
327                                 Resource definition = graph.getPossibleObject(type, STR.IsDefinedBy);
328                                 if(definition != null) {
329                                         Map<String, Resource> map = graph.syncRequest(new UnescapedChildMapOfResource(definition));
330                                         if (!map.isEmpty())
331                                                 return map;
332                                 } 
333                         }
334                         Map<String, Resource> directChildren = graph.syncRequest(new UnescapedChildMapOfResource(resource));
335                         return directChildren;
336                 }
337
338         }
339
340     static class StructuralChildMapOfResourceT extends ResourceRead<Map<String, Resource>> {
341
342         public StructuralChildMapOfResourceT(Resource resource) {
343             super(resource);
344         }
345
346         @Override
347         public Map<String, Resource> perform(ReadGraph graph) throws DatabaseException {
348             StructuralResource2 STR = StructuralResource2.getInstance(graph);
349             Resource definition = graph.getPossibleObject(resource, STR.IsDefinedBy);
350             if(definition != null) {
351                 Map<String, Resource> map = graph.syncRequest(new UnescapedChildMapOfResource(definition));
352                 if (!map.isEmpty())
353                     return map;
354             } 
355             return Collections.emptyMap();
356         }
357
358     }
359
360         static class StructuralRunChildMapOfResource extends ResourceRead<Map<String, Resource>> {
361
362                 public StructuralRunChildMapOfResource(Resource resource) {
363                         super(resource);
364                 }
365
366                 public Map<String, Resource> fromContext(ReadGraph graph, Resource context) throws DatabaseException {
367                         return graph.sync(new StructuralChildMapOfResource(context));
368                 }
369                 
370                 @Override
371                 public Map<String, Resource> perform(ReadGraph graph) throws DatabaseException {
372
373                         Layer0 L0 = Layer0.getInstance(graph);
374                         SimulationResource SIMU = SimulationResource.getInstance(graph);
375                         Resource model = graph.sync(new PossibleIndexRoot(resource));
376                         if(graph.isInstanceOf(model, L0.RVIContext)) {
377                                 return fromContext(graph, model);
378                         }
379                         Resource configuration = graph.getPossibleObject(model, SIMU.HasConfiguration);
380                         if(configuration != null) {
381                                 if(graph.isInstanceOf(configuration, L0.RVIContext)) {
382                                         return fromContext(graph, configuration);
383                                 }
384                         }
385                         
386                         return Collections.emptyMap();
387                         
388                 }
389                 
390         }
391         
392         private static class SubstructureRequest extends VariableRead<List<SubstructureElement>> {
393             public SubstructureRequest(Variable context) {
394             super(context);
395         }
396
397         @Override
398         public List<SubstructureElement> perform(ReadGraph graph) {
399             try {
400                 Resource type = variable.getPossibleType(graph);
401                 if(type == null)
402                     return null;
403                 return CompileProceduralComponentTypeRequest.compileAndEvaluate(graph, type, variable);
404             } catch (Throwable t) {
405                 t.printStackTrace();
406                 return null;
407             }
408         }
409         }
410
411     public static List<SubstructureElement> getProceduralDesc(ReadGraph graph, final Variable context) throws DatabaseException {
412         StructuralResource2 STR = StructuralResource2.getInstance(graph);
413         final Resource type = context.getPossibleType(graph);
414         if(type != null) {
415             if(graph.isInstanceOf(type, STR.ProceduralComponentType)) {
416                 return graph.syncRequest(new SubstructureRequest(context));
417             }
418         }
419         return null;
420     }  
421         
422          public static Map<String,Variable> getProcedural(ReadGraph graph, Variable context, List<SubstructureElement> elements, Map<String,Variable> map) throws DatabaseException {
423              
424          if(map == null) map = new THashMap<String,Variable>();
425          
426          MapList<String,org.simantics.structural2.procedural.Connection> conns = new MapList<String,org.simantics.structural2.procedural.Connection>();
427          for(SubstructureElement sub : elements) {
428              if(sub instanceof org.simantics.structural2.procedural.Connection) {
429                  org.simantics.structural2.procedural.Connection conn = (org.simantics.structural2.procedural.Connection)sub;
430                  for(ConnectionPoint cp : conn.connectionPoints) {
431                      if(cp instanceof Terminal) {
432                          Terminal t = (Terminal)cp;
433                          conns.add(t.component, conn);
434                      }
435                  }
436              }
437          }
438          
439          Map<String,Component> proceduralChildren = new THashMap<String, Component>();
440          for(SubstructureElement sub : elements) {
441              if(sub instanceof Component) {
442                  Component comp = (Component)sub;
443                  proceduralChildren.put(comp.name, comp);
444              }
445          }
446          
447          Collection<Object> nodeChildren = All.getPossibleNodeChildren(graph, (AbstractChildVariable)context);
448          Set<String> used = new HashSet<String>(nodeChildren.size());
449          for(Object nodeChild : nodeChildren) {
450              @SuppressWarnings("rawtypes")
451              NodeSupport support = ((AbstractChildVariable)context).node.support;
452              @SuppressWarnings("rawtypes")
453              NodeManager manager = support.manager;
454              @SuppressWarnings("unchecked")
455              String name = manager.getName(nodeChild);
456              used.add(name);
457              Component proceduralChild = proceduralChildren.get(name); 
458              if(proceduralChild != null) {
459                  map.put(proceduralChild.name, new StandardProceduralChildVariable(graph, context, new VariableNode(support, nodeChild), proceduralChild.name, proceduralChild.type, proceduralChild.properties, conns.getValues(proceduralChild.name)));
460              }
461          }
462          
463          for(Map.Entry<String, Component> entry : proceduralChildren.entrySet()) {
464              String name = entry.getKey();
465              if(used.contains(name)) continue;
466              Component proceduralChild = entry.getValue();
467              map.put(proceduralChild.name, new StandardProceduralChildVariable(graph, context, null, proceduralChild.name, proceduralChild.type, proceduralChild.properties, conns.getValues(proceduralChild.name)));
468          }
469          
470          return map;
471              
472      }  
473          
474          private static class ProceduralSubstructureRequest extends VariableRead<Map<String,Variable>> {
475
476              public ProceduralSubstructureRequest(Variable variable) {
477                  super(variable);
478              }
479
480              @Override
481              public Map<String, Variable> perform(ReadGraph graph)
482                      throws DatabaseException {
483                  List<SubstructureElement> elements = getProceduralDesc(graph, variable);
484                  if(elements != null)
485                      return getProcedural(graph, variable, elements, null);
486                  else
487                      return null;
488              }
489          }
490          
491         
492         @SCLValue(type = "VariableMap")
493         public static VariableMap structuralChildDomainChildren = new VariableMapImpl() {
494         
495                 @Override
496                 public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
497                         
498                 final Resource type = context.getPossibleType(graph);
499                 if(type != null) {
500                         StructuralResource2 STR = StructuralResource2.getInstance(graph);
501                     if(graph.isInstanceOf(type, STR.ProceduralComponentType)) {
502                             Map<String,Variable> map = graph.syncRequest(new ProceduralSubstructureRequest(context),
503                                 TransientCacheListener.<Map<String,Variable>>instance());
504                             if(map != null) return map.get(name);
505                     }
506                 }
507
508                     Resource represents = context.getPossibleRepresents(graph);
509             if(represents == null) {
510                 Map<String, Resource> children = graph.syncRequest(new StructuralChildMapOfResourceT(type));
511                 Resource child = children.get(name);
512                 return All.getStandardChildDomainChildVariable(graph, context, child, name);
513             }
514             Map<String, Resource> children = graph.syncRequest(new StructuralChildMapOfResource(represents));
515             Resource child = children.get(name);
516             return All.getStandardChildDomainChildVariable(graph, context, child, name);
517                 }
518
519                 @Override
520                 public Map<String, Variable> getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
521                         
522                 final Resource type = context.getPossibleType(graph);
523                 if(type != null) {
524                         StructuralResource2 STR = StructuralResource2.getInstance(graph);
525                     if(graph.isInstanceOf(type, STR.ProceduralComponentType)) {
526                         Map<String,Variable> mapPrime = graph.syncRequest(new ProceduralSubstructureRequest(context),
527                                         TransientCacheListener.<Map<String,Variable>>instance());
528                         if(mapPrime != null) {
529                                 if(map != null) {
530                                         map.putAll(mapPrime);
531                                         return map;
532                                 }
533                                 else
534                                         return mapPrime;
535                         }
536                     }
537                 }
538             Resource represents = context.getPossibleRepresents(graph);
539             if(represents == null) {
540                 Map<String, Resource> children = graph.syncRequest(new StructuralChildMapOfResourceT(type));
541                 return StandardChildDomainChildren.getStandardChildDomainChildVariables(graph, context, children, map);
542             }
543             Map<String, Resource> children = graph.syncRequest(new StructuralChildMapOfResource(represents));
544             return StandardChildDomainChildren.getStandardChildDomainChildVariables(graph, context, children, map);
545                 }
546                 
547         };
548         
549         @SCLValue(type = "VariableMap")
550         public static VariableMap structuralRunDomainChildren = new VariableMapImpl() {
551         
552                 @Override
553                 public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
554                     Map<String, Resource> children = graph.syncRequest(new StructuralRunChildMapOfResource(context.getRepresents(graph)));
555                         Resource child = children.get(name);
556             return StandardChildDomainChildren.getStandardChildDomainChildVariable(graph, context, child, name);
557                 }
558
559                 @Override
560                 public Map<String, Variable> getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
561             StandardGraphChildVariable variable = (StandardGraphChildVariable)context;
562             Map<String,Resource> children = graph.syncRequest(new StructuralRunChildMapOfResource(variable.resource));
563                     return StandardChildDomainChildren.getStandardChildDomainChildVariables(graph, context, children, map);
564                 }
565                 
566         };
567
568         @SCLValue(type = "ReadGraph -> [Resource] -> [Resource]")
569     public static List<Resource> connectionExtension(ReadGraph graph, List<Resource> rs) throws DatabaseException {
570
571         StructuralResource2 STR = StructuralResource2.getInstance(graph);
572         HashSet<Resource> extension = new HashSet<Resource>(8);
573         for(Resource r : rs) {
574                 if(graph.isInstanceOf(r, STR.Connection)) {
575                         extension.addAll(graph.syncRequest(new ConnectionComponents(r), TransientCacheListener.<Collection<Resource>>instance()));
576                 }
577                 if(graph.isInstanceOf(r, STR.ConnectionJoin)) {
578                         extension.addAll(graph.syncRequest(new ConnectionJoinComponents(r), TransientCacheListener.<Collection<Resource>>instance()));
579                 }
580         }
581
582         HashSet<Resource> components = new HashSet<Resource>(8);
583         for(Resource r : extension) {
584                 components.addAll(graph.sync(new ObjectsWithType(r, STR.Connects, STR.Component)));
585         }
586         
587         if(!extension.isEmpty()) {
588                 ArrayList<Resource> result = new ArrayList<Resource>(rs.size() + extension.size());
589                 result.addAll(rs);
590                 result.addAll(extension);
591                 result.addAll(components);
592                 rs = result;
593         }
594         
595         return rs;
596         
597     }
598
599         @SCLValue(type = "ReadGraph -> Resource -> [Issue]")
600     public static List<Issue> connectionValidator(ReadGraph graph, Resource component) throws DatabaseException {
601         
602                 if(!graph.hasStatement(component)) return Collections.emptyList();
603
604                 ArrayList<Issue> result = new ArrayList<Issue>();
605                 
606                 Layer0 L0 = Layer0.getInstance(graph);
607                 StructuralResource2 sr = StructuralResource2.getInstance(graph);
608
609                 Resource type = graph.getSingleType(component, sr.Component);
610                 
611                 Set<Resource> requiredConnections = new HashSet<Resource>();
612                 for(Resource connectionRelation : graph.sync(new ObjectsWithType(type, L0.ConsistsOf, sr.ConnectionRelation))) {
613                         Boolean required = graph.getPossibleRelatedValue(connectionRelation, sr.ConnectionRelation_connectionRequired, Bindings.BOOLEAN);
614                         if(required != null && required)
615                                 requiredConnections.add(connectionRelation);
616                 }
617                 
618                 Set<Resource> connections = new HashSet<Resource>();
619
620                 for(Statement stm : graph.getStatements(component, sr.IsConnectedTo)) {
621                         connections.add(stm.getPredicate());
622                         connections.addAll(graph.getSuperrelations(stm.getPredicate()));
623                 }
624
625                 for(Resource req : requiredConnections) {
626                         if(!connections.contains(req)) {
627                                 result.add(new StandardIssue(sr.ConnectionConstraint_ErrorIssue, component, req));
628                         }
629                 }
630
631                 return result;
632         
633     }
634
635     @SCLValue(type = "ReadGraph -> Resource -> Variable -> String")
636     public static String connectionIssueDescription(ReadGraph graph, Resource converter, Variable property) throws DatabaseException {
637         List<Resource> contexts = IssueUtils.getContextsForProperty(graph, property);
638         String attributeName = graph.getRelatedValue(contexts.get(1), Layer0.getInstance(graph).HasName);
639         return "'" + attributeName + "' should be connected.";
640     }
641
642     public static class InterfacePathMap extends VariableRead<GraphMap<Map<String,InterfaceResolution>>> {
643
644                 public InterfacePathMap(Variable context) {
645                         super(context);
646                 }
647
648                 @Override
649                 public GraphMap<Map<String,InterfaceResolution>> perform(ReadGraph graph) throws DatabaseException {
650
651                         return new GraphMap<Map<String,InterfaceResolution>>() {
652
653                                 @Override
654                                 Map<String, InterfaceResolution> get(ReadGraph graph, String key) throws DatabaseException {
655                                         
656                                         Variable child = variable.getChild(graph, key);
657                                         
658                                         Map<String,InterfaceResolution> childMap = new THashMap<String,InterfaceResolution>();
659                                         Collection<InterfaceResolution> paths = computeInterfacePaths(graph, child);//child.getPossiblePropertyValue(graph, "proceduralConnectionPointPath");
660                                         if(paths != null) {
661                                                 for(InterfaceResolution r : paths) {
662                                                         childMap.put(r.interfaceName, r);
663                                                 }
664                                         }
665                                         return childMap;
666
667                                 }
668                                 
669                         };
670                         
671                 }
672         
673     }
674     
675     public static String resolveInterfacePath(ReadGraph graph, Variable context, String component, Resource relation) throws DatabaseException {
676         
677         GraphMap<Map<String,InterfaceResolution>> map = graph.syncRequest(new InterfacePathMap(context), TransientCacheListener.<GraphMap<Map<String,InterfaceResolution>>>instance());
678         Map<String,InterfaceResolution> childMap = map.get(graph, component);
679         if(childMap == null) return "";
680
681         PropertyInfo info = graph.syncRequest(new PropertyInfoRequest(relation), TransientCacheListener.<PropertyInfo>instance());
682
683         InterfaceResolution match = childMap.get(info.name);
684         if(match != null) {
685                 String comp = URIStringUtils.escape(component);
686                 Variable newContext = context.getChild(graph, component);
687                 return "/" + comp + resolveInterfacePath(graph, newContext, match.componentName, match.connectionPoint);
688         } else {
689                 return "/" + URIStringUtils.escape(component) + "#" + URIStringUtils.escape(info.name); 
690         }
691                 
692     }
693     
694     public static class InterfaceResolution {
695         
696         public Resource interfaceConnectionPoint;
697         public String interfaceName;
698         public String componentName;
699         public Resource connectionPoint;
700         
701         public InterfaceResolution(Resource interfaceConnectionPoint, String interfaceName, String componentName, Resource connectionPoint) {
702                 this.interfaceConnectionPoint = interfaceConnectionPoint;
703                 this.interfaceName = interfaceName;
704                 this.componentName = componentName;
705                 this.connectionPoint = connectionPoint;
706         }
707         
708     }
709     
710     public static Collection<InterfaceResolution> computeInterfacePaths(ReadGraph graph, Variable variable) throws DatabaseException {
711
712                 StructuralResource2 STR = StructuralResource2.getInstance(graph);
713                 Resource type = variable.getPossibleType(graph);
714                 if(type != null) {
715                         if(graph.isInstanceOf(type, STR.ProceduralComponentType)) {
716                                 ArrayList<InterfaceResolution> result = new ArrayList<InterfaceResolution>();
717                                 List<SubstructureElement> elements = getProceduralDesc(graph, variable); 
718                                 if(elements != null) {
719                                         for(SubstructureElement e : elements) {
720                                                 if(e instanceof org.simantics.structural2.procedural.Connection) {
721                                                         org.simantics.structural2.procedural.Connection conn = (org.simantics.structural2.procedural.Connection)e;
722                                                         Interface inf = null;
723                                                         for(ConnectionPoint cp : conn.connectionPoints) {
724                                                                 if(cp instanceof Interface) {
725                                                                         if(inf != null) throw new DatabaseException("Multiple interfaces referenced in procedural connection.");
726                                                                         inf = (Interface)cp;
727                                                                 }
728                                                         }
729                                                         if(inf != null && conn.connectionPoints.size() > 1) {
730                                                                 Layer0 L0 = Layer0.getInstance(graph);
731                                                                 String cpName = URIStringUtils.escape( graph.<String>getRelatedValue(inf.relation, L0.HasName, Bindings.STRING) );
732                                                                 for(ConnectionPoint cp : conn.connectionPoints) {
733                                                                         if(cp == inf) continue;
734                                                                         Terminal t = (Terminal)cp;
735                                                                         result.add(new InterfaceResolution(inf.relation, cpName, t.component, t.relation));
736                                                                 }
737                                                         }
738                                                 }
739                                         }
740                                 }
741
742                                 return result;
743                                 
744                         }
745
746                         final Collection<InterfaceResolution> interfaces = graph.syncRequest(new DefinedUCInterfaceMap(type));
747                         if(interfaces != null) return interfaces;
748
749                 }
750                 
751                 return BUILTIN_STRUCTURAL_CPS;
752         
753     }
754     
755     static class InterfacePathRequest extends VariableRead<Collection<InterfaceResolution>> {
756
757                 public InterfacePathRequest(Variable variable) {
758                         super(variable);
759                 }
760                 
761                 @Override
762                 public Collection<InterfaceResolution> perform(ReadGraph graph) throws DatabaseException {
763                         return computeInterfacePaths(graph, variable);
764                 }
765         
766     }
767     
768     static class DefinedUCInterfaceMap extends ResourceRead<Collection<InterfaceResolution>> {
769
770         public DefinedUCInterfaceMap(Resource resource) {
771                 super(resource);
772         }
773
774         @Override
775         public Collection<InterfaceResolution> perform(ReadGraph graph)
776                         throws DatabaseException {
777
778                 StructuralResource2 STR = StructuralResource2.getInstance(graph);
779                 Resource definition = graph.getPossibleObject(resource, STR.IsDefinedBy);
780                 if(definition != null) {
781                         Collection<InterfaceResolution> result = new ArrayList<InterfaceResolution>();
782                         Layer0 L0 = Layer0.getInstance(graph);
783                         for(Resource cp : graph.syncRequest(new ObjectsWithType(resource, L0.ConsistsOf, STR.ConnectionRelation))) {
784                                         String cpName = graph.getRelatedValue(cp, L0.HasName, Bindings.STRING);
785                                 for(Resource conn : graph.getObjects(cp, STR.IsBoundBy)) {
786                                         Statement stm = graph.getPossibleStatement(conn, STR.Connects);
787                                         if(stm == null) continue;
788                                         Resource component = stm.getObject();
789                                         String componentName = graph.getRelatedValue(component, L0.HasName, Bindings.STRING);
790                                         result.add(new InterfaceResolution(cp, cpName, componentName, graph.getInverse(stm.getPredicate())));
791                                 }
792                         }
793                         return result;
794                 }
795                 return null;
796         }
797
798     }
799     
800     public static final Collection<InterfaceResolution> BUILTIN_STRUCTURAL_CPS = new ArrayList<InterfaceResolution>();
801
802         @SCLValue(type = "ReadGraph -> Resource -> Variable -> a")
803     public static Object computeExpression(ReadGraph graph, Resource converter, Variable context) throws DatabaseException {
804         return CompileStructuralValueRequest.compileAndEvaluate(graph, context);
805     }
806
807     public static Object computeExpressionInContext(ReadGraph graph, Variable context, final String expression) throws DatabaseException {
808         SCLContext sclContext = SCLContext.getCurrent();
809         Object oldGraph = sclContext.get("graph");
810         try {
811             Function1<Variable,Object> exp = graph.syncRequest(new CompileStructuralValueRequest(graph, context) {
812                 protected String getExpressionText(ReadGraph graph) throws DatabaseException {
813                     return expression;
814                 }
815             },
816             TransientCacheListener.<Function1<Variable,Object>>instance());
817             sclContext.put("graph", graph);
818             return exp.apply(context);
819         } catch (DatabaseException e) {
820             throw (DatabaseException)e;
821         } catch (Throwable t) {
822             throw new DatabaseException(t);
823         } finally {
824             sclContext.put("graph", oldGraph);
825         }
826     }    
827         
828         static abstract class InterfacePathProperty extends LazyPropertyVariable {
829                 
830                 public InterfacePathProperty(Variable parent) {
831                         super(parent, "proceduralConnectionPointPath", Bindings.STRING_ARRAY);
832                 }
833                 
834                 @Override
835                 public <T> T getValue(ReadGraph graph, Binding binding) throws DatabaseException {
836                         return getValue(graph);
837                 }
838                 
839         }
840         
841         static abstract class GraphMap<Value> {
842                 
843                 abstract Value get(ReadGraph graph, String key) throws DatabaseException;
844                 
845         }
846     
847 }