PhoenicisOrg / phoenicis

Phoenicis PlayOnLinux and PlayOnMac 5 repository
https://phoenicis.org/
GNU Lesser General Public License v3.0
686 stars 73 forks source link

Find better way to access script classes from Java #1236

Open plata opened 6 years ago

plata commented 6 years ago

Currently, the class name is computed in a pretty hacky way in WinePrefixContainerWineToolsTab#populate. It works as long as the ID is the snake case form of the class name. There must be a better solution for this.

Some possible solutions:

specified variable

JSON

no class

plata commented 6 years ago

I can't really follow your idea. Could you give a rough example how it could look like?

madoar commented 6 years ago

About my last suggestion:

We would create an Engine instance in JS, the same way we do now, e.g. via an include followed by new Wine(). The interesting point of my suggestion is, how the Java side handles a passed Wine instance object, i.e. the result of new Wine().

In a perfect world we would case the passed Wine object into an Engine interface and then access it, but because the Wine class/prototype doesn't directly implement the Engine interface we need another way to convert it into an Engine instance. This conversion is done via the EngineWrapper class.

After passing the resulting object from new Wine() to a Java method, the object will be of type ScriptObjectMirror, and can therefore be passed to the EngineWrapper constructor. Ideally the EngineWrapper constructor should also do a check, that ensures, that all required methods by the Engine interface are contained in the given ScriptObjectMirror object.

plata commented 6 years ago

There's two things I don't like about this:

  1. It's not clear that Wine shall "implement" the Engine interface.
  2. Different approach for engines than for installers/tools (requirement 5).
madoar commented 6 years ago

1) Yes, you're right about that, but I think this is a more common problem with Javascript/Nashorn.

If Nashorn would support the new ES6 class definitions and if its inheritance schema would work when inheriting from Java classes, we wouldn't face this problem. 2) You're right again, but I don't think we can use the same approach for the engines and for the installers/tools.

The reason for this is, that installers/tools don't require additional methods to the run method. In comparison, engines do need additional engine specific methods.

Again, in my eyes this is a problem located in the way inheritance and class definitions are done in Nashorn.

plata commented 6 years ago

It's true that the issues are caused by the way Nashorn does the inheritance. Nevertheless I believe that we could solve both problems I've described above by using composition over inheritance.

However, I would like to understand @qparis suggestion first. Maybe his idea solves the issues altogether.

plata commented 6 years ago

Another idea:

var engineImplementation = { ... }
var WineEngine = Java.extend(org.phoenicis.engines.EngineTool, toolImplementation);

Wine.prototype = Object.create(WineEngine);

Wine.prototype.foo = function () { ... }

If WineEngine is a Javascript object, this should work (I guess).

madoar commented 6 years ago

Are you sure the line:

Wine.prototype = Object.create(WineEngine);

works?

This is the first time, I've heard you can do this with Nashorn and a Java class (i.e. WineEngine).

plata commented 6 years ago

I'm not sure. Will have to try. I just thought that WineEngine should be a Javascript object but maybe it's not.

plata commented 6 years ago

Doesn't work. You get a type error ("is not an Object").

madoar commented 6 years ago

I'm not sure about what changes we've agreed on after all the new ideas we had.

Should I still change the applications and tools to an implementation looking like this:

include(["engines", "wine", "quick_script", "online_installer_script"]);

{
    run: function () {
        new OnlineInstallerScript()
            .name("7-zip")
            .editor("Igor Pavlov")
            .applicationHomepage("http://www.7-zip.org/")
            .author("ImperatorS79")
            .url("https://www.7-zip.org/a/7z1801.exe")
            .checksum("d56bca4973b1d1aa5915c41dce318b077ce8b5b2")
            .category("Accessories")
            .executable("7zFM.exe")
            .go();
    }
};
plata commented 6 years ago

Yes, I think you can do that in any case (don't forget to update the documentation like we've discussed above). Is it clear that the script exposes the anonymous object or should we write a return somewhere (if that works)?