EMF/Query2/DevGuide

From Eclipsepedia

< EMF‎ | Query2
Revision as of 06:51, 16 November 2010 by Ashw.kumar.gmail.com (Talk | contribs)

Jump to: navigation, search

EMF Query2 Developer Guide

Contents

Installation

Overview of Query2

Query2 provides easy mechanism to query emf metadata with minimal loading of resources. Query2 has an in-built indexing mechanism which indexes types, resources and references. This data is used during query execution and hence avoiding loading of resources wherever needed. Hence, if you want to use query2, you are mandatorily required to setup indexing. After that you can use it execute queries. We will see how to set it up in later sections. Query2 also provides you different ways to specify queries. We will see them in coming sections.

Using Query2

Setting up Indexes

Step 1 Create dependency to index plugin: Add dependency to the plugins

  • org.eclipse.emf.query.index.ui
  • org.eclipse.emf.query.index

Step 2 Using Indexing api: To index the resources, you can use IndexFactory as the starting point. It is a singleton class, which can keep the index for your complete workspace.

  • Following is code sample to index new resource:
IndexFactory.getInstance().executeUpdateCommand(
new UpdateCommandAdapter() {

@Override
public void execute(final IndexUpdater updater) {
      final ResourceIndexer indexer = new ResourceIndexer();
      final ResourceSet rs = new ResourceSetImpl();
	try {
		indexer.resourceChanged(updater, rs.getResource(URI.createPlatformResourceURI(resource.getFullPath().toString(),	true), true));
	} catch (Exception e) {
	// Put your logging here					
	}
	}
});

As mentioned in the example, use UpdateCommand on Index instead of directly using ResourceIndexer.resourceChanged() to ensure locking on the Index.

  • Following is a code sample to remove a resource from index:
IndexFactory.getInstance().executeUpdateCommand(
new UpdateCommandAdapter() {

	@Override
	public void execute(IndexUpdater updater) {
         updater.deleteResource(URI.createPlatformResourceURI(
               resource.getFullPath().toString(), true));
	}
});
  • To query the indexes, there is factory class: IndexQueryFactory which gives different queries possible in Index.

Following is a code sample to retrieve EObject of a type from Index:

final EObjectQuery<EObjectDescriptor> eObjectQuery = IndexQueryFactory.createEObjectQuery();
	eObjectQuery.eClassURI(eClassUris[i]);			index.executeQueryCommand(new QueryCommand() {

	@Override
	public void execute(QueryExecutor queryExecutor) {
	QueryResult<EObjectDescriptor> execute =  
                    queryExecutor.execute(eObjectQuery);
	for (EObjectDescriptor objDesc : execute) {
		URI candidateResourceUri = objDesc.getResourceURI();
		boolean isInScope = scope.contains(candidateResourceUri);
		if (isInclusiveScope == isInScope) {
		// add uri of instance to result
                 result.add(candidateResourceUri.
                 appendFragment(objDesc.getFragment()));
		}
	}
}
});

Following is a code sample to retrieve EReference from Index:

final EReferenceQuery<EReferenceDescriptor> eReferenceQuery = IndexQueryFactory.createEReferenceQuery();
eReferenceQuery.sourceEObject().resource().uri(fromResource.toString());
	eReferenceQuery.eReferenceURI(referenceUri);

	index.executeQueryCommand(new QueryCommand() {

	@Override
	public void execute(QueryExecutor queryExecutor) {
		QueryResult<EReferenceDescriptor> execute =
                             queryExecutor.execute(eReferenceQuery);
		for (EReferenceDescriptor eReferenceDescriptor : execute) {
		URI targetResourceUri =
                             eReferenceDescriptor.getTargetResourceURI();
		if (targetResourceUri != null) {
				result.add(targetResourceUri);
			}
		}
	}
});

Similarly you can IndexQueryFactory .createResourceQuery() to create queries on Resources on the common index.

Step 3 Using QueryIndexBuilder: In eclipse IDE, we work on eclipse resources. Query2 indexing component provides an utility to index all the resources in your project using a custom builder. To enable it, you have to execute following steps:

1. Add the project nature: “org.eclipse.emf.query.index.ui.queryIndexNature” Open the .project file for your project and add this nature.

