Next stop: EclipseCon Europe 2017

As every year EclipseCon Europe is fixed in my schedule, and I am excited to go there. It is a melting pot for the Eclipse Community, a big family come together. I am in the last preparations before departure to Ludwigsburg, and can’t wait to finally go there.

FullSizeRender.jpg

itemis is of course sponsoring EclipseCon Europe, and we will have a booth in front of the theater. With 12 talks, 8 speakers and about 20 attendees I am expecting that the it(emis)-Crowd is again the biggest party at EclipseCon Europe. The itemis booth will be the place where you will have the highest chance to meet me, but of course there is plenty of time to meet each other.

Meeting the Scout and Modeling community

As in the past years, I will start my journey already on sunday. I will again join the Eclipse Scout community’s pre-conference dinner at the Rossknecht. The past years I was joining on monday the Scout User Group meeting, but this year I committed to join the Guided Tour on Eclipse Modeling at the Unconference. At 14:40 I will give there my first talk, an insight on the Xtend language.

 

Xtext and Platform development

This Friday, Oct 20th, Xtext 2.13 was released finally and I have invested quite some time in the past months to find and resolve bugs. I have worked intensively with the Eclipse EARI system, and investigated together with Christian Dietrich the problem reports we are getting in. Until we now managed to get less problem reports in than we are processing. Christian and I are those who care most about user problems and we have fixed together the majority of bugs for this and the past releases. Christian does an incredible job! We will happily share insights on the current state on Xtext at the Unconference and all conference days.

The past months I starting getting involved into the Eclipse Platform itself. While before I completely focused on Xtext development and just used the platform, I thought it was time to give something back. I am using Eclipse every day and still love to work with it. I am recognizing that others prefer other IDEs, or even new ones are built, and there are reasons for that. But still for complex development tasks I believe that an extensible desktop IDE like Eclipse is the best tool. Eclipse has some flaws, and I could help there. Now I am frequently contributing to the Eclipse Platform (with focus on performance, usability and stability) and found into the development process, which took me some time. Because of this engagement I am expecting to have some interersting talks on platform development with some driving persons like Lars Vogel, Dani Megert, Alexander Kurtakov, Mickael Istria, Mikaël Barbero or Andrey Loskutov. I have to thank them for guiding me in the process and reviewing my changes carefully. Guys, I owe you a beer at the Nestor bar!

A conference day (almost) never ends

Nestor bar, the place to be after the long conference day! You will find me there each evening from monday on till late. Like every year it will be hard to celebrate long and get up early. But be sure, I’ll manage that. It isn’t the first time, and won’t be the last. The party ain’t over until it’s over.

I’m not staying at Nestor; like last year I reserved early a room at the nearby Villa Forêt. It is just a 5 minute walk (and some walking does not harm) and fine for me. It was in this hotel where I met Philip Wenig some years ago at breakfast. Ever since then I had nice talks with him and I always enjoy that. This year I already met him twice: At the Eclipse DemoCamp in Zurich, and at Eclipse Hackathon Hamburg.

Talks at the main conference

This year, besides my Xtend talk at the Unconference, I will give 2 talks at EclipseCon:

screenshot 21.png

“Introduction to Expression Languages with Xtext” (Tuesday 14:30, Silchersaal) will give you some patterns in Xtext grammers when you need to embed expressions in your language. Xtext ships with Xbase, which is a full expression langauge that you can easily integrate, but sometimes Xbase is not the right choice for you. Xbase is tightly bound to the Java typesystem and JDT, and for your language this could be undesired. Then you have to build your own expression language, which is a bit advanced. But you can learn a lot from Xbase, and in this talk I will show some grammar patterns that you could take from Xbase. I already gave this talk at EclipseCon France this year, so most of the slides are fortunately prepared.

screenshot 20.png

Different for my second talk: “Advanced Oomph Setup Authoring” (Wednesday 12:00, Silchersaal). This is completely new, and I am right now working on the slide deck. I was responsible for developing Xtext’s Oomph setup, which is compared to other setups at Eclipse more complex. But I have learned much from the other setups. Again, there are some patterns that can be recognized among the different setups. I will show and explain screenshots from different setups and discuss some advantages or disadvantages from then. Oomph is a mighty framework, and creating good setups is a time consuming and error prone work. The information given in this talk should give some help to author more robust setups, and build them faster. Advanced Oomph users might recognize that they do already much right, but even they might get the one or other idea to enhance their setups. Users rather new with Oomph will get the most out of this talk. They should at least have a basic idea about Oomph project setups.

