Saturday, May 31, 2008

ODA Ecore Driver Backport

This post is a continuation of the description of the ODA Ecore Enablement plug-ins, now available for download from the Eclipse datatools incubator.
Recently, the ODA Ecore plug-ins were backported for JDK 1.4 and Eclipse 3.2 compatibility. This project has been moved into the datatools incubator attic directory. The same functionality is there in both sets of plug-ins, but there is no guarantee of future support for the archived version.
The primary difference between the Europa version and the backport is the backport's use of the now-deprecated org.eclipse.emf.ocl API for running ocl queries that has since been replaced by a new org.eclipse.ocl query parser. The backport does work in Europa, but the newer, EMF 2.3-dependent version of the plug-in allows shorter, context-free ocl query syntax.

Set up the ODA Ecore Driver in Eclipse 3.2


Download Eclipse 3.2 Callisto and unzip it.
Download EMF 2.2 and unzip it into your Callisto directory.
Download the EMF 2.2 examples and unzip them into your Callisto directory if you want to try the example described in the ODA Ecore Getting Started Guide.
Download EMFT Validation 1.0.1 and unzip it into your Callisto directory.
Download EMFT Transaction 1.0.2 and unzip it into your Callisto directory.
Download EMFT OCL 1.0.1 and unzip it into your Callisto directory.
Download EMFT Query 1.0.1 and unzip it into your Callisto directory.

After starting this installation of Eclipse 3.2, install the following plug-ins from the Callisto discovery site:
Database Development -> Datatools Platform Enablement 0.9 and its dependencies
Charting and Reporting -> Eclipse BIRT Report Designer Framework 2.1 and its dependencies (to run the example described in the ODA Ecore Getting Started Guide).

Import The Archived ODA Ecore Driver projects from CVS.
The Host is dev.eclipse.org
The Repository path is /cvsroot/datatools
Browse to org.eclipse.datatools.incubator/attic, select
  • org.eclipse.datatools.enablement.oda.ecore
  • org.eclipse.datatools.enablement.oda.ecore.ui
and check the projects out to your workspace.

Because the plug-ins are JDK 1.4 compatible, if you have a later version of the JDK, you might want to set your Java Compiler Preference to 1.4 Compliance to eliminate any compiler warnings.
Everything should be set-up correctly, and you should now see no compiler errors.

Try the ODA Ecore driver extlibrary Example



We can now launch a new Eclipse runtime and set up an initial BIRT report and .extlibrary file in our workspace as described in the example from the ODA Ecore Getting Started Guide.
Data source creation is the same, so we can follow the instructions without changes.
Data Set creation is slightly different because the query syntax for the backport is more strict. The boolean query in the example, self.oclIsKindOf(Writer), will work for the backport. The differences show up with more complex queries.
Suppose we want to find only references to James Fenimore Cooper. While we can use self.name = 'James Fenimore Cooper' in the latest version of the plug-in, this query will not work in the backport. The query must read self.oclIsKindOf(Writer) and self.oclAsType(Writer).name = 'James Fenimore Cooper'. The newer org.eclipse.ocl query parser can handle the stricter old-style query, but the older org.eclipse.emf.ocl parser cannot properly interpret the shorter context-free query.
Aside from that slight difference in query syntax, the plug-ins currently have the same features. So if you have the restriction that you must continue using Eclipse 3.2 or Java 1.4 and cannot upgrade to Eclipse 3.3 or EMF 2.3, but you need the features exposed by the ODA Ecore driver, you have this backport as an option!

Sustainable Pace

Often the term sustainable pace implies working long hours over the course of a few weeks. On projects that have long release cycles (anywhere from three months to three or more years), discussions of sustainable pace crop up as deadlines approach and as teams work long hours and weekends to fit in all the features scheduled for the release. XP and other Agile processes recommend short release cycles, continuous code merge and continuous integration to establish a regular rhythm for a development team and automated test driven development to reduce the number of bugs in production code (and the after-hours fire-fighting that often accompanies production bug fixes).
I propose that there are (at least) three types of regular project rhythms for individuals, teams and development organizations, and there are corresponding forms of unsustainable pace that accompany each rhythm.

Day to Day Development


