Eclipse plugin dev: make bundle to explode inside `plugins` folder - eclipse

There is old Eclipse Image Viewer plugin https://github.com/persal/quickimage
that I want to update.
After adding maven/tycho build and building against Kepler.
It works in new Eclipse instance (project -> run as Eclipse application),
but when installing here is an issue #6
org.eclipse.swt.SWTException: i/o error (java.io.FileNotFoundException: file:\D:\Progs\Eclipses\eclipse-standard-luna-R-win32-x86_64\eclipse\plugins\nu.psnet.quickimage.plugin_1.1.0.201503030326.jar!\icons\previous.gif (The filename, directory name, or volume label syntax is incorrect.))
文件名、目录名或卷标语法不正确
Looking at the code there is line
iconsdir = FileLocator.resolve(QuickImagePlugin.getDefault().getBundle().getEntry("/")).getFile() + "icons" + File.separator;
that gets path like that.
The problem is that should work if the bungle jar becomes folder like nu.psnet.quickimage_1.0.3.2
UPDATE: As IDE using Luna 4.4.0

If you can change the source of the plugin you can change
iconsdir = FileLocator.resolve(QuickImagePlugin.getDefault().getBundle().getEntry("/")).getFile() + "icons" + File.separator;
to something like:
URL dir = FileLocator.find(QuickImagePlugin.getDefault().getBundle(),
new Path("icons"), null);
dir = FileLocator.toFileURL(dir);
String iconsdir = dir.getPath() + File.separator;
This should work even when the plugin is packaged in a jar.

This is controlled by a flag in feature.xml where the plugin is included.
<plugin id="..." unpack="true"/>

Related

Launch External Tools from Eclipse Plug-in View

