enso-org / enso

Hybrid visual and textual functional programming.
https://enso.org
Apache License 2.0
7.31k stars 318 forks source link

Encapsulation of `polyglot/java` Dependencies #7082

Open radeusgd opened 1 year ago

radeusgd commented 1 year ago

With the imports/exports discussion we are talking about encapsulation of out private modules.

Many of our libraries rely on Java helpers that are imported using the polyglot java import statements. To achieve proper encapsulation of library internals, we should ensure that these internal helper libraries (std-base, std-table etc.) are private and not accessible from user projects.

High level idea

For most cases, we want to ensure that a JAR file that is in a polyglot directory of a given project can only be imported from within that project and not from other places.

Re-exporting

We still want some helpers to be visible in other modules. For example, some helpers from std-table (the Table library companion JAR), are also used in the Database library. To do so we can re-export such symbols by wrapping them in Enso wrappers. This will be enough for helper methods, but it may not be enough for types.

For the time being this should be enough for our usecases. Potentially, for longer-term, maybe we should devise a better control over where the JARs are importable from. Maybe we can include some information in the package.yaml file or have a sibling directory public-polyglot - where such JARs would be visible to the outside world?

Implementation

Currently, loading a JAR is achieved by TruffleLanguage::Env::addToHostClassPath. This does not have the control for imports we need. We would probably need a check at compiler level which verifies if a given polyglot java import clause is allowed based on the contents of the polyglot directory associated with the project from which the compiled Enso file comes from.

This may require some non-trivial logic to scan each JAR added to the classpath and for each path it adds to the classpath, we would need to associate it with the project it comes from. Then the compiler can verify for each polyglot java import if the current project has the 'permission' to access a given path.

Collisions

This still leaves the question of - what if two libraries contain JARs in their polyglot directories that have clashing classpaths? For example, two versions of the same Java library? Ideally, due to the encapsulation each library should be able to import each own version, but that would require some stricter separation of classpaths.

Until we have some 'clever' solution for this, we may want to forbid importing clashing libraries. Ideally we should detect if adding a new library to the classpath will shadow another one and disallow importing such a library.

Alternatives

The Java Module System seems to be solving a similar task. Maybe we can somehow plug into it and exploit it instead of inventing our own wheels? It partially depends on if that is possible to do in how Truffle/Graal handles the modules for the polyglot interface.

### Tasks
- [ ] Remove workaround from https://github.com/enso-org/enso/pull/9664/commits/60b38f491853a7ed02e64debfbb730a36ee9a029
JaroslavTulach commented 6 months ago

Isolation can be achieved by using different ClassLoader for each library. E.g. having different HostClassLoader for each library.