On Fri, Apr 13, 2018 at 2:24 PM, Mark Raynsford <list+org.o...@io7m.com>

> On 2018-04-13T12:11:41 +0100
> Neil Bartlett <njbartl...@gmail.com> wrote:
> >
> > To be clear, I'm not convinced OSGi would ever want to do this. If we
> did,
> > we would likely invert the default from "closed" to "open". Closing off a
> > bundle to ALL access, even reflectively, seems like an extreme measure
> that
> > would only be necessary in fairly unusual circumstances, so I believe
> that
> > JPMS has the default the wrong way around. It's useful to compare with
> Java
> > classes, which can be made final but are not final by default.
> I'm not sure if we're talking about the same thing. It also seems a
> little strange to hear that: For me one of the main attractions about
> OSGi is that I get to state what's visible to the outside world and
> what isn't. This gives me the freedom to change things without breaking
> consumers. For the sake of the discussion, we could assume that bundles
> in the new magic OSGi container are all open for reflective access (but
> that the non-exported parts are still inaccessible, as with JPMS
> modules).

It's definitely possible that we're talking about different things, but let
me explain myself a little more.

In OSGi today, private packages are not ordinarily visible to other
bundles. That means I cannot just write plain code that depends on a
private type and have OSGi load that type for me. However I can load
classes, including classes that exist in private packages, from any bundle
using Bundle.loadClass(). Actually if Java security is enabled then we can
restrict the permissions around that, which gets very close to the
isolation that JPMS offers, but apparently nobody ever uses Java security
so here we are...

This is the equivalent of an "open module" in JPMS parlance, and I argue
that it is the better default. It makes bundles accessible to frameworks
such as dependency injectors, marshallers, ORM mappers, etc. I still have
the freedom to change my internals though: by not exporting a package I
have given a clear indication to other developers that the package is
private. If they go ahead and use reflection to work around the visibility
protections, then they cannot call foul when I change my internals and
break them. Therefore I believe that the strong isolation offered by
"closed" modules in JPMS is only needed for security-critical code.

> Mainly what I'm referring to is that I'd want the VM to believe that
> any assumptions that it can make about a JPMS module, for optimization
> purposes, it could also make those same assumptions about a bundle in
> our container. The same goes for assumptions that javac can make (but
> this is less interesting because it's easy to make something that's
> both an OSGi bundle and a JPMS module at compile time).

Yes I agree that's an additional benefit, but I'm not clear on what those
optimizations might be.

> There was a recent thread on the amber-experts list, for example, that
> talked about modifying the exhaustiveness check for switches over enum
> values based on whether the enum type is the same module as the switch
> or not. I got the feeling that this idea was rejected, but the
> point is that there's this looming possibility that language features
> will depend on module boundaries sooner or later, and so we should
> probably want to allow OSGi bundles to be treated as equals to JPMS
> modules, and for the VM and JIT to see them as the same thing.

That's an interesting use case, but surely it would only be useful where an
enum is private to a module? If it's exported then you cannot check switch
statements in modules that haven't been written yet. And if it's private to
the module/bundle then we can check all switch statements using existing

Java language features already do depend on the concept of accessibility:
e.g. the compiler can optimize access to a private field because it knows
all the places where the field is used, and potentially remove a redundant
volatile modifier or synchronization block. JPMS creates a new level of
accessibility applied to public types. I believe that any techniques the
compiler applies based on module membership could also be used when the
compiler can call my proposed checkAccess method... SO LONG AS the same
checkAccess is used at both compile and runtime. Admittedly this
complicates matters, and might require putting information into the module
metadata about the compile time checks that were used.

However I think that compile-time optimizations that depend on module
boundaries are a long way in the future, if they ever come. As long as the
module system is optional, you will be able to take a module and put it on
the classpath, invalidating all the assumptions the compiler made about

> > >
> > > Let's assume that, for the perspective of someone using this magic new
> > > OSGi container, the goal is to have it behave pretty much like an OSGi
> > > container already behaves (modulo the R7 java.* changes): An OSGi
> > > bundle can only depend on OSGi bundles,
> >
> > Note quite true. OSGi bundles depend on capabilities...
> Yes, agreed. I phrased it poorly. My point was more that you depend on
> something that is almost certainly provided by a bundle (perhaps via
> the system bundle exporting packages from a JPMS module). For the sake
> of limiting the scope a bit, I introduced the notion that "bundles
> depend on bundles" so that people wouldn't think I was talking about
> bundles being able to depend on arbitrary JPMS modules outside of the
> container without anything special being done by the container to make
> this work.


> > > What additions to the JPMS APIs would be needed to make this a reality
> > > today?
> > >
> >
> > I think the starting point is as simple as a callback interface along
> these
> > lines:
> >
> >      void checkAccess(Class from, Class to) throws
> IllegalAccessException;
> >
> > The JVM would call this each time it needs to check whether "from" is
> > allowed to access "to". It would be able to cache the answer because when
> > an OSGi bundle is updated we get a new ClassLoader and a new Class
> > identity. The JVM would also have some built-in checks before invoking
> this
> > method, to allow it to lock out the application layer from JVM internals.
> >
> > The above should work at runtime for both OSGi and JPMS. To implement
> > compile-time checks you need something else to stand in for the
> identities
> > or locations of the two input types.
> Would you intend this to be a fundamental primitive such that the JPMS
> would be reimplemented in terms of this callback? How and where would
> one implement this callback? If I have multiple OSGi containers in the
> same JVM, along with modules in a separate JPMS system... How many
> implementations of it are there, and which one "wins" (if any)?

I think that JPMS *could* be implemented on top of this as a fundamental
primitive, but it's very unlikely to happen.

These are obviously details that require careful consideration. My initial
thoughts are that the callback could be implemented as a service that is
configured once in the JVM, probably via a command line switch. In order to
support things like multiple OSGi frameworks, you could have a composite
implementation that delegates to child or sibling frameworks.

At this point I'm happy to wave my hands and say "a solution exists"
without spending too much time working out that solution. Given the
improbability of this going anywhere, any such effort feels like it would
be wasted.


> --
> Mark Raynsford | http://www.io7m.com
OSGi Developer Mail List

Reply via email to