Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian W. Damus2013-08-29 22:46:29 +0000
committerChristian W. Damus2013-09-06 18:38:59 +0000
commit18db5670f78a974f7b8cd62d6d2694169be8d614 (patch)
tree936ba0e48bca7d98fcc50be86ec1e46d35401d46 /plugins
parentfd811174e7210d1d1bdc1e18af8ced3ab2469d52 (diff)
downloadorg.eclipse.papyrus-18db5670f78a974f7b8cd62d6d2694169be8d614.tar.gz
org.eclipse.papyrus-18db5670f78a974f7b8cd62d6d2694169be8d614.tar.xz
org.eclipse.papyrus-18db5670f78a974f7b8cd62d6d2694169be8d614.zip
415371: [CDO] Pluggable query providers for simple and advanced text search.
Implement a new extension point for pluggable "query providers" that know how to query within the search scope identified by a URI in their "domain" (whether workspace, CDO repository, or other). The search UI partitions the search scope according to registered providers and delegates to them to instantiate the search queries, composing the results of those queries.
Diffstat (limited to 'plugins')
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.search.ui/build.properties3
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.search.ui/plugin.xml7
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.search.ui/schema/queryProviders.exsd129
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.search.ui/src/org/eclipse/papyrus/uml/search/ui/pages/PapyrusSearchPage.java68
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.search.ui/src/org/eclipse/papyrus/uml/search/ui/query/CompositePapyrusQueryProvider.java355
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.search.ui/src/org/eclipse/papyrus/uml/search/ui/query/IPapyrusQueryProvider.java65
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.search.ui/src/org/eclipse/papyrus/uml/search/ui/query/QueryInfo.java139
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.search.ui/src/org/eclipse/papyrus/uml/search/ui/query/WorkspaceQueryProvider.java92
8 files changed, 802 insertions, 56 deletions
diff --git a/plugins/uml/org.eclipse.papyrus.uml.search.ui/build.properties b/plugins/uml/org.eclipse.papyrus.uml.search.ui/build.properties
index 7915e442db0..b505af0e366 100644
--- a/plugins/uml/org.eclipse.papyrus.uml.search.ui/build.properties
+++ b/plugins/uml/org.eclipse.papyrus.uml.search.ui/build.properties
@@ -6,4 +6,5 @@ bin.includes = META-INF/,\
icons/,\
about.html,\
plugin.properties
-src.includes = about.html
+src.includes = about.html,\
+ schema/
diff --git a/plugins/uml/org.eclipse.papyrus.uml.search.ui/plugin.xml b/plugins/uml/org.eclipse.papyrus.uml.search.ui/plugin.xml
index 2837c7fa5f4..720fdd8ad0c 100644
--- a/plugins/uml/org.eclipse.papyrus.uml.search.ui/plugin.xml
+++ b/plugins/uml/org.eclipse.papyrus.uml.search.ui/plugin.xml
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>
+ <extension-point id="queryProviders" name="Papyrus Search Query Providers" schema="schema/queryProviders.exsd"/>
<extension
point="org.eclipse.search.searchPages">
<page
@@ -58,5 +59,11 @@
</adapter>
</factory>
</extension>
+ <extension
+ point="org.eclipse.papyrus.uml.search.ui.queryProviders">
+ <queryProvider
+ class="org.eclipse.papyrus.uml.search.ui.query.WorkspaceQueryProvider">
+ </queryProvider>
+ </extension>
</plugin>
diff --git a/plugins/uml/org.eclipse.papyrus.uml.search.ui/schema/queryProviders.exsd b/plugins/uml/org.eclipse.papyrus.uml.search.ui/schema/queryProviders.exsd
new file mode 100644
index 00000000000..91a4cbf3dd6
--- /dev/null
+++ b/plugins/uml/org.eclipse.papyrus.uml.search.ui/schema/queryProviders.exsd
@@ -0,0 +1,129 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.papyrus.uml.search.ui" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+ <appinfo>
+ <meta.schema plugin="org.eclipse.papyrus.uml.search.ui" id="queryProviders" name="Papyrus Search Query Providers"/>
+ </appinfo>
+ <documentation>
+ Pluggable providers of search query implementations for simple and advanced (not OCL) text searches.
+ </documentation>
+ </annotation>
+
+ <element name="extension">
+ <annotation>
+ <appinfo>
+ <meta.element />
+ </appinfo>
+ </annotation>
+ <complexType>
+ <sequence minOccurs="1" maxOccurs="unbounded">
+ <element ref="queryProvider"/>
+ </sequence>
+ <attribute name="point" type="string" use="required">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="id" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="name" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ <appinfo>
+ <meta.attribute translatable="true"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="queryProvider">
+ <complexType>
+ <attribute name="class" type="string" use="required">
+ <annotation>
+ <documentation>
+ A class implementing the &lt;tt&gt;IPapyrusQueryProvider&lt;/tt&gt; protocol.
+ </documentation>
+ <appinfo>
+ <meta.attribute kind="java" basedOn=":org.eclipse.papyrus.uml.search.ui.query.IPapyrusQueryProvider"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ <attribute name="priority" type="string" use="default" value="0">
+ <annotation>
+ <documentation>
+ The non-negative priority of the scope provider; the default is 0 (zero). Providers are invoked by the search framework in priority order, from highest to lowest.
+ </documentation>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="since"/>
+ </appinfo>
+ <documentation>
+ 1.0.0
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="examples"/>
+ </appinfo>
+ <documentation>
+ [Enter extension point usage example here.]
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="apiinfo"/>
+ </appinfo>
+ <documentation>
+ [Enter API information here.]
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="implementation"/>
+ </appinfo>
+ <documentation>
+ [Enter information about supplied implementation of this extension point.]
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="copyright"/>
+ </appinfo>
+ <documentation>
+ /*****************************************************************************
+ * Copyright (c) 2013 CEA LIST and others.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * CEA LIST - Initial API and implementation
+ *
+ *****************************************************************************/
+ </documentation>
+ </annotation>
+
+</schema>
diff --git a/plugins/uml/org.eclipse.papyrus.uml.search.ui/src/org/eclipse/papyrus/uml/search/ui/pages/PapyrusSearchPage.java b/plugins/uml/org.eclipse.papyrus.uml.search.ui/src/org/eclipse/papyrus/uml/search/ui/pages/PapyrusSearchPage.java
index bff352aa856..044a4a815e7 100644
--- a/plugins/uml/org.eclipse.papyrus.uml.search.ui/src/org/eclipse/papyrus/uml/search/ui/pages/PapyrusSearchPage.java
+++ b/plugins/uml/org.eclipse.papyrus.uml.search.ui/src/org/eclipse/papyrus/uml/search/ui/pages/PapyrusSearchPage.java
@@ -19,9 +19,7 @@ import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.List;
-import java.util.Set;
import java.util.regex.PatternSyntaxException;
import org.eclipse.core.runtime.IAdaptable;
@@ -78,16 +76,15 @@ import org.eclipse.papyrus.uml.search.ui.providers.ParticipantTypeContentProvide
import org.eclipse.papyrus.uml.search.ui.providers.ParticipantTypeElement;
import org.eclipse.papyrus.uml.search.ui.providers.ParticipantTypeLabelProvider;
import org.eclipse.papyrus.uml.search.ui.query.AbstractPapyrusQuery;
-import org.eclipse.papyrus.uml.search.ui.query.PapyrusAdvancedQuery;
+import org.eclipse.papyrus.uml.search.ui.query.CompositePapyrusQueryProvider;
import org.eclipse.papyrus.uml.search.ui.query.PapyrusOCLQuery;
-import org.eclipse.papyrus.uml.search.ui.query.PapyrusQuery;
+import org.eclipse.papyrus.uml.search.ui.query.QueryInfo;
+import org.eclipse.papyrus.uml.search.ui.query.WorkspaceQueryProvider;
import org.eclipse.papyrus.uml.stereotypecollector.StereotypeCollector;
import org.eclipse.papyrus.uml.tools.model.UmlModel;
import org.eclipse.papyrus.views.search.regex.PatternHelper;
import org.eclipse.papyrus.views.search.scope.ScopeCollector;
import org.eclipse.papyrus.views.search.scope.ScopeEntry;
-import org.eclipse.papyrus.views.search.utils.DefaultServiceRegistryTracker;
-import org.eclipse.papyrus.views.search.utils.IServiceRegistryTracker;
import org.eclipse.search.ui.IReplacePage;
import org.eclipse.search.ui.ISearchPage;
import org.eclipse.search.ui.ISearchPageContainer;
@@ -149,8 +146,6 @@ public class PapyrusSearchPage extends DialogPage implements ISearchPage, IRepla
private HashMap<ParticipantTypeElement, List<ParticipantTypeAttribute>> participantsList = new HashMap<ParticipantTypeElement, List<ParticipantTypeAttribute>>();
- private ArrayList<ParticipantTypeElement> result = new ArrayList<ParticipantTypeElement>();
-
private Collection<Stereotype> availableStereotypes;
private static final String REGULAR_EXPRESSION_ILLFORMED = Messages.PapyrusSearchPage_0;
@@ -220,8 +215,6 @@ public class PapyrusSearchPage extends DialogPage implements ISearchPage, IRepla
private Composite textQueryFieldsComposite;
- protected Set<EObject> umlMetaClasses = new HashSet<EObject>();
-
protected ParticipantTypeContentProvider participantTypeContentProvider = new ParticipantTypeContentProvider();
@@ -697,16 +690,6 @@ public class PapyrusSearchPage extends DialogPage implements ISearchPage, IRepla
btnSearchAllStringAttributes.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false, 1, 1));
}
- public void initMetaClasses() {
-
- for(EClassifier eClassifier : UMLPackage.eINSTANCE.getEClassifiers()) {
- if(eClassifier instanceof EClass) {
- umlMetaClasses.add(eClassifier);
- }
- }
-
- }
-
protected void createOCLSearchQueryField(EObject root) {
@@ -793,7 +776,8 @@ public class PapyrusSearchPage extends DialogPage implements ISearchPage, IRepla
if(container.getSelectedScope() == ISearchPageContainer.SELECTION_SCOPE) {
Collection<URI> scope = ScopeCollector.getInstance().computeSearchScope(container);
- Collection<ScopeEntry> scopeEntries = createScopeEntries(scope);
+ // this is only used for OCL queries, which currently assume workspace-like availability of the model content
+ Collection<ScopeEntry> scopeEntries = WorkspaceQueryProvider.createScopeEntries(scope);
if(scopeEntries.size() == 1) {
Object[] entries = scopeEntries.toArray();
@@ -968,45 +952,19 @@ public class PapyrusSearchPage extends DialogPage implements ISearchPage, IRepla
});
}
- /**
- * Create scopeEntries based on URIs.
- *
- * @return the created scopeEntries
- */
- private Collection<ScopeEntry> createScopeEntries(Collection<URI> scope) {
- IServiceRegistryTracker tracker = createServiceRegistryTracker();
- Collection<ScopeEntry> results = new HashSet<ScopeEntry>();
-
- for(URI uri : scope) {
-
- ScopeEntry scopeEntry = new ScopeEntry(uri, tracker);
-
- results.add(scopeEntry);
-
- }
-
- return results;
- }
-
- private IServiceRegistryTracker createServiceRegistryTracker() {
- return new DefaultServiceRegistryTracker();
- }
-
public boolean performAction() {
if(queryKind.getSelectionIndex() == TEXT_QUERY_KIND) {
if(validateRegex()) {
Collection<URI> scope = ScopeCollector.getInstance().computeSearchScope(container);
- Collection<ScopeEntry> scopeEntries = createScopeEntries(scope);
ISearchQuery query;
if(searchKind.getSelectionIndex() == SIMPLE_SEARCH) {
if(searchQueryText.getText().length() == 0) {
MessageDialog.openError(Display.getCurrent().getActiveShell(), Messages.PapyrusSearchPage_29, Messages.PapyrusSearchPage_30);
return false;
} else {
- initMetaClasses();
-
- query = new PapyrusQuery(searchQueryText.getText(), btnCaseSensitive.getSelection(), btnRegularExpression.getSelection(), scopeEntries, umlMetaClasses.toArray(), btnSearchAllStringAttributes.getSelection());
+ QueryInfo info = new QueryInfo(searchQueryText.getText(), btnCaseSensitive.getSelection(), btnRegularExpression.getSelection(), btnSearchAllStringAttributes.getSelection(), scope);
+ query = CompositePapyrusQueryProvider.getInstance().createSimpleSearchQuery(info);
}
} else {
@@ -1036,7 +994,8 @@ public class PapyrusSearchPage extends DialogPage implements ISearchPage, IRepla
}
}
- query = new PapyrusAdvancedQuery(searchQueryText.getText(), btnCaseSensitive.getSelection(), btnRegularExpression.getSelection(), scopeEntries, participantsToEvaluate.toArray());
+ QueryInfo info = new QueryInfo(searchQueryText.getText(), btnCaseSensitive.getSelection(), btnRegularExpression.getSelection(), participantsToEvaluate, scope);
+ query = CompositePapyrusQueryProvider.getInstance().createAdvancedSearchQuery(info);
}
@@ -1094,12 +1053,10 @@ public class PapyrusSearchPage extends DialogPage implements ISearchPage, IRepla
Collection<URI> scope = ScopeCollector.getInstance().computeSearchScope(container);
- Collection<ScopeEntry> scopeEntries = createScopeEntries(scope);
AbstractPapyrusQuery query;
if(searchKind.getSelectionIndex() == SIMPLE_SEARCH) {
- initMetaClasses();
-
- query = new PapyrusQuery(searchQueryText.getText(), btnCaseSensitive.getSelection(), btnRegularExpression.getSelection(), scopeEntries, umlMetaClasses.toArray(), btnSearchAllStringAttributes.getSelection());
+ QueryInfo info = new QueryInfo(searchQueryText.getText(), btnCaseSensitive.getSelection(), btnRegularExpression.getSelection(), btnSearchAllStringAttributes.getSelection(), scope);
+ query = CompositePapyrusQueryProvider.getInstance().createSimpleSearchQuery(info);
} else {
List<ParticipantTypeElement> participantsToEvaluate = new ArrayList<ParticipantTypeElement>();
for(ParticipantTypeElement element : this.participantsList.keySet()) {
@@ -1123,7 +1080,8 @@ public class PapyrusSearchPage extends DialogPage implements ISearchPage, IRepla
}
}
}
- query = new PapyrusAdvancedQuery(searchQueryText.getText(), btnCaseSensitive.getSelection(), btnRegularExpression.getSelection(), scopeEntries, participantsToEvaluate.toArray());
+ QueryInfo info = new QueryInfo(searchQueryText.getText(), btnCaseSensitive.getSelection(), btnRegularExpression.getSelection(), participantsToEvaluate, scope);
+ query = CompositePapyrusQueryProvider.getInstance().createAdvancedSearchQuery(info);
}
diff --git a/plugins/uml/org.eclipse.papyrus.uml.search.ui/src/org/eclipse/papyrus/uml/search/ui/query/CompositePapyrusQueryProvider.java b/plugins/uml/org.eclipse.papyrus.uml.search.ui/src/org/eclipse/papyrus/uml/search/ui/query/CompositePapyrusQueryProvider.java
new file mode 100644
index 00000000000..142a3ee98e9
--- /dev/null
+++ b/plugins/uml/org.eclipse.papyrus.uml.search.ui/src/org/eclipse/papyrus/uml/search/ui/query/CompositePapyrusQueryProvider.java
@@ -0,0 +1,355 @@
+/*****************************************************************************
+ * Copyright (c) 2013 CEA LIST and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * CEA LIST - Initial API and implementation
+ *****************************************************************************/
+package org.eclipse.papyrus.uml.search.ui.query;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.SortedSet;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.plugin.RegistryReader;
+import org.eclipse.papyrus.uml.search.ui.Activator;
+import org.eclipse.papyrus.uml.search.ui.results.PapyrusSearchResult;
+import org.eclipse.search.ui.ISearchResult;
+import org.eclipse.search.ui.text.AbstractTextSearchResult;
+
+
+/**
+ * A composite query provider that partitions the query scope according to the pluggable query providers that handle each URI and composes the
+ * resulting queries into a synthesized whole.
+ */
+public class CompositePapyrusQueryProvider implements IPapyrusQueryProvider {
+
+ private static final CompositePapyrusQueryProvider INSTANCE = new CompositePapyrusQueryProvider();
+
+ private final Iterable<? extends IPapyrusQueryProvider> queryProviders;
+
+ private CompositePapyrusQueryProvider() {
+ super();
+
+ this.queryProviders = loadQueryProviders();
+ }
+
+ public static IPapyrusQueryProvider getInstance() {
+ return INSTANCE;
+ }
+
+ public boolean canProvideFor(URI scope) {
+ // we never actually ask
+ return true;
+ }
+
+ public AbstractPapyrusQuery createSimpleSearchQuery(QueryInfo queryInfo) {
+ Map<IPapyrusQueryProvider, Collection<URI>> partitions = partitionSearchScope(queryInfo.getScope());
+ List<AbstractPapyrusQuery> result = new java.util.ArrayList<AbstractPapyrusQuery>(partitions.size());
+
+ for(Map.Entry<IPapyrusQueryProvider, Collection<URI>> next : partitions.entrySet()) {
+ AbstractPapyrusQuery query = next.getKey().createSimpleSearchQuery(queryInfo.partition(next.getValue()));
+
+ if(query != null) {
+ result.add(query);
+ }
+ }
+
+ return composite(result);
+ }
+
+ public AbstractPapyrusQuery createAdvancedSearchQuery(QueryInfo queryInfo) {
+ Map<IPapyrusQueryProvider, Collection<URI>> partitions = partitionSearchScope(queryInfo.getScope());
+ List<AbstractPapyrusQuery> result = new java.util.ArrayList<AbstractPapyrusQuery>(partitions.size());
+
+ for(Map.Entry<IPapyrusQueryProvider, Collection<URI>> next : partitions.entrySet()) {
+ AbstractPapyrusQuery query = next.getKey().createAdvancedSearchQuery(queryInfo.partition(next.getValue()));
+
+ if(query != null) {
+ result.add(query);
+ }
+ }
+
+ return composite(result);
+ }
+
+ private AbstractPapyrusQuery composite(final List<? extends AbstractPapyrusQuery> queries) {
+ AbstractPapyrusQuery result;
+
+ if(queries.isEmpty()) {
+ result = AbstractPapyrusQuery.Empty.INSTANCE;
+ } else if(queries.size() == 1) {
+ result = queries.get(0);
+ } else {
+ result = new CompositeQuery(queries);
+ }
+
+ return result;
+ }
+
+ Map<IPapyrusQueryProvider, Collection<URI>> partitionSearchScope(Collection<URI> scope) {
+ Map<IPapyrusQueryProvider, Collection<URI>> result = new java.util.HashMap<IPapyrusQueryProvider, Collection<URI>>();
+
+ Iterable<? extends IPapyrusQueryProvider> providers = getQueryProviders();
+ for(URI next : scope) {
+ for(IPapyrusQueryProvider provider : providers) {
+ if(provider.canProvideFor(next)) {
+ Collection<URI> myScope = result.get(provider);
+
+ if(myScope == null) {
+ // preserve order but ensure uniqueness
+ myScope = new java.util.LinkedHashSet<URI>();
+ result.put(provider, myScope);
+ }
+
+ myScope.add(next);
+ break; // don't consult the next provider
+ }
+ }
+ }
+
+ return result;
+ }
+
+ private Iterable<? extends IPapyrusQueryProvider> loadQueryProviders() {
+ return new ProvidersReader().load();
+ }
+
+ final Iterable<? extends IPapyrusQueryProvider> getQueryProviders() {
+ List<IPapyrusQueryProvider> result = new ArrayList<IPapyrusQueryProvider>();
+
+ synchronized(queryProviders) {
+ for(IPapyrusQueryProvider next : queryProviders) {
+ result.add(next);
+ }
+ }
+
+ return result;
+ }
+
+ //
+ // Nested types
+ //
+
+ private static class PriorityQueryProvider implements IPapyrusQueryProvider, Comparable<PriorityQueryProvider> {
+
+ private final IPapyrusQueryProvider delegate;
+
+ private final int priority;
+
+ public PriorityQueryProvider(IPapyrusQueryProvider delegate, int priority) {
+ this.delegate = delegate;
+ this.priority = priority;
+ }
+
+ public int compareTo(PriorityQueryProvider o) {
+ // sort by descending priority
+ return o.priority - this.priority;
+ }
+
+ @Override
+ public int hashCode() {
+ return delegate.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return (obj instanceof PriorityQueryProvider) && ((PriorityQueryProvider)obj).delegate.equals(delegate);
+ }
+
+ //
+ // API delegation
+ //
+
+ public boolean canProvideFor(URI scope) {
+ return delegate.canProvideFor(scope);
+ }
+
+ public AbstractPapyrusQuery createSimpleSearchQuery(QueryInfo queryInfo) {
+ return delegate.createSimpleSearchQuery(queryInfo);
+ }
+
+ public AbstractPapyrusQuery createAdvancedSearchQuery(QueryInfo queryInfo) {
+ return delegate.createAdvancedSearchQuery(queryInfo);
+ }
+
+ }
+
+ private class ProvidersReader extends RegistryReader {
+
+ private static final String EXT_PT = "queryProviders"; //$NON-NLS-1$
+
+ private static final String TAG_PROVIDER = "queryProvider"; //$NON-NLS-1$
+
+ private static final String ATTR_CLASS = "class"; //$NON-NLS-1$
+
+ private static final String ATTR_PRIORITY = "priority"; //$NON-NLS-1$
+
+ private final SortedSet<PriorityQueryProvider> providers = new java.util.TreeSet<PriorityQueryProvider>();
+
+ ProvidersReader() {
+ super(Platform.getExtensionRegistry(), Activator.PLUGIN_ID, EXT_PT);
+ }
+
+ Iterable<? extends IPapyrusQueryProvider> load() {
+ synchronized(providers) {
+ providers.clear();
+ readRegistry();
+ }
+
+ return providers;
+ }
+
+ @Override
+ protected boolean readElement(IConfigurationElement element, boolean add) {
+ boolean result = false;
+
+ if(TAG_PROVIDER.equals(element.getName())) {
+ result = true;
+
+ String className = element.getAttribute(ATTR_CLASS);
+ if((className == null) || (className.length() == 0)) {
+ logMissingAttribute(element, ATTR_CLASS);
+ } else if(add) {
+ addProvider(element, className);
+ } else {
+ removeProvider(element, className);
+ }
+ }
+
+ return result;
+ }
+
+ private void addProvider(IConfigurationElement element, String className) {
+ try {
+ Object provider = element.createExecutableExtension(ATTR_CLASS);
+
+ if(!(provider instanceof IPapyrusQueryProvider)) {
+ Activator.log.error("Query provider extension does not implement IPapyrusQueryProvider interface: " + className, null); //$NON-NLS-1$
+ } else {
+ String priorityString = element.getAttribute(ATTR_PRIORITY);
+ int priority = 0;
+
+ try {
+ if((priorityString) != null && (priorityString.length() > 0)) {
+ priority = Integer.parseInt(priorityString);
+ if(priority < 0) {
+ Activator.log.warn("Negative priority in query provider " + className); //$NON-NLS-1$
+ priority = 0;
+ }
+ }
+ } catch (NumberFormatException e) {
+ Activator.log.warn("Not an integer priority in query provider " + className); //$NON-NLS-1$
+ }
+
+ synchronized(providers) {
+ providers.add(new PriorityQueryProvider((IPapyrusQueryProvider)provider, priority));
+ }
+ }
+ } catch (CoreException e) {
+ Activator.getDefault().getLog().log(e.getStatus());
+ }
+ }
+
+ private void removeProvider(IConfigurationElement element, String className) {
+ synchronized(providers) {
+ for(Iterator<PriorityQueryProvider> iter = providers.iterator(); iter.hasNext();) {
+ if(iter.next().delegate.getClass().getName().equals(className)) {
+ iter.remove();
+ }
+ }
+ }
+ }
+ }
+
+ private static final class CompositeQuery extends AbstractPapyrusQuery {
+
+ private final List<? extends AbstractPapyrusQuery> queries;
+
+ CompositeQuery(List<? extends AbstractPapyrusQuery> queries) {
+ this.queries = queries;
+ }
+
+ public String getLabel() {
+ return queries.get(0).getLabel();
+ }
+
+ @Override
+ public String getSearchQueryText() {
+ return queries.get(0).getSearchQueryText();
+ }
+
+ public boolean canRerun() {
+ boolean result = true;
+
+ for(AbstractPapyrusQuery next : queries) {
+ if(!next.canRerun()) {
+ result = false;
+ break;
+ }
+ }
+
+ return result;
+ }
+
+ public boolean canRunInBackground() {
+ boolean result = true;
+
+ for(AbstractPapyrusQuery next : queries) {
+ if(!next.canRunInBackground()) {
+ result = false;
+ break;
+ }
+ }
+
+ return result;
+ }
+
+ public IStatus run(IProgressMonitor monitor) throws OperationCanceledException {
+ List<IStatus> result = new java.util.ArrayList<IStatus>(queries.size());
+
+ SubMonitor sub = SubMonitor.convert(monitor, result.size());
+ for(AbstractPapyrusQuery next : queries) {
+ IStatus status = next.run(sub.newChild(1));
+ if(!status.isOK()) {
+ result.add(status);
+ }
+ }
+
+ return result.isEmpty() ? Status.OK_STATUS : (result.size() == 1) ? result.get(0) : new MultiStatus(Activator.PLUGIN_ID, 0, result.toArray(new IStatus[result.size()]), "Problems occurred in search.", null);
+ }
+
+ public ISearchResult getSearchResult() {
+ PapyrusSearchResult result = new PapyrusSearchResult(this);
+
+ for(AbstractPapyrusQuery next : queries) {
+ AbstractTextSearchResult nextResult = (AbstractTextSearchResult)next.getSearchResult();
+
+ Object[] elements = nextResult.getElements();
+ for(int i = 0; i < elements.length; i++) {
+ result.addMatches(nextResult.getMatches(elements[i]));
+ }
+ }
+
+ return result;
+ }
+ }
+
+}
diff --git a/plugins/uml/org.eclipse.papyrus.uml.search.ui/src/org/eclipse/papyrus/uml/search/ui/query/IPapyrusQueryProvider.java b/plugins/uml/org.eclipse.papyrus.uml.search.ui/src/org/eclipse/papyrus/uml/search/ui/query/IPapyrusQueryProvider.java
new file mode 100644
index 00000000000..5a7d732a4d1
--- /dev/null
+++ b/plugins/uml/org.eclipse.papyrus.uml.search.ui/src/org/eclipse/papyrus/uml/search/ui/query/IPapyrusQueryProvider.java
@@ -0,0 +1,65 @@
+/*****************************************************************************
+ * Copyright (c) 2013 CEA LIST and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * CEA LIST - Initial API and implementation
+ *****************************************************************************/
+package org.eclipse.papyrus.uml.search.ui.query;
+
+import java.util.Collection;
+
+import org.eclipse.emf.common.util.URI;
+
+
+/**
+ * A pluggable provider of query implementations for URIs in different domains (workspace, CDO repositories, etc.).
+ * Providers are registered with a priority ordering. The first provider that returns a query for a given URI wins;
+ * lower-priority providers are not consulted.
+ */
+public interface IPapyrusQueryProvider {
+
+ /**
+ * Asks whether this provider can query a resource (or resources) identified by the given {@code scope} URI.
+ * This method is used to partition the overall search scope by query provider.
+ *
+ * @param scope
+ * a URI identifying one or more model resources in the workspace or elsewhere
+ *
+ * @return whether I can provide a query on this scope. If I can, I had better be prepared to supply one
+ * {@linkplain #createSimpleSearchQuery(String, boolean, boolean, boolean, Collection) when asked}
+ *
+ * @see #createSimpleSearchQuery(String, boolean, boolean, boolean, Collection)
+ * @see #createAdvancedSearchQuery(String, boolean, boolean, Collection, Collection)
+ */
+ boolean canProvideFor(URI scope);
+
+ /**
+ * Creates a simple text-based search query.
+ *
+ * @param queryInfo
+ * the query parameters
+ *
+ * @return the simple (for the user!) search query
+ */
+ AbstractPapyrusQuery createSimpleSearchQuery(QueryInfo queryInfo);
+
+ /**
+ * Creates an advanced text-based search query.
+ *
+ * @param queryInfo
+ * the query parameters
+ *
+ * @return the advanced (for the user!) search query
+ */
+ AbstractPapyrusQuery createAdvancedSearchQuery(QueryInfo queryInfo);
+
+ //
+ // Nested types
+ //
+
+}
diff --git a/plugins/uml/org.eclipse.papyrus.uml.search.ui/src/org/eclipse/papyrus/uml/search/ui/query/QueryInfo.java b/plugins/uml/org.eclipse.papyrus.uml.search.ui/src/org/eclipse/papyrus/uml/search/ui/query/QueryInfo.java
new file mode 100644
index 00000000000..1f0251bcec8
--- /dev/null
+++ b/plugins/uml/org.eclipse.papyrus.uml.search.ui/src/org/eclipse/papyrus/uml/search/ui/query/QueryInfo.java
@@ -0,0 +1,139 @@
+/*****************************************************************************
+ * Copyright (c) 2013 CEA LIST and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * CEA LIST - Initial API and implementation
+ *****************************************************************************/
+package org.eclipse.papyrus.uml.search.ui.query;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.papyrus.uml.search.ui.providers.ParticipantTypeElement;
+import org.eclipse.uml2.uml.NamedElement;
+
+/**
+ * A <em>Parameter Object</em> for creation of {@link AbstractPapyrusQuery} instances via an {@link IPapyrusQueryProvider}.
+ */
+public class QueryInfo {
+
+ private String queryText;
+
+ private boolean caseSensitive;
+
+ private boolean regularExpression;
+
+ private boolean searchAllStringAttributes;
+
+ private Collection<? extends ParticipantTypeElement> participantTypes;
+
+ private Collection<URI> scope;
+
+ /**
+ * Creates a query info for simple query.
+ *
+ * @param queryText
+ * the user-supplied search query text
+ * @param caseSensitive
+ * whether the {@code queryText} is to be applied in case-sensitive fashion
+ * @param regularExpression
+ * whether the {@code queryText} is to be taken as a regular expression
+ * @param searchAllStringAttributes
+ * whether to search all string attributes of UML metaclasses ({@code true}), or just named element {@linkplain NamedElement#getName()
+ * names} ({@code false})
+ * @param scope
+ * the domain-specific search scope
+ */
+ public QueryInfo(String queryText, boolean caseSensitive, boolean regularExpression, boolean searchAllStringAttributes, Collection<URI> scope) {
+ super();
+
+ this.queryText = queryText;
+ this.caseSensitive = caseSensitive;
+ this.regularExpression = regularExpression;
+ this.searchAllStringAttributes = searchAllStringAttributes;
+ this.participantTypes = Collections.emptyList();
+ this.scope = scope;
+ }
+
+ /**
+ * Creates a query info for advanced query.
+ *
+ * @param queryText
+ * the user-supplied search query text
+ * @param caseSensitive
+ * whether the {@code queryText} is to be applied in case-sensitive fashion
+ * @param regularExpression
+ * whether the {@code queryText} is to be taken as a regular expression
+ * @param participantTypes
+ * the participant types (identifying specific metaclasses and/or attributes) to include in the search
+ * @param scope
+ * the domain-specific search scope
+ */
+ public QueryInfo(String queryText, boolean caseSensitive, boolean regularExpression, Collection<? extends ParticipantTypeElement> participantTypes, Collection<URI> scope) {
+ super();
+
+ this.queryText = queryText;
+ this.caseSensitive = caseSensitive;
+ this.regularExpression = regularExpression;
+ this.searchAllStringAttributes = false;
+ this.participantTypes = participantTypes;
+ this.scope = scope;
+ }
+
+ /**
+ * Partition copy constructor.
+ */
+ private QueryInfo(QueryInfo original, Collection<URI> scope) {
+ super();
+
+ this.queryText = original.queryText;
+ this.caseSensitive = original.caseSensitive;
+ this.regularExpression = original.regularExpression;
+ this.searchAllStringAttributes = original.searchAllStringAttributes;
+ this.participantTypes = original.participantTypes;
+ this.scope = scope;
+ }
+
+ public String getQueryText() {
+ return queryText;
+ }
+
+ public boolean isCaseSensitive() {
+ return caseSensitive;
+ }
+
+ public boolean isRegularExpression() {
+ return regularExpression;
+ }
+
+ public boolean isSearchAllStringAttributes() {
+ return searchAllStringAttributes;
+ }
+
+ public Collection<? extends ParticipantTypeElement> getParticipantTypes() {
+ return participantTypes;
+ }
+
+ public Collection<URI> getScope() {
+ return scope;
+ }
+
+ /**
+ * Creates a new instance encapsulating query parameters for the specified partition (strict subset) of my {@linkplain #getScope() scope}.
+ *
+ * @param scopePartition a partition of my scope
+ *
+ * @return the partition query info
+ *
+ * @see #getScope()
+ */
+ public QueryInfo partition(Collection<URI> scopePartition) {
+ return new QueryInfo(this, scopePartition);
+ }
+}
diff --git a/plugins/uml/org.eclipse.papyrus.uml.search.ui/src/org/eclipse/papyrus/uml/search/ui/query/WorkspaceQueryProvider.java b/plugins/uml/org.eclipse.papyrus.uml.search.ui/src/org/eclipse/papyrus/uml/search/ui/query/WorkspaceQueryProvider.java
new file mode 100644
index 00000000000..18318084408
--- /dev/null
+++ b/plugins/uml/org.eclipse.papyrus.uml.search.ui/src/org/eclipse/papyrus/uml/search/ui/query/WorkspaceQueryProvider.java
@@ -0,0 +1,92 @@
+/*****************************************************************************
+ * Copyright (c) 2013 CEA LIST and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * CEA LIST - Initial API and implementation
+ * Christian W. Damus (CEA LIST) - Extracted portions of the PapyrusSearchPage code.
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.uml.search.ui.query;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EClassifier;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.papyrus.views.search.scope.ScopeEntry;
+import org.eclipse.papyrus.views.search.utils.DefaultServiceRegistryTracker;
+import org.eclipse.papyrus.views.search.utils.IServiceRegistryTracker;
+import org.eclipse.uml2.uml.UMLPackage;
+
+
+/**
+ * The default query provider implementation that knows how to query model resources in the Eclipse workspace.
+ */
+public class WorkspaceQueryProvider implements IPapyrusQueryProvider {
+
+ protected Set<EObject> umlMetaClasses = new HashSet<EObject>();
+
+ public WorkspaceQueryProvider() {
+ super();
+ }
+
+ public boolean canProvideFor(URI scope) {
+ // I always brute-force load the model to query it, so I can provide for any URI
+ return true;
+ }
+
+ public AbstractPapyrusQuery createSimpleSearchQuery(QueryInfo queryInfo) {
+ initMetaClasses();
+ Collection<ScopeEntry> scopeEntries = createScopeEntries(queryInfo.getScope());
+ return new PapyrusQuery(queryInfo.getQueryText(), queryInfo.isCaseSensitive(), queryInfo.isRegularExpression(), scopeEntries, umlMetaClasses.toArray(), queryInfo.isSearchAllStringAttributes());
+ }
+
+ public AbstractPapyrusQuery createAdvancedSearchQuery(QueryInfo queryInfo) {
+ Collection<ScopeEntry> scopeEntries = createScopeEntries(queryInfo.getScope());
+ return new PapyrusAdvancedQuery(queryInfo.getQueryText(), queryInfo.isCaseSensitive(), queryInfo.isRegularExpression(), scopeEntries, queryInfo.getParticipantTypes().toArray());
+ }
+
+
+ private void initMetaClasses() {
+ // the UML metamodel doesn't change once we have scraped it
+ if(umlMetaClasses.isEmpty()) {
+ for(EClassifier eClassifier : UMLPackage.eINSTANCE.getEClassifiers()) {
+ if(eClassifier instanceof EClass) {
+ umlMetaClasses.add(eClassifier);
+ }
+ }
+ }
+ }
+
+ /**
+ * Create scopeEntries based on URIs.
+ *
+ * @return the created scopeEntries
+ */
+ public static Collection<ScopeEntry> createScopeEntries(Collection<URI> scope) {
+ IServiceRegistryTracker tracker = createServiceRegistryTracker();
+ Collection<ScopeEntry> results = new HashSet<ScopeEntry>();
+
+ for(URI uri : scope) {
+
+ ScopeEntry scopeEntry = new ScopeEntry(uri, tracker);
+
+ results.add(scopeEntry);
+
+ }
+
+ return results;
+ }
+
+ static IServiceRegistryTracker createServiceRegistryTracker() {
+ return new DefaultServiceRegistryTracker();
+ }
+}

Back to the top