1 /*******************************************************************************
2 * Copyright (c) 2007, 2019 Association for Decentralized Information Management
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
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.db.layer0.adapter.impl;
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.Collections;
17 import java.util.List;
20 import org.simantics.db.ReadGraph;
21 import org.simantics.db.Resource;
22 import org.simantics.db.common.primitiverequest.Adapter;
23 import org.simantics.db.common.procedure.adapter.TransientCacheListener;
24 import org.simantics.db.common.request.ObjectsWithType;
25 import org.simantics.db.common.request.TernaryRead;
26 import org.simantics.db.exception.DatabaseException;
27 import org.simantics.db.layer0.adapter.Instances;
28 import org.simantics.db.layer0.genericrelation.Dependencies;
29 import org.simantics.db.layer0.genericrelation.IndexQueries;
30 import org.simantics.db.layer0.util.Layer0Utils;
31 import org.simantics.db.request.ReadExt;
32 import org.simantics.db.request.RequestFlags;
33 import org.simantics.db.service.CollectionSupport;
34 import org.simantics.layer0.Layer0;
35 import org.simantics.operation.Layer0X;
36 import org.simantics.scl.runtime.function.Function;
38 import gnu.trove.set.hash.THashSet;
41 * @author Antti Villberg
42 * @author Tuukka Lehtonen
44 public class EntityInstances implements Instances {
46 private static final boolean TRACE_QUERIES = false;
48 private final Resource type;
50 public EntityInstances(Resource type) {
55 public Collection<Resource> find(ReadGraph graph, Resource index) throws DatabaseException {
56 return find(graph, index, "");
60 * A (cacheable) query to optimize single index queries for immutable
61 * indexes such as ontologies.
63 public static class QueryIndex extends TernaryRead<Resource, Resource, String, List<Resource>> implements ReadExt {
65 public QueryIndex(Resource index, Resource type, String filter) {
66 super(index, type, filter);
70 public List<Resource> perform(ReadGraph graph)
71 throws DatabaseException {
72 Resource type = parameter2;
73 String filter = constructLuceneQuery(graph, type, parameter3);
75 return Collections.emptyList();
77 @SuppressWarnings({ "unchecked", "rawtypes" })
78 Function dependencyResources = graph.syncRequest(new Adapter(Layer0X.getInstance(graph).DependencyResources, Function.class), TransientCacheListener.<Function>instance());
81 System.out.println("EntityInstances.QueryIndex: finding " + filter + " from index " + graph.getPossibleURI(parameter));
82 //new Exception("EntityInstances: finding " + filter + " from index " + graph.getPossibleURI(parameter)).printStackTrace();
85 @SuppressWarnings("unchecked")
86 List<Resource> results = (List<Resource>)dependencyResources.apply(graph, parameter, filter);
87 if (results == null || results.isEmpty())
88 return Collections.emptyList();
91 System.out.println(" EntityInstances.QueryIndex: got " + results.size() + " results");
93 // Optimize single result case.
94 if (results.size() == 1) {
95 Resource singleResult = results.get(0);
96 List<Resource> result = graph.isInstanceOf(singleResult, type) ? results : Collections.emptyList();
98 System.out.println(" EntityInstances.QueryIndex: got " + results.size() + " unique type-matching results");
102 CollectionSupport coll = graph.getService(CollectionSupport.class);
103 List<Resource> result = coll.createList(results.size());
104 for (Resource res : Layer0Utils.sortByCluster(graph, results))
105 if (graph.isInstanceOf(res, type))
109 System.out.println(" EntityInstances.QueryIndex: got " + results.size() + " unique type-matching results");
114 private String constructLuceneQuery(ReadGraph graph, Resource type, String filter) throws DatabaseException {
115 Layer0 L0 = Layer0.getInstance(graph);
116 StringBuilder sb = new StringBuilder();
117 boolean emptyFilter = filter.isEmpty();
118 if (emptyFilter || !type.equals(L0.Entity)) {
119 IndexQueries.appendResourceIdTerm(sb, Dependencies.FIELD_TYPE_RESOURCE, type);
126 if (sb.length() == 0) {
129 return sb.toString();
133 public String toString() {
134 return "QueryIndex " + parameter + " " + parameter2 + " " + parameter3;
138 public boolean isImmutable(ReadGraph graph) throws DatabaseException {
139 return graph.isImmutable(parameter);
143 public int getType() {
144 // This query should not be immediate update since it takes a long time!
145 return RequestFlags.INVALIDATE;
150 private List<Resource> findRec(ReadGraph graph, Resource index, String filter, Set<Resource> visited) throws DatabaseException {
152 if(!visited.add(index)) return Collections.emptyList();
154 CollectionSupport coll = graph.getService(CollectionSupport.class);
156 List<Resource> indexResult = graph.syncRequest(new QueryIndex(index, type, filter), TransientCacheListener.<List<Resource>>instance());
158 Layer0 L0 = Layer0.getInstance(graph);
159 Collection<Resource> linkedRoots = graph.syncRequest(new ObjectsWithType(index, L0.IsLinkedTo, L0.IndexRoot));
160 if (linkedRoots.isEmpty())
163 List<Resource> result = indexResult;
164 for (Resource dep : linkedRoots) {
165 Collection<Resource> linkedIndexResults = findRec(graph, dep, filter, visited);
166 if (linkedIndexResults.isEmpty())
168 if (result == indexResult) {
169 result = coll.createList();
170 result.addAll(indexResult);
173 result.addAll(linkedIndexResults);
181 public Collection<Resource> find(ReadGraph graph, Resource index, String filter) throws DatabaseException {
182 CollectionSupport coll = graph.getService(CollectionSupport.class);
184 THashSet<Resource> visited = new THashSet<>();
185 List<Resource> rec_ = findRec(graph, index, filter, visited);
186 // We must not modify rec_!
187 List<Resource> rec = rec_;
188 for(Resource global : Layer0Utils.listGlobalOntologies(graph)) {
189 if(!visited.add(global)) continue;
190 List<Resource> rs = graph.syncRequest(new QueryIndex(global, type, filter), TransientCacheListener.<List<Resource>>instance());
193 rec = new ArrayList<>(rec);
197 Collection<Resource> result = coll.asSortedList(rec);
202 public Collection<Resource> findByName(ReadGraph graph, Resource model,
203 String name) throws DatabaseException {
204 return find(graph, model, IndexQueries.quoteTerm(name));