--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ * VTT Technical Research Centre of Finland - initial API and implementation\r
+ * Semantum Oy - index based searching (#4255)\r
+ *******************************************************************************/\r
+package org.simantics.debug.ui;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.Collections;\r
+import java.util.HashSet;\r
+import java.util.LinkedList;\r
+import java.util.List;\r
+import java.util.Set;\r
+import java.util.regex.Pattern;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.Statement;\r
+import org.simantics.db.common.request.Queries;\r
+import org.simantics.db.common.request.ReadRequest;\r
+import org.simantics.db.common.utils.NameUtils;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.request.Read;\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.utils.strings.EString;\r
+import org.simantics.utils.threads.IThreadWorkQueue;\r
+\r
+public class ResourceSearch extends ReadRequest {\r
+\r
+ public static final IResourceFilter FILTER_ALL = new IResourceFilter() {\r
+ @Override\r
+ public boolean acceptResource(ReadGraph g, Resource r) {\r
+ return true;\r
+ }\r
+ };\r
+\r
+ public static final IResourceFilter FILTER_RELATIONS = new IResourceFilter() {\r
+ @Override\r
+ public boolean acceptResource(ReadGraph g, Resource r) throws DatabaseException {\r
+ return g.isInstanceOf(r, Layer0.getInstance(g).Relation);\r
+ }\r
+ };\r
+\r
+ public static final IResourceFilter FILTER_TYPES = new IResourceFilter() {\r
+ @Override\r
+ public boolean acceptResource(ReadGraph g, Resource r) throws DatabaseException {\r
+ Layer0 L0 = Layer0.getInstance(g);\r
+ return g.isInstanceOf(r, L0.Type) && !g.isInstanceOf(r, L0.Relation);\r
+ }\r
+ };\r
+\r
+ /**\r
+ * Create filter that matches URI, ID and NAME using wildcard compare\r
+ * @param txt\r
+ * @return\r
+ */\r
+ public static final IResourceFilter createFilter(String txt) {\r
+ final Pattern p = EString.compileSimplePattern(txt);\r
+ return new IResourceFilter() {\r
+ @Override\r
+ public boolean acceptResource(ReadGraph g, Resource r) {\r
+ try {\r
+ String uri = g.syncRequest(Queries.possibleUri(r));\r
+ if (uri != null && p.matcher(uri).matches())\r
+ return true;\r
+ } catch (Throwable t) {}\r
+\r
+ try {\r
+ String name = NameUtils.getSafeName(g, r);\r
+ if (p.matcher(name).matches())\r
+ return true;\r
+ } catch (Throwable t) {}\r
+\r
+ String id = Long.toString(r.getResourceId());\r
+ if (p.matcher(id).matches())\r
+ return true;\r
+\r
+ return false;\r
+ }\r
+ };\r
+ }\r
+\r
+ public interface IResourceFilter {\r
+ boolean acceptResource(ReadGraph g, Resource r) throws DatabaseException;\r
+ }\r
+\r
+ public interface SearchListener {\r
+ /**\r
+ * \r
+ * @param s\r
+ * @param r\r
+ * @param g graph if listening is not async, if so then null\r
+ */\r
+ void onResourceFound(Read<?> s, Collection<Resource> r, ReadGraph g) throws DatabaseException;\r
+ void onSearchComplete(Read<?> s);\r
+ void onError(Read<?> s, Throwable e);\r
+ }\r
+\r
+ boolean canceled = false;\r
+ IResourceFilter filter;\r
+ SearchListener listener;\r
+ IThreadWorkQueue listenerThread;\r
+ ResFoundQueue resFoundQueue;\r
+ boolean asyncListening;\r
+\r
+ public ResourceSearch(IResourceFilter f, SearchListener l, IThreadWorkQueue listenerThread, boolean asyncListening)\r
+ {\r
+ assert(f!=null && l!=null);\r
+ this.filter = f;\r
+ this.listener = l;\r
+ this.listenerThread = listenerThread;\r
+ this.asyncListening = asyncListening;\r
+ if (listenerThread!=null)\r
+ resFoundQueue = new ResFoundQueue();\r
+ }\r
+\r
+ public void cancel() {\r
+ canceled = true;\r
+ }\r
+\r
+ public boolean isCanceled() {\r
+ return canceled;\r
+ }\r
+\r
+ private class ResFoundQueue implements Runnable {\r
+ ReadGraph g;\r
+ List<Resource> list = new ArrayList<Resource>();\r
+ /**\r
+ * add res to queue\r
+ * @param r\r
+ * @return true if other resources are still unhandled\r
+ */\r
+ synchronized boolean addResource(Resource r) {\r
+ list.add(r);\r
+ return list.size()>1;\r
+ }\r
+ @Override\r
+ public void run() {\r
+ try {\r
+ Collection<Resource> l = null;\r
+ synchronized(this) {\r
+ if (list.size()==0) return;\r
+ if (list.size()<10) {\r
+ listener.onResourceFound(ResourceSearch.this, list, g);\r
+ list.clear();\r
+ return;\r
+ }\r
+ l = new ArrayList<Resource>(list);\r
+ list.clear();\r
+ }\r
+ listener.onResourceFound(ResourceSearch.this, l, g);\r
+ } catch (DatabaseException e) {\r
+\r
+ }\r
+ }\r
+ }\r
+\r
+ @Override\r
+ public void run(ReadGraph g) {\r
+ try {\r
+ if (!asyncListening && resFoundQueue!=null) resFoundQueue.g = g;\r
+ Resource root = g.getResource("http:/");\r
+ Layer0 L0 = Layer0.getInstance(g);\r
+ LinkedList<Resource> queue = new LinkedList<Resource>();\r
+ queue.add(root);\r
+ Set<Resource> queued = new HashSet<Resource>();\r
+ while(!queue.isEmpty() && !canceled) {\r
+ Resource r = queue.removeFirst();\r
+ if (filter.acceptResource(g, r)) {\r
+ if (listenerThread==null)\r
+ listener.onResourceFound(ResourceSearch.this, Collections.singletonList(r), g);\r
+ else {\r
+ if (!resFoundQueue.addResource(r)) {\r
+ if (asyncListening)\r
+ listenerThread.asyncExec(resFoundQueue);\r
+ else\r
+ listenerThread.syncExec(resFoundQueue);\r
+ }\r
+ }\r
+ }\r
+ for (Statement stm : g.getStatements(r, L0.IsWeaklyRelatedTo))\r
+ {\r
+ Resource n = stm.getPredicate();\r
+ if (!queued.contains(n)) {\r
+ queue.add(n);\r
+ queued.add(n);\r
+ }\r
+\r
+ n = stm.getObject();\r
+ if (!queued.contains(n)) {\r
+ queue.add(n);\r
+ queued.add(n);\r
+ }\r
+ }\r
+ if (listenerThread==null)\r
+ listener.onSearchComplete(ResourceSearch.this);\r
+ else {\r
+ Runnable run = new Runnable() {\r
+ @Override\r
+ public void run() {\r
+ ResourceSearch.this.listener.onSearchComplete(ResourceSearch.this);\r
+ }};\r
+ if (asyncListening)\r
+ listenerThread.asyncExec(run);\r
+ else\r
+ listenerThread.syncExec(run);\r
+ }\r
+ }\r
+ } catch (final Throwable e) {\r
+ if (listenerThread==null)\r
+ listener.onError(ResourceSearch.this, e);\r
+ else {\r
+ Runnable r = new Runnable() {\r
+ @Override\r
+ public void run() {\r
+ listener.onError(ResourceSearch.this, e);\r
+ }};\r
+ if (asyncListening)\r
+ listenerThread.asyncExec(r);\r
+ else\r
+ listenerThread.syncExec(r);\r
+ }\r
+ }\r
+ }\r
+\r
+}\r