For an individual, the day to day rhythm of development may include rituals such as getting a morning coffee, reading /. before work, eating lunch, and any regular team-related events. For a team, daily rituals may include a morning stand-up, switching between driving and navigating when pair programming, or switching pairing partners every few hours. Disturbances to a normal pace might include a dentist appointment, illness, oversleeping. These occurrences rarely harm a project because they tend to be infrequent. More insidious are consistent distractions that become an irregular part of the regular day-to-day pace. For example, in a non-pairing environment, there are often a few members of a team who are in charge of code quality control, who are domain experts, or who have specific technical expertise, and these superstars face constant interruption from other team members asking questions or needing code reviews. This type of interruption drives down the productivity of the individual, but can improve the team through the spread of knowledge. One benefit of pairing is that this type of knowledge transfer and the constant review of code quality becomes a standard part of the day-to-day pace, instead of an interruption.
Any form of active notifications, such as instant messages or Outlook and Mylyn popups provide more intrusions. Open web browsers with unread articles of interest are a more passive distraction. Given enough open browser tabs, a developer will certainly notice a decrease in performance of other applications, such as development environments. Also, programmers will often justify reading technical articles on the job as a form of continuing education, even if the article is not related to the current project, or they will justify reading an article by saying that they will make up the time by working later or by working from home to finish the task that they should be working on. This line of thought is particularly dangerous and directly contributes to what is often called unsustainable pace. When developers bring laptops home to work on stories that should have been completed during the day, that is a sign of unsustainable pace. When developers start thinking that they can put personal, non-work related programs or other distractions on their laptops, that practice can lead to a decrease in productivity and to unsustainable pace. Maintaining good pace is not just a matter of estimating tasks in manageable chunks or of sitting at a desk for no more than eight hours per day. It is a matter of having the discipline on an individual and on a team level to minimize distractions that can lead to incomplete work and to long days.

Sprint to Sprint Development


For a team, the rhythm of inter- and intra-sprint development may include rituals such as release and iteration planning, retrospectives, or weekly drops of code into production. Intermittent disruptions to this pace might include temporary (vacation) or permanent (termination, death, quitting) loss of team members. Such disruptions will affect team velocity but should not affect the occurrence of rituals. One form of sprint to sprint unsustainable pace comes from the repeated disruption of sprint rhythms and the cancellation or postponement of rituals. For example, when teams over-commit to a group of stories or set stretch goals, often the pressure to finish billable work will cause individuals to question the time spent on retrospectives or daily standups, which do not directly generate revenue. Consistently falling short on point commmitments undermines the morale of a team, which is another form of unsustainability; it leads to unsatisfied product owners; and the rolling-over of committed stories or the unfinished work from one sprint to the next may result in the pushing-back of sprint deadlines. Stretching a sprint from two weeks to three because commitments were not met treats the symptom and not the cause, i.e., that past velocity should dictate point commitments and not that committing to an artificial stretch goal will inspire a team to work harder. Repeated sprint extension degrades the meaning of sprint boundaries and reduces the satisfaction of knowing that a sprint is really complete.

Project to Project Development


For an organization, the rhythm of project to project transitions may include rituals such as kick-offs, code hand-offs, post-mortems. Teams may fragment or may move in toto from one assignment to the next. The smooth transition of individuals and teams is especially difficult because it often entails accurately predicting the end of one project, while the beginning of another often depends on the timelines or budget deadlines or product launches that need to be coordinated with another team in the same or a different organization. Often, when one project runs past its expected end-date, the transition period is especially difficult because over-allocated individuals may be put in the position of working 60-hour weeks to meet commitments to multiple projects. One individual split between two teams can also cause disruptions in sprint rituals because of scheduling conflicts and because of unavailability for consistent pairing on both teams. A long overlap between projects is certainly unsustainable.
The immediate dove-tailing of individuals from one project to the next, even despite some over-allocation, is a healthy sign. Inconsistent transitions with breaks of weeks between revenue-generating work, however, is unhealthy. The persistent lack of proper coordination of an individual's time can lead to a very insidious form of company-wide unsustainable pace. One particular example of this would be the feast-or-famine professional services company. New project work comes in waves. As a new wave arrives, there is a rush in one department to hire new developers with a specific skill set, rather than to double-up some developers temporarily or to transition developers from a starving part of the organization and re-train them. Self-organizing teams sometimes fail to see the bigger, company-wide picture and are only focused on the immediate success of individual projects. As the wave subsides, the sales pipeline looks sparse, so some developers are let go instead of transitioned onto established teams temporarily to help out, put on internal projects, or put into other roles (e.g., writing RFPs, going on sales calls) that have the potential to generate revenue. This cycle of hiring and laying-off is incredibly wasteful. The hiring process and the acclimation of any new employee to a company's culture and processes is very expensive. The lay-off process, as well, is expensive, and any number of lay-offs in a company for non-performance reasons erodes morale by generating fear, uncertainty and doubt, not necessarily about the quality of what is produced by the company, but about the position of the company in the marketplace.