2. Add Builder: “org.eclipse.emf.query.index.ui.queryIndexBuilder” Open the .project file and add this builder.

3. The Builder will index all the files with extensions registered in EMF extensionToFactoryMap. You can add your file extension to factory using plugin.xml e.g as in following snippet:

<extension point="org.eclipse.emf.ecore.extension_parser">
      <parser class="com.demo.ResourceFactoryImpl"
       type="xml">
      </parser>
</extension>

Writing Queries in SQL like syntax

The support to write string based queries is present if you install query2.syntax feature. If you have these features execute following steps to have the setup ready for execution: 1. In your plugin create a new file by some name and file extension “query” e.g searchQueries.query This file will contain all the queries you want to execute

2. Specify query in the file:

a. Specify import statement to the URI which will be used to identify types in the Package at runtime e.g.

 import "http://www.sap.com/sap.ui.library.xsd" 

b. Specify title for the query

c. Specify the query

An example for b and c is below:

SearchAllLibraries:
from Library withoutsubtypes as lib select lib

SearchAllTypes:
from SimpleType withoutsubtypes as type select type

For execution of query, the queries in the .query file are loaded and used for execution. A sample code for execution is following:

new StandaloneSetup().setPlatformUri("..");
Injector injector = new QueryStandaloneSetup().createInjectorAndDoEMFRegistration();

XtextResourceSet set = injector.getInstance(XtextResourceSet.class);
set.addLoadOption(XtextResource.OPTION_RESOLVE_ALL, Boolean.TRUE);
URI resourceURI = URI.createURI(
         "platform:/plugin/<plugin-name>/queries/searchQueries.query");
URI normalized = set.getURIConverter().normalize(resourceURI);
LazyLinkingResource xtextResource = (LazyLinkingResource) set.getResource(normalized, true);
Model	model = (Model) xtextResource.getContents().get(0);
MQLquery query = findQuery("SearchAllLibraries");
Query internalQuery = QueryTransformer.transform(query);
Index indexFactory = IndexFactory.getInstance();
QueryProcessorImpl queryProcessor = new QueryProcessorImpl(indexFactory);
final ResultSet result = queryProcessor.execute(internalQuery, getQueryContext(rs));

Samples Queries

Note: The model used in the queries is mentioned in Appendix: Sample data 1. Select all books borrowed by an author:

from Book as b 
	select b 
	where b.borrowedBy in (
		from Manuscript as m, Person as p  select p where m.author = p
	)

2. Select pages with title “Linux made easy”

from Manuscript as m select m.pages where m.title = 'Linux Made Easy'

3. Select all Manuscripts only In Berlin.xml or Hamburg.xmi

from Library as lib 
        in resources {"platform:/resource/org.eclipse.emf.query2.librarytest/data/library/Hamburg.xmi","platform:/resource/org.eclipse.emf.query2.librarytest/data/library/Berlin.xmi"},
	Book as b, 
	Manuscript as m 
	select m 
	where lib.books = b
		and b.instanceOf = m

For accessing sample data, refer to Appendix: Sample data

Retrieving Query Results

After execution, the query processor returns a ResultSet. It can used to retrieve the results of the query. Main methods of ResultSet are:


 Metohd  Description
getQueryColumnTypes() Returns ColumnType for each select entry in the query
getUris(String alias) Returns all the URIs in the result for a given alias
URI getUri(int position, String alias) Returns URI at particular index in the results for a given alias
getSize() Returns the size of the results





Appendix

String based Syntax

from <EClass> withoutsubtypes as <alias> in resources { uri1, uri2 … } select <alias> where <alias>.<attribute> = <alias or alias-attribute> and\or <alias or alias attribute> in ( <nested-query> )

  • Optional keywords: withoutsubtypes, and\or, in resources, in
  • Mandatory keywords: from, as, select, where

Sample Data

The samples data exists in eclipse CVS at following location: “/cvsroot/modeling/org.eclipse.emf/org.eclipse.emf.query/tests/org.eclipse.emf.query2.librarytest” For accessing eclipse CVS you can refer to following page: CVS_HowTo.

Use “:pserver:anonymous@dev.eclipse.org:/cvsroot/modeling” to access projects related to Modeling. The model used in the samples data is following:

LibraryModeForQuery2Demo.png