Lightning Talks at the itemis booth

This year we will give some 5-Minute Lightning Talks at our booth in pauses. We have a lot of interesting small talks this time, from Xtext to Java 9, and even where plastic plants play a role. Just come around to the exhibitor’s area in front of the theater and get some inspiration.

Also here I have 2 slots:

  • Tuesday 15:50: “What’s new in Eclipse Photon?”: Let me show you a sneak preview on some features coming in Photon. You will see some of my contributions and some other.What's New in Eclipse Photon.001.jpeg
  • Wednesday 15:20: “A committer’s view on Eclipse Automated Error Reporting”: As said before, AERI helped me a lot to improve Xtext and Eclipse Platform. I’ll show you what committers see from problems reported to it and how it can help to find bugs. Also, a big Thank You to the guys from Codetrails for the support!ACommittersViewOnEARI.001.jpeg

Follow @itemis on Twitter to get notice on further talks from us!

The most important thing at EclipseCon is…

the people! I love to meet all the people again, from which most of them I only see once a year. This year I have already attended Eclipse Converge/, DevoXX US and EclipseCon France, so some of you folks I have already met again. But EclipseCon Europe is by far larger and more intensive. To all the people I already know, from year to year they become more.

Eclipse on the roll

It is a pleasure to see which companies and projects joined the Eclipse Foundation recently. Since I have a background in Java Enterprise development from early beginnings (yes, I had to implement bean managed persistence with EJB 1.0 in the ancient days and it was NOT funny!), I was delighted to see EE4J at Eclipse. Then IBM’s J9, Deeplearning4J, and the story is not over yet. If this continues, the Eclipse Foundation has a bright future and I am glad that itemis is a driving part of the story.

For this year’s EclipseCon Europe some of this hot new stuff might come a bit too late, but I expect more talks related to these exciting technologies next year. Yes, there are already some talks, but I think the focus will shift from now on.

And finally: Time to rest

After EclipseCon I’m taking a week off. I need this already, and will desperately need this after this exciting and exhausting week. Back to my beloved family, who is awaiting me after a long week. Who knows, maybe my second daughter Sophia is walking then? Can’t be long anymore.

 

Advertisements

Enabling Spring in Scout applications

Today I am attending the first Scout User Day 2014 in Ludwigsburg, which is aligned with EclipseCon Europe 2014 starting tomorrow. Yesterday we had a pre-event dinner with some attendees and the organizers at the Rossknecht restaurant. IMG_3161IMG_3160 I got into a chat with Nejc Gasper, who will give a talk titled “Build a Scout backend with Spring” today. I was a bit surprised as he told me he did not manage to get Spring’s classpath scanning working yet. Since we are doing this in our application, I think it is worth writing now down what we had to do to get this working. The goal in our application is primarely to use Spring as dependency injection container, since the customer uses Spring in all their other Java based applications, too, and wanted us to do so also.

Spring Configuration

The Spring configuration files are located in the folder META-INF/spring of the *.client, *.shared, *.server projects. In this configuration files, we mainly activate classpath scanning:

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:beans="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">

    <context:annotation-config />
    <context:component-scan base-package="com.rhenus.fl" />
    <!--  http://docs.spring.io/spring/docs/4.0.x/spring-framework-reference/html/validation.html#core-convert-Spring-config -->
    <beans:bean id="conversionService" class="org.springframework.core.convert.support.DefaultConversionService" />
</beans:beans>

The next important thing is to copy the files spring.handlers, spring.schemas<, spring.tooling into the META-INF folder. The files can be found in the META-INF directory of bundle org.springframework.context. screenshot 21 Without doing this, you will get errors while loading the Spring configuration like this:

Caused by: 
org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Unable to locate Spring NamespaceHandler for XML schema namespace [http://www.springframework.org/schema/context]|Offending resource: URL [bundleresource://9.fwk1993775065:1/META-INF/spring/fl_client.xml]|
	at org.springframework.beans.factory.parsing.FailFastProblemReporter.error(FailFastProblemReporter.java:70)
	at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:85)
	at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:80)
	at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.error(BeanDefinitionParserDelegate.java:316)
	at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1421)
	at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1414)
	at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:187)
	at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:141)
	at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:110)
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(XmlBeanDefinitionReader.java:508)
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:391)
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:335)
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:303)
	at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:180)
	at org.springframework.context.support.GenericXmlApplicationContext.load(GenericXmlApplicationContext.java:116)

