Sync git svn branch with SVN repository r33389.
[simantics/platform.git] / bundles / org.simantics.db.layer0 / src / org / simantics / db / layer0 / adapter / impl / EntityInstances.java
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
3  * in Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.db.layer0.adapter.impl;\r
13 \r
14 import java.util.ArrayList;\r
15 import java.util.Collection;\r
16 import java.util.Collections;\r
17 import java.util.List;\r
18 import java.util.Set;\r
19 \r
20 import org.simantics.databoard.Bindings;\r
21 import org.simantics.db.ReadGraph;\r
22 import org.simantics.db.Resource;\r
23 import org.simantics.db.common.primitiverequest.Adapter;\r
24 import org.simantics.db.common.procedure.adapter.TransientCacheListener;\r
25 import org.simantics.db.common.request.ObjectsWithType;\r
26 import org.simantics.db.common.request.TernaryRead;\r
27 import org.simantics.db.exception.DatabaseException;\r
28 import org.simantics.db.layer0.adapter.Instances;\r
29 import org.simantics.db.layer0.genericrelation.IndexQueries;\r
30 import org.simantics.db.layer0.util.Layer0Utils;\r
31 import org.simantics.db.request.ReadExt;\r
32 import org.simantics.db.request.RequestFlags;\r
33 import org.simantics.db.service.CollectionSupport;\r
34 import org.simantics.layer0.Layer0;\r
35 import org.simantics.operation.Layer0X;\r
36 import org.simantics.scl.runtime.function.Function;\r
37 \r
38 import gnu.trove.set.hash.THashSet;\r
39 \r
40 /**\r
41  * @author Antti Villberg\r
42  * @author Tuukka Lehtonen\r
43  */\r
44 public class EntityInstances implements Instances {\r
45 \r
46     private static final boolean TRACE_QUERIES = false;\r
47 \r
48     private final Resource type;\r
49 \r
50     public EntityInstances(Resource type) {\r
51         this.type = type;\r
52     }\r
53 \r
54     @Override\r
55     public Collection<Resource> find(ReadGraph graph, Resource index) throws DatabaseException {\r
56         return find(graph, index, "");\r
57     }\r
58 \r
59     /**\r
60      * A (cacheable) query to optimize single index queries for immutable\r
61      * indexes such as ontologies.\r
62      */\r
63     public static class QueryIndex extends TernaryRead<Resource, Resource, String, List<Resource>> implements ReadExt {\r
64 \r
65         public QueryIndex(Resource index, Resource type, String filter) {\r
66             super(index, type, filter);\r
67         }\r
68 \r
69         @Override\r
70         public List<Resource> perform(ReadGraph graph)\r
71                 throws DatabaseException {\r
72             Resource type = parameter2;\r
73 \r
74             Layer0 L0 = Layer0.getInstance(graph);\r
75             Layer0X L0X = Layer0X.getInstance(graph);\r
76             String typeName = graph.getRelatedValue(type, L0.HasName);\r
77             if (typeName.isEmpty())\r
78                 return Collections.emptyList();\r
79 \r
80             @SuppressWarnings({ "unchecked", "rawtypes" })\r
81             Function dependencyResources = graph.syncRequest(new Adapter(L0X.DependencyResources, Function.class), TransientCacheListener.<Function>instance());\r
82 \r
83             StringBuilder filtersb = new StringBuilder();\r
84             filtersb.append("Types:*").append( IndexQueries.escape( typeName, true ) );\r
85             if (parameter3.length() > 0)\r
86                 filtersb.append(" AND ").append( parameter3 );\r
87             String filter = filtersb.toString();\r
88 \r
89             if (TRACE_QUERIES) {\r
90                 System.out.println("EntityInstances.QueryIndex: finding " + filter + " from index " + graph.getPossibleURI(parameter));\r
91                 //new Exception("EntityInstances: finding " + filter + " from index " + graph.getPossibleURI(parameter)).printStackTrace();\r
92             }\r
93             \r
94             @SuppressWarnings("unchecked")\r
95                         List<Resource> results = (List<Resource>)dependencyResources.apply(graph, parameter, filter);\r
96             if (results == null || results.isEmpty())\r
97                 return Collections.emptyList();\r
98 \r
99             if (TRACE_QUERIES)\r
100                 System.out.println("  EntityInstances.QueryIndex: got " + results.size() + " results");\r
101 \r
102 //            // TreeSet to keep the results in deterministic order.\r
103 //            Set<Resource> resultSet = new TreeSet<Resource>();\r
104 //            for (Map<String, Object> entry : results) {\r
105 //                Resource res = (Resource)entry.get("Resource");\r
106 //                if (res != null && !resultSet.contains(res))\r
107 //                    resultSet.add(res);\r
108 //            }\r
109 \r
110             CollectionSupport coll = graph.getService(CollectionSupport.class);\r
111             List<Resource> result = coll.createList();\r
112             \r
113             for (Resource res : Layer0Utils.sortByCluster(graph, results)) {\r
114                 if (graph.isInstanceOf(res, type))\r
115                     result.add(res);\r
116             }\r
117 \r
118             if (TRACE_QUERIES)\r
119                 System.out.println("  EntityInstances.QueryIndex: got " + results.size() + " unique type-matching results");\r
120             \r
121             return result;\r
122 \r
123         }\r
124         \r
125         @Override\r
126         public String toString() {\r
127                 return "QueryIndex " + parameter + " " + parameter2 + " " + parameter3;\r
128         }\r
129 \r
130                 @Override\r
131                 public boolean isImmutable(ReadGraph graph) throws DatabaseException {\r
132                         // TODO Auto-generated method stub\r
133                         return false;\r
134                 }\r
135 \r
136                 @Override\r
137                 public int getType() {\r
138                         return RequestFlags.IMMEDIATE_UPDATE;\r
139                 }\r
140 \r
141     }\r
142 \r
143     private List<Resource> findRec(ReadGraph graph, Resource index, String filter, Set<Resource> visited) throws DatabaseException {\r
144 \r
145         if(!visited.add(index)) return Collections.emptyList();\r
146 \r
147         CollectionSupport coll = graph.getService(CollectionSupport.class);\r
148 \r
149         List<Resource> indexResult = graph.syncRequest(new QueryIndex(index, type, filter), TransientCacheListener.<List<Resource>>instance());\r
150 \r
151         Layer0 L0 = Layer0.getInstance(graph);\r
152         Collection<Resource> linkedRoots = graph.syncRequest(new ObjectsWithType(index, L0.IsLinkedTo, L0.IndexRoot));\r
153         if (linkedRoots.isEmpty())\r
154             return indexResult;\r
155 \r
156         List<Resource> result = indexResult;\r
157         for (Resource dep : linkedRoots) {\r
158             Collection<Resource> linkedIndexResults = findRec(graph, dep, filter, visited);\r
159             if (linkedIndexResults.isEmpty())\r
160                 continue;\r
161             if (result == indexResult) {\r
162                 result = coll.createList();\r
163                 result.addAll(indexResult);\r
164             } else {\r
165             }\r
166             result.addAll(linkedIndexResults);\r
167         }\r
168         \r
169         return result;\r
170         \r
171     }\r
172 \r
173     @Override\r
174     public Collection<Resource> find(ReadGraph graph, Resource index, String filter) throws DatabaseException {\r
175         CollectionSupport coll = graph.getService(CollectionSupport.class);\r
176         \r
177         THashSet<Resource> visited = new THashSet<>();\r
178         List<Resource> rec = findRec(graph, index, filter, visited);\r
179         for(Resource global : Layer0Utils.listGlobalOntologies(graph)) {\r
180                 if (!visited.add(global)) continue;\r
181                 List<Resource> rs = graph.syncRequest(new QueryIndex(global, type, filter), TransientCacheListener.<List<Resource>>instance());\r
182                 if(rec.isEmpty() && !rs.isEmpty()) {\r
183                         // TODO: rec could be an immutable empty list\r
184                         rec = new ArrayList<Resource>();\r
185                 }\r
186                 rec.addAll(rs);\r
187         }\r
188         Collection<Resource> result = coll.asSortedList(rec);\r
189         return result; \r
190     }\r
191     \r
192     @Override\r
193     public Collection<Resource> findByName(ReadGraph graph, Resource model,\r
194             String name) throws DatabaseException {\r
195         Layer0 L0 = Layer0.getInstance(graph);\r
196         CollectionSupport coll = graph.getService(CollectionSupport.class);\r
197         List<Resource> results = coll.createList();\r
198         for(Resource match : find(graph, model, name)) {\r
199             if(name.equals(graph.getPossibleRelatedValue(match, L0.HasName, Bindings.STRING))) results.add(match);\r
200         }\r
201         return results;\r
202     }\r
203 \r
204 }\r