The term sustainable pace means more than just 40-hour work weeks. Maintaining a company-wide sustainable pace may require interruptions to the normal rhythms of day to day or sprint to sprint development. It may require individuals to work long days or weeks for some period of time. It may require that individuals leave their comfort zone by stepping into other roles and being re-trained. Mostly sustainable pace means knowing when to be flexible and when to rigidly follow ritual.

Saturday, April 19, 2008

Threadsafe Lazy Instantiation Without Synchronized

The Problem to Solve

When I first read about the Threadsafe Lazy Singleton pattern, I was impressed by its elegance and wished there was something equally elegant for threadsafe lazy-loading of instance fields without the Java synchronized keyword. In most cases, declaring my fields as final and initializing them in the Constructor, even if they are never used in a given run of an application, has been satisfactory because Object allocation is generally cheap. Recently, however, I have encountered a situation where eagerly-loading a field is prohibitively expensive. The field must also be accessed in a threadsafe way. Because the accessor method will be called frequently after the first time it is called, I would prefer not to wrap the accessor implementation with a synchronized block (even though the performance hit can be small). This situtation has provided the right opportunity for me to investigate how the Java 5 concurrency utilities might help.

Start with a Test

Personally, I find it good practice to start the implementation of any new feature with a test. Here we want to verify that, if multiple threads call an accessor that lazily creates an Object, then the same Object instance is always returned from the accessor.
Since we are writing a test of thread-safety, it makes sense that the test case should use multiple threads. All threads should start at the same time and the results from each thread's execution should be evaluated only after all the threads have finished. This appears to be an opportunity to use a CountDownLatch, or rather two CountDownLatches: the first signals all threads to start; the second signals when all threads have finished.

So the structure of our test case can be mapped out as follows:

  • Setup some threads that will call the lazy-accessor method.
  • Run the threads to completion.
  • Collect the results from the lazy-accessor calls in each thread.
  • Verify that the same Object has been returned for every call.

The code below provides a starting point for what we need.


public class TestLazyCreation {
private static final int NUMBER_OF_THREADS = 10;
private CountDownLatch startSignal;
private CountDownLatch doneSignal;

@Before
public void setUp() {
startSignal = new CountDownLatch(1);
doneSignal = new CountDownLatch(NUMBER_OF_THREADS);
}

@Test
public void threadsafeLazyCreationReturnsExactlyOneInstance()
throws Exception {
final List<Future<Object>> futures =
submitCallables(/*A class instance with an accessor*/);
allowTheThreadsToRunToCompletion();
assertThatExactlyOneNonNullObjectWasReturned(futures);
}

private List<Future<Object>> submitCallables(/*A class with an accessor*/) {
final ExecutorService executorService = Executors
.newFixedThreadPool(NUMBER_OF_THREADS);
final List<Future<Object>> futures = new ArrayList<Future<Object>>();
for (int i = 0; i < NUMBER_OF_THREADS; i++) {
futures.add(
executorService.submit(/*The accessor class wrapped with a Callable*/));
}
return futures;
}

private void allowTheThreadsToRunToCompletion() throws InterruptedException {
Thread.sleep(250);
startSignal.countDown();
doneSignal.await();
}

private static void assertThatExactlyOneNonNullObjectWasReturned(
final List<Future<Object>> futures) throws InterruptedException,
ExecutionException {
final Set<Object> lazilyCreatedObjects = new HashSet<Object>();
for (final Future<Object> future : futures) {
lazilyCreatedObjects.add(future.get());
}
assertEquals(1, lazilyCreatedObjects.size());
assertNotNull(lazilyCreatedObjects.iterator().next());
}
}

Typical Lazy Instantiation

We still need to fill in the code above in two spots:
  • We need a class with an accessor.
  • We need a Callable that wraps that accessor class.
This code should suffice for the accessor class:

abstract class LazyGetter {
protected Object performLongRunningInitialization() {
try {
Thread.sleep(1);
} catch (final InterruptedException e) {
}
return new Object();
}
abstract Object get();
}

class TypicalLazyGetter extends LazyGetter {
private Object lazilyCreatedObject;
@Override
Object get() {
if (lazilyCreatedObject == null) {
lazilyCreatedObject = performLongRunningInitialization();
}
return lazilyCreatedObject;
}
}

This inner class inside TestLazyCreation will work as a Callable wrapper that uses the startSignal and doneSignal setup by the test class:

