-package org.simantics.workbench.search;\r
-\r
-import java.io.CharArrayWriter;\r
-import java.io.File;\r
-import java.io.IOException;\r
-import java.net.URL;\r
-import java.net.URLDecoder;\r
-import java.util.ArrayList;\r
-import java.util.Collection;\r
-import java.util.HashSet;\r
-import java.util.List;\r
-import java.util.Map;\r
-import java.util.Set;\r
-\r
-import org.eclipse.core.runtime.FileLocator;\r
-import org.eclipse.core.runtime.Path;\r
-import org.eclipse.core.runtime.Platform;\r
-import org.osgi.framework.Bundle;\r
-import org.simantics.NameLabelMode;\r
-import org.simantics.NameLabelUtil;\r
-import org.simantics.db.ReadGraph;\r
-import org.simantics.db.Resource;\r
-import org.simantics.db.exception.DatabaseException;\r
-import org.simantics.scl.runtime.function.Function;\r
-import org.simantics.scl.runtime.function.Function4;\r
-import org.simantics.utils.datastructures.MapList;\r
-import org.simantics.utils.datastructures.Pair;\r
-\r
-import freemarker.template.Configuration;\r
-import freemarker.template.DefaultObjectWrapper;\r
-import freemarker.template.Template;\r
-import freemarker.template.TemplateException;\r
-\r
-/**\r
- * @author Tuukka Lehtonen\r
- * @author Marko Luukkainen\r
- */\r
-public final class Searching {\r
- \r
- static final boolean USE_PAGING = false; // create multipage results (currently paging is handled by DataTables (JavaScript)) \r
- static final int MAX_PER_PAGE = 100;\r
- \r
-\r
- /**\r
- * @param graph\r
- * @param query\r
- * @throws DatabaseException\r
- */\r
- public static Collection<Map<String, Object>> performSearch(ReadGraph graph, Resource searchFunction, Resource model, String query, int maxResults)\r
- throws DatabaseException {\r
- @SuppressWarnings("unchecked")\r
- Function4<ReadGraph, Resource, String, Integer, Collection<Map<String, Object>>> f = graph.adapt(searchFunction, Function.class);\r
- Collection<Map<String, Object>> results = f.apply(graph, model, query, maxResults);\r
- return results;\r
- }\r
-\r
- /**\r
- * @param graph\r
- * @param query\r
- * @param maxResultsPerModel\r
- * @param results\r
- * @return\r
- * @throws IOException\r
- * @throws TemplateException\r
- * @throws DatabaseException\r
- */\r
- public static List<QueryResult> generatePage(ReadGraph graph, Collection<SearchEngine> searchEngines, SearchQuery query, int maxResultsPerModel, \r
- MapList<Resource, Pair<SearchEngine,SearchResult>> results) throws IOException, TemplateException, DatabaseException {\r
- URL fileUrl = getSearchFileURL();\r
- File dataDir = getAbsoluteFile(fileUrl);\r
-\r
- SearchData data = new SearchData();\r
- data.dataUrl = fileUrl.toString();\r
- data.dataDirectory = dataDir;\r
- data.query = query;\r
- data.maxResults = maxResultsPerModel;\r
- data.model = null;\r
- data.results = new SearchResult();\r
- data.resultCount = 0;\r
- data.searchEngines = searchEngines;\r
-\r
- \r
- int resultCount = 0;\r
- int resultNumber = 0;\r
- \r
- int itemsOnPreviousPage = 0;\r
-\r
- \r
- List<QueryResult> result = new ArrayList<QueryResult>();\r
- \r
- QueryResult header = applyTemplate(graph, "header.ftl", data);\r
- QueryResult footer = applyTemplate(graph, "footer.ftl", data);\r
- StringBuilder body = new StringBuilder(1024 * 80);\r
- \r
- if (USE_PAGING) {\r
- List<Pair<SearchEngine, SearchResult>> allResults = results.getAllValuesSnapshot();\r
- for (Pair<SearchEngine,SearchResult> entry : allResults) {\r
- List<SearchResultRow> items = entry.second.rows;\r
- resultCount += items.size();\r
- }\r
- data.resultCount = resultCount;\r
- \r
- \r
- for (Resource model : results.getKeys()) {\r
- List<Pair<SearchEngine,SearchResult>> modelResults = results.getValues(model);\r
- for (Pair<SearchEngine,SearchResult> entry : modelResults) {\r
- \r
- \r
- List<SearchResultRow> items = entry.second.rows;\r
- int start = 0;\r
- int count = items.size();\r
- \r
- while (count + itemsOnPreviousPage > MAX_PER_PAGE) {\r
- int toPage = MAX_PER_PAGE-itemsOnPreviousPage;\r
- QueryResult content = generateResultTable(graph, query, maxResultsPerModel, data, resultNumber, resultCount, model, entry.first,entry.second.subset(start, start+toPage));\r
- body.append( content.getHtml() );\r
- result.add( new QueryResult(header.getHtml(),body.toString(),footer.getHtml(), resultCount));\r
- start += toPage;\r
- count -= toPage;\r
- itemsOnPreviousPage = 0;\r
- body = new StringBuilder(1024 * 80);\r
- }\r
- if (count > 0) {\r
- QueryResult content = generateResultTable(graph, query, maxResultsPerModel, data, resultNumber, resultCount, model, entry.first,entry.second.subset(start, start+count)); \r
- body.append( content.getHtml() );\r
- itemsOnPreviousPage += count;\r
- }\r
-\r
- ++resultNumber;\r
- \r
- \r
- }\r
- }\r
- if (body.length() > 0)\r
- result.add( new QueryResult(header.getHtml(),body.toString(),footer.getHtml(), resultCount));\r
- } else {\r
- List<Pair<SearchEngine, SearchResult>> allResults = results.getAllValuesSnapshot();\r
- for (Pair<SearchEngine,SearchResult> entry : allResults) {\r
- List<SearchResultRow> items = entry.second.rows;\r
- resultCount += items.size();\r
- }\r
- data.resultCount = resultCount;\r
- \r
- for (Resource model : results.getKeys()) {\r
- List<Pair<SearchEngine,SearchResult>> modelResults = results.getValues(model);\r
- for (Pair<SearchEngine,SearchResult> entry : modelResults) {\r
- QueryResult content = generateResultTable(graph, query, maxResultsPerModel, data, resultNumber, resultCount, model, entry.first, entry.second); \r
- body.append( content.getHtml() );\r
- ++resultNumber;\r
- }\r
- }\r
- result.add( new QueryResult(header.getHtml(),body.toString(),footer.getHtml(), resultCount));\r
- }\r
- if (result.size() == 0) {\r
- result.add( new QueryResult(header.getHtml(),body.toString(),footer.getHtml(), resultCount));\r
- }\r
-\r
- return result;\r
-\r
- \r
- }\r
-\r
- /**\r
- * @param graph\r
- * @param query\r
- * @param maxResultsPerModel\r
- * @param resultNumber \r
- * @param results\r
- * @return\r
- * @throws IOException\r
- * @throws TemplateException\r
- * @throws DatabaseException\r
- */\r
- public static QueryResult generateResultTable(ReadGraph graph, SearchQuery query, int maxResultsPerModel,\r
- SearchData template, int resultNumber, int resultCount, Resource model, SearchEngine searchEngine, SearchResult results)\r
- throws IOException, TemplateException, DatabaseException {\r
- SearchData data = template.clone();\r
- data.resultNumber = resultNumber;\r
- data.query = query;\r
- data.maxResults = maxResultsPerModel;\r
- data.model = NamedResource.of(graph, model);\r
- data.results = results;\r
- data.searchEngine = searchEngine;\r
-\r
- return applyTemplate(graph, "searchtable.ftl", data);\r
- }\r
-\r
- /**\r
- * @return\r
- * @throws IOException\r
- */\r
- private static URL getSearchFileURL() throws IOException {\r
- Bundle b = Platform.getBundle(Activator.PLUGIN_ID);\r
- URL dataUrl = FileLocator.find(b, new Path("search"), null);\r
- if (dataUrl == null)\r
- throw new IOException("Could not find search template data");\r
-\r
- URL fileUrl = FileLocator.toFileURL(dataUrl);\r
- return fileUrl;\r
- }\r
-\r
- /**\r
- * @return\r
- * @throws IOException\r
- */\r
- private static File getAbsoluteFile(URL fileUrl) throws IOException {\r
- File dataDir = new File(URLDecoder.decode(fileUrl.getPath(), "UTF-8")).getAbsoluteFile();\r
- return dataDir;\r
- }\r
-\r
- \r
- /**\r
- * @param graph\r
- * @param templateName\r
- * @param data\r
- * @return\r
- * @throws IOException\r
- * @throws TemplateException\r
- * @throws DatabaseException\r
- */\r
- public static QueryResult applyTemplate(ReadGraph graph, String templateName, SearchData data)\r
- throws IOException, TemplateException, DatabaseException {\r
- Configuration cfg = new Configuration();\r
- cfg.setDirectoryForTemplateLoading(data.getDataDirectory());\r
- cfg.setObjectWrapper(new DefaultObjectWrapper());\r
-\r
- Template temp = cfg.getTemplate(templateName);\r
- CharArrayWriter writer = new CharArrayWriter(1024 * 128);\r
- temp.process(data, writer);\r
-\r
- return new QueryResult(writer.toString(), data.results.rows.size());\r
- }\r
-\r
- /**\r
- * @param graph\r
- * @param results\r
- * @return map: model -> SearchResult\r
- * @throws DatabaseException\r
- */\r
- public static final SearchResult generateDependenciesSearchResult(ReadGraph graph,\r
- Collection<Map<String, Object>> results) throws DatabaseException {\r
- Set<Resource> processed = new HashSet<Resource>();\r
- SearchResult result = new SearchResult(NameAndTypeRow.columns);\r
-\r
- NameLabelMode mode = NameLabelUtil.getNameLabelMode(graph);\r
-\r
- for (Map<String, Object> r : results) {\r
- Resource resource = (Resource) r.get("Resource");\r
-\r
- // Prevent index corruption from producing duplicate results.\r
- if (!processed.add(resource))\r
- continue;\r
-\r
- Resource parent = (Resource) r.get("Parent");\r
- String name = (String) r.get("Name");\r
-\r
- NameAndTypeRow rst = new NameAndTypeRow();\r
- rst.resource = NamedResource.of(graph, resource, name);\r
- rst.parent = NamedResource.of(graph, parent, NameLabelUtil.modalName(graph, parent, mode));\r
-\r
- Collection<Resource> typeResources = graph.getTypes(resource);\r
- Collection<Resource> principalTypeResources = graph.getPrincipalTypes(resource);\r
- if (!typeResources.isEmpty()) {\r
- rst.types = new ArrayList<NamedResource>(typeResources.size());\r
- rst.principalTypes = new ArrayList<NamedResource>(principalTypeResources.size());\r
- for (Resource t : typeResources) {\r
- NamedResource nr = NamedResource.of(graph, t);\r
- rst.types.add(nr);\r
- if (principalTypeResources.contains(t))\r
- rst.principalTypes.add(nr);\r
- }\r
- }\r
-\r
- result.addRow(rst);\r
- }\r
-\r
- return result;\r
- }\r
-\r
-}\r
+package org.simantics.workbench.search;
+
+import java.io.CharArrayWriter;
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.osgi.framework.Bundle;
+import org.simantics.NameLabelMode;
+import org.simantics.NameLabelUtil;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.scl.runtime.function.Function;
+import org.simantics.scl.runtime.function.Function4;
+import org.simantics.utils.datastructures.MapList;
+import org.simantics.utils.datastructures.Pair;
+
+import freemarker.template.Configuration;
+import freemarker.template.DefaultObjectWrapper;
+import freemarker.template.Template;
+import freemarker.template.TemplateException;
+
+/**
+ * @author Tuukka Lehtonen
+ * @author Marko Luukkainen
+ */
+public final class Searching {
+
+ static final boolean USE_PAGING = false; // create multipage results (currently paging is handled by DataTables (JavaScript))
+ static final int MAX_PER_PAGE = 100;
+
+
+ /**
+ * @param graph
+ * @param query
+ * @throws DatabaseException
+ */
+ public static Collection<Map<String, Object>> performSearch(ReadGraph graph, Resource searchFunction, Resource model, String query, int maxResults)
+ throws DatabaseException {
+ @SuppressWarnings("unchecked")
+ Function4<ReadGraph, Resource, String, Integer, Collection<Map<String, Object>>> f = graph.adapt(searchFunction, Function.class);
+ Collection<Map<String, Object>> results = f.apply(graph, model, query, maxResults);
+ return results;
+ }
+
+ /**
+ * @param graph
+ * @param query
+ * @param maxResultsPerModel
+ * @param results
+ * @return
+ * @throws IOException
+ * @throws TemplateException
+ * @throws DatabaseException
+ */
+ public static List<QueryResult> generatePage(ReadGraph graph, Collection<SearchEngine> searchEngines, SearchQuery query, int maxResultsPerModel,
+ MapList<Resource, Pair<SearchEngine,SearchResult>> results) throws IOException, TemplateException, DatabaseException {
+ URL fileUrl = getSearchFileURL();
+ File dataDir = getAbsoluteFile(fileUrl);
+
+ SearchData data = new SearchData();
+ data.dataUrl = fileUrl.toString();
+ data.dataDirectory = dataDir;
+ data.query = query;
+ data.maxResults = maxResultsPerModel;
+ data.model = null;
+ data.results = new SearchResult();
+ data.resultCount = 0;
+ data.searchEngines = searchEngines;
+
+
+ int resultCount = 0;
+ int resultNumber = 0;
+
+ int itemsOnPreviousPage = 0;
+
+
+ List<QueryResult> result = new ArrayList<QueryResult>();
+
+ QueryResult header = applyTemplate(graph, "header.ftl", data);
+ QueryResult footer = applyTemplate(graph, "footer.ftl", data);
+ StringBuilder body = new StringBuilder(1024 * 80);
+
+ if (USE_PAGING) {
+ List<Pair<SearchEngine, SearchResult>> allResults = results.getAllValuesSnapshot();
+ for (Pair<SearchEngine,SearchResult> entry : allResults) {
+ List<SearchResultRow> items = entry.second.rows;
+ resultCount += items.size();
+ }
+ data.resultCount = resultCount;
+
+
+ for (Resource model : results.getKeys()) {
+ List<Pair<SearchEngine,SearchResult>> modelResults = results.getValues(model);
+ for (Pair<SearchEngine,SearchResult> entry : modelResults) {
+
+
+ List<SearchResultRow> items = entry.second.rows;
+ int start = 0;
+ int count = items.size();
+
+ while (count + itemsOnPreviousPage > MAX_PER_PAGE) {
+ int toPage = MAX_PER_PAGE-itemsOnPreviousPage;
+ QueryResult content = generateResultTable(graph, query, maxResultsPerModel, data, resultNumber, resultCount, model, entry.first,entry.second.subset(start, start+toPage));
+ body.append( content.getHtml() );
+ result.add( new QueryResult(header.getHtml(),body.toString(),footer.getHtml(), resultCount));
+ start += toPage;
+ count -= toPage;
+ itemsOnPreviousPage = 0;
+ body = new StringBuilder(1024 * 80);
+ }
+ if (count > 0) {
+ QueryResult content = generateResultTable(graph, query, maxResultsPerModel, data, resultNumber, resultCount, model, entry.first,entry.second.subset(start, start+count));
+ body.append( content.getHtml() );
+ itemsOnPreviousPage += count;
+ }
+
+ ++resultNumber;
+
+
+ }
+ }
+ if (body.length() > 0)
+ result.add( new QueryResult(header.getHtml(),body.toString(),footer.getHtml(), resultCount));
+ } else {
+ List<Pair<SearchEngine, SearchResult>> allResults = results.getAllValuesSnapshot();
+ for (Pair<SearchEngine,SearchResult> entry : allResults) {
+ List<SearchResultRow> items = entry.second.rows;
+ resultCount += items.size();
+ }
+ data.resultCount = resultCount;
+
+ for (Resource model : results.getKeys()) {
+ List<Pair<SearchEngine,SearchResult>> modelResults = results.getValues(model);
+ for (Pair<SearchEngine,SearchResult> entry : modelResults) {
+ QueryResult content = generateResultTable(graph, query, maxResultsPerModel, data, resultNumber, resultCount, model, entry.first, entry.second);
+ body.append( content.getHtml() );
+ ++resultNumber;
+ }
+ }
+ result.add( new QueryResult(header.getHtml(),body.toString(),footer.getHtml(), resultCount));
+ }
+ if (result.size() == 0) {
+ result.add( new QueryResult(header.getHtml(),body.toString(),footer.getHtml(), resultCount));
+ }
+
+ return result;
+
+
+ }
+
+ /**
+ * @param graph
+ * @param query
+ * @param maxResultsPerModel
+ * @param resultNumber
+ * @param results
+ * @return
+ * @throws IOException
+ * @throws TemplateException
+ * @throws DatabaseException
+ */
+ public static QueryResult generateResultTable(ReadGraph graph, SearchQuery query, int maxResultsPerModel,
+ SearchData template, int resultNumber, int resultCount, Resource model, SearchEngine searchEngine, SearchResult results)
+ throws IOException, TemplateException, DatabaseException {
+ SearchData data = template.clone();
+ data.resultNumber = resultNumber;
+ data.query = query;
+ data.maxResults = maxResultsPerModel;
+ data.model = NamedResource.of(graph, model);
+ data.results = results;
+ data.searchEngine = searchEngine;
+
+ return applyTemplate(graph, "searchtable.ftl", data);
+ }
+
+ /**
+ * @return
+ * @throws IOException
+ */
+ private static URL getSearchFileURL() throws IOException {
+ Bundle b = Platform.getBundle(Activator.PLUGIN_ID);
+ URL dataUrl = FileLocator.find(b, new Path("search"), null);
+ if (dataUrl == null)
+ throw new IOException("Could not find search template data");
+
+ URL fileUrl = FileLocator.toFileURL(dataUrl);
+ return fileUrl;
+ }
+
+ /**
+ * @return
+ * @throws IOException
+ */
+ private static File getAbsoluteFile(URL fileUrl) throws IOException {
+ File dataDir = new File(URLDecoder.decode(fileUrl.getPath(), "UTF-8")).getAbsoluteFile();
+ return dataDir;
+ }
+
+
+ /**
+ * @param graph
+ * @param templateName
+ * @param data
+ * @return
+ * @throws IOException
+ * @throws TemplateException
+ * @throws DatabaseException
+ */
+ public static QueryResult applyTemplate(ReadGraph graph, String templateName, SearchData data)
+ throws IOException, TemplateException, DatabaseException {
+ Configuration cfg = new Configuration();
+ cfg.setDirectoryForTemplateLoading(data.getDataDirectory());
+ cfg.setObjectWrapper(new DefaultObjectWrapper());
+
+ Template temp = cfg.getTemplate(templateName);
+ CharArrayWriter writer = new CharArrayWriter(1024 * 128);
+ temp.process(data, writer);
+
+ return new QueryResult(writer.toString(), data.results.rows.size());
+ }
+
+ /**
+ * @param graph
+ * @param results
+ * @return map: model -> SearchResult
+ * @throws DatabaseException
+ */
+ public static final SearchResult generateDependenciesSearchResult(ReadGraph graph,
+ Collection<Map<String, Object>> results) throws DatabaseException {
+ Set<Resource> processed = new HashSet<Resource>();
+ SearchResult result = new SearchResult(NameAndTypeRow.columns);
+
+ NameLabelMode mode = NameLabelUtil.getNameLabelMode(graph);
+
+ for (Map<String, Object> r : results) {
+ Resource resource = (Resource) r.get("Resource");
+
+ // Prevent index corruption from producing duplicate results.
+ if (!processed.add(resource))
+ continue;
+
+ Resource parent = (Resource) r.get("Parent");
+ String name = (String) r.get("Name");
+
+ NameAndTypeRow rst = new NameAndTypeRow();
+ rst.resource = NamedResource.of(graph, resource, name);
+ rst.parent = NamedResource.of(graph, parent, NameLabelUtil.modalName(graph, parent, mode));
+
+ Collection<Resource> typeResources = graph.getTypes(resource);
+ Collection<Resource> principalTypeResources = graph.getPrincipalTypes(resource);
+ if (!typeResources.isEmpty()) {
+ rst.types = new ArrayList<NamedResource>(typeResources.size());
+ rst.principalTypes = new ArrayList<NamedResource>(principalTypeResources.size());
+ for (Resource t : typeResources) {
+ NamedResource nr = NamedResource.of(graph, t);
+ rst.types.add(nr);
+ if (principalTypeResources.contains(t))
+ rst.principalTypes.add(nr);
+ }
+ }
+
+ result.addRow(rst);
+ }
+
+ return result;
+ }
+
+}