eclipse RCP UI through java code - eclipse-plugin

Can I implement Eclipse RCP UI using java code only and not plugin.xml?

While it might be possible in theory (eclipse plugins are OSGi bundle which are read by the extension registry), I don't think it is practical (unless you re-implement the extension registry lifecycle).
Eclipse Equinox precisely extends the concept of bundles with the concept of extension points, hence the mandatory presence of plugin.xml.

You can programmatically add and remove extensions. See following example methods (adapt on demand):
public void addExtension() throws UnsupportedEncodingException {
String pluginXmlAsString = "<a string with the content of plugin.xml";
InputStream pluginXmlIs = new ByteArrayInputStream(pluginXmlAsString.getBytes(StandardCharsets.UTF_8.name()));
IExtensionRegistry extensionRegistry = Platform.getExtensionRegistry();
Object token = ((ExtensionRegistry) extensionRegistry).getTemporaryUserToken();
IContributor contributor = ContributorFactoryOSGi.createContributor(Platform.getBundle("org.acme.mybundle"));
extensionRegistry.addContribution(pluginXmlIs, contributor, false, null, null, token);
}
public static void removeExtensionsContributedByMe() {
String extensionPointId = "<ID of the extension point for remove an extension of";
String extensionContributor = "org.acme.mybundle";
ExtensionRegistry extensionRegistry = (ExtensionRegistry) Platform.getExtensionRegistry();
IExtensionPoint extensionPoint = extensionRegistry.getExtensionPoint(extensionPointId);
IExtension[] extensions = extensionPoint.getExtensions();
Object token = extensionRegistry.getTemporaryUserToken();
for (IExtension extension : extensions) {
if (extensionContributor.equals(extension.getContributor().getName())) {
extensionRegistry.removeExtension(extension, token);
}
}
}
We use this for unit tests which add extensions as preparation and remove extension to clean up. This way the tests do not influence each other (which would be the case if the extensions are "hard coded" in plugin.xml or fragment.xml).

Related

Dokka uses fully qualified class names