private final class CallableLazyGetter implements Callable<Object> {
private final LazyGetter lazyGetter;

CallableLazyGetter(final LazyGetter lazyGetter) {
this.lazyGetter = lazyGetter;
}

public Object call() throws Exception {
try {
startSignal.await();
return lazyGetter.get();
} finally {
doneSignal.countDown();
}
}
}

Now we can change the TestLazyCreation class to use the lazy accesor and the Callable wrapper just defined:

public class TestLazyCreation {
....
@Test
public void threadsafeLazyCreationReturnsExactlyOneInstance()
throws Exception {
final List<Future<Object>> futures = submitCallables(new TypicalLazyGetter());
....
}

private List<Future<Object>> submitCallables(final LazyGetter lazyGetter) {
....
futures.add(executorService.submit(new CallableLazyGetter(lazyGetter)));
....
}
....
private final class CallableLazyGetter implements Callable<Object> {
....
}
}

Looking at the code above, what do you think will happen when we run this test case?
Try running it a few times. What do you see?

My typical JUnit results show a failure similar to this:

JUnit test case failure because the accessor is not threadsafe.

The TypicalLazyGetter could be called NotThreadsafeLazyGetter. So how can we make this type of lazy instantiation threadsafe?
Java provides three keywords that are often associated with a class' synchronization policy: synchronized, final and volatile.
We can declare lazilyCreatedObject final and instantiate it in the constructor for TypicalLazyGetter, but then the Object would not be created lazily, so that solution is not what we want.
We can change the accessor declaration to synchronized Object get(), but we are trying to avoid the synchronized keyword.
We can change the declaration of lazilyCreatedObject to private volatile Object lazilyCreatedObject, but this does not solve our problem because the test-then-set critical section of the accessor method is not atomic. Run the test case again using the volatile declaration if you do not believe me.

Threadsafe Lazy Instantiation

The solution is fairly simple and boilerplate, if not as compact as the typical non-threadsafe lazy instantiation method. The key is to use an AtomicReference, and in particular, the method compareAndSet(V expect, V update). The code below will satisfy what we need:

class ThreadsafeLazyGetter extends LazyGetter {
private final AtomicReference<Object> lazilyCreatedObject =
new AtomicReference<Object>();

@Override
Object get() {
final Object existingValue = lazilyCreatedObject.get();
if (existingValue != null) {
return existingValue;
}
final Object newValue = performLongRunningInitialization();
if (lazilyCreatedObject.compareAndSet(null, newValue)) {
return newValue;
}
return lazilyCreatedObject.get();
}
}

What is the worst that could happen?
Multiple threads might enter the accessor, see that the lazilyCreatedObject referent has not been set and call performLongRunningInitialization(). As long as performLongRunningInitialization() can be called multiple times (i.e., it does not have side-effects or requirements that it be called at most once), then we should be safe. The accessor will return the same instance of the lazilyCreatedObject each time it is called.
Now we can modify our test class as follows:

@Test
public void threadsafeLazyCreationReturnsExactlyOneInstance()
throws Exception {
final List<Future<Object>> futures = submitCallables(new ThreadsafeLazyGetter());
allowTheThreadsToRunToCompletion();
assertThatExactlyOneNonNullObjectWasReturned(futures);
}

@Test(expected = AssertionError.class)
public void nonThreadsafeLazyCreationCanReturnMultipleInstances()
throws Exception {
final List<Future<Object>> futures = submitCallables(new NotThreadsafeLazyGetter());
allowTheThreadsToRunToCompletion();
assertThatExactlyOneNonNullObjectWasReturned(futures);
}

The second test case is silly but emphasizes that we expect the typical NotThreadsafeLazyGetter to fail in a mutli-threaded environment.

Lazy Instantiation in Eclipse

As previously mentioned, Object allocation is cheap with the latest releases of Java, so lazy-instantiation is often not necessary. Because I have spent the last 1 1/2 years programming Eclipse plug-ins, an example from Eclipse might provide a demonstration of a good use of lazy-instantiation.
First, we can define a class that lazily instantiates an Object from an Eclipse plug-in that does not typically get started when Eclipse is started. For this example, I chose to use something from org.eclipse.xsd:

class ClassThatLazilyCreatesAnObjectInAnotherPlugin {
private final AtomicReference<XSDSimpleTypeDefinition> lazilyCreatedObject =
new AtomicReference<XSDSimpleTypeDefinition>();

XSDSimpleTypeDefinition get() {
final XSDSimpleTypeDefinition existingValue = lazilyCreatedObject.get();
if (existingValue != null) {
return existingValue;
}
final XSDSimpleTypeDefinition newValue = XSDFactory.eINSTANCE
.createXSDSimpleTypeDefinition();
if (lazilyCreatedObject.compareAndSet(null, newValue)) {
return newValue;
}
return lazilyCreatedObject.get();
}
}

