Modify

Opened 7 years ago

Closed 7 years ago

Last modified 7 years ago

#7703 closed defect (fixed)

How to get resources from inside plugin?

Reported by: kendzi Owned by: bastiK
Priority: critical Milestone:
Component: Core Version:
Keywords: Cc:

Description (last modified by kendzi)

In plugin loading class I try to get resource file from my plugin jar (kendzi3d.jar) using call:

getClass().getResource(“/resources/pluginProperties.properties”);

but in response I get:

jar:file:/C:/Documents%20and%20Settings/kendzi/Dane%20aplikacji/JOSM/plugins/ImportImagePlugin.jar!/resources/pluginProperties.properties

So url is pointing to file inside different plugin! ImportImagePlugin plugin have file with same name.

call to getClass()
result:
class kendzi.josm.kendzi3d.Kendzi3DPlugin (inside kendzi3d.jar)

It seems that it is bug with plugin class loader.

Or there is any other way to get files from my plugin jar?

Attachments (0)

Change History (7)

comment:1 Changed 7 years ago by kendzi

Description: modified (diff)

comment:2 Changed 7 years ago by bastiK

Owner: changed from team to bastiK
Status: newassigned

comment:3 Changed 7 years ago by bastiK

Currently we have a single class loader for all plugins. I can change it such that each plugin has its own class loader that only sees the plugin jar, the main josm jar and the jar files of the required plugins.

However, there seem to be some side effects of having multiple class loaders:

  • instances of the same class that are instantiated by different class loaders are type-incompatible, i.e. you cannot cast one to the other
  • static initialization code may be executed multiple times
  • there are multiple instances of static fields, one for each class loader

These problems only apply to plugin dependencies, e.g. opendata requires jts.

Given these issues, I suggest, we keep the current broken behaviour.

comment:4 in reply to:  description Changed 7 years ago by bastiK

Replying to kendzi:

Or there is any other way to get files from my plugin jar?

As a workaround, we could provide a plugin class loader, that is only used to get resources, but not classes.

comment:5 Changed 7 years ago by bastiK

Resolution: fixed
Status: assignedclosed

In 5241/josm:

fixed #7703 - How to get resources from inside plugin?

comment:6 in reply to:  5 ; Changed 7 years ago by kendzi

Replying to bastiK:

In 5241/josm:

fixed #7703 - How to get resources from inside plugin?

I well test solution but as I understand it solve this one problem but the rest remains.

And problems are:

  • what if two plugins use the same class in the same package?
  • what if two plugins try loads externals jar file with different and not compatible version?
  • how to load external jar from plugin? (eg jog4j) I’m using reflection on class loader [1], but it should be some “official” way to do it.
  • as I saw some plugins extract class from externals jar into plugins jar, this may cause problems if two plugins are using the same jars
  • it should be possible to share some code between plugins, but really should plugins see each other? Maybe plugins should declared some public api to internals?
  • it should be possible to share resources between plugins eg icons. But it would be nice if in first place they were take from orginal jar.
  • provided solution won’t work with external libraries which usually using call to getResource()

Did I say that I hate class loaders?

Maybe some solution to problems can be solve by using OSGi for plugins?

[1] https://github.com/kendzi/kendzi3d/blob/master/kendzi.josm.plugin3d/src/kendzi/josm/kendzi3d/NativeLibPlugin.java#L206

comment:7 in reply to:  6 Changed 7 years ago by bastiK

Replying to kendzi:

Replying to bastiK:

In 5241/josm:

fixed #7703 - How to get resources from inside plugin?

I well test solution but as I understand it solve this one problem but the rest remains.

And problems are:

  • what if two plugins use the same class in the same package?

Java conventions dictate, that you use a unique package name for each project.

  • what if two plugins try loads externals jar file with different and not compatible version?

Right, that wouldn't work, but let's wait until this actually happens. There are still workarounds given the current setup.

  • how to load external jar from plugin? (eg jog4j) I’m using reflection on class loader [1], but it should be some “official” way to do it.

I think a good solution would be to list the required libs in the Manifest, e.g.

Class-Path: resource://lib/mylib.jar resource://lib/otherlib.jar

The "resource:" prefix would indicate that the file needs to be copied from the plugin jar to the plugin folder before loading the plugin. (Or write a custom class loader, that gets the class files from the inner jars on the fly. this site has interesting info on class loaders, especially in the comments.)

It gets more complicated, when there is some code that gets to decide which libraries to load (e.g. depending on operating system and architecture).

In case you haven't seen it already: the ImportImagePlugin also loads external libs, but uses a different hack, if I remember correctly.

  • as I saw some plugins extract class from externals jar into plugins jar, this may cause problems if two plugins are using the same jars
  • it should be possible to share some code between plugins, but really should plugins see each other? Maybe plugins should declared some public api to internals?

Ideally, each plugin would see the classes of the dependent plugins and JOSM core. However, the obvious solution doesn't work as written above. What do you suggest?

  • it should be possible to share resources between plugins eg icons. But it would be nice if in first place they were take from orginal jar.

I can provide a similar fix for icon loading. It would look something like this: new ImageProvider(name).setClassLoader(plugin.getResourceClassLoader()).get();

  • provided solution won’t work with external libraries which usually using call to getResource()

True, unless you use a designated class loader.

Did I say that I hate class loaders?

I'm not too enthusiastic about it either. Also, the plugin code is serious foobar, so it feels like opening a can of worms. Anyway, I wouldn't mind if you provided some patches for core. :)

Maybe some solution to problems can be solve by using OSGi for plugins?

[1] https://github.com/kendzi/kendzi3d/blob/master/kendzi.josm.plugin3d/src/kendzi/josm/kendzi3d/NativeLibPlugin.java#L206

Here is a temporary "solution" that avoids hacking the JVM: Your plugin consists of a single bootstrap class and the real plugin is a jar file wrapped inside the plugin jar. Your single class would copy the real plugin jar and some libraries to the plugin folder and execute everything using a URLClassLoader. This would work similar to the plugin loading code in JOSM core.

Modify Ticket

Change Properties
Set your email in Preferences
Action
as closed The owner will remain bastiK.
as The resolution will be set.
The resolution will be deleted.

Add Comment


E-mail address and name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.