Bundle Activator

The Spring configuration files are loaded in the Bundle Activator classes of the three “main” Scout projects (client/shared/server). The Activator can also be used then to access the ApplicationContext. We use the GenericXmlApplicationContext to initialize the context from the XML configuration above. One important thing is that this class uses the ClassLoader of the Activator. Otherwise you will get again the error mentioned in the section above. The Activator class looks then as follows:


public class Activator extends Plugin {

 // The plug-in ID
 public static final String PLUGIN_ID = "com.rhenus.fl.application.client";
 public final static String SPRING_CONFIG_FILE = "META-INF/spring/fl_client.xml";

 // The shared instance
 private static Activator plugin;
 private ApplicationContext ctx;

 @Override
 public void start(BundleContext context) throws Exception {
  super.start(context);
  plugin = this;
  init(context);
 }

 @Override
 public void stop(BundleContext context) throws Exception {
  plugin = null;
  super.stop(context);
 }

 public static Activator getDefault() {
  return plugin;
 }

 private void init(BundleReference bundleContext) {
  URL url = getClass().getClassLoader().getResource(SPRING_CONFIG_FILE);

  UrlResource usr = new UrlResource(url);

  ctx = new GenericXmlApplicationContext() {
  @Override
  public ClassLoader getClassLoader() {
   return Activator.class.getClassLoader();
  }
 };
  ((GenericXmlApplicationContext) ctx).load(usr);
  ((AbstractApplicationContext) ctx).refresh();

 }

 public ApplicationContext getContext() {
  return ctx;
 }
}

Service Factory

In order to use dependency injection in Scout services, the services themselves must be instantiated through the Spring ApplicationContext. The default implementation of course is not aware of Spring, so we need to customize this. Unfortunately we have to copy the class org.eclipse.scout.rt.server.services.ServerServiceFactory. We need just to exchange one single line in the method updateInstanceCache(), where the service is instantiated, but this method is private in Scout. The line

m_service = m_serviceClass.newInstance();

is replaced by

m_service = getContext().getBean(m_serviceClass);

Since we have to provide different ApplicationContexts in the different plugins, we put this into the abstract class AbstractSpringAwareServerServiceFactory (full code):

public abstract class AbstractSpringAwareServerServiceFactory implements IServiceFactory {

 private void updateInstanceCache(ServiceRegistration registration) {
  synchronized (m_serviceLock) {
   if (m_service == null) {
    try {
     // CUSTOMIZING BEGIN
//     m_service = m_serviceClass.newInstance();
     m_service = getContext().getBean(m_serviceClass);
     // CUSTOMIZING END
     if (m_service instanceof IService2) {
      ((IService2) m_service).initializeService(registration);
     } else if (m_service instanceof IService) {
      ((IService) m_service).initializeService(registration);
     }
    } catch (Throwable t) {
     LOG.error("Failed creating instance of " + m_serviceClass,
       t);
    }
   }
  }
 }
 
 // CUSTOMIZING BEGIN
 protected abstract ApplicationContext getContext();
 // CUSTOMIZING END

}

The concrete classes implement the method getContext() by accessing the method from the Bundle Activator:

public class ServerServiceFactory extends AbstractSpringAwareServerServiceFactory {

  /**
   * @param serviceClass
   */
  public ServerServiceFactory(Class<?> serviceClass) {
    super(serviceClass);
  }

  @Override
  protected ApplicationContext getContext() {
    return Activator.getDefault().getContext();
  }

}

plugin.xml

The service factory class implemented above must be used now to create the services. This is done in the plugin.xml file:

<service
 factory="com.rhenus.fl.application.server.services.ServerServiceFactory"
 class="com.rhenus.fl.tmi.server.tmirln010.TMIRLN010Service"
 session="com.rhenus.fl.application.server.ServerSession">
</service>

Use Dependency Injection

Now we are finally able to use Dependency Injection with javax.inject.Inject with Scout services.

import org.springframework.stereotype.Component;
import javax.inject.Inject;
...

