]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.workbench.search/src/org/simantics/workbench/search/Searching.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.workbench.search / src / org / simantics / workbench / search / Searching.java
1 package org.simantics.workbench.search;\r
2 \r
3 import java.io.CharArrayWriter;\r
4 import java.io.File;\r
5 import java.io.IOException;\r
6 import java.net.URL;\r
7 import java.net.URLDecoder;\r
8 import java.util.ArrayList;\r
9 import java.util.Collection;\r
10 import java.util.HashSet;\r
11 import java.util.List;\r
12 import java.util.Map;\r
13 import java.util.Set;\r
14 \r
15 import org.eclipse.core.runtime.FileLocator;\r
16 import org.eclipse.core.runtime.Path;\r
17 import org.eclipse.core.runtime.Platform;\r
18 import org.osgi.framework.Bundle;\r
19 import org.simantics.NameLabelMode;\r
20 import org.simantics.NameLabelUtil;\r
21 import org.simantics.db.ReadGraph;\r
22 import org.simantics.db.Resource;\r
23 import org.simantics.db.exception.DatabaseException;\r
24 import org.simantics.scl.runtime.function.Function;\r
25 import org.simantics.scl.runtime.function.Function4;\r
26 import org.simantics.utils.datastructures.MapList;\r
27 import org.simantics.utils.datastructures.Pair;\r
28 \r
29 import freemarker.template.Configuration;\r
30 import freemarker.template.DefaultObjectWrapper;\r
31 import freemarker.template.Template;\r
32 import freemarker.template.TemplateException;\r
33 \r
34 /**\r
35  * @author Tuukka Lehtonen\r
36  * @author Marko Luukkainen\r
37  */\r
38 public final class Searching {\r
39         \r
40         static final boolean USE_PAGING = false; // create multipage results (currently paging is handled by DataTables (JavaScript)) \r
41     static final int MAX_PER_PAGE = 100;\r
42     \r
43 \r
44     /**\r
45      * @param graph\r
46      * @param query\r
47      * @throws DatabaseException\r
48      */\r
49     public static Collection<Map<String, Object>> performSearch(ReadGraph graph, Resource searchFunction, Resource model, String query, int maxResults)\r
50             throws DatabaseException {\r
51         @SuppressWarnings("unchecked")\r
52         Function4<ReadGraph, Resource, String, Integer, Collection<Map<String, Object>>> f = graph.adapt(searchFunction, Function.class);\r
53         Collection<Map<String, Object>> results = f.apply(graph, model, query, maxResults);\r
54         return results;\r
55     }\r
56 \r
57     /**\r
58      * @param graph\r
59      * @param query\r
60      * @param maxResultsPerModel\r
61      * @param results\r
62      * @return\r
63      * @throws IOException\r
64      * @throws TemplateException\r
65      * @throws DatabaseException\r
66      */\r
67     public static List<QueryResult> generatePage(ReadGraph graph, Collection<SearchEngine> searchEngines, SearchQuery query, int maxResultsPerModel, \r
68             MapList<Resource, Pair<SearchEngine,SearchResult>> results) throws IOException, TemplateException, DatabaseException {\r
69         URL fileUrl = getSearchFileURL();\r
70         File dataDir = getAbsoluteFile(fileUrl);\r
71 \r
72         SearchData data = new SearchData();\r
73         data.dataUrl = fileUrl.toString();\r
74         data.dataDirectory = dataDir;\r
75         data.query = query;\r
76         data.maxResults = maxResultsPerModel;\r
77         data.model = null;\r
78         data.results = new SearchResult();\r
79         data.resultCount = 0;\r
80         data.searchEngines = searchEngines;\r
81 \r
82       \r
83         int resultCount = 0;\r
84         int resultNumber = 0;\r
85         \r
86         int itemsOnPreviousPage = 0;\r
87 \r
88         \r
89         List<QueryResult> result = new ArrayList<QueryResult>();\r
90         \r
91         QueryResult header = applyTemplate(graph, "header.ftl", data);\r
92         QueryResult footer = applyTemplate(graph, "footer.ftl", data);\r
93         StringBuilder body = new StringBuilder(1024 * 80);\r
94         \r
95         if (USE_PAGING) {\r
96                 List<Pair<SearchEngine, SearchResult>> allResults = results.getAllValuesSnapshot();\r
97                 for (Pair<SearchEngine,SearchResult> entry : allResults) {\r
98                          List<SearchResultRow> items = entry.second.rows;\r
99                          resultCount += items.size();\r
100                 }\r
101                 data.resultCount = resultCount;\r
102                 \r
103                 \r
104                 for (Resource model : results.getKeys()) {\r
105                         List<Pair<SearchEngine,SearchResult>> modelResults = results.getValues(model);\r
106                         for (Pair<SearchEngine,SearchResult> entry : modelResults) {\r
107                         \r
108                         \r
109                                 List<SearchResultRow> items = entry.second.rows;\r
110                                 int start = 0;\r
111                                 int count = items.size();\r
112                                 \r
113                                 while (count + itemsOnPreviousPage > MAX_PER_PAGE) {\r
114                                         int toPage = MAX_PER_PAGE-itemsOnPreviousPage;\r
115                                         QueryResult content = generateResultTable(graph, query, maxResultsPerModel, data, resultNumber, resultCount, model, entry.first,entry.second.subset(start, start+toPage));\r
116                                         body.append( content.getHtml() );\r
117                                         result.add( new QueryResult(header.getHtml(),body.toString(),footer.getHtml(), resultCount));\r
118                                         start += toPage;\r
119                                         count -= toPage;\r
120                                         itemsOnPreviousPage = 0;\r
121                                         body = new StringBuilder(1024 * 80);\r
122                                 }\r
123                                 if (count > 0) {\r
124                                         QueryResult content = generateResultTable(graph, query, maxResultsPerModel, data, resultNumber, resultCount, model, entry.first,entry.second.subset(start, start+count));       \r
125                                         body.append( content.getHtml() );\r
126                                         itemsOnPreviousPage += count;\r
127                                 }\r
128 \r
129                             ++resultNumber;\r
130                   \r
131                     \r
132                         }\r
133                 }\r
134                 if (body.length() > 0)\r
135                         result.add( new QueryResult(header.getHtml(),body.toString(),footer.getHtml(), resultCount));\r
136         } else {\r
137                 List<Pair<SearchEngine, SearchResult>> allResults = results.getAllValuesSnapshot();\r
138                 for (Pair<SearchEngine,SearchResult> entry : allResults) {\r
139                          List<SearchResultRow> items = entry.second.rows;\r
140                          resultCount += items.size();\r
141                 }\r
142                 data.resultCount = resultCount;\r
143                 \r
144                  for (Resource model : results.getKeys()) {\r
145                          List<Pair<SearchEngine,SearchResult>> modelResults = results.getValues(model);\r
146                          for (Pair<SearchEngine,SearchResult> entry : modelResults) {\r
147                                  QueryResult content = generateResultTable(graph, query, maxResultsPerModel, data, resultNumber, resultCount, model, entry.first, entry.second);        \r
148                                  body.append( content.getHtml() );\r
149                                  ++resultNumber;\r
150                         }\r
151                  }\r
152                  result.add( new QueryResult(header.getHtml(),body.toString(),footer.getHtml(), resultCount));\r
153         }\r
154         if (result.size() == 0) {\r
155                 result.add( new QueryResult(header.getHtml(),body.toString(),footer.getHtml(), resultCount));\r
156         }\r
157 \r
158         return result;\r
159 \r
160         \r
161     }\r
162 \r
163     /**\r
164      * @param graph\r
165      * @param query\r
166      * @param maxResultsPerModel\r
167      * @param resultNumber \r
168      * @param results\r
169      * @return\r
170      * @throws IOException\r
171      * @throws TemplateException\r
172      * @throws DatabaseException\r
173      */\r
174     public static QueryResult generateResultTable(ReadGraph graph, SearchQuery query, int maxResultsPerModel,\r
175             SearchData template, int resultNumber, int resultCount, Resource model, SearchEngine searchEngine, SearchResult results)\r
176                     throws IOException, TemplateException, DatabaseException {\r
177         SearchData data = template.clone();\r
178         data.resultNumber = resultNumber;\r
179         data.query = query;\r
180         data.maxResults = maxResultsPerModel;\r
181         data.model = NamedResource.of(graph, model);\r
182         data.results = results;\r
183         data.searchEngine = searchEngine;\r
184 \r
185         return applyTemplate(graph, "searchtable.ftl", data);\r
186     }\r
187 \r
188     /**\r
189      * @return\r
190      * @throws IOException\r
191      */\r
192     private static URL getSearchFileURL() throws IOException {\r
193         Bundle b = Platform.getBundle(Activator.PLUGIN_ID);\r
194         URL dataUrl = FileLocator.find(b, new Path("search"), null);\r
195         if (dataUrl == null)\r
196             throw new IOException("Could not find search template data");\r
197 \r
198         URL fileUrl = FileLocator.toFileURL(dataUrl);\r
199         return fileUrl;\r
200     }\r
201 \r
202     /**\r
203      * @return\r
204      * @throws IOException\r
205      */\r
206     private static File getAbsoluteFile(URL fileUrl) throws IOException {\r
207         File dataDir = new File(URLDecoder.decode(fileUrl.getPath(), "UTF-8")).getAbsoluteFile();\r
208         return dataDir;\r
209     }\r
210 \r
211     \r
212     /**\r
213      * @param graph\r
214      * @param templateName\r
215      * @param data\r
216      * @return\r
217      * @throws IOException\r
218      * @throws TemplateException\r
219      * @throws DatabaseException\r
220      */\r
221     public static QueryResult applyTemplate(ReadGraph graph, String templateName, SearchData data)\r
222             throws IOException, TemplateException, DatabaseException {\r
223         Configuration cfg = new Configuration();\r
224         cfg.setDirectoryForTemplateLoading(data.getDataDirectory());\r
225         cfg.setObjectWrapper(new DefaultObjectWrapper());\r
226 \r
227         Template temp = cfg.getTemplate(templateName);\r
228         CharArrayWriter writer = new CharArrayWriter(1024 * 128);\r
229         temp.process(data, writer);\r
230 \r
231         return new QueryResult(writer.toString(), data.results.rows.size());\r
232     }\r
233 \r
234     /**\r
235      * @param graph\r
236      * @param results\r
237      * @return map: model -> SearchResult\r
238      * @throws DatabaseException\r
239      */\r
240     public static final SearchResult generateDependenciesSearchResult(ReadGraph graph,\r
241             Collection<Map<String, Object>> results) throws DatabaseException {\r
242         Set<Resource> processed = new HashSet<Resource>();\r
243         SearchResult result = new SearchResult(NameAndTypeRow.columns);\r
244 \r
245         NameLabelMode mode = NameLabelUtil.getNameLabelMode(graph);\r
246 \r
247         for (Map<String, Object> r : results) {\r
248             Resource resource = (Resource) r.get("Resource");\r
249 \r
250             // Prevent index corruption from producing duplicate results.\r
251             if (!processed.add(resource))\r
252                 continue;\r
253 \r
254             Resource parent = (Resource) r.get("Parent");\r
255             String name = (String) r.get("Name");\r
256 \r
257             NameAndTypeRow rst = new NameAndTypeRow();\r
258             rst.resource = NamedResource.of(graph, resource, name);\r
259             rst.parent = NamedResource.of(graph, parent, NameLabelUtil.modalName(graph, parent, mode));\r
260 \r
261             Collection<Resource> typeResources = graph.getTypes(resource);\r
262             Collection<Resource> principalTypeResources = graph.getPrincipalTypes(resource);\r
263             if (!typeResources.isEmpty()) {\r
264                 rst.types = new ArrayList<NamedResource>(typeResources.size());\r
265                 rst.principalTypes = new ArrayList<NamedResource>(principalTypeResources.size());\r
266                 for (Resource t : typeResources) {\r
267                     NamedResource nr = NamedResource.of(graph, t);\r
268                     rst.types.add(nr);\r
269                     if (principalTypeResources.contains(t))\r
270                         rst.principalTypes.add(nr);\r
271                 }\r
272             }\r
273 \r
274             result.addRow(rst);\r
275         }\r
276 \r
277         return result;\r
278     }\r
279 \r
280 }\r