1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package org.modeshape.connector.store.jpa.model.basic;
25
26 import java.util.HashMap;
27 import java.util.LinkedList;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.UUID;
31 import javax.persistence.EntityManager;
32 import javax.persistence.NoResultException;
33 import javax.persistence.Query;
34 import org.modeshape.graph.ExecutionContext;
35 import org.modeshape.graph.Location;
36 import org.modeshape.graph.property.Name;
37 import org.modeshape.graph.property.NameFactory;
38 import org.modeshape.graph.property.Path;
39 import org.modeshape.graph.property.PathFactory;
40
41
42
43
44
45
46
47
48
49
50
51 public class SubgraphQuery {
52
53
54
55
56
57
58
59
60
61
62
63
64 public static SubgraphQuery create( ExecutionContext context,
65 EntityManager entities,
66 Long workspaceId,
67 UUID subgraphRootUuid,
68 Path subgraphRootPath,
69 int maxDepth ) {
70 assert entities != null;
71 assert subgraphRootUuid != null;
72 assert workspaceId != null;
73 assert maxDepth >= 0;
74
75 if (maxDepth == 0) maxDepth = Integer.MAX_VALUE;
76 final String subgraphRootUuidString = subgraphRootUuid.toString();
77
78 SubgraphQueryEntity query = new SubgraphQueryEntity(workspaceId, subgraphRootUuidString);
79 entities.persist(query);
80 Long queryId = query.getId();
81
82 try {
83
84 SubgraphNodeEntity root = new SubgraphNodeEntity(queryId, subgraphRootUuidString, 0);
85 entities.persist(root);
86
87
88
89
90
91 Query statement = entities.createNamedQuery("SubgraphNodeEntity.insertChildren");
92 int numChildrenInserted = 0;
93 int parentLevel = 0;
94 while (parentLevel <= maxDepth) {
95
96 statement.setParameter("queryId", queryId);
97 statement.setParameter("workspaceId", workspaceId);
98 statement.setParameter("parentDepth", parentLevel);
99 numChildrenInserted = statement.executeUpdate();
100 if (numChildrenInserted == 0) break;
101 parentLevel = parentLevel + 1;
102 }
103 } catch (RuntimeException t) {
104
105 try {
106 Query search = entities.createNamedQuery("SubgraphNodeEntity.deleteByQueryId");
107 search.setParameter("queryId", query.getId());
108 search.executeUpdate();
109 } finally {
110 entities.remove(query);
111 }
112 throw t;
113 }
114
115 return new SubgraphQuery(context, entities, workspaceId, query, subgraphRootPath, maxDepth);
116 }
117
118 private final ExecutionContext context;
119 private final EntityManager manager;
120 private final Long workspaceId;
121 private SubgraphQueryEntity query;
122 private final int maxDepth;
123 private final Path subgraphRootPath;
124
125 protected SubgraphQuery( ExecutionContext context,
126 EntityManager manager,
127 Long workspaceId,
128 SubgraphQueryEntity query,
129 Path subgraphRootPath,
130 int maxDepth ) {
131 assert manager != null;
132 assert query != null;
133 assert context != null;
134 assert subgraphRootPath != null;
135 assert workspaceId != null;
136 this.context = context;
137 this.manager = manager;
138 this.workspaceId = workspaceId;
139 this.query = query;
140 this.maxDepth = maxDepth;
141 this.subgraphRootPath = subgraphRootPath;
142 }
143
144
145
146
147 public int getMaxDepth() {
148 return maxDepth;
149 }
150
151
152
153
154 public EntityManager getEntityManager() {
155 return manager;
156 }
157
158
159
160
161 public Path getSubgraphRootPath() {
162 return subgraphRootPath;
163 }
164
165
166
167
168 public SubgraphQueryEntity getSubgraphQueryEntity() {
169 if (query == null) throw new IllegalStateException();
170 return query;
171 }
172
173 public int getNodeCount( boolean includeRoot ) {
174 if (query == null) throw new IllegalStateException();
175
176 Query search = manager.createNamedQuery("SubgraphNodeEntity.getCount");
177 search.setParameter("queryId", query.getId());
178
179
180 try {
181 return (Integer)search.getSingleResult() - (includeRoot ? 0 : 1);
182 } catch (NoResultException e) {
183 return 0;
184 }
185 }
186
187
188
189
190
191
192 public ChildEntity getNode() {
193
194 Query search = manager.createNamedQuery("SubgraphNodeEntity.getChildEntities");
195 search.setParameter("queryId", query.getId());
196 search.setParameter("workspaceId", workspaceId);
197 search.setParameter("depth", 0);
198 search.setParameter("maxDepth", 0);
199
200
201 return (ChildEntity)search.getSingleResult();
202 }
203
204
205
206
207
208
209
210
211
212 @SuppressWarnings( "unchecked" )
213 public List<ChildEntity> getNodes( boolean includeRoot,
214 boolean includeChildrenOfMaxDepthNodes ) {
215 if (query == null) throw new IllegalStateException();
216
217 Query search = manager.createNamedQuery("SubgraphNodeEntity.getChildEntities");
218 search.setParameter("queryId", query.getId());
219 search.setParameter("workspaceId", workspaceId);
220 search.setParameter("depth", includeRoot ? 0 : 1);
221 search.setParameter("maxDepth", includeChildrenOfMaxDepthNodes ? maxDepth : maxDepth - 1);
222
223
224 return search.getResultList();
225 }
226
227
228
229
230
231
232
233
234
235
236 @SuppressWarnings( "unchecked" )
237 public List<PropertiesEntity> getProperties( boolean includeRoot,
238 boolean includeChildrenOfMaxDepthNodes ) {
239 if (query == null) throw new IllegalStateException();
240
241 Query search = manager.createNamedQuery("SubgraphNodeEntity.getPropertiesEntities");
242 search.setParameter("queryId", query.getId());
243 search.setParameter("workspaceId", workspaceId);
244 search.setParameter("depth", includeRoot ? 0 : 1);
245 search.setParameter("maxDepth", includeChildrenOfMaxDepthNodes ? maxDepth : maxDepth - 1);
246
247
248 return search.getResultList();
249 }
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264 public List<Location> getNodeLocations( boolean includeRoot,
265 boolean includeChildrenOfMaxDepthNodes ) {
266 if (query == null) throw new IllegalStateException();
267
268
269 Map<String, Path> pathByUuid = new HashMap<String, Path>();
270 LinkedList<Location> locations = new LinkedList<Location>();
271 String subgraphRootUuid = query.getRootUuid();
272 pathByUuid.put(subgraphRootUuid, subgraphRootPath);
273 UUID uuid = UUID.fromString(subgraphRootUuid);
274 if (includeRoot) {
275 locations.add(Location.create(subgraphRootPath, uuid));
276 }
277
278
279 final PathFactory pathFactory = context.getValueFactories().getPathFactory();
280 final NameFactory nameFactory = context.getValueFactories().getNameFactory();
281 for (ChildEntity entity : getNodes(false, includeChildrenOfMaxDepthNodes)) {
282 String parentUuid = entity.getParentUuidString();
283 Path parentPath = pathByUuid.get(parentUuid);
284 assert parentPath != null;
285 String nsUri = entity.getChildNamespace().getUri();
286 String localName = entity.getChildName();
287 int sns = entity.getSameNameSiblingIndex();
288 Name childName = nameFactory.create(nsUri, localName);
289 Path childPath = pathFactory.create(parentPath, childName, sns);
290 String childUuid = entity.getId().getChildUuidString();
291 pathByUuid.put(childUuid, childPath);
292 uuid = UUID.fromString(childUuid);
293 locations.add(Location.create(childPath, uuid));
294
295 }
296 return locations;
297 }
298
299
300
301
302
303
304
305
306 @SuppressWarnings( "unchecked" )
307 public List<ReferenceEntity> getInternalReferences() {
308 Query references = manager.createNamedQuery("SubgraphNodeEntity.getInternalReferences");
309 references.setParameter("queryId", query.getId());
310 references.setParameter("workspaceId", workspaceId);
311 return references.getResultList();
312 }
313
314
315
316
317
318
319
320 @SuppressWarnings( "unchecked" )
321 public List<ReferenceEntity> getOutwardReferences() {
322 Query references = manager.createNamedQuery("SubgraphNodeEntity.getOutwardReferences");
323 references.setParameter("queryId", query.getId());
324 references.setParameter("workspaceId", workspaceId);
325 return references.getResultList();
326 }
327
328
329
330
331
332
333
334
335 @SuppressWarnings( "unchecked" )
336 public List<ReferenceEntity> getInwardReferences() {
337
338 Query references = manager.createNamedQuery("SubgraphNodeEntity.getInwardReferences");
339 references.setParameter("queryId", query.getId());
340 references.setParameter("workspaceId", workspaceId);
341 return references.getResultList();
342 }
343
344
345
346
347
348
349
350 @SuppressWarnings( "unchecked" )
351 public void deleteSubgraph( boolean includeRoot ) {
352 if (query == null) throw new IllegalStateException();
353
354
355
356
357
358
359
360
361
362 Query withLargeValues = manager.createNamedQuery("SubgraphNodeEntity.getPropertiesEntitiesWithLargeValues");
363 withLargeValues.setParameter("queryId", query.getId());
364 withLargeValues.setParameter("depth", includeRoot ? 0 : 1);
365 withLargeValues.setParameter("workspaceId", workspaceId);
366 List<PropertiesEntity> propertiesWithLargeValues = withLargeValues.getResultList();
367 if (propertiesWithLargeValues.size() != 0) {
368 for (PropertiesEntity props : propertiesWithLargeValues) {
369 props.getLargeValues().clear();
370 }
371 manager.flush();
372 }
373
374
375 Query delete = manager.createNamedQuery("SubgraphNodeEntity.deletePropertiesEntities");
376 delete.setParameter("queryId", query.getId());
377 delete.setParameter("workspaceId", workspaceId);
378 delete.executeUpdate();
379
380
381 delete = manager.createNamedQuery("SubgraphNodeEntity.deleteChildEntities");
382 delete.setParameter("queryId", query.getId());
383 delete.setParameter("workspaceId", workspaceId);
384 delete.executeUpdate();
385
386
387 delete = manager.createNamedQuery("SubgraphNodeEntity.deleteReferences");
388 delete.setParameter("queryId", query.getId());
389 delete.setParameter("workspaceId", workspaceId);
390 delete.executeUpdate();
391
392
393 LargeValueEntity.deleteUnused(manager);
394
395 manager.flush();
396 }
397
398
399
400
401
402 public void close() {
403 if (query == null) return;
404
405 try {
406 Query search = manager.createNamedQuery("SubgraphNodeEntity.deleteByQueryId");
407 search.setParameter("queryId", query.getId());
408 search.executeUpdate();
409 } finally {
410 try {
411 manager.remove(query);
412 } finally {
413 query = null;
414 }
415 }
416 }
417 }