]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.diagram/src/org/simantics/diagram/adapter/DiagramContentRequest.java
Multiple reader thread support for db client
[simantics/platform.git] / bundles / org.simantics.diagram / src / org / simantics / diagram / adapter / DiagramContentRequest.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2018 Association for Decentralized Information Management
3  * in Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.diagram.adapter;
13
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.Set;
17 import java.util.concurrent.atomic.AtomicInteger;
18
19 import org.simantics.db.ReadGraph;
20 import org.simantics.db.Resource;
21 import org.simantics.db.common.procedure.adapter.ProcedureAdapter;
22 import org.simantics.db.common.utils.OrderedSetUtils;
23 import org.simantics.db.exception.DatabaseException;
24 import org.simantics.db.request.AsyncRead;
25 import org.simantics.diagram.content.ConnectionPartData;
26 import org.simantics.diagram.content.ConnectionPartRequest;
27 import org.simantics.diagram.content.DiagramContents;
28 import org.simantics.diagram.content.EdgeResource;
29 import org.simantics.diagram.content.RouteGraphConnectionPartData;
30 import org.simantics.diagram.content.RouteGraphConnectionPartRequest;
31 import org.simantics.diagram.stubs.DiagramResource;
32 import org.simantics.diagram.synchronization.ErrorHandler;
33 import org.simantics.g2d.canvas.ICanvasContext;
34
35 import gnu.trove.list.array.TIntArrayList;
36 import gnu.trove.map.hash.THashMap;
37 import gnu.trove.procedure.TIntProcedure;
38 import gnu.trove.set.hash.THashSet;
39
40 /**
41  * @author Tuukka Lehtonen
42  */
43 public class DiagramContentRequest extends BaseRequest<Resource, DiagramContents> {
44
45     int previousElementCount = 32;
46     ErrorHandler errorHandler;
47
48     public DiagramContentRequest(ICanvasContext canvas, Resource resource, ErrorHandler errorHandler) {
49         super(canvas, resource);
50         this.errorHandler = errorHandler;
51     }
52
53     @Override
54     public DiagramContents perform(ReadGraph g) throws DatabaseException {
55
56         final DiagramResource DIA = DiagramResource.getInstance(g);
57
58         // These help loading result.elements in the correct order.
59         final AtomicInteger index = new AtomicInteger();
60         final TIntArrayList unrecognizedElementIndices = new TIntArrayList();
61
62         Collection<Resource> components = OrderedSetUtils.toList(g, data);
63         DiagramContents res = g.syncRequest((AsyncRead<DiagramContents>)(graph, procedure) -> {
64
65             DiagramContents result = new DiagramContents();
66             procedure.execute(graph, result);
67
68             result.elements =   new ArrayList<Resource>(previousElementCount);
69             result.nodeSet = new THashSet<Resource>();
70             result.connectionSet = new THashSet<Resource>();
71             result.connectionSegments = new THashSet<EdgeResource>();
72             result.branchPoints = new THashSet<Resource>();
73             result.routeGraphConnectionSet = new THashSet<Resource>();
74             result.routeLinks = new THashSet<EdgeResource>();
75             result.routeLines = new THashSet<Resource>();
76             result.routePoints = new THashSet<Resource>();
77
78             result.partToConnection = new THashMap<Object, Resource>();
79
80             for (Resource component : components) {
81
82                 // Must add the elements to the result set here in order to
83                 // keep their order the same as in the ordered set.
84                 final int elementIndex = index.getAndIncrement();
85                 result.elements.add(component);
86
87                 graph.forTypes(component, new ProcedureAdapter<Set<Resource>>() {
88
89                     @Override
90                     public void execute(Set<Resource> types) {
91
92                         if (types.contains(DIA.Connection)) {
93                             if (types.contains(DIA.RouteGraphConnection)) {
94                                 graph.asyncRequest(
95                                         new RouteGraphConnectionPartRequest(errorHandler, DIA, component),
96                                         new ProcedureAdapter<RouteGraphConnectionPartData>() {
97                                             @Override
98                                             public void execute(RouteGraphConnectionPartData partData) {
99                                                 synchronized (result) {
100                                                     for (EdgeResource link : partData.links) {
101                                                         result.routeLinks.add(link);
102                                                         result.partToConnection.put(link, component);
103                                                         result.connectionToParts.add(component, link);
104                                                     }
105                                                     for (Resource line : partData.routeLines) {
106                                                         result.routeLines.add(line);
107                                                         result.connectionToParts.add(component, line);
108                                                         result.partToConnection.put(line, component);
109                                                     }
110                                                     for (Resource point : partData.routePoints) {
111                                                         result.routePoints.add(point);
112                                                         result.connectionToParts.add(component, point);
113                                                         result.partToConnection.put(point, component);
114                                                     }
115                                                 }
116                                             }
117                                         });
118
119                                 synchronized (result.routeGraphConnectionSet) {
120                                     result.routeGraphConnectionSet.add(component);
121                                 }
122                             } else {
123                                 graph.asyncRequest(
124                                         new ConnectionPartRequest(errorHandler, DIA, component),
125                                         new ProcedureAdapter<ConnectionPartData>() {
126                                             @Override
127                                             public void execute(ConnectionPartData partData) {
128                                                 synchronized (result) {
129                                                     for (EdgeResource er : partData.edges) {
130                                                         result.connectionSegments.add(er);
131                                                         result.partToConnection.put(er, component);
132                                                         result.connectionToParts.add(component, er);
133                                                     }
134                                                     for (Resource bp : partData.branchPoints) {
135                                                         result.branchPoints.add(bp);
136                                                         result.connectionToParts.add(component, bp);
137                                                         result.partToConnection.put(bp, component);
138                                                     }
139                                                 }
140                                             }
141                                         });
142
143                                 synchronized (result.connectionSet) {
144                                     result.connectionSet.add(component);
145                                 }
146                             }
147                         }
148                         else if (types.contains(DIA.Element)) {
149                             synchronized (result.nodeSet) {
150                                 result.nodeSet.add(component);
151                             }
152                         }
153                         else {
154                             synchronized (unrecognizedElementIndices) {
155                                 // Unrecognized element, mark it to be
156                                 // removed after everything is processed.
157                                 unrecognizedElementIndices.add(elementIndex);
158                             }
159                         }
160                     }
161                 });
162             }
163         });
164
165         // Remove elements that were not recognized in descending order.
166         unrecognizedElementIndices.sort();
167         unrecognizedElementIndices.forEachDescending(new TIntProcedure() {
168             @Override
169             public boolean execute(int index) {
170                 res.elements.remove(index);
171                 return true;
172             }
173         });
174
175         // Help successive request executions by remembering the previous
176         // element count. This will relieve some ArrayList reallocation
177         // strain down the road.
178         previousElementCount = res.elements.size();
179
180         return res;
181     }
182 }