Put OOMPH product versions in separate files

Just a quick tip for those who have big setup files for OOMPH products. I recently split up one by putting product versions in other files. Here is how to proceed.

One big setup file would look like this…

<?xml version="1.0" encoding="UTF-8"?>
<setup:ProductCatalog
    xmi:version="2.0"
    xmlns:xmi="http://www.omg.org/XMI"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:setup="http://www.eclipse.org/oomph/setup/1.0"
    name="my.product"
    label="some label">
    
  <!-- ... -->

  <product name="myproduct" label="Custom Eclipse">
    <annotation
        source="http://www.eclipse.org/oomph/setup/BrandingInfo">
      <detail
          key="folderName">
        <value>eclipse</value>
      </detail>
      <detail
          key="folderName.macosx">
        <value>Eclipse</value>
      </detail>
    </annotation>
    
    <version name="neon"
        label="Latest Neon"
        requiredJavaVersion="1.8">

        <!-- ... -->

    </version>

    <!-- Maybe with several versions. -->

    <description>...</description>
  </product>
</setup:ProductCatalog>

Now, to split it up, just add a reference to another file.

<?xml version="1.0" encoding="UTF-8"?>
<setup:ProductCatalog
    xmi:version="2.0"
    xmlns:xmi="http://www.omg.org/XMI"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:setup="http://www.eclipse.org/oomph/setup/1.0"
    name="my.product"
    label="some label">
    
  <!-- ... -->

  <product name="myproduct" label="Custom Eclipse">
    <annotation
        source="http://www.eclipse.org/oomph/setup/BrandingInfo">
      <detail
          key="folderName">
        <value>eclipse</value>
      </detail>
      <detail
          key="folderName.macosx">
        <value>Eclipse</value>
      </detail>
    </annotation>
    
    <version href="neon/my.products.neon.setup#/" />
    <description>...</description>
  </product>
</setup:ProductCatalog>

The important part is the reference to a sub-model file: version href=”neon/my.products.neon.setup#/”. And here is its content.

<?xml version="1.0" encoding="UTF-8"?>
<setup:ProductVersion
    xmi:version="2.0"
    xmlns:xmi="http://www.omg.org/XMI"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:setup="http://www.eclipse.org/oomph/setup/1.0"
    name="neon"
    label="Latest Neon"
    requiredJavaVersion="1.8">

      <!-- Force the loading of the parent when we open this file directly. -->
      <annotation source="ProductReference">
            <reference href="../my-other-product.setup#/" />
      </annotation>

      <!-- ... -->
      
</setup:ProductVersion>

The essential part here is the ProductReference annotation. It is has no meaning for the EMF model itself, but it forces EMF to load the parent. If you drop this annotation, and that you open this setup file, you will have an error stating that the required feature ‘product’ of ‘Custom Eclipse’ must be set. With it, no matter which setup file you open, everything will be resolved correctly, without an error in the setup editor.

I made this summary after asking on Eclipse’s forums.
Many thanks to Ed Merks for his help.

Custom Setup Task in OOMPH and namespace conflict

OOMPH is a solution that helps to install official and custom Eclipse distributions.

Those who use it for their own distro can extend its behaviour thanks to setup tasks. A setup task is made up of both an EMF model (that extends the setup.ecore/#SetupTask element from OOMPH) and Java code. This code is partially generated by EMF. People only have to complete the perform method to make it do something at runtime. Obviously, OOMPH provides a wizard to help in the creation of such a thing.

However, I recently had to maintain an existing set of setup tasks. And when I opened the genmodel file for my tasks, I had a weird error message in the genmodel editor.

EMF error due to conflicting namespaces

The exact error message indicates…


Problems encountered in the model
- The package 'http://www.eclipse.org/oomph/setup/1.0#/' has the same namespace URI 'http://www.eclipse.org/oomph/setup/1.0' as package 'platform:/resource/org.eclipse.oomph.setup/model/Setup.ecore#/'
- The package 'http://www.eclipse.org/oomph/setup/1.0#/' has the same namespace URI 'http://www.eclipse.org/oomph/setup/1.0' as package 'platform:/resource/org.eclipse.oomph.base/model/Base.ecore#/'

That’s a weird message.
Even worse, it does not appear if you create a new setup task project. I compared everything: the models, the project settings… everything.

Anyway… One important thing is that this message is not blocking. The EMF editor is made up of two tabs. When such an error is found, this editor shows the problems tab. But the generator tab is still available and you can perform generations anyway. So, you can ignore the message. Or, you can rid of it by following the explanations below. Notice this just a workaround.

Taking a detailed look at the error message, it indicates that two EMF projects from OOMPH export the same package. In fact, both packages export different classes but within the same namespace. And they reference each other (Setup extends classes from Base). Anyway, EMF does not know which package pick up as both could match.

The workaround for this is to update the ecore model.
Indeed, the generated ecore contains…

<eClassifiers
   xsi:type="ecore:EClass"
   name="YourTaskName"
   eSuperTypes="http://www.eclipse.org/oomph/setup/1.0#//SetupTask">

The super type is resolved by namespace.
If you reference it by the location of the ecore model, that will solve the problem.

<eClassifiers 
   xsi:type="ecore:EClass"
   name="YourTaskName"
   eSuperTypes="platform:/resource/org.eclipse.oomph.setup/model/Setup.ecore#//SetupTask">

The Setup classes extends the Base ones.
So, you can directly reference the Setup.ecore file. You can also update your genmodel file with the URL of the existing generators.

usedGenPackages="platform:/resource/org.eclipse.oomph.base/model/Base.genmodel#//base platform:/resource/org.eclipse.oomph.setup/model/Setup.genmodel#//setup"

… instead of…

usedGenPackages="../../org.eclipse.oomph.base/model/Base.genmodel#//base ../../org.eclipse.oomph.setup/model/Setup.genmodel#//setup"

Eventually, you will opt for a solution that prevents the genmodel from rewriting the ecore file. Just remove the publicationLocation attribute from your genmodel. Otherwise, every time you generate code from your genmodel file, it will rewrite the super types in your ecore file. Definitely not what you want.

PS: I have still not understood why the error sometimes appears.
In my case, the ecore file defined several setup tasks in the same file. My other example did not. Maybe that’s the reason.

Eclipse freezes on save

The symptoms: I use Eclipse Luna on Ubuntu 14.04.
My workspace is quite old and contains many projects. At some moment, I could not save any file anymore. When clicking Ctrl + S, Eclipse was freezing forever.

The cure: I deleted the projects I was not working on anymore. Reducing the number of files managed in my workspace solved the problem.

Notice this could also be due to an OS limit.
Or it could be due to the number of files managed by the workspace. In any case, clean it up. Save actions should work again.

Maximizing a JFace dialog programmatically

A short snippet to show you how to maximize a JFace dialog.
If you have googled it, you must have heard about the method setMaximized of the Shell class. However, you have to call this method at the right place in your code. Otherwise, it will not work.

The secret is to invoke this method on the dialog’s shell only once this shell has been created. You cannot configure it before. I have struggled a long time to understand why Shell#setMaximized did not work when invoked from Dialog#createContents(Composite). At least, it does not work on Windows 7. Eventually, I found it. The solution is to invoke it in Dialog#constrainShellSize().

public class ApplicationUI extends ApplicationWindow {

	public ApplicationUI() {
		super( null );
		// ...
	}

	@Override
	protected void constrainShellSize() {
		super.constrainShellSize();
		getShell().setMaximized( true );
	}

	// ...
}