CoastalHacking / semiotics-main

Semiotics models and stand-alone product / UI
Apache License 2.0
0 stars 0 forks source link

Context menu: Projects #22

Closed jpasski closed 8 years ago

jpasski commented 8 years ago

From @jonpasski on July 2, 2016 16:35

Context Menu

Copied from original issue: OpenSemanticsIO/semiotics-main#37

jpasski commented 8 years ago

Task

Successfully built on travis CI, closing.

Lessons Learned

e4 Menu Contributions and Core Expressions

This was the first time I worked with e4 menu additions. I still dunno if I'm doing the right approach with an e4 model fragment or not. I'm assuming some of the views I'm working with are still Eclipse 3.x based, so using a model fragment that hooks into the legacy component seems to make sense. Anywho, learned a lot!

As usual, vogella helped out :)

Had difficulties on getting pop-up menus to work. I tried the following:

None of those worked. Some of that was me throwing spaghetti against the wall to see what worked. What was really confusing is that org.eclipse.ui.popup.any didn't work, which was the catch-all for 3.x I guess.

What did work was explicitly stating the target:

Another one to try in the future:

In all cases, these were added as a Menu Contribution on the element ID org.eclipse.e4.legacy.ide.application.

Another thing that was confusing is how visibility and core expressions worked. This was also the first time I used core expressions. Core expressions are still managed via Eclipse extensions. This expression did not work:

 <extension
       point="org.eclipse.core.expressions.definitions">
    <definition
          id="io.opensemantics.semiotics.extension.e4.expression.projectshow">
       <with variable="selection">
          <iterate>
             <adapt type="org.eclipse.core.resources.IProject">
                <test
                      property="org.eclipse.core.resources.open"
                      value="true">
                </test>
             </adapt>
          </iterate>
       </with>
    </definition>
 </extension>

I tried a bunch of incantations using selection and other values, no change. The magic that worked was this:

-            <iterate>
+            <iterate ifEmpty="false">

It seems that an empty selection returned true by default. WTF...

As can be seen above, I also learned about property testers. Those are nifty!

I went with dynamic menu contributions. To pass data (strings) around, it seemed the recommended approach is to use Eclipse Commands. The e4 model fragment adds a command that requires a parameter. When the dynamic menu creates sub-menus, it populates the sub-menu's command with a string value that can be passed to the menu handler. This was all new too. I had some false starts until I came across a good SO answer that called out the use of MParameter. I was using older API method calls IIRC that were not very effective.

The documentation on menu item creation emphasizes not being computationally expensive, which makes sense. I.e., don't be doing a lot of silly things when the menu is being populated. This led to the next journey :)

Event Handling in OSGi and Eclipse

With the menus, I didn't want any long-running code, so using some type of pub-sub service makes sense. Eclipse has one via IEventBroker, which uses Eclipse dependency injection (DI).

DI uses magic to make annotations like @javax.inject.Inject work when an Eclipse context is available. What's cool about this is standard OSGi declarative services (DS) can also be injected using such annotations. However, the inverse is not true.

In a standard DS, the @Inject annotation doesn't work, since, well, OSGi doesn't define that annotation to mean anything. Also, that means a DS can't use other Eclipse services like IEventBroker, since those assume an Eclipse context of some sorts.

I wanted to keep the DS as vanilla as possible and not tie it to Eclipse, which meant not using IEventBroker. No problem, EventAdmin to the rescue! The EclipseSource people compete with Vogella on providing great Eclipse and OSGi documentation.

Anywho, when an IProject is selected, its name is published via EventAdmin. An EventHandler subscribes to the same topic and handles the flip side of generating the correct EMF objects for the ECP project. This asynchronous nature makes testing a bit more complicated, but at least meets the requirement on not doing a lot of blocking operations when working with the menu / UI thread.

Also started using the OSGi log services here, again via an EclipseSource blog.

And got dirty with the ECP API! Speaking of which, I was previously using the EMFStore API directly. The ECP API is a better abstraction, focusing more on the projects the data. I was unsure on if I wanted to stay w/ ECP / EMFStore due to the odd bugs here and there I came across. I'm liking it more, the less ignorant I become.

OSGi Capabilities

Learned a bunch on OSGi capabilities via two blog posts by Dirk Fauth:

The problem I had is not all OSGi services in use declare they provide capabilities. This would lead to dependency resolution errors in either PDE or Tycho/p2, like so:

[ERROR]   Missing requirement: io.opensemantics.semiotics.extension.integration.tests 1.0.0.qualifier requires 'osgi.service org.eclipse.emf.ecp.changebroker.spi.NotificationProvider 0.0.0' but it could not be found

This was really painful in the integration tests. Since the test run configuration by default includes all workspace bundles, service providers would be resolved, and the tests would pass (yay!). However, when running with Tycho, the tests would fail (boo!). Dirk's testing blog post pointed to Tycho documentation on how to make explicit what I was hoping would be implicit. The extension provider test case pom.xml needed to include such a declaration:

<plugin>
   <groupId>org.eclipse.tycho</groupId>
   <artifactId>target-platform-configuration</artifactId>
   <configuration>
      <dependency-resolution>
         <extraRequirements>
            <!-- https://wiki.eclipse.org/Tycho/Packaging_Types#eclipse-test-plugin -->
            <requirement>
               <type>eclipse-feature</type>
               <id>io.opensemantics.semiotics.app.dependencies.feature</id>
               <versionRange>[1.0.0,1.1.0)</versionRange>
            </requirement>
            <!-- not included in the app dependency feature -->
            <requirement>
               <type>eclipse-plugin</type>
               <id>org.eclipse.emf.ecp.changebroker.provider</id>
               <versionRange>[1.9.0,2.0.0)</versionRange>
            </requirement>
         </extraRequirements>
      </dependency-resolution>
   </configuration>
</plugin>

Regardless, the extension provider now includes the necessary metadata in the Manifest and also for p2. It's not ideal that they're manually managed (unlike bndtools).

Filed Eclipse bug 498602 for ECP on some of their bundles that could benefit from capabilities.

Tycho Debug Testing and Other Maven Tricks

Learned some debugging trick for Tycho. Since I wanted everything in Eclipse, I had to create two run configurations: a Maven one for Tycho and a remote application one to debug. Kinda cumbersome.

Talking about cumbersome, I found it strange that the Maven run configuration requires the command line switches to be in the Goals section of the run configuration. Alas.

Additionally, got familiar with the Maven -pl '!submodule1,!submodule2' command, like so:

-pl '!io.opensemantics.semiotics:io.opensemantics.semiotics.model.product'

Nice to speed up retesting!

Command line used: mvn verify -X -DdebugPort=8000 -l ../maven.log -f builds/io.opensemantics.semiotics.parent/pom.xml -pl '!io.opensemantics.semiotics:io.opensemantics.semiotics.model.product'

Mockito

OMG, this really confused me a bunch. The target definition originally included only one dependency from Orbit: JUnit. After adding Mockito, I was getting a bunch of resolution errors around org.objensis not being found:

[ERROR] Missing requirement: org.mockito 1.9.5.v201605172210 requires 'package org.objenesis [1.0.0,2.0.0)' but it could not be found

The vogella blog on Mockito refers to an older Orbit 2015 drop that includes "Hamcrest-core & Objenesis" in including in the plugin name. So I tried adding just that feature to the target definition. No love. It took me a bit to realize that the "Java Library for Object Instantiation" is the bundle I needed. Then pretty much every Hamcrest plugin needed to be included. This relates to split packaging, which is something I've heard of but not quite familiar. Regardless, got it working with some integration tests, now with the following: