]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/adapter/impl/EntityInstances.java
07ddce7bd176e1fe2d8eca40819a0183ca3b64bf
[simantics/platform.git] / bundles / org.simantics.db.layer0 / src / org / simantics / db / layer0 / adapter / impl / EntityInstances.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2010 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.db.layer0.adapter.impl;
13
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.Collections;
17 import java.util.List;
18 import java.util.Set;
19
20 import org.simantics.databoard.Bindings;
21 import org.simantics.db.ReadGraph;
22 import org.simantics.db.Resource;
23 import org.simantics.db.common.primitiverequest.Adapter;
24 import org.simantics.db.common.procedure.adapter.TransientCacheListener;
25 import org.simantics.db.common.request.ObjectsWithType;
26 import org.simantics.db.common.request.TernaryRead;
27 import org.simantics.db.exception.DatabaseException;
28 import org.simantics.db.layer0.adapter.Instances;
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;
37
38 import gnu.trove.set.hash.THashSet;
39
40 /**
41  * @author Antti Villberg
42  * @author Tuukka Lehtonen
43  */
44 public class EntityInstances implements Instances {
45
46     private static final boolean TRACE_QUERIES = false;
47
48     private final Resource type;
49
50     public EntityInstances(Resource type) {
51         this.type = type;
52     }
53
54     @Override
55     public Collection<Resource> find(ReadGraph graph, Resource index) throws DatabaseException {
56         return find(graph, index, "");
57     }
58
59     /**
60      * A (cacheable) query to optimize single index queries for immutable
61      * indexes such as ontologies.
62      */
63     public static class QueryIndex extends TernaryRead<Resource, Resource, String, List<Resource>> implements ReadExt {
64
65         public QueryIndex(Resource index, Resource type, String filter) {
66             super(index, type, filter);
67         }
68
69         @Override
70         public List<Resource> perform(ReadGraph graph)
71                 throws DatabaseException {
72             Resource type = parameter2;
73             String filter = constructLuceneQuery(graph, type, parameter3);
74             if (filter == null)
75                 return Collections.emptyList();
76
77             @SuppressWarnings({ "unchecked", "rawtypes" })
78             Function dependencyResources = graph.syncRequest(new Adapter(Layer0X.getInstance(graph).DependencyResources, Function.class), TransientCacheListener.<Function>instance());
79
80             if (TRACE_QUERIES) {
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();
83             }
84
85             @SuppressWarnings("unchecked")
86             List<Resource> results = (List<Resource>)dependencyResources.apply(graph, parameter, filter);
87             if (results == null || results.isEmpty())
88                 return Collections.emptyList();
89
90             if (TRACE_QUERIES)
91                 System.out.println("  EntityInstances.QueryIndex: got " + results.size() + " results");
92
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();
97                 if (TRACE_QUERIES)
98                     System.out.println("  EntityInstances.QueryIndex: got " + results.size() + " unique type-matching results");
99                 return result;
100             }
101
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))
106                     result.add(res);
107
108             if (TRACE_QUERIES)
109                 System.out.println("  EntityInstances.QueryIndex: got " + results.size() + " unique type-matching results");
110
111             return result;
112         }
113
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                 String typeName = graph.getPossibleRelatedValue(type, L0.HasName, Bindings.STRING);
120                 if (typeName == null || typeName.isEmpty())
121                     return null;
122                 sb.append("Types:").append( IndexQueries.escape( typeName, true ) );
123             }
124             if (!emptyFilter) {
125                 if (sb.length() > 0)
126                     sb.append(" AND ");
127                 sb.append(filter);
128             }
129             return sb.toString();
130         }
131
132         @Override
133         public String toString() {
134                 return "QueryIndex " + parameter + " " + parameter2 + " " + parameter3;
135         }
136
137         @Override
138         public boolean isImmutable(ReadGraph graph) throws DatabaseException {
139             return graph.isImmutable(parameter);
140         }
141
142                 @Override
143                 public int getType() {
144                         return RequestFlags.IMMEDIATE_UPDATE;
145                 }
146
147     }
148
149     private List<Resource> findRec(ReadGraph graph, Resource index, String filter, Set<Resource> visited) throws DatabaseException {
150
151         if(!visited.add(index)) return Collections.emptyList();
152
153         CollectionSupport coll = graph.getService(CollectionSupport.class);
154
155         List<Resource> indexResult = graph.syncRequest(new QueryIndex(index, type, filter), TransientCacheListener.<List<Resource>>instance());
156
157         Layer0 L0 = Layer0.getInstance(graph);
158         Collection<Resource> linkedRoots = graph.syncRequest(new ObjectsWithType(index, L0.IsLinkedTo, L0.IndexRoot));
159         if (linkedRoots.isEmpty())
160             return indexResult;
161
162         List<Resource> result = indexResult;
163         for (Resource dep : linkedRoots) {
164             Collection<Resource> linkedIndexResults = findRec(graph, dep, filter, visited);
165             if (linkedIndexResults.isEmpty())
166                 continue;
167             if (result == indexResult) {
168                 result = coll.createList();
169                 result.addAll(indexResult);
170             } else {
171             }
172             result.addAll(linkedIndexResults);
173         }
174         
175         return result;
176         
177     }
178
179     @Override
180     public Collection<Resource> find(ReadGraph graph, Resource index, String filter) throws DatabaseException {
181         CollectionSupport coll = graph.getService(CollectionSupport.class);
182         
183         THashSet<Resource> visited = new THashSet<>();
184         List<Resource> rec = findRec(graph, index, filter, visited);
185         for(Resource global : Layer0Utils.listGlobalOntologies(graph)) {
186                 if(!visited.add(global)) continue;
187                 List<Resource> rs = graph.syncRequest(new QueryIndex(global, type, filter), TransientCacheListener.<List<Resource>>instance());
188                 if(rec.isEmpty() && !rs.isEmpty()) {
189                         // TODO: rec could be an immutable empty list
190                         rec = new ArrayList<Resource>();
191                 }
192                 rec.addAll(rs);
193         }
194         Collection<Resource> result = coll.asSortedList(rec);
195         return result; 
196     }
197     
198     @Override
199     public Collection<Resource> findByName(ReadGraph graph, Resource model,
200             String name) throws DatabaseException {
201         Layer0 L0 = Layer0.getInstance(graph);
202         CollectionSupport coll = graph.getService(CollectionSupport.class);
203         List<Resource> results = coll.createList();
204         for(Resource match : find(graph, model, name)) {
205             if(name.equals(graph.getPossibleRelatedValue(match, L0.HasName, Bindings.STRING))) results.add(match);
206         }
207         return results;
208     }
209
210 }