]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.structural2/src/org/simantics/structural2/variables/ConnectionBrowser.java
Work in progress
[simantics/platform.git] / bundles / org.simantics.structural2 / src / org / simantics / structural2 / variables / ConnectionBrowser.java
1 package org.simantics.structural2.variables;
2
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.Collections;
6 import java.util.HashMap;
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.db.ReadGraph;
14 import org.simantics.db.Resource;
15 import org.simantics.db.Statement;
16 import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener;
17 import org.simantics.db.common.request.BinaryRead;
18 import org.simantics.db.common.request.ResourceRead;
19 import org.simantics.db.common.request.TransientUnaryRead;
20 import org.simantics.db.common.utils.CommonDBUtils;
21 import org.simantics.db.common.utils.NameUtils;
22 import org.simantics.db.exception.DatabaseException;
23 import org.simantics.db.exception.NoSingleResultException;
24 import org.simantics.db.layer0.exception.MissingVariableException;
25 import org.simantics.db.layer0.exception.MissingVariableValueException;
26 import org.simantics.db.layer0.request.VariableRead;
27 import org.simantics.db.layer0.variable.Variable;
28 import org.simantics.db.service.CollectionSupport;
29 import org.simantics.db.service.QueryControl;
30 import org.simantics.layer0.Layer0;
31 import org.simantics.modeling.ModelingResources;
32 import org.simantics.structural.stubs.StructuralResource2;
33 import org.simantics.structural2.Functions;
34 import org.simantics.structural2.Functions.InterfaceResolution;
35 import org.simantics.structural2.queries.ConnectionSet;
36 import org.simantics.structural2.utils.StructuralUtils;
37 import org.simantics.structural2.utils.StructuralUtils.StructuralComponentClass;
38 import org.simantics.structural2.variables.StandardProceduralChildVariable.FixedConnection;
39 import org.simantics.utils.datastructures.Pair;
40
41 import gnu.trove.map.hash.THashMap;
42 import gnu.trove.set.hash.THashSet;
43
44 public class ConnectionBrowser {
45
46     /**
47      * Finds the components connected by the connection. Also connections
48      * in 
49      * 
50      * @param graph 
51      * @param connection A connection whose related modules are searched.
52      * @param configuration A variable that represents the composite where the connection belongs to.
53      * @return A map whose keys are components and they are mapped to 
54      *         related variables.
55      */
56     public static Collection<ResourceWithContext> findConnectedComponents(
57             ReadGraph graph, Resource connection, Variable configuration) 
58             throws DatabaseException {
59         // Create state
60         ArrayList<ResourceWithContext> result = 
61             new ArrayList<ResourceWithContext>();
62         THashSet<Resource> visitedConnections = new THashSet<Resource>();
63
64         // Do actual work
65         findConnectedComponents(graph, connection, configuration, result,
66                 visitedConnections);
67         return result;
68     }
69
70     private static void findConnectedComponents(
71             ReadGraph graph, Resource connection, Variable configuration,
72             ArrayList<ResourceWithContext> result,
73             THashSet<Resource> visitedConnections) throws DatabaseException {
74          if(visitedConnections.add(connection)) {
75              StructuralResource2 STR = StructuralResource2.getInstance(graph);
76              Layer0 L0 = Layer0.getInstance(graph);
77
78              // Browse related components
79              for(Statement stat : graph.getStatements(connection, STR.Connects)) {
80                  Resource component = stat.getObject();
81                  Resource relation = graph.getInverse(stat.getPredicate());
82                  //System.out.println(NameUtils.getSafeName(graph, component) + "." + NameUtils.getSafeName(graph, relation));
83                  Resource boundConnection = graph.getPossibleObject(relation, STR.IsBoundBy);
84                  Resource type = StructuralUtils.getComponentType(graph, configuration, component);
85                  //
86                  //Resource type = StructuralUtils.getComponentType(graph, configuration, component);
87                  //Resource type = newContext != null ? newContext.getPossibleType(graph) : graph.getPossibleObject(component, L0.InstanceOf); 
88                  Resource def = type != null ? graph.getPossibleObject(type, STR.IsDefinedBy) : null;
89                  if(boundConnection != null && def != null) {
90                      // The connection point is bound in component type
91                      Variable newContext = configuration.browsePossible(graph, component);
92                      Resource newComposite = getCompositeOfConnection(graph, boundConnection);
93                      if(newContext != null && newComposite != null) {
94                          newContext = browse(graph, def, newContext, newComposite);
95                          if (newContext != null)
96                              findConnectedComponents(graph, boundConnection,
97                                      newContext,
98                                      result, visitedConnections);
99                      }
100                  }
101                  else {
102                      //System.out.println("added result");
103                      // A primitive connection point
104                      Variable context = configuration.browsePossible(graph, component);
105                      if (context != null)
106                          result.add(new ResourceWithContext(component, context)); 
107                  }
108              }
109
110              // Browse over connection joins
111              for(Resource join : graph.getObjects(connection, STR.IsJoinedBy))
112                  for(Resource otherConnection : graph.getObjects(join, STR.Joins))
113                      if(!connection.equals(otherConnection)) {
114                          Resource sourceComposite = getCompositeOfConnection(graph, connection);
115                          Resource targetComposite = getCompositeOfConnection(graph, otherConnection);
116                          if (sourceComposite != null && targetComposite != null) {
117                              Variable sibling = browseSibling(graph, 
118                                      sourceComposite,
119                                      configuration,
120                                      targetComposite);
121                              if (sibling != null)
122                                  findConnectedComponents(graph, otherConnection,
123                                          sibling, result, visitedConnections);
124                          }
125                      }
126
127              // Browse to parents
128              try {
129                  for(Resource relation : graph.getObjects(connection, STR.Binds)) {
130                      Resource composite = getCompositeOfConnection(graph, connection);
131                      if (composite == null)
132                          continue;
133
134                      Variable curConfiguration = configuration;
135                      while(!graph.hasStatement(composite, STR.Defines)) {
136                          composite = graph.getSingleObject(composite, L0.PartOf);
137                          curConfiguration = curConfiguration.getParent(graph);
138                      }
139                      Variable parent = curConfiguration.getParent(graph);
140                      Resource component = curConfiguration.getRepresents(graph);
141                      for(Resource c : graph.getObjects(component, relation))
142                          findConnectedComponents(graph, c, 
143                                  parent, result, visitedConnections);
144                  }
145              } catch(NoSingleResultException e) {
146              } catch(MissingVariableException e) {
147              } catch(MissingVariableValueException e) {
148              }
149          }
150     }
151
152     public static Collection<VariableConnectionPointDescriptor> drill(ReadGraph graph, VariableConnectionPointDescriptor pair) throws DatabaseException {
153
154         Collection<InterfaceResolution> interfaceDescription = pair.getInterfaceDescription(graph);
155         if(interfaceDescription != null && interfaceDescription.size() > 0) {
156
157                 Variable cp = pair.getVariable(graph);
158                 Variable context = cp.getParent(graph);
159                 String cpName = cp.getName(graph);
160
161                 Collection<VariableConnectionPointDescriptor> result = new ArrayList<VariableConnectionPointDescriptor>();
162                 for(InterfaceResolution r : interfaceDescription) {
163                         if(r.interfaceName.equals(cpName)) {
164                                 String path = Functions.resolveInterfacePath(graph, context, r.componentName, r.connectionPoint);
165                                 result.add(new BrowseConnectionDescriptor(context, path));
166                         }
167                 }
168                 
169                 if(result.isEmpty()) return null;
170                 
171                 return result;
172                 
173         } else {
174                 return Collections.singleton(pair);
175         }
176
177     }
178     
179     public static class JoinConnections extends ResourceRead<Collection<Resource>> {
180
181                 public JoinConnections(Resource join) {
182                         super(join);
183                 }
184
185                 @Override
186                 public Collection<Resource> perform(ReadGraph graph) throws DatabaseException {
187                 ConnectionSet cs = new ConnectionSet(graph);
188                 cs.addJoin(graph, resource);
189                 return cs.getConnections();
190                 }
191         
192     }
193
194     
195     public static final class VariableChildren extends TransientUnaryRead<Variable, Map<Resource,Variable>> {
196
197                 public VariableChildren(ReadGraph graph, Variable variable) throws DatabaseException {
198                         super(graph, variable);
199                 }
200
201                 public VariableChildren(ReadGraph graph, QueryControl qc, Variable variable) throws DatabaseException {
202                         super(graph, qc, variable);
203                 }
204
205                 @Override
206                 public Map<Resource, Variable> perform(ReadGraph graph, Variable parameter) throws DatabaseException {
207                         CollectionSupport cs = graph.getService(CollectionSupport.class);
208                         Map<Resource,Variable> result = cs.createMap(Variable.class);
209                         for(Variable child : parameter.getChildren(graph)) {
210                                 Resource represents = child.getPossibleRepresents(graph);
211                                 if(represents != null) result.put(represents, child);
212                         }
213                         return result;
214                 }
215         
216     }
217     
218     static Variable resolve(ReadGraph graph, Variable base, Resource component) throws DatabaseException {
219         Map<Resource,Variable> map = graph.syncRequest(new VariableChildren(graph, base), TransientCacheAsyncListener.<Map<Resource,Variable>>instance());
220         Variable result = map.get(component);
221         if(result != null) return result;
222         else {
223                 Layer0 L0 = Layer0.getInstance(graph);
224                 Resource parent = graph.getPossibleObject(component, L0.PartOf);
225                 if(parent == null) return null;
226                 Variable v = resolve(graph, base, parent);
227                 if (v == null) return null;
228                 map = graph.syncRequest(new VariableChildren(graph, v), TransientCacheAsyncListener.<Map<Resource,Variable>>instance());
229                 return map.get(component);
230         }
231     }
232     
233     public static class ConnectionComponentsWithAncestor extends TransientUnaryRead<Resource, List<Resource>> {
234
235         final private List<Resource> result;
236
237                 public ConnectionComponentsWithAncestor(ReadGraph graph, Resource conn) throws DatabaseException {
238                         this(graph, conn, null);
239                 }
240
241         public ConnectionComponentsWithAncestor(ReadGraph graph, QueryControl qc, Resource conn, List<Resource> result) throws DatabaseException {
242                         super(graph, qc, conn);
243                         this.result = result;
244         }
245
246                 public ConnectionComponentsWithAncestor(ReadGraph graph, Resource conn, List<Resource> result) throws DatabaseException {
247                         super(graph, conn);
248                         this.result = result;
249                 }
250
251                 private ConnectionSet connSet(ReadGraph graph, Resource r ) throws DatabaseException {
252                         ConnectionSet cs = new ConnectionSet(graph);
253                         cs.addConnection(graph, r);
254                         return cs;
255                 }
256                 
257                 @Override
258                 public List<Resource> perform(ReadGraph graph, Resource resource) throws DatabaseException {
259                         
260                         if(result != null) return result;
261                         
262                         Layer0 L0 = Layer0.getInstance(graph);
263                         StructuralResource2 STR = StructuralResource2.getInstance(graph);
264                         CollectionSupport colls = graph.getService(CollectionSupport.class);
265                         THashSet<Resource> ancestorGenerators = new THashSet<Resource>();
266                         Set<Resource> parts = colls.createSet();
267                         ConnectionSet cs = connSet(graph, resource);
268             for(Resource connRes : cs.getConnections()) {
269                 for(Statement stm : graph.getStatements(connRes, STR.Connects)) {
270                         Resource component = stm.getObject();
271                         Resource parent = graph.getPossibleObject(component, L0.PartOf);
272                         if(parent != null && !graph.isInstanceOf(component, ModelingResources.getInstance(graph).ReferenceElement))
273                                 ancestorGenerators.add(parent);
274                 }
275                 parts.add(connRes);
276             }
277             for (Resource join : cs.getJoins()) {
278                 parts.add(join);
279                 for (Resource composite : graph.getObjects(join, STR.JoinsComposite))
280                         ancestorGenerators.add(composite);
281             }
282             Resource ancestor = ancestorGenerators.size() == 1 ? ancestorGenerators.iterator().next() : CommonDBUtils.getNearestOwner(graph, ancestorGenerators);
283             
284             List<Resource> result = colls.createList();
285             result.add(ancestor);
286             result.addAll(colls.asSortedList(parts));
287             
288             if(parameter != WITH_PARENT) {
289                 for(int i=1;i<result.size();i++) {
290                         Resource r = result.get(i);
291                         // Cache 'em all
292                         if(!r.equals(resource))
293                                 graph.syncRequest(new ConnectionComponentsWithAncestor(graph, r, result), TransientCacheAsyncListener.<List<Resource>>instance());
294                     }
295             }
296             
297             return result;
298             
299                 }
300         
301     }
302     
303     public static Collection<VariableConnectionPointDescriptor> climb(ReadGraph graph, Variable child, Resource cp, String subPath_) throws DatabaseException {
304         
305         boolean isStructural = false;
306
307         Variable curConfiguration = child.getParent(graph);
308
309         {
310
311                         Collection<InterfaceResolution> interfaceDescription = Functions.computeInterfacePaths(graph, curConfiguration);
312                 if(interfaceDescription != null) {
313                         isStructural = interfaceDescription != Functions.BUILTIN_STRUCTURAL_CPS;
314                         if(interfaceDescription.size() > 0) {
315                                 
316                                 if(subPath_ == null) {
317                                         
318                                         String childName = child.getName(graph);
319                                         for(InterfaceResolution r : interfaceDescription) {
320                                                 if(r.componentName.equals(childName) && r.connectionPoint.equals(cp)) {
321                                                         Variable pConn = curConfiguration.getPossibleProperty(graph, r.interfaceName);
322                                                         if(pConn != null) {
323                                                                 Resource cp2 = pConn.getPossiblePredicateResource(graph);
324                                                                 Collection<VariableConnectionPointDescriptor> res = climb(graph, curConfiguration, cp2, null);
325                                                                 if(res != null) return res;
326                                                         }
327                                                         return Collections.emptyList();
328                                                 }
329                                         }
330
331                                 } else {
332                                         throw new UnsupportedOperationException("");
333                                 }
334                         }
335                 }
336
337         }
338         
339         if(child instanceof StandardProceduralChildVariable) {
340                 
341                 Variable conn = child.getPossibleProperty(graph, cp);
342             FixedConnection fc = (FixedConnection)conn.getValue(graph);
343             Set<VariableConnectionPointDescriptor> result = new THashSet<VariableConnectionPointDescriptor>(1+fc.cps.size());
344             result.add(new ComponentConnectionDescriptor(child, cp));// (graph, STR, curConfiguration, "/" + c.name + "#" + conn.getName(graph)));
345             for(Pair<String,Resource> cpzz : fc.cps) {
346                 if(cpzz.first == null) {
347                         throw new DatabaseException("Lifted connection was not resolved.");
348                 }
349                 result.add(new PairConnectionDescriptor(curConfiguration, cpzz));
350             }
351             return result;
352             
353         } else {
354
355             Resource res = cp;
356             Resource represents = child.getRepresents(graph);
357
358                 if(isStructural) {
359
360                         Collection<Resource> conns = graph.getObjects(represents, res);
361                         HashSet<VariableConnectionPointDescriptor> result = new HashSet<VariableConnectionPointDescriptor>();
362                         for(Resource c : conns) {
363                                 List<Resource> rs = graph.syncRequest(new ConnectionComponentsWithAncestor(graph, c), TransientCacheAsyncListener.<List<Resource>>instance()); 
364                         for(Resource r : rs) {
365                                 System.err.println("--connections " + NameUtils.getSafeName(graph, r));
366                         }
367                                 result.addAll(graph.syncRequest(ConnectionVariables.forStructural(graph, curConfiguration, rs)));
368                                 for(VariableConnectionPointDescriptor desc2 : result) {
369                                         reportDescriptor(graph, desc2);
370                                 }
371                         }
372                         return result;
373                         
374                 } else {
375
376                 Resource connection = graph.getPossibleObject(represents, res);
377                 if(connection != null) {
378                         List<Resource> rs = graph.syncRequest(new ConnectionComponentsWithAncestor(graph, connection), TransientCacheAsyncListener.<List<Resource>>instance());
379                         for(Resource r : rs) {
380                                 System.err.println("--connections " + NameUtils.getSafeName(graph, r));
381                         }
382                         return graph.syncRequest(ConnectionVariables.forConfiguration(graph, curConfiguration, rs));
383                 }
384                 else {
385                         Collection<Resource> conns = graph.getObjects(represents, res);
386                         HashSet<VariableConnectionPointDescriptor> result = new HashSet<VariableConnectionPointDescriptor>();
387                         for(Resource c : conns) {
388                                 List<Resource> rs = graph.syncRequest(new ConnectionComponentsWithAncestor(graph, c), TransientCacheAsyncListener.<List<Resource>>instance()); 
389                                 result.addAll(graph.syncRequest(ConnectionVariables.forConfiguration(graph, curConfiguration, rs)));
390                         }
391                         return result;
392                 }
393                         
394                 }
395                 
396         }
397         
398     }
399     
400     public static void reportDescriptor(ReadGraph graph, VariableConnectionPointDescriptor d) throws DatabaseException {
401
402         if(d instanceof ActualConnectionDescriptor) {
403                 ActualConnectionDescriptor d2 = (ActualConnectionDescriptor)d; 
404                 
405                 System.err.println("--ActualConnectionPointDescriptor2");
406                 System.err.println("---root: " + d2.root.getURI(graph));
407                 System.err.println("---component: " + graph.getPossibleURI(d2.component));
408                 System.err.println("---type: " + graph.getPossibleURI(d2.componentType));
409                 System.err.println("---cp: " + graph.getPossibleURI(d2.cp));
410                 System.err.println("---var: " + d2.getVariable(graph).getURI(graph));
411         }
412         
413     }
414     
415     public static class ConnectionVariables extends BinaryRead<Variable, List<Resource>, Collection<VariableConnectionPointDescriptor>> {
416
417         private ConnectionVariables(Variable parameter1, List<Resource> parameter2) {
418                         super(parameter1, parameter2);
419                 }
420
421                 public static ConnectionVariables forConfiguration(ReadGraph graph, Variable configuration, List<Resource> rs) throws DatabaseException {
422                         return new ConnectionVariables(parent(graph, configuration, rs.get(0)), rs);
423                 }
424
425                 public static ConnectionVariables forStructural(ReadGraph graph, Variable configuration, List<Resource> rs) throws DatabaseException {
426                         return new ConnectionVariables(configuration, rs);
427                 }
428
429                 /**
430                  * Finds the parent variable of <code>configuration</code> that
431                  * represents <code>ancestor</code>.
432                  * 
433                  * @param graph
434                  * @param configuration
435                  * @param ancestor
436                  * @return
437                  * @throws DatabaseException if no parent was found that represents ancestor
438                  */
439                 private static Variable parent(ReadGraph graph, Variable configuration, Resource ancestor) throws DatabaseException {
440                 Variable v = configuration;
441                 Resource represents = v.getRepresents(graph);
442                 while(!represents.equals(ancestor)) {
443                         v = v.getParent(graph);
444                         if (v == null) {
445                                         throw new DatabaseException(
446                                                         "parent representing ancestor not found for variable, configuration="
447                                                                         + safeURI(graph, configuration)
448                                                                         + ", ancestor="
449                                                                         + NameUtils.getURIOrSafeNameInternal(graph, ancestor));
450                         }
451                         represents = v.getRepresents(graph);
452                 }
453                 return v;
454                 }
455
456                 @Override
457                 public Collection<VariableConnectionPointDescriptor> perform(ReadGraph graph) throws DatabaseException {
458                         if(parameter == null) return Collections.emptyList();
459                         System.err.println("ConnectionVariables " + parameter.getURI(graph));
460                         StructuralResource2 STR = StructuralResource2.getInstance(graph);
461             ArrayList<VariableConnectionPointDescriptor> result = null;
462             for(int i=1;i<parameter2.size();i++) {
463                 Resource connRes = parameter2.get(i);
464                 for(Statement stm : graph.getStatements(connRes, STR.Connects)) {
465                         Layer0 L0 = Layer0.getInstance(graph);
466                         Resource component = stm.getObject();
467                         Resource connectionPoint = graph.getInverse(stm.getPredicate());
468                         if(result == null) result = new ArrayList<VariableConnectionPointDescriptor>();
469                         String componentName = graph.getRelatedValue(component, L0.HasName, Bindings.STRING);
470                         if(parameter.getURI(graph).endsWith("SelectionView/Instance") && componentName.equals("Explorer1"))
471                                 System.err.println("asd");
472                         Variable possibleChild = parameter.getPossibleChild(graph, componentName);
473                         if(possibleChild != null) {
474                                 result.add(new ActualConnectionDescriptor(parameter, component, possibleChild.getType(graph), connectionPoint));
475                         } else {
476                                 throw new DatabaseException("No child with name " + componentName + " could be resolved for variable " + parameter.getURI(graph));
477                         }
478                 }
479             }
480             if(result == null) return Collections.emptyList();
481             return result;
482                 }
483         
484     }
485     
486     static class IsLeafType extends ResourceRead<Boolean> {
487
488                 protected IsLeafType(Resource type) {
489                         super(type);
490                 }
491
492                 @Override
493                 public Boolean perform(ReadGraph graph) throws DatabaseException {
494                         
495                         StructuralComponentClass clazz = StructuralComponentClass.get(graph, resource);
496                         return StructuralComponentClass.PRIMITIVE.equals(clazz);
497
498                 }
499         
500     }
501     
502     static class ChildMapOfVariable extends VariableRead<Map<Resource,Variable>> {
503
504                 public ChildMapOfVariable(Variable variable) {
505                         super(variable);
506                 }
507
508                 @Override
509                 public Map<Resource, Variable> perform(ReadGraph graph) throws DatabaseException {
510                         HashMap<Resource,Variable> result = new HashMap<Resource,Variable>();
511                         for(Variable child : variable.getChildren(graph)) {
512                                 Resource represents = child.getPossibleRepresents(graph);
513                                 if(represents != null) result.put(represents, child);
514                         }
515                         return result;
516                 }
517         
518     }
519
520     /**
521      * Given a root composite, related variable and some other component inside the composite,
522      * finds the related variable for that component.
523      */
524     public static Variable browse(ReadGraph graph, Resource root, Variable rootContext, Resource target) throws DatabaseException {
525         if(target.equals(root))
526             return rootContext;
527         else {
528             Layer0 L0 = Layer0.getInstance(graph);
529             String name = (String)graph.getPossibleRelatedValue(target, L0.HasName, Bindings.STRING);
530             Resource parent = graph.getPossibleObject(target, L0.PartOf);
531             if(name == null || parent == null)
532                 return null;
533             Variable parentVariable = browse(graph, root, rootContext, parent);
534             if(parentVariable == null)
535                 return null;
536             return parentVariable.getPossibleChild(graph, name);
537         }
538     }
539
540     /**
541      * Finds a variable whose location related to sourceContext is the same as 
542      * between target and source. In other words, the method solves {@code targetContext}
543      * in the following equations:
544      * <pre>
545      *     URI(source)        = resourceURIBase + sourceSuffix
546      *     URI(sourceContext) = variableURIBase + sourceSuffix
547      *     URI(target)        = resourceURIBase + targetSuffix
548      *     URI(targetContext) = variableURIBase + targetSuffix
549      * </pre>
550      */
551     public static Variable browseSibling(ReadGraph graph, Resource source, Variable sourceContext, Resource target) throws DatabaseException {
552         Layer0 L0 = Layer0.getInstance(graph);
553         THashMap<Resource, Variable> sourceMap = new THashMap<Resource, Variable>();
554         while(source != null && sourceContext != null) {
555             sourceMap.put(source, sourceContext);
556             source = graph.getPossibleObject(source, L0.PartOf);
557             sourceContext = sourceContext.getParent(graph);
558         }
559         return browseSibling(graph, sourceMap, target);
560     }
561
562     private static Variable browseSibling(ReadGraph graph, THashMap<Resource, Variable> sourceMap, Resource target) throws DatabaseException {
563         Layer0 L0 = Layer0.getInstance(graph);
564         Variable result = sourceMap.get(target);
565         if(result != null)
566             return result;
567         String name = (String)graph.getPossibleRelatedValue(target, L0.HasName, Bindings.STRING);
568         Resource parent = graph.getPossibleObject(target, L0.PartOf);
569         if(name == null || parent == null)
570             return null;
571         Variable parentVariable = browseSibling(graph, sourceMap, parent);
572         if(parentVariable == null)
573             return null;
574         return parentVariable.getPossibleChild(graph, name);
575     }
576
577     /**
578      * Returns the composite where the connection given as a parameter resides.
579      */
580     public static Resource getCompositeOfConnection(ReadGraph graph, Resource connection) throws DatabaseException {
581         Layer0 L0 = Layer0.getInstance(graph);
582         StructuralResource2 STR = StructuralResource2.getInstance(graph);
583         // First from connected components
584         for(Resource component : graph.getObjects(connection, STR.Connects))
585             for(Resource composite : graph.getObjects(component, L0.PartOf))
586                 return composite;
587         // It could be that the connection is only supported by joins (input flag -> output flag) - use diagram info TODO!!
588         Resource connToDiagramConn = graph.getPossibleResource("http://www.simantics.org/Modeling-1.2/ConnectionToDiagramConnection");
589         if(connToDiagramConn != null) {
590             Resource diagramConnection = graph.getPossibleObject(connection, connToDiagramConn);
591             if(diagramConnection != null) {
592                 Resource diagram = graph.getPossibleObject(diagramConnection, L0.PartOf);
593                 if(diagram != null) {
594                     Resource diagramToComposite = graph.getPossibleResource("http://www.simantics.org/Modeling-1.2/DiagramToComposite");
595                     if(diagramToComposite != null) {
596                         return graph.getPossibleObject(diagram, diagramToComposite);
597                     }
598                 }
599             }
600         }
601         return null;
602     }
603     
604         static class Flatten extends BinaryRead<Variable,Resource,Collection<VariableConnectionPointDescriptor>> {
605
606                 public Flatten(Variable parameter1,
607                                 Resource parameter2) {
608                         super(parameter1, parameter2);
609                 }
610
611                 @Override
612                 public Collection<VariableConnectionPointDescriptor> perform(ReadGraph graph)
613                                 throws DatabaseException {
614                         return doFlatten(graph, parameter, parameter2, null);
615                 }
616                 
617         }
618     
619     public static Collection<VariableConnectionPointDescriptor> flatten(ReadGraph graph, Variable child, Resource cp, Resource relationType) throws DatabaseException {
620
621         if(relationType == null) return graph.syncRequest(new Flatten(child, cp));
622
623         return doFlatten(graph, child, cp, relationType);
624
625     }
626
627         public static Collection<VariableConnectionPointDescriptor> doFlatten(ReadGraph graph, Variable child, Resource cp, Resource relationType) throws DatabaseException {
628         
629         Set<VariableConnectionPointDescriptor> result = null;
630         Set<VariableConnectionPointDescriptor> needDrill = null;
631
632         String debug = child.getURI(graph) + " " + NameUtils.getSafeLabel(graph, cp);
633                 System.err.println("doFlatten " + debug);
634         
635         if(debug.endsWith("01/TreeTable01 parent"))
636                 System.err.println("asd");
637         
638                 Collection<VariableConnectionPointDescriptor> climbed = climb(graph, child, cp, null);
639         for(VariableConnectionPointDescriptor desc : climbed) {
640                 if(!desc.isLeaf(graph)) {
641                         if(needDrill == null)
642                                 needDrill = new THashSet<VariableConnectionPointDescriptor>(climbed.size());
643                         needDrill.add(desc);
644                 } else {
645                         if(result == null)
646                                 result = new THashSet<VariableConnectionPointDescriptor>(climbed.size());
647                         result.add(desc);
648                 }
649         }
650         
651         if(needDrill == null) {
652                 /*
653                  * All descriptors were already flat - just take case of filtering
654                  */
655             if(relationType != null) {
656                 ArrayList<VariableConnectionPointDescriptor> filtered = new ArrayList<VariableConnectionPointDescriptor>(climbed.size());
657                 for(VariableConnectionPointDescriptor desc : climbed)
658                     if(filterByRelationType(graph, desc, relationType))
659                         filtered.add(desc);
660                 return filtered;
661             } else {
662                 return climbed;
663             }
664         }
665         
666
667         /*
668          * There were some descriptors that require drill
669          */
670         for(VariableConnectionPointDescriptor top : needDrill) {
671                 
672                 if(debug.endsWith("01/TreeTable01 parent"))
673                         System.err.println("asd");
674
675                 Collection<VariableConnectionPointDescriptor> drilled = drill(graph, top);
676             if(drilled != null) {
677                 for(VariableConnectionPointDescriptor drill : drilled) {
678                         if(relationType != null) {
679                                 if(!filterByRelationType(graph, drill, relationType))
680                                         continue;
681                         }
682                         if(result == null)
683                                 result = new THashSet<VariableConnectionPointDescriptor>(climbed.size());
684                         result.add(drill);
685                 }
686             }
687         }
688
689                 System.err.println("doFlatten finished: " + debug);
690
691         if(debug.endsWith("01/TreeTable01 parent"))
692                 System.err.println("asd");
693
694                 for(VariableConnectionPointDescriptor desc2 : result) {
695                         reportDescriptor(graph, desc2);
696                 }
697         
698         return result;
699         
700     }
701     
702     private static boolean filterByRelationType(ReadGraph graph, VariableConnectionPointDescriptor desc, Resource relationType) throws DatabaseException {
703         Resource predicateResource = desc.getConnectionPointResource(graph);
704         return predicateResource != null && graph.isInstanceOf(predicateResource, relationType);
705     }
706
707     private static String safeURI(ReadGraph graph, Variable v) {
708         if (v == null)
709             return "null variable";
710         try {
711             return v.getURI(graph);
712         } catch (DatabaseException e) {
713             return v.toString();
714         }
715     }
716 }