Next, we create a "Hello World" Command Contribution using the standard Eclipse Extension Wizard. We can insert the following code into the generated Hello World AbstractHandler:

private boolean firstTimeIn = true;

public Object execute(final ExecutionEvent event) throws ExecutionException {
final IWorkbenchWindow window = HandlerUtil
.getActiveWorkbenchWindowChecked(event);
if (firstTimeIn) {
new ClassThatLazilyCreatesAnObjectInAnotherPlugin();
MessageDialog.openInformation(window.getShell(),
"Threadsafe Lazy Initialization Plug-in",
"The Sample Object has been created.");
firstTimeIn = false;
} else {
new ClassThatLazilyCreatesAnObjectInAnotherPlugin().get();
MessageDialog.openInformation(window.getShell(),
"Threadsafe Lazy Initialization Plug-in",
"The Internal Object from another plug-in has been created.");
}
return null;
}

The implementation is a toy example, so do not read much into it. The first time the command is executed, the ClassThatLazilyCreatesAnObjectInAnotherPlugin is instantiated. During each subsequent command execution, the ClassThatLazilyCreatesAnObjectInAnotherPlugin is instantiated and its accessor is called.

Now on the Manifest.MF Overview, we can run an Eclipse application that uses our Command contribution. In the launch configuration, on the Arguments tab, make sure to pass the Program argument -console to start the OSGi console so we can view plug-in state when we execute our command.

Use the launch configuration to start the osgi console.

