IDE Extension Structure
Let’s take a closer look at how an IDE extension should be structured:
ide ├─ src // sources folder │ └─ main │ ├─ java │ │ └─ org.eclipse.che.plugin.menu.ide │ │ ├─ ... │ │ ├─ inject │ │ │ └─ SampleMenuGinModule.java // GIN module │ │ └─ SampleMenuExtension.java // IDE extension class │ ├─ resources │ │ └─ org.eclipse.che.ide.ext.demo.client │ └─ module.gwt.xml // template for generating GWT module [1] ├─ target // build output │ └─ classes │ ├─ META-INF │ │ └─ gwt │ │ └─ mainModule // contains GWT module name [2] │ └─ org.eclipse.che.plugin.menu │ ├─ ... │ └─ SampleMenuExtension.gwt.xml // generated GWT module [3] └─ pom.xml
pom.xml
There are several important parts in the pom.xml of the Che IDE plugin:
-
Packaging of the Maven project is
gwt-libwhich triggersgwt-libMaven lifecycle that will build a GWT library:<packaging>gwt-lib</packaging> -
Dependency on the Che IDE API library that provides a set of APIs for extending Che IDE:
<dependency> <groupId>org.eclipse.che.core</groupId> <artifactId>che-core-ide-api</artifactId> </dependency> -
Name of the GWT module is defined in the configuration of
gwt-maven-plugin:<plugin> <groupId>net.ltgt.gwt.maven</groupId> <artifactId>gwt-maven-plugin</artifactId> <extensions>true</extensions> <configuration> <moduleName>org.eclipse.che.plugin.menu.SampleMenuExtension</moduleName> </configuration> </plugin>For details on the generating GWT module, read the
gwt:generate-modulemojo description. GWT library is a JAR that contains compiled classes, project’s (re-)sources, GWT module descriptor (*.gwt.xml) and possibly other GWT-specific files.
gwt.xml
Project’s *.gwt.xml file is generated within the gwt-lib Maven lifecycle and contains:
-
the declarations for the default source folders:
<source path="client"/> <source path="shared"/> <super-source path="super"/> -
<inherits/>directives for the project’s direct dependencies which were packaged as agwt-lib.
Optional template may be provided in src/main/module.gwt.xml for generating project’s *.gwt.xml file.
The most common cases when you may require a template:
-
need to override the default source folders, like here;
-
need to add
<inherits/>directive for a GWT lib that isn’t packaged as agwt-libartifact (doesn’t contain GWT-specific meta information).
Consuming Shared Libs
The shared libraries don’t require any GWT-specific files or configuration in pom.xml to be consumed by a GWT library.
To use shared code in a GWT library:
-
declare a dependency on the "normal" artifact (JAR with compiled classes);
-
declare a dependency on the "sources" artifact (with
<classifier>sources</classifier>).
See an example here.
IDE extension class
Che IDE plugin has an entry point - Java class annotated with an @org.eclipse.che.ide.api.extension.Extension annotation. Plugin entry point is called immediately after initializing the core part of the Che IDE.
Here’s an entry point of the plugin that will add a new top level menu group using IDE actions:
package org.eclipse.che.plugin.menu.ide;
import static org.eclipse.che.ide.api.action.IdeActions.GROUP_HELP;
import static org.eclipse.che.ide.api.action.IdeActions.GROUP_MAIN_MENU;
import static org.eclipse.che.ide.api.constraints.Anchor.AFTER;
import com.google.inject.Inject;
import org.eclipse.che.ide.api.action.ActionManager;
import org.eclipse.che.ide.api.action.DefaultActionGroup;
import org.eclipse.che.ide.api.constraints.Constraints;
import org.eclipse.che.ide.api.extension.Extension;
import org.eclipse.che.plugin.menu.ide.action.SampleAction;
@Extension(title = "Sample Menu")
public class SampleMenuExtension {
private static final String SAMPLE_GROUP_MAIN_MENU = "Sample";
@Inject
private void prepareActions(SampleAction sampleAction, ActionManager actionManager) {
DefaultActionGroup mainMenu = (DefaultActionGroup) actionManager.getAction(GROUP_MAIN_MENU);
DefaultActionGroup sampleGroup =
new DefaultActionGroup(SAMPLE_GROUP_MAIN_MENU, true, actionManager);
actionManager.registerAction("sampleGroup", sampleGroup);
mainMenu.add(sampleGroup, new Constraints(AFTER, GROUP_HELP));
actionManager.registerAction("sayHello", sampleAction);
sampleGroup.add(sampleAction, Constraints.FIRST);
}
}
Dependency Injection
Che IDE use Google GIN for dependency injection. Che IDE plugin can provide a GIN module. In order to be picked-up by IDE, plugin’s GIN module should be annotated with an @org.eclipse.che.ide.api.extension.ExtensionGinModule annotation.
Here’s a GIN module of the plugin:
package org.eclipse.che.plugin.menu.ide.inject;
import com.google.gwt.inject.client.AbstractGinModule;
import org.eclipse.che.ide.api.extension.ExtensionGinModule;
@ExtensionGinModule
public class SampleMenuGinModule extends AbstractGinModule {
@Override
protected void configure() {}
}
In this example an extension GIN module isn’t really necessary since the plugin does not really need to put anything in a container. Read more about dependency injection and take a look at example Gin modules.
Extension Points
Debugging With Super DevMode
There are two options available to launch GWT Super DevMode, depending on the state of the Che sources: whether it’s built or not since a lot of sources are generated during the Maven build.
-
Case 1: Che sources have been already built. Use the following command:
mvn gwt:codeserver -pl :che-ide-gwt-app -am -Dmaven.main.skip -Dmaven.resources.skip -Dche.dto.skip -Dskip-enforce -Dskip-validate-sources
-
Case 2: Che sources haven’t been built, e.g. freshly cloned or after executing
mvn cleanor you just don’t need to build the whole project. Use the following command:
mvn gwt:codeserver -pl :che-ide-gwt-app -am -Dskip-enforce -Dskip-validate-sources
The second one requires more time to launch GWT CodeServer since it executes process-classes build phase for each maven module. Thus, using the first command is preferable.
Note, both commands have to be performed in the root folder of the Che project.
Once codeserver is started, open the prompted URL, drag bookmarks on your bookmarks bar. Note that you may face the error saying there are no GWT modules on the page. It happens because the IDE is opened in an iframe. Just, cut dashboard/#/ide/ from the URL. To debug client side code, follow instructions from quickstart.
Run in Che
Once your extension is ready, you can build, run and debug it in Che itself. Just use an existing sample and add a custom plugin with its dependencies.
Add to a Custom Assembly
You can build your custom Che assembly outside Che and/or use any IDE to develop extensions. Once done, run mvn clean install in the root of the assembly to get a Tomcat bundle that is ready to be run either in Docker or deployed to OpenShift.