]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.structural2/src/org/simantics/structural2/Functions.java
foobaz
[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.PossibleObjectWithType;
31 import org.simantics.db.common.request.ResourceRead;
32 import org.simantics.db.common.uri.UnescapedChildMapOfResource;
33 import org.simantics.db.exception.DatabaseException;
34 import org.simantics.db.layer0.function.All;
35 import org.simantics.db.layer0.function.StandardChildDomainChildren;
36 import org.simantics.db.layer0.request.PropertyInfo;
37 import org.simantics.db.layer0.request.PropertyInfoRequest;
38 import org.simantics.db.layer0.request.VariableRead;
39 import org.simantics.db.layer0.variable.AbstractChildVariable;
40 import org.simantics.db.layer0.variable.AbstractPropertyVariable;
41 import org.simantics.db.layer0.variable.LazyPropertyVariable;
42 import org.simantics.db.layer0.variable.NodeSupport;
43 import org.simantics.db.layer0.variable.StandardGraphChildVariable;
44 import org.simantics.db.layer0.variable.StandardGraphPropertyVariable;
45 import org.simantics.db.layer0.variable.ValueAccessor;
46 import org.simantics.db.layer0.variable.ValueAccessorWithBinding;
47 import org.simantics.db.layer0.variable.Variable;
48 import org.simantics.db.layer0.variable.VariableMap;
49 import org.simantics.db.layer0.variable.VariableMapImpl;
50 import org.simantics.db.layer0.variable.VariableNode;
51 import org.simantics.db.service.CollectionSupport;
52 import org.simantics.issues.common.IssueUtils;
53 import org.simantics.layer0.Layer0;
54 import org.simantics.scl.reflection.annotations.SCLValue;
55 import org.simantics.scl.runtime.SCLContext;
56 import org.simantics.scl.runtime.function.Function1;
57 import org.simantics.simulation.ontology.SimulationResource;
58 import org.simantics.simulator.variable.NodeManager;
59 import org.simantics.structural.stubs.StructuralResource2;
60 import org.simantics.structural2.procedural.Component;
61 import org.simantics.structural2.procedural.ConnectionPoint;
62 import org.simantics.structural2.procedural.Interface;
63 import org.simantics.structural2.procedural.SubstructureElement;
64 import org.simantics.structural2.procedural.Terminal;
65 import org.simantics.structural2.queries.ConnectionComponents;
66 import org.simantics.structural2.queries.ConnectionJoinComponents;
67 import org.simantics.structural2.queries.ConnectionPointMapOfResource;
68 import org.simantics.structural2.queries.PossibleConnectionPointInfo;
69 import org.simantics.structural2.scl.CompileStructuralValueRequest;
70 import org.simantics.structural2.scl.procedural.CompileProceduralComponentTypeRequest;
71 import org.simantics.structural2.utils.StructuralUtils.StructuralComponentClass;
72 import org.simantics.structural2.variables.Connection;
73 import org.simantics.structural2.variables.StandardProceduralChildVariable;
74 import org.simantics.utils.datastructures.MapList;
75
76 import gnu.trove.map.hash.THashMap;
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         @SCLValue(type="ValueAccessor")
157         public static final ValueAccessor connectionValueAccessor = new ValueAccessor() {
158
159                 @Override
160                 public void setValue(WriteGraph graph, Variable context, Object value) throws DatabaseException {
161                         throw new UnsupportedOperationException();
162                 }
163                 
164                 public void setValue(WriteGraph graph, Variable context, Object value, Binding binding) throws DatabaseException {
165                         throw new UnsupportedOperationException();
166                 }
167
168                 public Object getValue(ReadGraph graph, Variable context, Binding binding) throws DatabaseException {
169             try {
170                 Object value = getValue(graph, context);
171                 Binding srcBinding = Bindings.OBJECT.getContentBinding(value);
172                                 return Bindings.adapt(value, srcBinding, binding);
173                         } catch (AdaptException e) {
174                                 throw new DatabaseException(e);
175                         } catch (BindingException e) {
176                                 throw new DatabaseException(e);
177                         }
178                 }
179
180                 @Override
181                 public Object getValue(ReadGraph graph, Variable context) throws DatabaseException {
182                         StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context; 
183                         return new ConnectionImpl(context.getParent(graph), variable.property.predicate);
184                 }
185
186                 @Override
187                 public Datatype getDatatype(ReadGraph graph, Variable context) throws DatabaseException {
188                         try {
189                                 return Datatypes.getDatatype(Connection.class);
190                         } catch (DatatypeConstructionException e) {
191                                 throw new DatabaseException(e);
192                         }
193                 }
194                 
195         };      
196
197
198         @SCLValue(type = "VariableMap")
199         public static VariableMap structuralChildDomainProperties = new VariableMapImpl() {
200         
201                 public Variable getPossibleConnectionPointFromContext(ReadGraph graph, Variable variable, Resource context, String name) throws DatabaseException {
202
203                         Map<String, PropertyInfo> connectionPoints = graph.syncRequest(new ConnectionPointMapOfResource(graph, context), TransientCacheAsyncListener.<Map<String,PropertyInfo>>instance());
204                         PropertyInfo cp = connectionPoints.get(name);
205                         if(cp == null) return null;
206                         else return new StandardGraphPropertyVariable(graph, variable, cp.predicate);
207                         
208                 }
209                 
210                 public Map<String, Variable> collectConnectionPointsFromContext(ReadGraph graph, StructuralResource2 STR, Variable variable, Resource context, Map<String, Variable> map, boolean needSynchronized) throws DatabaseException {
211                         
212                         if(graph.isImmutable(context)) {
213
214                                 Map<String, PropertyInfo> cps = graph.syncRequest(new ConnectionPointMapOfResource(graph, context), TransientCacheAsyncListener.<Map<String,PropertyInfo>>instance());
215                                 if(cps.size() == 0) return map;
216                                 
217                                 if(map == null) map = new THashMap<String,Variable>(cps.size());
218                                 
219                                 for(Map.Entry<String, PropertyInfo> entry : cps.entrySet()) {
220                                         String name = entry.getKey();
221                                         PropertyInfo cp = entry.getValue();
222                                         if(needSynchronized && !graph.isInstanceOf(cp.predicate, STR.SynchronizedConnectionRelation)) continue;
223                                         map.put(name, new StandardGraphPropertyVariable(graph, variable, cp.predicate));
224                                 }
225                                 
226                                 return map;
227
228                         } else {
229                                 
230                                 Collection<Resource> predicates = graph.getPredicates(context);
231                                 
232                                 for(Resource predicate : predicates) {
233                                         
234                                         PropertyInfo info = graph.isImmutable(predicate) ?
235                                                         graph.syncRequest(new PossibleConnectionPointInfo(predicate), TransientCacheAsyncListener.<PropertyInfo>instance()) :
236                                                                 graph.syncRequest(new PossibleConnectionPointInfo(predicate));
237                                                         
238                                         if(info != null) {
239                                                 if(map == null) map = new THashMap<String,Variable>(4);
240                                                 if(needSynchronized && !graph.isInstanceOf(predicate, STR.SynchronizedConnectionRelation)) continue;
241                                                 map.put(info.name, new StandardGraphPropertyVariable(graph, variable, predicate));
242                                         }
243                                         
244                                 }
245
246                                 return map;
247
248                         }
249                         
250                 }
251
252                 @Override
253                 public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
254                 final StandardGraphChildVariable variable = (StandardGraphChildVariable)context;
255                 Variable cp = getPossibleConnectionPointFromContext(graph, variable, variable.resource, name);
256                 if(cp != null) return cp;
257             return All.getStandardChildDomainPropertyVariable(graph, context, name);
258                 }
259
260                 @Override
261                 public Map<String, Variable> getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
262                 StandardGraphChildVariable variable = (StandardGraphChildVariable)context;
263                 StructuralResource2 STR = StructuralResource2.getInstance(graph);
264                 map = collectConnectionPointsFromContext(graph, STR, variable, variable.resource, map, false);
265             return All.getStandardChildDomainPropertyVariables(graph, context, map);
266                 }
267                 
268                 public Map<String,Variable> getVariables(ReadGraph graph, Variable context, String classification, Map<String,Variable> map) throws DatabaseException {
269                         if (StructuralResource2.URIs.SynchronizedRelation.equals(classification)) {
270                                 return All.getStandardChildDomainPropertyVariables(graph, context, classification, map);
271                         } else if (StructuralResource2.URIs.SynchronizedConnectionRelation.equals(classification)) {
272                         StandardGraphChildVariable variable = (StandardGraphChildVariable)context;
273                         return collectConnectionPointsFromContext(graph, StructuralResource2.getInstance(graph), variable, variable.resource, map, true);
274                         } else if(StructuralResource2.URIs.ConnectionRelation.equals(classification)) {
275                         StandardGraphChildVariable variable = (StandardGraphChildVariable)context;
276                         return collectConnectionPointsFromContext(graph, StructuralResource2.getInstance(graph), variable, variable.resource, map, false);
277                         }
278                         return super.getVariables(graph, context, classification, map);
279                 }
280                 
281         };
282
283         static class StructuralRunContext extends ResourceRead<Resource> {
284
285                 public StructuralRunContext(Resource resource) {
286                         super(resource);
287                 }
288
289                 @Override
290                 public Resource perform(ReadGraph graph) throws DatabaseException {
291
292                         Layer0 L0 = Layer0.getInstance(graph);
293                         SimulationResource SIMU = SimulationResource.getInstance(graph);
294                         Resource model = graph.sync(new PossibleIndexRoot(resource));
295                         if(graph.isInstanceOf(model, L0.RVIContext)) {
296                                 return model;
297                         }
298                         Resource configuration = graph.getPossibleObject(model, SIMU.HasConfiguration);
299                         if(configuration != null) {
300                                 if(graph.isInstanceOf(configuration, L0.RVIContext)) {
301                                         return configuration;
302                                 }
303                         }
304
305                         return null;
306
307                 }
308                 
309         }
310         
311     public static class StructuralChildMapOfResource extends ResourceRead<Map<String, Resource>> {
312
313         public StructuralChildMapOfResource(Resource resource) {
314             super(resource);
315         }
316
317         @Override
318         public Map<String, Resource> perform(ReadGraph graph) throws DatabaseException {
319             StructuralResource2 STR = StructuralResource2.getInstance(graph);
320             Resource type = graph.getPossibleType(resource, STR.Component);
321             if(type != null) {
322                 Resource definition = graph.getPossibleObject(type, STR.IsDefinedBy);
323                 if(definition != null) {
324                     Map<String, Resource> map = graph.syncRequest(new UnescapedChildMapOfResource(definition));
325                     if (!map.isEmpty())
326                         return map;
327                 } 
328             }
329             Map<String, Resource> directChildren = graph.syncRequest(new UnescapedChildMapOfResource(resource));
330             return directChildren;
331         }
332
333     }
334
335     public static class StructuralChildMapOfResourceT extends ResourceRead<Map<String, Resource>> {
336
337         public StructuralChildMapOfResourceT(Resource resource) {
338             super(resource);
339         }
340
341         @Override
342         public Map<String, Resource> perform(ReadGraph graph) throws DatabaseException {
343             StructuralResource2 STR = StructuralResource2.getInstance(graph);
344             Resource definition = graph.getPossibleObject(resource, STR.IsDefinedBy);
345             if(definition != null) {
346                 Map<String, Resource> map = graph.syncRequest(new UnescapedChildMapOfResource(definition));
347                 if (!map.isEmpty())
348                     return map;
349             } 
350             return Collections.emptyMap();
351         }
352
353     }
354
355     static class StructuralRunChildMapOfResource extends ResourceRead<Map<String, Resource>> {
356
357         public StructuralRunChildMapOfResource(Resource resource) {
358             super(resource);
359         }
360
361         public Map<String, Resource> fromContext(ReadGraph graph, Resource context) throws DatabaseException {
362             return graph.sync(new StructuralChildMapOfResource(context));
363         }
364         
365         @Override
366         public Map<String, Resource> perform(ReadGraph graph) throws DatabaseException {
367
368             Layer0 L0 = Layer0.getInstance(graph);
369             SimulationResource SIMU = SimulationResource.getInstance(graph);
370             Resource model = graph.sync(new PossibleIndexRoot(resource));
371             if(graph.isInstanceOf(model, L0.RVIContext)) {
372                 return fromContext(graph, model);
373             }
374             Resource configuration = graph.getPossibleObject(model, SIMU.HasConfiguration);
375             if(configuration != null) {
376                 if(graph.isInstanceOf(configuration, L0.RVIContext)) {
377                     return fromContext(graph, configuration);
378                 }
379             }
380             
381             return Collections.emptyMap();
382             
383         }
384         
385     }
386
387         private static class SubstructureRequest extends VariableRead<List<SubstructureElement>> {
388             public SubstructureRequest(Variable context) {
389             super(context);
390         }
391
392         @Override
393         public List<SubstructureElement> perform(ReadGraph graph) {
394             try {
395                 Resource type = variable.getPossibleType(graph);
396                 if(type == null)
397                     return null;
398                 return CompileProceduralComponentTypeRequest.compileAndEvaluate(graph, type, variable);
399             } catch (Throwable t) {
400                 t.printStackTrace();
401                 return null;
402             }
403         }
404         }
405
406     public static List<SubstructureElement> getProceduralDesc(ReadGraph graph, final Variable context) throws DatabaseException {
407         StructuralResource2 STR = StructuralResource2.getInstance(graph);
408         final Resource type = context.getPossibleType(graph);
409         if(type != null) {
410             if(graph.isInstanceOf(type, STR.ProceduralComponentType)) {
411                 return graph.syncRequest(new SubstructureRequest(context));
412             }
413         }
414         return null;
415     }  
416         
417          public static Map<String,Variable> getProcedural(ReadGraph graph, Variable context, List<SubstructureElement> elements, Map<String,Variable> map) throws DatabaseException {
418              
419          if(map == null) map = new THashMap<String,Variable>();
420          
421          MapList<String,org.simantics.structural2.procedural.Connection> conns = new MapList<String,org.simantics.structural2.procedural.Connection>();
422          for(SubstructureElement sub : elements) {
423              if(sub instanceof org.simantics.structural2.procedural.Connection) {
424                  org.simantics.structural2.procedural.Connection conn = (org.simantics.structural2.procedural.Connection)sub;
425                  for(ConnectionPoint cp : conn.connectionPoints) {
426                      if(cp instanceof Terminal) {
427                          Terminal t = (Terminal)cp;
428                          conns.add(t.component, conn);
429                      }
430                  }
431              }
432          }
433          
434          Map<String,Component> proceduralChildren = new THashMap<String, Component>();
435          for(SubstructureElement sub : elements) {
436              if(sub instanceof Component) {
437                  Component comp = (Component)sub;
438                  proceduralChildren.put(comp.name, comp);
439              }
440          }
441          
442          Collection<Object> nodeChildren = All.getPossibleNodeChildren(graph, (AbstractChildVariable)context);
443          Set<String> used = new HashSet<String>(nodeChildren.size());
444          for(Object nodeChild : nodeChildren) {
445              @SuppressWarnings("rawtypes")
446              NodeSupport support = ((AbstractChildVariable)context).node.support;
447              @SuppressWarnings("rawtypes")
448              NodeManager manager = support.manager;
449              @SuppressWarnings("unchecked")
450              String name = manager.getName(nodeChild);
451              used.add(name);
452              Component proceduralChild = proceduralChildren.get(name); 
453              if(proceduralChild != null) {
454                  map.put(proceduralChild.name, new StandardProceduralChildVariable(graph, context, new VariableNode(support, nodeChild), proceduralChild.name, proceduralChild.type, proceduralChild.properties, conns.getValues(proceduralChild.name)));
455              }
456          }
457          
458          for(Map.Entry<String, Component> entry : proceduralChildren.entrySet()) {
459              String name = entry.getKey();
460              if(used.contains(name)) continue;
461              Component proceduralChild = entry.getValue();
462              map.put(proceduralChild.name, new StandardProceduralChildVariable(graph, context, null, proceduralChild.name, proceduralChild.type, proceduralChild.properties, conns.getValues(proceduralChild.name)));
463          }
464          
465          return map;
466              
467      }  
468          
469          private static class ProceduralSubstructureRequest extends VariableRead<Map<String,Variable>> {
470
471              public ProceduralSubstructureRequest(Variable variable) {
472                  super(variable);
473              }
474
475              @Override
476              public Map<String, Variable> perform(ReadGraph graph)
477                      throws DatabaseException {
478                  List<SubstructureElement> elements = getProceduralDesc(graph, variable);
479                  if(elements != null)
480                      return getProcedural(graph, variable, elements, null);
481                  else
482                      return null;
483              }
484          }
485          
486         public static class StructuralTypeOverrideMap extends ResourceRead<Map<Resource,Resource>> {
487
488                 protected StructuralTypeOverrideMap(Resource composite) {
489                         super(composite);
490                 }
491
492                 @Override
493                 public Map<Resource, Resource> perform(ReadGraph graph) throws DatabaseException {
494                         
495                         Layer0 L0 = Layer0.getInstance(graph);
496                         
497                         StructuralResource2 STR = StructuralResource2.getInstance(graph);
498                         
499                         CollectionSupport cs = graph.getService(CollectionSupport.class);
500                         
501                         Map<Resource,Resource> result = null;
502                         
503                         for(Resource override : graph.getObjects(resource, STR.HasTypeOverride)) {
504                                 Resource original = graph.getSingleObject(override, STR.TypeOverride_HasOriginalType);
505                                 Resource replacement = graph.getSingleObject(override, STR.TypeOverride_HasReplacementType);
506                                 if(result == null) result = cs.createMap(Resource.class);
507                                 result.put(original, replacement);
508                         }
509                         
510                         if(result == null) return Collections.emptyMap();
511                         
512                         return result;
513                         
514                 }
515                 
516         }
517         
518         public static class StructuralOverrideData {
519                 @Override
520                 public int hashCode() {
521                         final int prime = 31;
522                         int result = 1;
523                         result = prime * result + ((actualRepresents == null) ? 0 : actualRepresents.hashCode());
524                         result = prime * result + ((actualType == null) ? 0 : actualType.hashCode());
525                         result = prime * result + ((overrideType == null) ? 0 : overrideType.hashCode());
526                         return result;
527                 }
528                 @Override
529                 public boolean equals(Object obj) {
530                         if (this == obj)
531                                 return true;
532                         if (obj == null)
533                                 return false;
534                         if (getClass() != obj.getClass())
535                                 return false;
536                         StructuralOverrideData other = (StructuralOverrideData) obj;
537                         if (actualRepresents == null) {
538                                 if (other.actualRepresents != null)
539                                         return false;
540                         } else if (!actualRepresents.equals(other.actualRepresents))
541                                 return false;
542                         if (actualType == null) {
543                                 if (other.actualType != null)
544                                         return false;
545                         } else if (!actualType.equals(other.actualType))
546                                 return false;
547                         if (overrideType == null) {
548                                 if (other.overrideType != null)
549                                         return false;
550                         } else if (!overrideType.equals(other.overrideType))
551                                 return false;
552                         return true;
553                 }
554                 Resource actualRepresents;
555                 Resource actualType;
556                 Resource overrideType;
557                 public StructuralOverrideData(Resource actualRepresents, Resource actualType, Resource overrideType) {
558                         this.actualRepresents = actualRepresents;
559                         this.actualType = actualType;
560                         this.overrideType = overrideType;
561                 }
562
563                 public static StructuralOverrideData compute(ReadGraph graph, Variable context) throws DatabaseException {
564                         return graph.syncRequest(new StructuralOverrideDataRequest(context));
565                 }
566                 
567                 public Resource type() {
568                         if(overrideType != null)
569                                 return overrideType;
570                         return actualType;
571                 }
572
573                 public Resource represents() {
574                         return actualRepresents;
575                 }
576
577         }
578         
579         public static class StructuralOverrideDataRequest extends VariableRead<StructuralOverrideData> {
580
581                 public StructuralOverrideDataRequest(Variable component) {
582                         super(component);
583                 }
584
585                 public StructuralOverrideData walk(ReadGraph graph, Variable component, Resource actualRepresents, Resource actualType) throws DatabaseException {
586                 Resource represents = component.getPossibleRepresents(graph);
587                 if(represents != null) {
588                         Layer0 L0 = Layer0.getInstance(graph);
589                         StructuralResource2 STR = StructuralResource2.getInstance(graph);
590                         Resource container = graph.syncRequest(new PossibleObjectWithType(represents, L0.PartOf, STR.Composite));
591                         if(container != null) {
592                         Map<Resource,Resource> overrides = graph.syncRequest(new StructuralTypeOverrideMap(container));
593                         Resource override = overrides.get(actualType);
594                         if(override != null) {
595                                 return new StructuralOverrideData(actualRepresents, actualType, override);
596                         }
597                         }
598                 }
599                 Variable parent = component.getParent(graph);
600                 if(parent == null) return new StructuralOverrideData(actualRepresents, actualType, null);
601                 else return walk(graph, parent, represents, actualType);
602                 }
603                 
604                 @Override
605                 public StructuralOverrideData perform(ReadGraph graph) throws DatabaseException {
606
607                 Resource represents = variable.getPossibleRepresents(graph);
608                 if(represents == null) {
609                         String uri = variable.getPossiblePropertyValue(graph, "typeURI");
610                         if(uri != null) {
611                                 Resource actualType = graph.syncRequest(new org.simantics.db.common.primitiverequest.Resource(uri), TransientCacheAsyncListener.<Resource>instance()); 
612                                 return walk(graph, variable, null, actualType);
613                         }
614                         throw new DatabaseException("No type for " + variable.getURI(graph));
615                 } else {
616                         return walk(graph, variable, represents, graph.getPossibleType(represents, Layer0.getInstance(graph).Entity));
617                 }
618                         
619                 }
620                 
621         }
622
623         
624         @SCLValue(type = "VariableMap")
625         public static VariableMap structuralChildDomainChildren = new VariableMapImpl() {
626         
627                 @Override
628                 public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
629                         
630                         Resource type = context.getPossibleType(graph);
631                         if(type == null) return null;
632                         
633                         StructuralComponentClass clazz = StructuralComponentClass.get(graph, type);
634                         if(StructuralComponentClass.PROCEDURAL.equals(clazz)) {
635                     Map<String,Variable> map = graph.syncRequest(new ProceduralSubstructureRequest(context),
636                         TransientCacheListener.<Map<String,Variable>>instance());
637                     if(map != null) return map.get(name);
638                     return null;
639                         } else if (StructuralComponentClass.DEFINED.equals(clazz)) {
640                                 StructuralResource2 STR = StructuralResource2.getInstance(graph);
641                                 Resource def = graph.getSingleObject(type, STR.IsDefinedBy);
642                 Map<String, Resource> children = graph.syncRequest(new UnescapedChildMapOfResource(def));
643                 Resource child = children.get(name);
644                 if(child == null) return null;
645                 return StandardChildDomainChildren.getStandardChildDomainChildVariable(graph, context, child, name);
646                         } else {
647                                 Resource represents = context.getPossibleRepresents(graph);
648                                 if(represents == null) return null;
649                 Map<String, Resource> children = graph.syncRequest(new UnescapedChildMapOfResource(represents));
650                 Resource child = children.get(name);
651                 if(child == null) return null;
652                 return StandardChildDomainChildren.getStandardChildDomainChildVariable(graph, context, child, name);
653                         }
654
655                 }
656
657                 @Override
658                 public Map<String, Variable> getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
659                         
660                         Resource type = context.getPossibleType(graph);
661                         if(type == null) return null;
662                         
663                         StructuralComponentClass clazz = StructuralComponentClass.get(graph, type);
664                         if(StructuralComponentClass.PROCEDURAL.equals(clazz)) {
665                 Map<String,Variable> mapPrime = graph.syncRequest(new ProceduralSubstructureRequest(context),
666                                 TransientCacheListener.<Map<String,Variable>>instance());
667                 if(mapPrime != null) {
668                         if(map != null) {
669                                 map.putAll(mapPrime);
670                                 return map;
671                         }
672                         else
673                                 return mapPrime;
674                 }
675                 return map;
676                         } else if (StructuralComponentClass.DEFINED.equals(clazz)) {
677                                 StructuralResource2 STR = StructuralResource2.getInstance(graph);
678                                 Resource def = graph.getSingleObject(type, STR.IsDefinedBy);
679                 Map<String, Resource> children = graph.syncRequest(new UnescapedChildMapOfResource(def));
680                 return StandardChildDomainChildren.getStandardChildDomainChildVariables(graph, context, children, map);
681                         } else {
682                                 Resource represents = context.getPossibleRepresents(graph);
683                                 if(represents == null) return null;
684                 Map<String, Resource> children = graph.syncRequest(new UnescapedChildMapOfResource(represents));
685                 return StandardChildDomainChildren.getStandardChildDomainChildVariables(graph, context, children, map);
686                         }
687             
688                 }
689                 
690         };
691         
692         @SCLValue(type = "VariableMap")
693         public static VariableMap structuralRunDomainChildren = new VariableMapImpl() {
694         
695                 @Override
696                 public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
697                         Resource ctx = graph.syncRequest(new StructuralRunContext(context.getRepresents(graph)));
698                         if(ctx == null) return null;
699                     Map<String, Resource> children = graph.syncRequest(new UnescapedChildMapOfResource(ctx));
700                         Resource child = children.get(name);
701             return StandardChildDomainChildren.getStandardChildDomainChildVariable(graph, context, child, name);
702                 }
703
704                 @Override
705                 public Map<String, Variable> getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
706                         Resource ctx = graph.syncRequest(new StructuralRunContext(context.getRepresents(graph)));
707                         if(ctx == null) return map;
708                     Map<String, Resource> children = graph.syncRequest(new UnescapedChildMapOfResource(ctx));
709                     return StandardChildDomainChildren.getStandardChildDomainChildVariables(graph, context, children, map);
710                 }
711                 
712         };
713
714         @SCLValue(type = "ReadGraph -> [Resource] -> [Resource]")
715     public static List<Resource> connectionExtension(ReadGraph graph, List<Resource> rs) throws DatabaseException {
716
717         StructuralResource2 STR = StructuralResource2.getInstance(graph);
718         HashSet<Resource> extension = new HashSet<Resource>(8);
719         for(Resource r : rs) {
720                 if(graph.isInstanceOf(r, STR.Connection)) {
721                         extension.addAll(graph.syncRequest(new ConnectionComponents(r), TransientCacheListener.<Collection<Resource>>instance()));
722                 }
723                 if(graph.isInstanceOf(r, STR.ConnectionJoin)) {
724                         extension.addAll(graph.syncRequest(new ConnectionJoinComponents(r), TransientCacheListener.<Collection<Resource>>instance()));
725                 }
726         }
727
728         HashSet<Resource> components = new HashSet<Resource>(8);
729         for(Resource r : extension) {
730                 components.addAll(graph.sync(new ObjectsWithType(r, STR.Connects, STR.Component)));
731         }
732         
733         if(!extension.isEmpty()) {
734                 ArrayList<Resource> result = new ArrayList<Resource>(rs.size() + extension.size());
735                 result.addAll(rs);
736                 result.addAll(extension);
737                 result.addAll(components);
738                 rs = result;
739         }
740         
741         return rs;
742         
743     }
744
745         @SCLValue(type = "ReadGraph -> Resource -> [Issue]")
746     public static List<Issue> connectionValidator(ReadGraph graph, Resource component) throws DatabaseException {
747         
748                 if(!graph.hasStatement(component)) return Collections.emptyList();
749
750                 ArrayList<Issue> result = new ArrayList<Issue>();
751                 
752                 Layer0 L0 = Layer0.getInstance(graph);
753                 StructuralResource2 sr = StructuralResource2.getInstance(graph);
754
755                 Resource type = graph.getSingleType(component, sr.Component);
756                 
757                 Set<Resource> requiredConnections = new HashSet<Resource>();
758                 for(Resource connectionRelation : graph.sync(new ObjectsWithType(type, L0.ConsistsOf, sr.ConnectionRelation))) {
759                         Boolean required = graph.getPossibleRelatedValue(connectionRelation, sr.ConnectionRelation_connectionRequired, Bindings.BOOLEAN);
760                         if(required != null && required)
761                                 requiredConnections.add(connectionRelation);
762                 }
763                 
764                 Set<Resource> connections = new HashSet<Resource>();
765
766                 for(Statement stm : graph.getStatements(component, sr.IsConnectedTo)) {
767                         connections.add(stm.getPredicate());
768                         connections.addAll(graph.getSuperrelations(stm.getPredicate()));
769                 }
770
771                 for(Resource req : requiredConnections) {
772                         if(!connections.contains(req)) {
773                                 result.add(new StandardIssue(sr.ConnectionConstraint_ErrorIssue, component, req));
774                         }
775                 }
776
777                 return result;
778         
779     }
780
781     @SCLValue(type = "ReadGraph -> Resource -> Variable -> String")
782     public static String connectionIssueDescription(ReadGraph graph, Resource converter, Variable property) throws DatabaseException {
783         List<Resource> contexts = IssueUtils.getContextsForProperty(graph, property);
784         String attributeName = graph.getRelatedValue(contexts.get(1), Layer0.getInstance(graph).HasName);
785         return "'" + attributeName + "' should be connected.";
786     }
787
788     public static class InterfacePathMap extends VariableRead<GraphMap<Map<String,InterfaceResolution>>> {
789
790                 public InterfacePathMap(Variable context) {
791                         super(context);
792                 }
793
794                 @Override
795                 public GraphMap<Map<String,InterfaceResolution>> perform(ReadGraph graph) throws DatabaseException {
796
797                         return new GraphMap<Map<String,InterfaceResolution>>() {
798
799                                 @Override
800                                 Map<String, InterfaceResolution> get(ReadGraph graph, String key) throws DatabaseException {
801                                         
802                                         Variable child = variable.getChild(graph, key);
803                                         
804                                         Map<String,InterfaceResolution> childMap = new THashMap<String,InterfaceResolution>();
805                                         Collection<InterfaceResolution> paths = computeInterfacePaths(graph, child);//child.getPossiblePropertyValue(graph, "proceduralConnectionPointPath");
806                                         if(paths != null) {
807                                                 for(InterfaceResolution r : paths) {
808                                                         childMap.put(r.interfaceName, r);
809                                                 }
810                                         }
811                                         return childMap;
812
813                                 }
814                                 
815                         };
816                         
817                 }
818         
819     }
820     
821     public static String resolveInterfacePath(ReadGraph graph, Variable context, String component, Resource relation) throws DatabaseException {
822         
823         GraphMap<Map<String,InterfaceResolution>> map = graph.syncRequest(new InterfacePathMap(context), TransientCacheListener.<GraphMap<Map<String,InterfaceResolution>>>instance());
824         Map<String,InterfaceResolution> childMap = map.get(graph, component);
825         if(childMap == null) return "";
826
827         PropertyInfo info = graph.syncRequest(new PropertyInfoRequest(relation), TransientCacheListener.<PropertyInfo>instance());
828
829         InterfaceResolution match = childMap.get(info.name);
830         if(match != null) {
831                 String comp = URIStringUtils.escape(component);
832                 Variable newContext = context.getChild(graph, component);
833                 return "/" + comp + resolveInterfacePath(graph, newContext, match.componentName, match.connectionPoint);
834         } else {
835                 return "/" + URIStringUtils.escape(component) + "#" + URIStringUtils.escape(info.name); 
836         }
837                 
838     }
839     
840     public static class InterfaceResolution {
841         
842         public Resource interfaceConnectionPoint;
843         public String interfaceName;
844         public String componentName;
845         public Resource connectionPoint;
846         
847         public InterfaceResolution(Resource interfaceConnectionPoint, String interfaceName, String componentName, Resource connectionPoint) {
848                 this.interfaceConnectionPoint = interfaceConnectionPoint;
849                 this.interfaceName = interfaceName;
850                 this.componentName = componentName;
851                 this.connectionPoint = connectionPoint;
852         }
853         
854     }
855     
856     public static Collection<InterfaceResolution> computeInterfacePaths(ReadGraph graph, Variable variable) throws DatabaseException {
857
858                 StructuralResource2 STR = StructuralResource2.getInstance(graph);
859                 Resource type = variable.getPossibleType(graph);
860                 if(type != null) {
861                         if(graph.isInstanceOf(type, STR.ProceduralComponentType)) {
862                                 ArrayList<InterfaceResolution> result = new ArrayList<InterfaceResolution>();
863                                 List<SubstructureElement> elements = getProceduralDesc(graph, variable); 
864                                 if(elements != null) {
865                                         for(SubstructureElement e : elements) {
866                                                 if(e instanceof org.simantics.structural2.procedural.Connection) {
867                                                         org.simantics.structural2.procedural.Connection conn = (org.simantics.structural2.procedural.Connection)e;
868                                                         Interface inf = null;
869                                                         for(ConnectionPoint cp : conn.connectionPoints) {
870                                                                 if(cp instanceof Interface) {
871                                                                         if(inf != null) throw new DatabaseException("Multiple interfaces referenced in procedural connection.");
872                                                                         inf = (Interface)cp;
873                                                                 }
874                                                         }
875                                                         if(inf != null && conn.connectionPoints.size() > 1) {
876                                                                 Layer0 L0 = Layer0.getInstance(graph);
877                                                                 String cpName = URIStringUtils.escape( graph.<String>getRelatedValue(inf.relation, L0.HasName, Bindings.STRING) );
878                                                                 for(ConnectionPoint cp : conn.connectionPoints) {
879                                                                         if(cp == inf) continue;
880                                                                         Terminal t = (Terminal)cp;
881                                                                         result.add(new InterfaceResolution(inf.relation, cpName, t.component, t.relation));
882                                                                 }
883                                                         }
884                                                 }
885                                         }
886                                 }
887
888                                 return result;
889                                 
890                         }
891
892                         final Collection<InterfaceResolution> interfaces = graph.syncRequest(new DefinedUCInterfaceMap(type));
893                         if(interfaces != null) return interfaces;
894
895                 }
896                 
897                 return BUILTIN_STRUCTURAL_CPS;
898         
899     }
900     
901     static class InterfacePathRequest extends VariableRead<Collection<InterfaceResolution>> {
902
903                 public InterfacePathRequest(Variable variable) {
904                         super(variable);
905                 }
906                 
907                 @Override
908                 public Collection<InterfaceResolution> perform(ReadGraph graph) throws DatabaseException {
909                         return computeInterfacePaths(graph, variable);
910                 }
911         
912     }
913     
914     public static final Collection<InterfaceResolution> BUILTIN_STRUCTURAL_CPS = new ArrayList<InterfaceResolution>();
915
916         @SCLValue(type = "ReadGraph -> Resource -> Variable -> a")
917     public static Object computeExpression(ReadGraph graph, Resource converter, Variable context) throws DatabaseException {
918         return CompileStructuralValueRequest.compileAndEvaluate(graph, context);
919     }
920
921     public static Object computeExpressionInContext(ReadGraph graph, Variable context, final String expression) throws DatabaseException {
922         SCLContext sclContext = SCLContext.getCurrent();
923         Object oldGraph = sclContext.get("graph");
924         try {
925             Function1<Variable,Object> exp = graph.syncRequest(new CompileStructuralValueRequest(graph, context) {
926                 protected String getExpressionText(ReadGraph graph) throws DatabaseException {
927                     return expression;
928                 }
929             },
930             TransientCacheListener.<Function1<Variable,Object>>instance());
931             sclContext.put("graph", graph);
932             return exp.apply(context);
933         } catch (DatabaseException e) {
934             throw (DatabaseException)e;
935         } catch (Throwable t) {
936             throw new DatabaseException(t);
937         } finally {
938             sclContext.put("graph", oldGraph);
939         }
940     }    
941         
942         static abstract class InterfacePathProperty extends LazyPropertyVariable {
943                 
944                 public InterfacePathProperty(Variable parent) {
945                         super(parent, "proceduralConnectionPointPath", Bindings.STRING_ARRAY);
946                 }
947                 
948                 @Override
949                 public <T> T getValue(ReadGraph graph, Binding binding) throws DatabaseException {
950                         return getValue(graph);
951                 }
952                 
953         }
954         
955         static abstract class GraphMap<Value> {
956                 
957                 abstract Value get(ReadGraph graph, String key) throws DatabaseException;
958                 
959         }
960     
961 }