@Component
@InputValidation(IValidationStrategy.PROCESS.class)
public class TMIRLN010Service extends AbstractTMIRLN010Service {
  @Inject
  protected ConversionService conversionService;
  ...
}

Go!

If everything is correct, you will now recognize the following lines in the console when starting up the Scout application:

Okt 27, 2014 8:45:28 AM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from URL [bundleresource://9.fwk1993775065:1/META-INF/spring/fl_client.xml]
Okt 27, 2014 8:45:29 AM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from URL [bundleresource://10.fwk1993775065:1/META-INF/spring/fl_shared.xml]
Okt 27, 2014 8:45:29 AM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing com.rhenus.fl.application.shared.Activator$1@b40d694: startup date [Mon Oct 27 08:45:29 CET 2014]; root of context hierarchy
Okt 27, 2014 8:45:29 AM org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor 
INFO: JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
Okt 27, 2014 8:45:29 AM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing com.rhenus.fl.application.client.Activator$1@292f062b: startup date [Mon Oct 27 08:45:29 CET 2014]; root of context hierarchy
Okt 27, 2014 8:45:29 AM org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor 
INFO: JSR-330 'javax.inject.Inject' annotation found and supported for autowiring

Scout tables with fixed columns

For tables with many columns it is often better if some of the first columns stay fixed when the user scrolls the table content horizontally. Since RAP 2.0, tables and trees support fixed columns, but Scout (current: 4.0/Eclipse Luna) does not provide this feature for its Table implementation. Since Scout supports different UI frameworks (Swing,SWT,RAP) and only RAP provides a table implementation with fixed columns support, this might be a reason for this missing feature.

The necessary additions can be added to Scout without changing Scout sources themselves. Scout allows to customize UI components, including existing ones. We can add this feature with fragments. The code mentioned below can be fetched from Github “scout-experimental”.

Client Extension Plugin

AbstractTableWithFixedColumns

First, we need a Table implementation that provides an additional configuration property fixedColumns. The value is stored using the element’s Property Support:

package org.eclipse.scout.rt.extension.client.ui.basic.table;

import org.eclipse.scout.commons.annotations.ConfigProperty;

/**
 * A table that supports Fixed Columns.
 *
 * @see http://eclipse.org/rap/developers-guide/devguide.php?topic=tree-table.html&version=2.0
 */
public class AbstractTableWithFixedColumns extends AbstractExtensibleTable {
	public static final String PROP_FIXED_COLUMNS = "org.eclipse.rap.rwt.fixedColumns"; // =RWT.FIXED_COLUMNS
	/**
	 * Configures how many of the visible columns should be fixed.
	 * @return A value greater than 0
	 */
	@ConfigProperty(ConfigProperty.INTEGER)
	protected int getConfiguredFixedColumns () {
		return -1;
	}

	public void setFixedColumns (int n) {
		propertySupport.setPropertyInt(PROP_FIXED_COLUMNS, n);
	}

	public int getFixedColumns () {
		return propertySupport.getPropertyInt(PROP_FIXED_COLUMNS);
	}

	@Override
	protected void initConfig() {
		super.initConfig();
		setFixedColumns(getConfiguredFixedColumns());
	}

}

This custom class can be specified as default base class for tables in the Scout workspace preferences:
Scout base class

In the client code, the table field would be defined like this:

public class CtyTableField
      extends
      AbstractTableField<CtyTableField.Table> {
          public class Table extends AbstractTableWithFixedColumns {
             @Override
             protected int getConfiguredFixedColumns() {
                return 2;
             }
          }
}

Scout RAP UI extension fragment

RwtScoutTableExt

The class that must be customized is org.eclipse.scout.rt.ui.rap.basic.table.RwtScoutTable. I’m not good in creating names, so I call its extension just RwtScoutTableExt.


package org.eclipse.scout.rt.ui.rap.basic.table;

import org.eclipse.rap.rwt.RWT;
import org.eclipse.scout.rt.client.ui.basic.table.columns.IColumn;
import org.eclipse.scout.rt.ui.rap.ext.table.TableEx;
import org.eclipse.swt.widgets.Composite;

public class RwtScoutTableExt extends RwtScoutTable {
	@Override
	protected void initializeUi(Composite parent) {
	    super.initializeUi(parent);
	    TableEx table = getUiField();
		// Fixed Columns Support
		// see
		// http://eclipse.org/rap/developers-guide/devguide.php?topic=tree-table.html&version=2.0
		// the configured fixed columns refer to visible columns only, but for
		// the RWT table the number of fixed
		// columns include also the non-visible ones. Compute how many columns
		// should be fixed in the RWT table.
		Integer configuredFixedColumns = (Integer) getScoutObject().getProperty(
				RWT.FIXED_COLUMNS);
		if (configuredFixedColumns != null && configuredFixedColumns > 0) {
			int fixedColumns = 0;
			int visibleColumns = 0;
			for (IColumn<?> column : getScoutObject().getColumns()) {
				fixedColumns++;
				if (column.isDisplayable() && column.isInitialVisible()) {
					visibleColumns++;
				}
				if (visibleColumns == configuredFixedColumns) {
					break;
				}
			}
			table.setData(RWT.FIXED_COLUMNS, new Integer(fixedColumns));
		}
	}
}

After Scout has initialized the table component (call of super), the table has to be configured with the number of fixed columns:


table.setData(RWT.FIXED_COLUMNS, new Integer(fixedColumns));

The number of configured fixed columns has to be specified by a property of the table field. For now, you might wonder why we do not simply set the configured fixed column value. The reason is, that some columns might not be visible, and when configuring the fixed columns, you would expect that only the visible ones should count.

RwtScoutTableFieldExt

The table class itself is constructed by RwtScoutTableField. In order to construct our customized class, RwtScoutTableField must be subclassed and override the createRwtScoutTable() method:

package org.eclipse.scout.rt.ui.rap.form.fields.tablefield;

import org.eclipse.scout.rt.client.ui.form.fields.smartfield.IContentAssistFieldProposalForm;
import org.eclipse.scout.rt.ui.rap.basic.table.IRwtScoutTable;
import org.eclipse.scout.rt.ui.rap.basic.table.RwtScoutTable;
import org.eclipse.scout.rt.ui.rap.basic.table.RwtScoutTableExt;
import org.eclipse.scout.rt.ui.rap.util.RwtUtility;

public class RwtScoutTableFieldExt extends RwtScoutTableField {
	@Override
	protected IRwtScoutTable createRwtScoutTable() {
		if (getScoutObject().getForm() instanceof IContentAssistFieldProposalForm) {
			return new RwtScoutTable(RwtUtility.VARIANT_PROPOSAL_FORM);
		} else {
			return new RwtScoutTableExt();
		}
	}

}

MANIFEST.MF

The created fragment is a fragment of the bundle org.eclipse.scout.rt.ui.rap. At least from Scout version 3.9.0 on, likely earlier, the mentioned solution should work.

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Scout UI RAP - Extension
Bundle-SymbolicName: de.kthoms.scout.rt.ui.rap;singleton:=true
Bundle-Version: 1.0.0.qualifier
Fragment-Host: org.eclipse.scout.rt.ui.rap;bundle-version="3.9.0"
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Export-Package: org.eclipse.scout.rt.ui.rap.form.fields.tablefield

fragment.xml

The extended field class has to be configured in the fragment’s descriptor fragment.xml by using the org.eclipse.scout.rt.ui.rap.formfields extension point:


<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<fragment>
  <extension
        point="org.eclipse.scout.rt.ui.rap.formfields">
      <formField
            active="true"
            modelClass="org.eclipse.scout.rt.client.ui.form.fields.tablefield.ITableField"
            name="Table field"
            scope="global">
            <uiClass
              class="com.itemis.scout.rt.ui.rap.form.fields.tablefield.RwtScoutTableFieldExt">
            </uiClass>
      </formField>
  </extension>

</fragment>

Note the scope="global" configuration. The interface org.eclipse.scout.rt.ui.rap.extension.IFormFieldExtension defines 3 scopes: default, global, local. The description for the global scope is:

IFormFieldExtension.SCOPE_GLOBAL to indicate this extension to have a global scope (whole eclipse). Global defined extensions overwrite the default implementation.

Overwriting the default implementation is exactly what we try to achieve here.

Result

The first 2 columns are marked as fixed. In fact, in front of the first visible column the table has a non-displayable Id column. When scrolling the table horizontally, the columns “Iso 2 Code” and “Description” are fixed.

screenshot 2014-07-07 um 12.10.50
screenshot 2014-07-07 um 12.11.02