After the Eclipse workbench comes up, we will see a new Coolbar button for our Command contribution. We will also see in your console view the osgi> prompt (For a good introduction to using the osgi console for more than viewing plug-in state, see Explore Eclipse's OSGi console).
In the console, type ss to see the state of all the plug-ins in the running Eclipse application, and look for the org.eclipse.xsd plug-in. You will see something like this:

836 <<LAZY>> org.eclipse.xsd_2.4.0.v200801152000

Now press our Command contribution button once so the dialog pops up. Again, type ss in the osgi console. The org.eclipse.xsd plug-in state has not changed:

836 <<LAZY>> org.eclipse.xsd_2.4.0.v200801152000

Press our command contribution button once more so the dialog pops up again. Type ss in the osgi console and what do you see?   The org.eclipse.xsd plug-in has been activated!  If you are as fortunate as I am to be running on low-powered hardware, you might even notice the slight lag before the dialog pops up as the plug-in is being activated:

836 ACTIVE org.eclipse.xsd_2.4.0.v200801152000

There you have it: in Eclipse, it does make sense in some cases to use lazy-instantiation. In this case, if the XSDSimpleTypeDefinition were created in the class' constructor, then the xsd plug-in would be activated even if the Command were never executed more than once in a given run of the Eclipse application. It is a contrived example, but the situation does apply not infrequently.   For plug-ins that are expensive to start, the usefulness is obvious.


Thursday, April 10, 2008

ODA Ecore Getting Started Guide

Overview


Now that the ODA Ecore enablement plug-ins are in the Data Tools Project incubator at Eclipse, a quick-start guide seems in order.
The Oda Ecore enablement plug-in provides a JDBC-like interface for querying object models defined with EMF. These queries are written with OCL and use the EMF Model Query OCL bridge.
The Oda Ecore UI plug-in contributes two Wizards for configuring BIRT reports: the first allows specification of a Data Source; the second provides a graphical interface for constructing queries.

Dependencies


In order to use the Oda Ecore enablement plug-in, you will need to install the following dependencies:

Datatools Connectivity
EMF Query
EMF Model Query OCL Integration
The Data Tools Platform Enablement for JDBC

In addition, to run the example, you will need to install the following plug-ins:
BIRT (for reporting query results)
EMF Examples (for the extlibrary sample)

This example has been tested so far with Ganymede M5 and M6.

Enablement Plug-ins In CVS


First, we will need to download the Oda Ecore enablement plug-ins from CVS.
File -> Import -> Projects from CVS
The Host is dev.eclipse.org
The Repository path is /cvsroot/datatools
Unless you are a committer, the User is anonymous.
Checkout from CVS at dev.eclipse.org

Browse to org.eclipse.datatools.incubator/plugins, select
org.eclipse.datatools.enablement.oda.ecore
org.eclipse.datatools.enablement.oda.ecore.ui
and check them out to your workspace.
Find the ODA Ecore enablement plug-ins in the datatools incubator.

Model File


You will also need a model file. You can create one yourself using New -> Other -> Example EMF Model Creation Wizards -> EXTLibrary Model or you can use the sample model below, which sets up two libraries with an assortment of books, some of which are in one library or both libraries, and authors, some of whom are also in one or both libraries:

my.extlibrary


<?xml version="1.0" encoding="UTF-8"?>
<xmi:XMI xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:extlib="http:///org/eclipse/emf/examples/library/extlibrary.ecore/1.0.0">
<extlib:Library address="1000 4th Ave, Seattle, WA 98104" name="Seattle Public Library">
<stock xsi:type="extlib:Book" title="David Copperfield" category="Biography" author="/0/@writers.1"/>
<stock xsi:type="extlib:Book" title="Nicholas Nickleby" category="Biography" author="/0/@writers.1"/>
<stock xsi:type="extlib:Book" title="The Deerslayer" category="Biography" author="/1/@writers.0"/>
<stock xsi:type="extlib:Book" title="The Last of the Mohicans" category="Biography"/>
<writers firstName="James" lastName="Fenimore Cooper"/>
<writers firstName="Charles" lastName="Dickens" books="/0/@stock.1 /1/@stock.3 /0/@stock.0"/>
</extlib:Library>
<extlib:Library address="308 Kirkland Ave, Kirkland, WA 98033" name="Kirkland Public Library">
<stock xsi:type="extlib:Book" title="The Last of the Mohicans" category="Biography" author="/1/@writers.0"/>
<stock xsi:type="extlib:Book" title="The Pioneers"/>
<stock xsi:type="extlib:Book" title="Around The World In 80 Days" category="ScienceFiction" author="/1/@writers.2"/>
<stock xsi:type="extlib:Book" title="The Pickwick Papers" author="/0/@writers.1"/>
<writers firstName="James Fenimore" lastName="Cooper" books="/0/@stock.2 /1/@stock.0"/>
<writers firstName="Charles" lastName="Dickens"/>
<writers address="" firstName="Jules" lastName="Verne" books="/1/@stock.2"/>
</extlib:Library>
</xmi:XMI>



my.extlibrary example file
Feel free to modify the model file with the extlibrary example editor.

Launch Eclipse


There is nothing special to do here. Just open the Run Configurations Dialog, create a new Eclipse Application runtime configuration, if you do not already have one, and hit Run.
An example Eclipse runtime configuration.

BIRT Report


In this new Eclipse runtime, create a new General project. Here we can call it hello.world.oda.ecore. Drop your .extlibrary sample file into the new project. Now create a new Blank BIRT Report and switch to the Reporting perspective. Here we use the Wizard's default name for the report. It should be automatically opened in an editor.
A new BIRT report in your worspace.

Data Source


In the Data Explorer View, specify a new Data Source. From the Wizard, select Ecore ODA Data Source on the first page.
Select a new Ecore Data Source.

On the second page, select the sample .extlibrary file in your workspace and "Ping" it to make sure that it can be loaded.
Select and test the sample file.

Data Set


Again in the Data Explorer View, specify a new Data Set. The Data Source that we just created should be automatically selected on the first page of the Wizard, and the Wizard should know that the Data Set Type is Ecore ODA Data Set.
Select the Ecore Data Source we just created.

On the next two pages, we will choose the Model Object that we are querying from, the columns that we are selecting to use for the query result, and we will fill in the OCL Condition that will restrict the query results.
A very simple query would be to find the names of all writers in all libraries. For this, we will
select Writer -> name,
from the invariant Writer,
where self.oclIsKindOf(Writer)

Add the OCL Conditional Query and select an Invariant.
If you do not select an invariant from the combo, then all EAttributes and EReferences in the Model will be available for selection. Try it out!

Select the Columns for the Report.
The EAttributes and EReferences displayed are based on the invariant selection on the previous Wizard page. Here, a Writer is also an Addressable Person, so the EStructuralFeatures for those model elements are also available.


After we are finished with the Wizard, we can Edit the Data Set properties, preview the results of the query, and modify our query conditional, selected columns and invariant.
Edit the Invariant and Query condition.
Edit the Invariant and the conditional query.

Edit the Columns for reporting.
Edit the columns that will appear in the report.

Preview the Query Results.
Preview the query results. You can switch among the pages, so preview different conditional queries, different invariants and different column selections if you feel adventurous!

Run a Report


Now that we have a Data Set, we can drag it into our report to add all the column data (in this case, there is just one column name). From the Preview subtab, we can then preview the report and see our query results!
Drag the Data Set into the report to set up the result set table.

Backport


A backport of these plug-ins for Eclipse 3.2, JDK 1.4 and EMF 2.2 is also available, but future support is not guaranteed. A description of these plug-ins and a comparison between the latest version and the backport is available here.

Part Two


Continue to part 2 of this guide for more advanced features ->

Monday, February 11, 2008

Eclipse 3.4M5 solaris-gtk-x86 Build Script for Nexenta

Last week I finally installed NexentaCP Beta since the Gnusolaris Alpha apt repository has been taken offline. I probably could have found an indirect way to upgrade from Alpha to Beta but opted to wipe the window clean. The re-install was completely painless. Getting the nexenta-gnome desktop required adding the unstable repository to my /etc/apt/sources.list. Upgrading to the unstable repository gave me a small taste of the new Nexenta and the power of ZFS. The ease of the debian-based update manager had always impressed me, but adding ZFS to the mix makes the entire process worry-free as well. If an upgrade ever goes wrong, rolling back to a previous state is easy.

My Nexenta upgrade coincided nicely with the release of Eclipse 3.4M5. Because I had to re-install Eclipse anyway, and because a shiny new Nexenta install deserves nothing less than the latest-and-greatest Eclipse release, I downloaded the M5 source, installed the Eclipse build dependencies, ran my 3.4M4 modification script and with a few minor tweaks was quickly able to get Ganymede up and running, Java editor bread-crumb saccharine and all.
The script for building Eclipse 3.4 M5 for solaris-gtk-x86 can be downloaded from the solipse downloads page. Please be aware of the Nexenta-specific instructions for building the SWT library with gcc instead of SunStudio cc.
 


Eclipse 3.4 M5 running on Nexenta (Solaris) x86 GTK.
Breadcrumbs in the Java Editor are one of the sauciest additions to this latest release. Even though they do not add functionality that is not already in the workbench and they occupy precious screen real estate, they are great eye candy.

Thursday, January 17, 2008

Load XSDs Without Dependencies

Recently my colleague, Jeff Ramsdale, and I were faced with an Eclipse XSD problem: how can we load the contents of an XSD Resource without loading its transitive dependencies?
In our particular situation, we have the following requirements:
  • There are some logical groupings of xsd files.
  • In each grouping there are upwards of 150 schemas, some of which are very large.
  • Many of these schemas refer to one another or refer to schemas that refer to other schemas, etc.
  • We have a TreeViewer that displays these groups and we need to display the schemas in each group and the contents of each schema.
  • We have a custom ItemProviderAdapter for each schema group, and each group's children is a simple object that displays the schema name.
  • For each schema, the getChildren method of the ItemProviderAdapter uses a ResourceSet to demand-load the contents of the XSDResourceImpl to get its contents.
We found that the top level groups were displayed very quickly, but when we tried to open each schema (i.e., load it from the ResourceSet), it could take any number of seconds (10-20 in some cases) to display the schema contents.
Some schemas were causing many transitive dependencies to be loaded into the ResourceSet, even though the contents of those schemas were not displayed in the UI.
The solution, which we implemented thanks to a suggestion by Ed Merks, is to not use the ResourceSet for loading the XSDResourceImpl. We found that we could get the schema contents in much less time and without loading dependent resources just by instantiating the XSDResourceImpl directly with its corresponding URI.
Below I will show you how to set up a test case to demonstrate this solution.

Create a New Eclipse Project


Goto File -> New -> Other -> Plug-in Development -> Plug-in Project and create a project called transitive.dependencies.example.
We will need to declare the following Plug-in dependencies in the MANIFEST.MF
  • org.junit4
  • org.eclipse.emf
  • org.eclipse.emf.ecore
  • org.eclipse.xsd

Plug-in dependencies

Create XSDs With Transitive Dependencies


For this example I created 3 schemas (a.xsd, b.xsd and c.xsd) with transitive dependencies such that a.xsd refers to b.xsd, which refers to c.xsd, which refers to xml.xsd.
The three schemas are below and can be dropped into the folder /transitive.dependencies.example/xsd in our workspace.

a.xsd

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xsd:schema xmlns="http://transitive.dependencies.example/a"
xmlns:b="http://transitive.dependencies.example/b"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://transitive.dependencies.example/a">
<xsd:annotation>
<xsd:documentation>schema a ($Date: 2008/01/16 00:14:59 $) </xsd:documentation>
</xsd:annotation>
<xsd:import namespace="http://transitive.dependencies.example/b"
schemaLocation="xsd/b.xsd"/>
<xsd:attributeGroup name="a.attributes">
<xsd:attribute ref="b:b.type"/>
</xsd:attributeGroup>
</xsd:schema>


b.xsd

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xsd:schema xmlns="http://transitive.dependencies.example/b"
xmlns:c="http://transitive.dependencies.example/c"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://transitive.dependencies.example/b">
<xsd:annotation>
<xsd:documentation>schema b ($Date: 2008/01/16 00:14:59 $) </xsd:documentation>
</xsd:annotation>
<xsd:import namespace="http://transitive.dependencies.example/c"
schemaLocation="xsd/c.xsd"/>
<xsd:attribute name="b.type" type="xsd:anyURI"/>
<xsd:attributeGroup name="b.attributes">
<xsd:attribute ref="c:c.type"/>
</xsd:attributeGroup>
</xsd:schema>


c.xsd

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xsd:schema xmlns="http://transitive.dependencies.example/c"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://transitive.dependencies.example/c">
<xsd:annotation>
<xsd:documentation>schema c ($Date: 2008/01/16 00:14:59 $) </xsd:documentation>
</xsd:annotation>
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"
schemaLocation="http://www.w3.org/2001/xml.xsd"/>
<xsd:attribute name="c.type" type="xsd:anyURI"/>
<xsd:attributeGroup name="c.attributes">
<xsd:attribute ref="xml:id"/>
<xsd:attribute ref="xml:lang"/>
</xsd:attributeGroup>
</xsd:schema>


Create a New Test Case


For our first test, we want to show that when we demand-load an XSDResourceImpl through a ResourceSet, all of its transitive dependencies are also loaded into the ResourceSet.


package transitive.dependencies.example;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.xsd.impl.XSDSchemaImpl;
import org.eclipse.xsd.util.XSDResourceImpl;
import org.junit.Test;

public class LoadXsdTest {

@Test
public void demandLoadFromResourceSet() throws Exception {
final ResourceSet resourceSet = XSDSchemaImpl.createResourceSet();
assertNotNull(resourceSet.getResource(URI.createFileURI("xsd/a.xsd"),
true));
assertEquals(4, resourceSet.getResources().size());
assertNotNull(resourceSet.getResource(URI.createFileURI("xsd/b.xsd"),
false));
assertNotNull(resourceSet.getResource(URI.createFileURI("xsd/c.xsd"),
false));
assertNotNull(resourceSet.getResource(
URI.createURI("http://www.w3.org/2001/xml.xsd"), false));
}
}



For our next test, we want to show that when we load an orphaned XSDResourceImpl and manually put it into and retrieve it from the ResourceSet, that its dependencies are not automatically resolved.


....
@Test
public void createAndAddDetachedResources() throws Exception {
final ResourceSet resourceSet = XSDSchemaImpl.createResourceSet();
final URI uri = URI.createFileURI("xsd/a.xsd");
resourceSet.getResources().add(new XSDResourceImpl(uri));
assertEquals(1, resourceSet.getResources().size());

assertNotNull(resourceSet.getResource(uri, false));
assertEquals(1, resourceSet.getResources().size());
}
....


Interestingly, in the second test case, if we set the demandLoad flag to true when we get the XSDResourceImpl from the ResourceSet, the ResourceSet will load all the dependent resources, even though a.xsd has already been loaded and is present in the ResourceSet.  In that case, the second assertion will fail.

Both of the above test cases should pass as written.  Run them to get a green bar!

Friday, January 11, 2008

Dynamic Labels Redux

This is an update to a previous blog posting about contributing menu items with dynamic labels to popups. The constructor

public CommandContributionItem(IServiceLocator serviceLocator, String id, String commandId, Map parameters, ImageDescriptor icon, ImageDescriptor disabledIcon, ImageDescriptor hoverIcon, String label, String mnemonic, String tooltip, int style)

has been deprecated in Ganymede (Eclipse 3.4) in favor of the less unwieldy

public CommandContributionItem(CommandContributionItemParameter contributionParameters)

CommandContributionItemParameter has both a complete and a minimal constructor (for injecting just the required parameters), and its fields are public and non-final, so they can be set as needed.

The equivalent revised example class looks something like this:


public class MyCompoundContributionItem extends CompoundContributionItem {
private static int counter = 0;

@Override
protected IContributionItem[] getContributionItems() {
final CommandContributionItemParameter contributionParameter =
new CommandContributionItemParameter(
PlatformUI.getWorkbench().getActiveWorkbenchWindow(),
"my.project.myCommandContributionItem", "my.project.myCommand",
SWT.NONE);
contributionParameter.label = "Dynamic Menu Item " + counter++;
return new IContributionItem[] {
new CommandContributionItem(contributionParameter) };
}
}