I'm using dokka to auto generate javadoc for me. Though when it encounters any class not from my project it uses fully qualified names.
Is it possible to use only class names and make dokka provide a link for it? For example:
java.lang.String getName()
I'd want instead of java.lang.String to have String with link to Java doc
My gradle config:
ext.simpleName = project.name.substring(project.name.indexOf('-') + 1, project.name.size())
dokka {
outputFormat = 'javadoc'
outputDirectory = "${rootProject.buildDir}/javadoc/$project.ext.simpleName"
linkMapping {
dir = 'src/main/java'
url = "https://github.com/mibac138/ArgParser/blob/master/$project.ext.simpleName/src/main/java"
}
linkMapping {
dir = 'src/main/kotlin'
url = "https://github.com/mibac138/ArgParser/blob/master/$project.ext.simpleName/src/main/kotlin"
}
}
Also, what exactly is linkMapping? I'm not sure what it does.
For linking to 3rd party libraries you should use externalDocumentationLink pointing to Oracle Java documentation:
dokka{
externalDocumentationLink {
url = new URL("https://docs.oracle.com/javase/8/docs/api/")
}
If you use Kotlin and Java in the same project fully qualified names for Java classes may be necessary

Setting the version number for .NET Core projects

What are the options for setting a project version with .NET Core / ASP.NET Core projects?
Found so far:
Set the version property in project.json. Source: DNX Overview, Working with DNX projects. This seems to set the AssemblyVersion, AssemblyFileVersion and AssemblyInformationalVersion unless overridden by an attribute (see next point).
Setting the AssemblyVersion, AssemblyFileVersion, AssemblyInformationalVersion attributes also seems to work and override the version property specified in project.json.
For example, including 'version':'4.1.1-*' in project.json and setting [assembly:AssemblyFileVersion("4.3.5.0")] in a .cs file will result in AssemblyVersion=4.1.1.0, AssemblyInformationalVersion=4.1.1.0 and AssemblyFileVersion=4.3.5.0
Is setting the version number via attributes, e.g. AssemblyFileVersion, still supported?
Have I missed something - are there other ways?
Context
The scenario I'm looking at is sharing a single version number between multiple related projects. Some of the projects are using .NET Core (project.json), others are using the full .NET Framework (.csproj). All are logically part of a single system and versioned together.
The strategy we used up until now is having a SharedAssemblyInfo.cs file at the root of our solution with the AssemblyVersion and AssemblyFileVersion attributes. The projects include a link to the file.
I'm looking for ways to achieve the same result with .NET Core projects, i.e. have a single file to modify.
You can create a Directory.Build.props file in the root/parent folder of your projects and set the version information there.
However, now you can add a new property to every project in one step by defining it in a single file called Directory.Build.props in the root folder that contains your source. When MSBuild runs, Microsoft.Common.props searches your directory structure for the Directory.Build.props file (and Microsoft.Common.targets looks for Directory.Build.targets). If it finds one, it imports the property. Directory.Build.props is a user-defined file that provides customizations to projects under a directory.
For example:
<Project>
<PropertyGroup>
<Version>0.0.0.0</Version>
<FileVersion>0.0.0.0</FileVersion>
<InformationalVersion>0.0.0.0.myversion</InformationalVersion>
</PropertyGroup>
</Project>
Another option for setting version info when calling build or publish is to use the undocumented /p option.
dotnet command internally passes these flags to MSBuild.
Example:
dotnet publish ./MyProject.csproj /p:Version="1.2.3" /p:InformationalVersion="1.2.3-qa"
See here for more information: https://github.com/dotnet/docs/issues/7568
Not sure if this helps, but you can set version suffixes at publish time. Our versions are usually datetime driven, so that developers don't have to remember to update them.
If your json has something like "1.0-*"
"dotnet publish --version-suffix 2016.01.02" will make it "1.0-2016.01.02".
It's important to stick to "semvar" standards, or else you'll get errors. Dotnet publish will tell you.
Why not just change the value in the project.json file. Using CakeBuild you could do something like this (optimizations probably possible)
Task("Bump").Does(() => {
var files = GetFiles(config.SrcDir + "**/project.json");
foreach(var file in files)
{
Information("Processing: {0}", file);
var path = file.ToString();
var trg = new StringBuilder();
var regExVersion = new System.Text.RegularExpressions.Regex("\"version\":(\\s)?\"0.0.0-\\*\",");
using (var src = System.IO.File.OpenRead(path))
{
using (var reader = new StreamReader(src))
{
while (!reader.EndOfStream)
{
var line = reader.ReadLine();
if(line == null)
continue;
line = regExVersion.Replace(line, string.Format("\"version\": \"{0}\",", config.SemVer));
trg.AppendLine(line);
}
}
}
System.IO.File.WriteAllText(path, trg.ToString());
}
});
Then if you have e.g. a UnitTest project that takes a dependency on the project, use "*" for dependency resolution.
Also, do the bump before doing dotnet restore. My order is as follows:
Task("Default")
.IsDependentOn("InitOutDir")
.IsDependentOn("Bump")
.IsDependentOn("Restore")
.IsDependentOn("Build")
.IsDependentOn("UnitTest");
Task("CI")
.IsDependentOn("Default")
.IsDependentOn("Pack");
Link to full build script: https://github.com/danielwertheim/Ensure.That/blob/3a278f05d940d9994f0fde9266c6f2c41900a884/build.cake
The actual values, e.g. the version is coming from importing a separate build.config file, in the build script:
#load "./buildconfig.cake"
var config = BuildConfig.Create(Context, BuildSystem);
The config file looks like this (taken from https://github.com/danielwertheim/Ensure.That/blob/3a278f05d940d9994f0fde9266c6f2c41900a884/buildconfig.cake):
public class BuildConfig
{
private const string Version = "5.0.0";
public readonly string SrcDir = "./src/";
public readonly string OutDir = "./build/";
public string Target { get; private set; }
public string Branch { get; private set; }
public string SemVer { get; private set; }
public string BuildProfile { get; private set; }
public bool IsTeamCityBuild { get; private set; }
public static BuildConfig Create(
ICakeContext context,
BuildSystem buildSystem)
{
if (context == null)
throw new ArgumentNullException("context");
var target = context.Argument("target", "Default");
var branch = context.Argument("branch", string.Empty);
var branchIsRelease = branch.ToLower() == "release";
var buildRevision = context.Argument("buildrevision", "0");
return new BuildConfig
{
Target = target,
Branch = branch,
SemVer = Version + (branchIsRelease ? string.Empty : "-b" + buildRevision),
BuildProfile = context.Argument("configuration", "Release"),
IsTeamCityBuild = buildSystem.TeamCity.IsRunningOnTeamCity
};
}
}
If you still want to have the Solution Level SharedVersionInfo.cs you can do it by adding these lines to your project.json file:
"buildOptions": {
"compile": {
"includeFiles": [
"../../SharedVersionInfo.cs"
]
}
}
Your relative path may vary, of course.
use external version.txt file with version, and prebuild step to publish this version in projects

How do I launch a certain project using SWTBot

Not every plugin can be tested without project. For example, I want to test CDT-Plug-in, therefore I need to import a C-project. But there is no such point in Run Configuration and when I'm trying to record importing actions via SWT Plug-in Test recorder SWTBot can't replay them afterwards. Google is silent on this topic. How do I do that?
A nice way to do this is using the eclipse recource model
Have a look at the package
org.eclipse.core.resources
Here is a method, that creates a new project in the workspace
private IProject getNewOpenProject(IWorkspace wks, String name)
throws CoreException {
System.out.print("Creating project " + name + "...");
IProjectDescription prj1ProjectDescription = wks
.newProjectDescription(name);
IProject prj = wks.getRoot().getProject(name);
prj.create(prj1ProjectDescription, null);
prj.open(null);
System.out.println(" [OK]");
return prj;
}
This method will import your content into the eclipse project
private void importDirIntoProject(File srcPath, IProject prj,
IOverwriteQuery overwriteQuery) throws InvocationTargetException,
InterruptedException {
ImportOperation op = new ImportOperation(prj.getFullPath(), srcPath,
FileSystemStructureProvider.INSTANCE, overwriteQuery);
op.setCreateContainerStructure(false);
op.run(new NullProgressMonitor());
}
This approach uses native eclipse mechanisms. I think this is better than using the inconvenient way over SWTBot.
It's the responsibility of your test to create the necessary resources in its setup method, and clean them after. It's not something to configure in the Run Configuration, but to code in your test.
You can either use SWTBot to import/create a C project, or use the project APIs suggested by beanie.

How to unit or integration test use of injected messageSource for i18n in Grails 2.0 service

I make use of a message bundle in one of my services in a Grails 2.0 project for internationalized text. The use case is an email subject that is sent via the mail plugin in an asynchronous way, so it really doesn't make sense to have this in a controller or TagLib (given the usual argument of not accessing your text or views in a service). This code works fine in my running Grails app, but I'm not sure how to test it.
I tried a PluginAwareResourceBundleMessageSource in my defineBeans as that is what my running application injects, but it led to nullpointers as it appears it needs a bunch of setup around plugin managers and such that my test environment is not giving (even integration).
I then tried a ReloadableResourceBundleMessageSource as it was pure Spring, but it can't seem to see my .properties files, and fails with a No message found under code 'my.email.subject' for locale 'en'.
I feel like I'm going down a wormhole a bit as accessing Grails i18n in a service is not documented in the grails docs, so if there is a preferred way to do this, let me know.
Note my .properties file is in the standard grails-app/i18n location.
The test
#TestFor(EmailHelperService)
class EmailHelperServiceTests {
void testSubjectsDefaultLocale() {
defineBeans {
//messageSource(PluginAwareResourceBundleMessageSource); Leads to nullpointers
messageSource(ReloadableResourceBundleMessageSource);
}
String expected = "My Expected subject Passed1 Passed2";
String actual = service.getEmailSubjectForStandardMustGiveGiftFromBusiness(Locale.ENGLISH, Passed1 Passed2);
assertEquals("email subject", expected, actual);
}
Service:
class EmailHelperService {
def messageSource;
public String getEmailSubject(Locale locale, String param1, String param2) {
Object[] params = [param1, param2].toArray();
return messageSource.getMessage("my.email.subject", params, locale );
}
There is already a messageSource in unit tests in Grails, it is a StaticMessageSource (see http://static.springsource.org/spring/docs/2.5.4/api/org/springframework/context/support/StaticMessageSource.html), you can add mock messages with the addMessage method:
messageSource.addMessage("foo.bar", request.locale, "My Message")
In unit tests and the local side of functional tests, sometimes you want the real properties that are in the 18n directory.
This works for me:
MessageSource getI18n() {
// assuming the test cwd is the project dir (where application.properties is)
URL url = new File('grails-app/i18n').toURI().toURL()
def messageSource = new ResourceBundleMessageSource()
messageSource.bundleClassLoader = new URLClassLoader(url)
messageSource.basename = 'messages'
messageSource
}
i18n.getMessage(key, params, locale)
In a unit test you could ensure that you're wired up correctly by doing something like this:
void testSubjectsDefaultLocale() {
def messageSource = new Object()
messageSource.metaClass.getMessage = {subject, params, locale ->
assert "my.email.subject" == subject
assert ["Passed1", "Passed2"] == params
assert Locale.ENGLISH == locale
"It Worked!!!"
}
service.messageSource = messageSource
String actual = service.getEmailSubjectForStandardMustGiveGiftFromBusiness(Locale.ENGLISH, Passed1 Passed2)
assert "It Worked!!!" == actual
}
This will help ensure that you're wired up correctly but it will not ensure that what you're doing actually works. If you're comfortable with that then this would work for you. If you're trying to test that when you give "XYZ" to your .properties file it returns "Hello" then this will not work for you.

Eclipse: Within a plug-in, how to access another plug-ins preference store?

I have an Eclipse plug-in with a checkbox in the plug-in's preference page.
This checkbox is used for enabling and disabling an editor, which is being launched from this plug-in.
However, the problem is, I would also like to be able to enable and disable this 'editor-launch' from another plug-in, by having actions which change the value of the checkbox in the above mentioned preference page.
Here's the problem, how do I access that local preference store from another plug-in?
I've tried things like..
View myView = (View) PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().findView("ViewID");
But this 'myView' always seems to be null.. And also, what would I do with the view since it's the Plug-in I want.
Platform.getBundle('bundleName')...
Same here, want the Plugin, not the bundle corresponding to is.
No matter what I try nothing seems to work.
Does anyone have any ideas?
There are two ways of doing this:
Please refer to http://www.vogella.com/tutorials/EclipsePreferences/article.html#preferences_pluginaccess
Using .getPluginPreferences(). For example, there is a plugin class "com.xxx.TestPlugin" which extends org.eclipse.ui.plugin.AbstractUIPlugin.Plugin, in order to get access to the preferences of TestPlugin. The plugin code could be below:
public class TestPlugin extends AbstractUIPlugin {
private static TestPlugin plugin;
public static final String PREF_TEST = "test_preference";
/**
* The constructor.
*/
public TestPlugin() {
plugin = this;
}
/**
* This method is called upon plug-in activation
*/
public void start(BundleContext context) throws Exception {
super.start(context);
}
/**
* This method is called when the plug-in is stopped
*/
public void stop(BundleContext context) throws Exception {
super.stop(context);
plugin = null;
}
/**
* Returns the shared instance.
*/
public static TestPlugin getDefault() {
return plugin;
}
}
To access the preference of TestPlugin, the code could be:
TestPlugin.getDefault().getPluginPreferences().getDefaultBoolean(TestPlugin.PREF_TEST);
Or have a look at this answer: Writing Eclipse plugin to modify Editor Preferences
This thread recommend the use of a Service tracker:
ServiceTracker tracker = new ServiceTracker(ToolkitPlugin.getDefault().getBundle().getBundleContext(),
IProxyService.class.getName(), null);
tracker.open();
proxyService = (IProxyService) tracker.getService();
proxyService.addProxyChangeListener(this);
This may work.
Prefs stores are found per plugin. This is one way to get a prefs store for the plugin whose activator class is ActivatorA.
IPreferenceStore store = ActivatorA.getDefault().getPreferenceStore();
If you want another plugin to refer to the same store, perhaps you could expose some api on ActivatorA for it to get there, e.g.
public IPreferenceStore getSharedPrefs() {
return ActivatorA.getDefault().getPreferenceStore();
}
The second plugin would find the shared store by doing this
IPreferenceStore sharedPrefs = ActivatorA.getSharedPrefs();
Good luck.