I'm building a simple Eclipse plug-in out of preexisting Java application project that relays on 2 external files, one x-executable/application and one .sh script.
The call is implemented in application like this, (which wouldn't work in plug-in):
Process p = new ProcessBuilder("external/application_name", "-d", path).start();
I used External Tool Configuration to define how I want this external files to be launch (when user clicks button on View) and I've exported configuration (example of one):
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramLaunchConfigurationType">
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/softwareevolution/external/application_name}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="-d ${project_loc}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${project_loc}"/>
</launchConfiguration>
How can I have this application install along with Eclipse plug in,
or a as a part of it? (see #howlger answer billow) - I set plugin to install as directory /
Connected plugin to Feature project- checked unpack after
installation - and exported Feature project. Select application's
folder on Build/Binary build.
Can I then make use out of this exported .launch files, and if so
under which extension point should I include them in plugin.xml? -
No. (see #greg-449)
The application is supposed to produce 2 files on the path where it
is executed from. I am facing permission denied when trying to
launch it in terminal from plug-in's install directory but not when
launching in workspace. (see #howlger answer billow) - Upon exporting the plugin, initial
permissions of application had changed. Used instructions in p2.inf
to chmod them back.
The newly generated files (from runing .sh script) are missing write permission.
ProcessBuilder
After finally setting up plugin correctly and adding ProcessBuilder I was getting exception message : Cannot run program "rfind_20" (in
directory
"home/adminuser/.p2/pool/plugins/rFindTest3_1.0.0.201809030453/external"
error=2:, No such file or directory
File rfind_20 did exist and permission were 777. The targeted project also existed.
Although the working directory was set to applications folder, the application name was not enough, the absolute path was required as
command argument.
pb = new ProcessBuilder(url.getPath(), "-d", project.getProject().getLocation().toString());
#Override
public Object execute(ExecutionEvent event) throws ExecutionException {
IProject project= sampleGetSelectedProject();
ProcessBuilder pb;
Process rfind, ajust, copy;
Bundle bundle = FrameworkUtil.getBundle(getClass());//Bundle bundle = Platform.getBundle("rFindTest3");
URL url = FileLocator.find(bundle, new Path("external/rfind_20"), null);
URL dirurl = FileLocator.find(bundle, new Path("external/"), null);
IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindowChecked(event);
try {
MessageDialog.openInformation(
window.getShell(),
"Test",
project.getProject().getLocation().toString());
url = FileLocator.toFileURL(url);
dirurl = FileLocator.toFileURL(dirurl);
pb = new ProcessBuilder(url.getPath(), "-d", project.getProject().getLocation().toString());
//no matter the working directory the absolute path was required!! sending "rfind_20" as command did not work as command
pb.directory(new File(dirurl.getFile()));
rfind = pb.start();
rfind.waitFor();
rfind.destroy();
}catch(Exception e) {
MessageDialog.openInformation(
window.getShell(),
"Test",
e.getMessage());
}
return null;
}
The only remaining mystery is why my sampleGetProject() method wouldn't work in Plug-in Perspective. So just keep in mind to switch to other Perspectives when testing your plug-in.
There are two ways to ship an application as part of a plugin and run it via ProcessBuilder (the *.launch file cannot be used inside a plugin for that):
Extract the executable files from the plugin JAR to a (temp) directory and change their file permissions before running them
Install the plugin as a directory:
In META-INF/MANIFEST.MF add the line Eclipse-BundleShape: dir (see "The Eclipse-BundleShape Header" in Eclipse help - Platform Plug-in Developer Guide - OSGi Bundle Manifest Headers)
Create a Feature Project and connect your plug-in in Included Plug-in, check "Unpack the plug-in archive after the installation"
Create a META-INF/p2.inf file that contains the following (see Eclipse help - Platform Plug-in Developer Guide: "Touchpoint Instruction Advice" in Customizing p2 metadata and "chmod" in Provisioning Actions and Touchpoints):
instructions.install = \
chmod(targetDir:${artifact.location},targetFile:path/to/executable1,permissions:755);\
chmod(targetDir:${artifact.location},targetFile:path/to-executale_which_generates_files/executable2,permissions:733);\
chmod(targetDir:${artifact.location},targetFile:path/to-executale_which_generates_files/,permissions:766);
instructions.install.import = org.eclipse.equinox.p2.touchpoint.eclipse.chmod
If you have a xxx.launch file in the workspace you can launch it using
IFile file = ... get IFile for workspace file
ILaunchConfiguration config = DebugPlugin.getDefault().getLaunchManager().getLaunchConfiguration(file);
DebugUITools.launch(config, ILaunchManager.RUN_MODE, false);
If you have an executable as part of a plug-in then you can't use a .launch file. Instead use FileLocator to get the location of the executable and run it with ProcessBuilder
Bundle bundle = FrameworkUtil.getBundle(getClass());
URL url = FileLocator.find(bundle, new Path("relative path to executable"));
url = FileLocator.toFileURL(url);

Eclipse Projectdependency on multiple src directories

today I have a special problem which already took me a while at the debugger.
I have two projects Project A and Project B.
Project A has multiple src-directories.
src
├───main
│ └───java
└───generated
└───java
both are recognized by eclipse as actual src directories. Both will be compiled to bin which looks like this:
bin
├───main
└───generated
Project B has a Project-dependencie on Project A.
And now comes the strange part: When I look for a class from Project A/src/main/java via Class.forName() inside Project B it will be found. When i look for a class from Project A/src/generated/java I get a ClassNotFound exception.
I would be very glad if you could point out a way to tell eclipse to create a dependencie on both src-directories.
btw, just in case it is important: I am using java 9.
and here is an excerpt of .classpath from Project B
<classpathentry kind="src" path="/Project A"/>
Thanks for your help.
This looks like a bug of Eclipse, Gradle or a combination of both. Try to delete the run configuration and restart the application. Make also sure the gradle.build file is in sync with the Eclipse project. If all this doesn't help, you can use a single output folder as workaround:
Manually in Project > Properties: Java Build Path, in the tab Source:
Uncheck the checkbox Allow output folders for source folders
In the field Default output folder enter bin/main
or via following gradle.build snippet:
apply plugin: 'eclipse'
eclipse.classpath.file.whenMerged {
entries.find { it.path == 'src/main/java' }.output = 'bin/main'
entries.find { it.path == 'src/generated/java' }.output = 'bin/main'
}

Use Eclipse Runtime Configuration to start jar file

I need to start a Java program using an Eclipse Runtime Configuration (ILaunchConfiguration). However, I want to provide the program to run as a .jar file (as part of the plugin), not as an Eclipse project.
It seems in order to start a Java program from an Eclipse Runtime Configuration I need to specify a project (and main class).
How can I use the Configuration framework to start an arbitrary .jar file?
This article helps:
http://eclipse.org/articles/Article-Java-launch/launching-java.html
I use the following code to run a .jar file which is inside my plugin's lib directory:
IPath path = new Path("lib" + File.separator + "some.jar");
Bundle bundle = Platform.getBundle(IDs.PLUGIN_ID);
URL url = FileLocator.find(bundle, path, null);
URI uri = FileLocator.resolve(url).toURI();
File file = URIUtil.toFile(uri);
IPath resolvedPath = new Path(file.toString());
IRuntimeClasspathEntry jar = JavaRuntime.newArchiveRuntimeClasspathEntry(resolvedPath);
IPath systemLibsPath = new Path(JavaRuntime.JRE_CONTAINER);
IRuntimeClasspathEntry systemLibsEntry =
JavaRuntime.newRuntimeContainerClasspathEntry(systemLibsPath, IRuntimeClasspathEntry.STANDARD_CLASSES);
List<String> classpath = new LinkedList<>();
classpath.add(aproveJar.getMemento());
classpath.add(systemLibsEntry.getMemento());
configuration.setAttribute(IJavaLaunchConfigurationConstants.ATTR_CLASSPATH, classpath);
configuration.setAttribute(IJavaLaunchConfigurationConstants.ATTR_DEFAULT_CLASSPATH, false);

Missing required library classes_managed

Im using play 2.0 and trying to modularize the project into a subproject.
In $project_home, created folder structure ${project_home}/data/app/models/MyModel.java
The Build.scala looks
val dataDependencies = Seq(
)
val dataProject = PlayProject(appName + "-data", appVersion, dataDependencies, path = file("data"), mainLang = JAVA)
val main = PlayProject(appName, appVersion, appDependencies, mainLang = JAVA).settings(
// Add your own project settings here
).dependsOn(dataProject).aggregate(dataProject)
I run a play eclpsify command.
In eclipse, I've imported two projects, the main project and the data project.
The data project shows the following error
Project '-data' is missing required library: '/path/to/myprojects/data/target/scala-2.9.1/classes_managed'
What am I doing wrong here? Any help would be appreciated
This is what worked for me (on Windows).
Edit .classpath, there should be an entry similar to this:
<classpathentry path="D:\your_play_project_folder\target\scala-2.10\classes_managed" kind="lib"></classpathentry>
Remove the path portion before "target" to get this:
<classpathentry path="target\scala-2.10\classes_managed" kind="lib"></classpathentry>
Refresh Eclipse.
I encountered the similar problem when building a project with play 2.0.2
I created manually the target/scala-2.9.1/classes_managed folder and I run clean all projects in eclipse
I hope it helps
I think you have 3 possibilities:
create data/target/scala-2.9.1/classes_managed manually.
Remove the path from class-path (if not necessary)
Switch to 2.1-snapshot
For me helped:
manually removed target/scala-2.9.1/classes_managed from the .classpath file
added target/scala-2.9.1/classes_managed via eclipse: project/properties/Java Build Path --> tab Libraries --> Add Class Folder...
Try "play clean" and then "play eclipse", to re-generate the eclipse project files from a command prompt in the project's base folder.
try this:
1) sbt> clean/compile in parent, followed by child project
2) add target/src-managed/main as source folder in eclipse, both projects
3) in child
java build path > projects > (add parent)
project references > (add parent)
What does dataProject do, btw? My base project provides a DAO layer and other nuts & bolts that have nothing to do with Play; therefore, I just define it as a root sbt project, and pull it in to child project via dependsOn(root)
Anyway, hope this gets the issue sorted...

Programmatically adding a library to an Eclipse project

How can I create a new build path entry for any *.jar file and add this classpath entry to the build path of an Eclipse project.
I have a plugin that should automatically setup my target project. So this project needs to have some library imports and I want to add this imports automatically using a wizard. The user just selects the location of a certain SDK and then some libraries have to be linked with the target project.
However, I found some references:
Importing libraries in Eclipse programmatically
How to add a folder to java build path as library, having multiple jars or entries in it?
Unfortunately, I failed to implement the second solution as I cannot find the classes IClasspathContainer, JavaCore and IJavaProject.
I'm using Eclipse Helios and JDK. Do I need any additional libraries to make changes to the build path or is there a simpler solution to import a jar library programmatically?
Regards,
Florian
I'm assuming that you are creating a plugin and need your plugin to manage the extra jars added to the classpath.
As you mention, you need to create a custom classpath container. First, create the classpath container extension by exending this extension point:
org.eclipse.jdt.core.classpathContainerInitializer
Then, you create a class that implements org.eclipse.jdt.core.IClasspathContainer and associate it with the extension point you just created.
You mention that you cannot find the org.eclipse.jdt.core.IClasspathContainer interface. You need to make sure that your plugin references the org.eclipse.jdt.core plugin in its MANIFEST.MF.
Here you can find some examples, how to define new classpath entries and classpath containers to java projects. I think it would handy for someone reading this question.
In order to get access to IJavaProject etc, goto your plugin.xml and add org.eclipse.jdt.core to the classpath. Thereafter you can import those packages into your project.
String projectName = "MyProject"; // project to add a library to
IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
IJavaProject jProject = JavaCore.create(project);
for(File file : new File("path-to-some-directory-of-libraries-to-add").listFiles()){
if(file.isFile() && file.getName().endsWith(".jar")){
addProjectLibrary(jProject, file);
}
}
private static void addProjectLibrary(IJavaProject jProject, File jarLibrary) throws IOException, URISyntaxException, MalformedURLException, CoreException {
// copy the jar file into the project
InputStream jarLibraryInputStream = new BufferedInputStream(new FileInputStream(jarLibrary));
IFile libFile = jProject.getProject().getFile(jarLibrary.getName());
libFile.create(jarLibraryInputStream, false, null);
// create a classpath entry for the library
IClasspathEntry relativeLibraryEntry = new org.eclipse.jdt.internal.core.ClasspathEntry(
IPackageFragmentRoot.K_BINARY,
IClasspathEntry.CPE_LIBRARY, libFile.getLocation(),
ClasspathEntry.INCLUDE_ALL, // inclusion patterns
ClasspathEntry.EXCLUDE_NONE, // exclusion patterns
null, null, null, // specific output folder
false, // exported
ClasspathEntry.NO_ACCESS_RULES, false, // no access rules to combine
ClasspathEntry.NO_EXTRA_ATTRIBUTES);
// add the new classpath entry to the project's existing entries
IClasspathEntry[] oldEntries = jProject.getRawClasspath();
IClasspathEntry[] newEntries = new IClasspathEntry[oldEntries.length + 1];
System.arraycopy(oldEntries, 0, newEntries, 0, oldEntries.length);
newEntries[oldEntries.length] = relativeLibraryEntry;
jProject.setRawClasspath(newEntries, null);
}
Note that as Andrew Eisenberg mentioned, you need to include the org.eclipse.jdt.core plugin dependency in your plugin's MANIFEST.MF.
Note that you may also need to programmatically refresh the project too.