]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.workbench/src/org/simantics/workbench/internal/contributions/search/SearchServiceImpl.java
e0a96ed12c39d62c880743b945bd6a1fecea2738
[simantics/platform.git] / bundles / org.simantics.workbench / src / org / simantics / workbench / internal / contributions / search / SearchServiceImpl.java
1 package org.simantics.workbench.internal.contributions.search;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.net.MalformedURLException;
6 import java.net.URI;
7 import java.net.URISyntaxException;
8 import java.net.URL;
9 import java.util.ArrayList;
10 import java.util.Collection;
11 import java.util.Collections;
12 import java.util.HashMap;
13 import java.util.HashSet;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.Set;
17
18 import org.eclipse.core.runtime.IProgressMonitor;
19 import org.eclipse.core.runtime.IStatus;
20 import org.eclipse.core.runtime.NullProgressMonitor;
21 import org.eclipse.core.runtime.Status;
22 import org.eclipse.core.runtime.SubMonitor;
23 import org.eclipse.core.runtime.jobs.Job;
24 import org.eclipse.jface.viewers.ISelection;
25 import org.eclipse.jface.viewers.StructuredSelection;
26 import org.eclipse.swt.SWT;
27 import org.eclipse.swt.browser.LocationEvent;
28 import org.eclipse.swt.browser.LocationListener;
29 import org.eclipse.swt.events.DisposeEvent;
30 import org.eclipse.swt.events.DisposeListener;
31 import org.eclipse.swt.widgets.Control;
32 import org.eclipse.swt.widgets.Display;
33 import org.eclipse.swt.widgets.Shell;
34 import org.eclipse.ui.IViewPart;
35 import org.eclipse.ui.IViewReference;
36 import org.eclipse.ui.IWorkbenchPage;
37 import org.eclipse.ui.IWorkbenchWindow;
38 import org.eclipse.ui.PartInitException;
39 import org.eclipse.ui.PlatformUI;
40 import org.simantics.ObjectIdentitySchedulingRule;
41 import org.simantics.Simantics;
42 import org.simantics.databoard.Bindings;
43 import org.simantics.db.ReadGraph;
44 import org.simantics.db.Resource;
45 import org.simantics.db.Session;
46 import org.simantics.db.exception.DatabaseException;
47 import org.simantics.db.layer0.adapter.Instances;
48 import org.simantics.db.layer0.request.ActiveModels;
49 import org.simantics.db.request.Read;
50 import org.simantics.db.service.SerialisationSupport;
51 import org.simantics.editors.Browser;
52 import org.simantics.editors.BrowserInput;
53 import org.simantics.layer0.Layer0;
54 import org.simantics.scl.runtime.function.Function;
55 import org.simantics.scl.runtime.function.Function5;
56 import org.simantics.ui.workbench.action.ChooseActionRequest;
57 import org.simantics.utils.FileUtils;
58 import org.simantics.utils.datastructures.MapList;
59 import org.simantics.utils.datastructures.Pair;
60 import org.simantics.utils.ui.ErrorLogger;
61 import org.simantics.utils.ui.ExceptionUtils;
62 import org.simantics.utils.ui.workbench.WorkbenchUtils;
63 import org.simantics.workbench.internal.Activator;
64 import org.simantics.workbench.ontology.WorkbenchResource;
65 import org.simantics.workbench.search.ISearchService;
66 import org.simantics.workbench.search.QueryResult;
67 import org.simantics.workbench.search.SearchEngine;
68 import org.simantics.workbench.search.SearchQuery;
69 import org.simantics.workbench.search.SearchResult;
70 import org.simantics.workbench.search.Searching;
71
72 import freemarker.template.TemplateException;
73
74 /**
75  * @author Tuukka Lehtonen
76  * @author Marko Luukkainen
77  */
78 public class SearchServiceImpl implements ISearchService{
79
80         private static final String SEARCH_TEMP_FILE_SUFFIX = "search.html";
81         private static final String SEARCH_TEMP_DIR = "search";
82         private static final String        BROWSER_VIEW = BrowserView.ID;
83         private static final Integer       MAX_RESULTS = 1000;
84
85         @Override
86         public void performQuery(SearchQuery query, ResultBrowser browserType, boolean activateResultBrowser) {
87                 try {
88                         Set<SearchEngine> searchEngines = getSearchEngines();
89                         
90                         // if query does not define used engines, use all available engines.
91                         boolean containsEngines = false;
92                         for (SearchEngine e : searchEngines) {
93                                 if (query.getSearchFlags().containsKey(e.getId())) {
94                                         containsEngines = true;
95                                         break;
96                                 }
97                         }
98                         if (!containsEngines) {
99                                 for (SearchEngine e : searchEngines)
100                                         if (e.isEnabledByDefault())
101                                                 query.setSearchFlag(e.getId(), "on");
102                         }
103                 } catch (DatabaseException e) {
104                         ExceptionUtils.logError(e);
105                 }
106         switch (browserType) {
107             case EDITOR:
108                 performEditorQuery(query);
109                 break;
110             case VIEW:
111                 performViewQuery(query, activateResultBrowser);
112                 break;
113         }
114                 
115         }
116
117          private void performViewQuery(SearchQuery query, boolean activateResultBrowser) {
118                 try {
119                     browserView = (BrowserView) showLocalView(
120                             BROWSER_VIEW,
121                             activateResultBrowser ? IWorkbenchPage.VIEW_ACTIVATE : IWorkbenchPage.VIEW_CREATE);
122                     if (browserView.getBrowser() != browserViewBrowser) {
123                         browserViewBrowser = browserView.getBrowser();
124                         browserViewTemporaryFiles = new ArrayList<File>();
125                         browserViewTemporaryFiles.add(getNewTemporaryFile());
126                         browserView.getBrowser().addLocationListener(browserViewLocationListener);
127                         browserView.getBrowser().addDisposeListener(new DisposeListener() {
128                             @Override
129                             public void widgetDisposed(DisposeEvent e) {
130                                 browserViewBrowser = null;
131                             }
132                         });
133                     }
134                     browserView.setPartProperty(BrowserView.LAST_QUERY_PROPERTY, query.getOriginalQuery());
135                     updateViewQuery(browserView, browserViewTemporaryFiles, query);
136                 } catch (IOException e1) {
137                     ErrorLogger.defaultLogError(e1);
138                 } catch (PartInitException e1) {
139                     ErrorLogger.defaultLogError(e1);
140                 }
141             }
142
143     private IViewPart showLocalView(String id, int mode) throws PartInitException {
144         final IWorkbenchWindow wb = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
145         if (wb == null)
146             return null;
147
148         // Is view already created in the currently active workbench window?
149         IViewPart vp = findViewFromWindow(wb, id, false);
150         if (vp != null) {
151             if (mode == IWorkbenchPage.VIEW_CREATE)
152                 return vp;
153             IWorkbenchPage page = vp.getViewSite().getPage();
154             if (mode == IWorkbenchPage.VIEW_VISIBLE) {
155                 page.bringToTop(vp);
156             } else if (mode == IWorkbenchPage.VIEW_ACTIVATE) {
157                 page.activate(vp);
158             }
159             return vp;
160         }
161
162         // Create the view on the active window's active page
163         IWorkbenchPage page = wb.getActivePage();
164         if (page == null) {
165             IWorkbenchPage pages[] = wb.getPages();
166             if (pages.length == 0) return null;
167             page = pages[0];
168         }
169         return page.showView(id, null, mode);
170     }
171
172     private static IViewPart findViewFromWindow(IWorkbenchWindow wb, String viewId, boolean restore) {
173         for (IWorkbenchPage page : wb.getPages()) {
174             IViewReference vr = page.findViewReference(viewId);
175             if (vr != null) {
176                 IViewPart vp = vr.getView(restore);
177                 if (vp != null)
178                     return vp;
179             }
180         }
181         return null;
182     }
183
184         /**
185              * There's always only one of these around.
186              */
187             BrowserView                     browserView                 = null;
188
189             org.eclipse.swt.browser.Browser browserViewBrowser          = null;
190
191             List<File>                      browserViewTemporaryFiles    = null;
192
193             LocationListener                browserViewLocationListener = new LocationListener() {
194                 @Override
195                 public void changing(LocationEvent event) {
196                     //System.out.println("changing: " + event);
197                     try {
198                         URI newUri = new URI(event.location);
199
200                         // Handle resource links by opening an editor for them
201                         if ("resource".equals(newUri.getScheme())) {
202                             event.doit = false;
203                             openResource(getShell(event), newUri.getSchemeSpecificPart());
204                             return;
205                         }
206                     } catch (URISyntaxException e) {
207                         // This URI was not needed anyway, resource: URIs will always parse properly so let
208                         // it go without logging.
209                     } catch (DatabaseException e) {
210                         ErrorLogger.defaultLogError(e);
211                     }
212                 }
213
214                 @Override
215                 public void changed(LocationEvent event) {
216                     // System.out.println("changed: " + event);
217                     try {
218                         URL newUrl = new URL(event.location);
219                         String query = newUrl.getQuery();
220                         if (query != null) {
221                                 SearchQuery searchQuery = SearchQuery.decode(newUrl);
222                                 if (searchQuery.getOriginalQuery() != null) {
223                                     event.doit = updateViewQuery(
224                                             browserView,
225                                             browserViewTemporaryFiles,
226                                             searchQuery);
227                                 
228                             }
229                         }
230                     } catch (IOException e) {
231                         ErrorLogger.defaultLogError(e);
232                     }
233                 }
234             };
235
236             class ViewQueryJob extends Job {
237
238                 SearchQuery      query;
239
240                 List<File>        temporaryFiles;
241
242                 BrowserView browserView;
243
244                 Display     display;
245
246                 public ViewQueryJob(SearchQuery query, List<File> temporaryFiles, BrowserView browserView) {
247                     super("Search...");
248                     this.query = query;
249                     this.temporaryFiles = temporaryFiles;
250                     this.browserView = browserView;
251                     this.display = browserView.getBrowser().getDisplay();
252                 }
253
254                 @Override
255                 protected IStatus run(IProgressMonitor monitor) {
256                     try {
257                         SubMonitor mon = SubMonitor.convert(monitor);
258                         monitor.beginTask("Performing search '" + query + "'", 10);
259                         monitor.subTask("Querying index");
260                         final List<QueryResult> result = createResultPage(mon.newChild(8), query, MAX_RESULTS);
261                         if (result == null) {
262                             return Status.CANCEL_STATUS;
263                         }
264                         monitor.worked(8);
265                         monitor.subTask("Generating results");
266                         updatePages(result, temporaryFiles);
267                         monitor.worked(2);
268                         updateBrowser(browserView, result.get(0));
269                         return Status.OK_STATUS;
270                     } catch (DatabaseException e1) {
271                         return new Status(IStatus.ERROR, Activator.PLUGIN_ID,
272                                 "Unexpected database problems during search result processing, see exception.", e1);
273                     } catch (IOException e1) {
274                         return new Status(IStatus.ERROR, Activator.PLUGIN_ID,
275                                 "Unexpected I/O problems during search result processing, see exception.", e1);
276                     } finally {
277                         monitor.done();
278                     }
279                 }
280
281                 void updateBrowser(final BrowserView browserView, final QueryResult result) {
282                     if (display.isDisposed())
283                         return;
284                     display.asyncExec(new Runnable() {
285                         @Override
286                         public void run() {
287                             if (browserView.isDisposed())
288                                 return;
289
290                             try {
291                                 long t1 = System.currentTimeMillis();
292                                 browserView.setUrl(temporaryFiles.get(0).toURI().toURL());
293                                 //browserView.setContentDescription("'" + query + "' - " + result.getHitCount() + " matches in active model");
294                                 long t2 = System.currentTimeMillis();
295                                 System.out.println("Updating UI " + (t2-t1) + " ms");
296                             } catch (MalformedURLException e) {
297                                 ErrorLogger.defaultLogError(e);
298                             }
299                         }
300                     });
301                 }
302             }
303
304             protected boolean updateViewQuery(BrowserView browserView, List<File> temporaryFiles, SearchQuery query) {
305                 ViewQueryJob job = new ViewQueryJob(query, temporaryFiles, browserView);
306                 job.setRule(new ObjectIdentitySchedulingRule(browserView));
307                 job.schedule();
308                 return true;
309             }
310
311             protected Shell getShell(LocationEvent event) {
312                 if (event.widget instanceof Control) {
313                     Control c = (Control) event.widget;
314                     if (c.isDisposed())
315                         return null;
316                     return c.getShell();
317                 }
318                 return null;
319             }
320
321             /**
322              * @param query
323              */
324             protected void performEditorQuery(final SearchQuery query) {
325                 try {
326                     final List<File> temporaryFiles = new ArrayList<File>();
327                     temporaryFiles.add(getNewTemporaryFile());
328                     final BrowserInput input = createBrowserInput(temporaryFiles.get(0), query);
329                     updateInput(input, temporaryFiles.get(0), query);
330
331                     final Browser browser = (Browser) WorkbenchUtils.openEditor("org.simantics.editors.browser", input);
332
333                     browser.getBrowser().addLocationListener(new LocationListener() {
334                         @Override
335                         public void changing(LocationEvent event) {
336                             // System.out.println("changing: " + event);
337                             try {
338                                 // TODO : is there a better way to escape location?
339                                 URI newUri = new URI(event.location.replaceAll(" ", "%20"));
340                                 // Handle resource links by opening an editor for them
341                                 if ("resource".equals(newUri.getScheme())) {
342                                     event.doit = false;
343                                     openResource(getShell(event), newUri.getSchemeSpecificPart());
344                                     return;
345                                 }
346                             } catch (URISyntaxException e) {
347                                 ErrorLogger.defaultLogError(e);
348                             } catch (DatabaseException e) {
349                                 ErrorLogger.defaultLogError(e);
350                             }
351                         }
352
353                         @Override
354                         public void changed(LocationEvent event) {
355                             if (query != null) {
356                                 // OpenEditor does not seem to pass any parameters (anything after '?' character) 
357                                 SearchQuery searchQuery = query;
358                                 if (searchQuery.getOriginalQuery() != null) {
359                                     event.doit = updateQuery(browser, input, temporaryFiles, searchQuery);
360                                 }
361                             }
362                         }
363                     });
364                 } catch (IOException e1) {
365                     ErrorLogger.defaultLogError(e1);
366                 } catch (PartInitException e1) {
367                     ErrorLogger.defaultLogError(e1);
368                 }
369             }
370
371             protected void openResource(Shell shell, String link) throws DatabaseException {
372                 try {
373                     Session session = Simantics.getSession();
374                     final long id = Long.parseLong(link);
375
376                     Resource resource = session.syncRequest(new Read<Resource>() {
377                         @Override
378                         public Resource perform(ReadGraph graph) throws DatabaseException {
379                             SerialisationSupport ss = graph.getService(SerialisationSupport.class);
380                             return ss.getResource(id);
381                         }
382                     });
383
384                     ISelection input = new StructuredSelection(resource);
385                     String perspectiveId = WorkbenchUtils.getCurrentPerspectiveId();
386
387                     // Try the doubleClick-extensions
388                     session.asyncRequest(new ChooseActionRequest(shell, input, perspectiveId, false, true));
389                 } catch (NumberFormatException e) {
390                     return;
391                 }
392             }
393
394             /**
395              * @param query
396              */
397             protected static boolean updateQuery(Browser browser, BrowserInput input, List<File> temporaryFiles, final SearchQuery query) {
398                 try {
399                     String url = browser.getBrowser().getUrl();
400                     String inputUrl = input.getUrl().toString();
401                     if (url.equals(inputUrl))
402                         return false;
403
404                     List<QueryResult> result = createResultPage(new NullProgressMonitor(), query, MAX_RESULTS);
405                     updateInput(input, temporaryFiles.get(0), query);
406                     updatePages(result,temporaryFiles);
407                     // browser.getBrowser().setUrl(inputUrl);
408                     browser.getBrowser().refresh();
409                     // temporaryFile.delete();
410                     for (File temporaryFile : temporaryFiles)
411                         temporaryFile.deleteOnExit();
412                     return true;
413                 } catch (DatabaseException e1) {
414                     ErrorLogger.defaultLogError(e1);
415                 } catch (IOException e1) {
416                     ErrorLogger.defaultLogError(e1);
417                 }
418                 return false;
419             }
420
421             private static File ensureTemporaryDirectoryExists() throws IOException {
422                 return Simantics.getTemporaryDirectory(SEARCH_TEMP_DIR); 
423             }
424
425             /**
426              * @param html
427              * @return
428              * @throws IOException
429              */
430             private static File getNewTemporaryFile() throws IOException {
431                 return Simantics.getTempfile(SEARCH_TEMP_DIR, SEARCH_TEMP_FILE_SUFFIX); 
432             }
433
434             /**
435              * @param query
436              * @param html
437              * @return
438              * @throws IOException
439              */
440             private static BrowserInput createBrowserInput(File file, SearchQuery query) throws IOException {
441                 // new BrowserInput(file.toURI().toURL()
442                 return new BrowserInput(SearchQuery.encode(file, query), query.getOriginalQuery(), false, false, SWT.NONE);
443             }
444             
445             private static void updatePages(List<QueryResult> result, List<File> temporaryFiles) throws IOException{
446                 ensureTemporaryDirectoryExists();
447                 for (int i = temporaryFiles.size(); i < result.size(); i++) {
448                         temporaryFiles.add(getNewTemporaryFile());
449                 }
450                 if (result.size() > 1) {
451                         createPageControls(result,temporaryFiles);
452                 }
453                 if (result.size() > 0) {
454                         for (int i = 0; i < result.size(); i++) {
455                                 updatePage(temporaryFiles.get(i), result.get(i).getHtml());
456                         }
457                 } else {
458                         updatePage(temporaryFiles.get(0), "");
459                 }
460             }
461
462             /**
463              * @param html
464              * @return
465              * @throws IOException
466              */
467             private static void updatePage(File file, String html) throws IOException {
468                 long t1 = System.currentTimeMillis();
469                 FileUtils.writeFile(file, html.getBytes("UTF-8"));
470                 long t2 = System.currentTimeMillis();
471                 System.out.println("Writing html page took " + (t2-t1) + " ms");
472             }
473             
474             private static void createPageControls(List<QueryResult> result, List<File> temporaryFiles) throws IOException{
475                 if (result.size() == 1)
476                         return;
477                 for (int i = 0; i < result.size(); i++) {
478                         boolean first = i == 0;
479                         boolean last = i == result.size() -1;
480                         QueryResult current = result.get(i);
481                         String pageContrtol = "<div class=\"resultInfo\">";
482                         pageContrtol += "Page " + (i+1) + " of "+ + result.size() + " ";
483                         if (first) {
484                                 pageContrtol += "First";
485                                 pageContrtol += " Previous";
486                                 pageContrtol += " <a href=\"" + temporaryFiles.get(i+1).toURI().toURL().toString() + "\">Next</a>";
487                                 pageContrtol += " <a href=\"" + temporaryFiles.get(result.size()-1).toURI().toURL().toString() + "\">Last</a>";
488                         } else if (last) {
489                                 pageContrtol += "<a href=\"" + temporaryFiles.get(0).toURI().toURL().toString() + "\">First</a>";
490                                 pageContrtol += " <a href=\"" + temporaryFiles.get(i-1).toURI().toURL().toString() + "\">Previous</a>";
491                                 pageContrtol += " Next";
492                                 pageContrtol += " Last";
493                         } else {
494                                 pageContrtol += "<a href=\"" + temporaryFiles.get(0).toURI().toURL().toString() + "\">First</a>";
495                                 pageContrtol += " <a href=\"" + temporaryFiles.get(i-1).toURI().toURL().toString() + "\">Previous</a>";
496                                 pageContrtol += " <a href=\"" + temporaryFiles.get(i+1).toURI().toURL().toString() + "\">Next</a>";
497                                 pageContrtol += " <a href=\"" + temporaryFiles.get(result.size()-1).toURI().toURL().toString() + "\">Last</a>";
498                         }
499                         pageContrtol += "</div><br>";
500                         
501                         result.set(i, new QueryResult(current.getHeader(), pageContrtol+current.getContent()+pageContrtol,current.getFooter(),current.getHitCount()));
502                 }
503                 
504             }
505             
506             
507
508             /**
509              * @param html
510              * @return
511              * @throws IOException
512              */
513             private static void updateInput(BrowserInput input, File file, SearchQuery query) throws IOException {
514                 URL url = SearchQuery.encode(file, query);
515                 input.setUrl(url);
516                 input.setName(query.getOriginalQuery());
517                 // System.out.println("update input: " + url + " - " + query + " - " + input);
518             }
519             
520             private static Set<SearchEngine> getSearchEngines() throws DatabaseException{
521                   return Simantics.getSession().syncRequest(new Read<Set<SearchEngine>>() {
522                           @Override
523                         public Set<SearchEngine> perform(ReadGraph graph)
524                                         throws DatabaseException {
525                                   Resource project = Simantics.peekProjectResource();
526                                   if (project == null)
527                                           return Collections.emptySet();
528                                   return getSearchEngines(graph, project);
529                         }
530                   });
531             }
532             
533             private static Set<SearchEngine> getSearchEngines(ReadGraph graph, Resource project) throws DatabaseException{
534                 Set<SearchEngine> searchEngines = new HashSet<SearchEngine>();
535                 Map<Resource, Set<SearchEngine>> result = getSearchEnginesByModel(graph, project);
536                 for (Set<SearchEngine> set : result.values())
537                         searchEngines.addAll(set);
538                 return searchEngines;
539             }
540             
541            
542                 private static Map<Resource,Set<SearchEngine>> getSearchEnginesByModel(ReadGraph graph, Resource project) throws DatabaseException{
543                 WorkbenchResource WB = WorkbenchResource.getInstance(graph);
544                 Layer0 L0 = Layer0.getInstance(graph);
545                 Map<Resource, Set<SearchEngine>> result = new HashMap<Resource, Set<SearchEngine>>();
546                 Collection<Resource> activeModels = graph.syncRequest(new ActiveModels(project));
547                 for (Resource model : activeModels) {
548                         Set<SearchEngine> searchEngines = new HashSet<SearchEngine>();
549                         
550                         List<Resource> searchFunctions = new ArrayList<Resource>();
551                     searchFunctions.addAll(graph.getObjects(model, WB.HasWorkbenchSearchFunction));
552                     if (searchFunctions.size() == 0) {
553                         searchEngines.addAll(findSearchContributions(graph, model));
554                     }
555                     if (searchFunctions.isEmpty() && searchEngines.isEmpty()) {
556                         // TODO : backwards compatibility, to be removed.
557                         searchFunctions.addAll(graph.getObjects(project, WB.HasWorkbenchSearchFunction));
558                     }
559                     if (searchFunctions.isEmpty() && searchEngines.isEmpty())
560                         searchFunctions.add( WB.DependenciesSearchFunction);
561
562                     for (Resource searchFunction : searchFunctions) {
563                         @SuppressWarnings("rawtypes")
564                         Function f = graph.adapt(searchFunction, Function.class);
565                         String id = graph.getURI(searchFunction);
566                         String name = graph.getPossibleRelatedValue2(searchFunction, L0.HasLabel);
567                         @SuppressWarnings("unchecked")
568                         SearchEngine engine = new SearchEngine(id,name,(Function5<IProgressMonitor, ReadGraph, Resource, SearchQuery, Integer, SearchResult>)f, true);
569                         {
570                                 engine.addSupportedParam("Name");
571                                 engine.addSupportedParam("Types");
572                         }
573                         searchEngines.add(engine);
574                     }
575                     result.put(model, searchEngines);
576                 }
577                 return result;
578             }
579             
580
581             /**
582              * @param subMonitor 
583              * @param query
584              * @param maxResults
585              * @return
586              * @throws DatabaseException
587              */
588             private static List<QueryResult> createResultPage(final IProgressMonitor monitor, final SearchQuery query, final int maxResults) throws DatabaseException {
589                 return Simantics.getSession().syncRequest(new Read<List<QueryResult>>() {
590                                 @Override
591                     public List<QueryResult> perform(ReadGraph graph) throws DatabaseException {
592                         Resource project = Simantics.peekProjectResource();
593                         if (project == null)
594                             return null;
595
596                         Collection<Resource> activeModels = graph.syncRequest(new ActiveModels(project));
597                         //if (activeModels.isEmpty())
598                         //    return null;
599                         long t1 = System.currentTimeMillis();
600                         Set<SearchEngine> searchEngines = new HashSet<SearchEngine>();
601                         MapList<Resource, Pair<SearchEngine,SearchResult>> searchResults = new MapList<Resource, Pair<SearchEngine,SearchResult>>();
602                         Map<Resource,Set<SearchEngine>> searchEngineMap = getSearchEnginesByModel(graph, project);
603                         
604                         for (Resource model : activeModels) {
605                                 for (SearchEngine engine : searchEngineMap.get(model)) {
606                   
607                                     if (query.getBooleanFlag(engine.getId())) {
608                                             SearchResult result = engine.getSearchFunction().apply(monitor, graph, model, query, maxResults);
609                                             if (!result.isEmpty()) {
610                                                 searchResults.add(model, new Pair<SearchEngine,SearchResult>(engine, result));
611                                             }
612                                     }
613                                     searchEngines.add(engine);
614                             }
615 //                          searchResults.put(model, result);
616                         }
617                         long t2 = System.currentTimeMillis();
618                         System.out.println("Running search queries took " + (t2-t1) + " ms for query '" + query + "'");
619
620                         try {
621                             return Searching.generatePage(graph, searchEngines,query, maxResults, searchResults);
622                         } catch (IOException e) {
623                             Activator.logError("I/O problem while generating search result page.", e);
624                         } catch (TemplateException e) {
625                             Activator.logError("Template definition problem in search result page generation. Please inform the developers.", e);
626                         }
627                         return null;
628                     }
629                 });
630             }
631
632         private static Collection<SearchEngine> findSearchContributions(ReadGraph graph, Resource model) throws DatabaseException {
633                 WorkbenchResource WB = WorkbenchResource.getInstance(graph);
634                 Instances contributionFinder = graph.adapt(WB.SearchContribution, Instances.class);
635                 Resource index = model;
636                 List<SearchEngine> result = new ArrayList<SearchEngine>();
637                 for (Resource r : contributionFinder.find(graph, index)) {
638                         SearchEngine engine = contributionToEngine(graph, r);
639                         if (engine != null)
640                                 result.add(engine);
641                 }
642                 return result;
643         }
644
645         private static SearchEngine contributionToEngine(ReadGraph graph, Resource searchContribution) throws DatabaseException {
646                 Layer0 L0 = Layer0.getInstance(graph);
647                 WorkbenchResource WB = WorkbenchResource.getInstance(graph);
648
649                 Resource searchFunction = graph.getPossibleObject(searchContribution, WB.hasSearchFunction);
650                 if (searchFunction == null)
651                         return null;
652
653                 @SuppressWarnings("rawtypes")
654                 Function f = graph.adapt(searchFunction, Function.class);
655                 String id = graph.getURI(searchFunction);
656                 String name = graph.getPossibleRelatedValue2(searchFunction, L0.HasLabel);
657
658                 Boolean enabledByDefault = graph.getPossibleRelatedValue2(searchContribution, WB.SearchContribution_isEnabledByDefault, Bindings.BOOLEAN);
659                 boolean enabled = !Boolean.FALSE.equals(enabledByDefault);
660
661                 @SuppressWarnings("unchecked")
662                 SearchEngine engine = new SearchEngine(id,name,(Function5<IProgressMonitor, ReadGraph, Resource, SearchQuery, Integer, SearchResult>)f, enabled);
663                 {
664                         engine.addSupportedParam("Name");
665                         engine.addSupportedParam("Types");
666                 }
667                 return engine;
668         }
669
670 }