Exporting things (Was: Re: Module-system requirements)
mark.reinhold at oracle.com
mark.reinhold at oracle.com
Mon Mar 9 21:00:17 UTC 2015
2015/2/20 6:33 -0800, david.lloyd at redhat.com:
> On 02/16/2015 07:15 AM, David M. Lloyd wrote:
>> ...
>>
>> What you are saying here implies (to me) inspecting the call stack to
>> ensure that the caller actually exists within the module being
>> referenced. I'm not certain we really want to go this far, if my
>> interpretation is accurate. Such a rule is reasonable on the face of
>> it, but it does more or less break all the code in existence which
>> currently uses resources as a sort of API into a library, and this
>> includes very common patterns for loading configuration (among many
>> other things).
>
> Going into a little more detail on this, I picture a number of scenarios:
>
> 1) A resource is fully internal to a module, and there's no reason that
> any external code ought to need or get access to this data. The module
> could restrict access to the resource by caller as inferred above.
>
> 2) A resource is an internal part of the module, but other things might
> need access to the resource for specific purposes (like direct .class
> access for instrumentation). The access restriction of this use case is
> "solved" by existing containers today by isolating class loaders, so the
> user has to have access to the target class loader in order to read the
> resource(s) in question. You could subdivide this into (2a) the .class
> files themselves and (2b) anything else that might fall under this
> category, as I believe the use cases for (2a) are fairly specific to
> run-time analysis and instrumentation tooling and similar uses.
>
> 3) A resource is a part of the module's self-configuration, but is not
> of interest to importers. This would include configuration files (like
> Java EE deployment descriptors, and other framework-XML-ish things).
> Access is typically presently solved similarly to #2 above, or by simply
> accessing the target resource archive directly, bypassing class loading.
>
> 4) A resource is a part of a public API intended to be imported and used
> by consumers. Examples include framework configurations like logging
> and some other framework-XML-ish things, ServiceLoader, etc. Today this
> is solved as an unavoidable consequence of flat classpaths, but also (in
> containers) by implicitly or explicitly exporting and importing some or
> all of a class loader's resource file/directory structure.
I think cases (2) and (3) are supported by the requirement I suggested in
my previous reply, which allows suitably-privileged code to read class
and resource files from a module's defining artifact.
As to (4), I wonder if it's really all that different from (3). If a
logging framework, e.g., is invoked by some module and then needs to read
that module's logging-configuration file then can't it just read it out
of the module's artifact? (I suspect it's reasonable to assume that a
logging framework will have the permissions required to do so.)
> While JBoss Modules does in fact solve cases 2-4 well enough, there is
> no provision for things falling under (1). This is not however due to
> any fundamental ideal; quite the opposite in fact. I simply could not
> work out a consistent (and simple) set of rules for treating classes and
> packages separately from resources and their directories that didn't
> simply break everything*.
>
> The questions are: Are there yet more use cases that I have failed to
> identify? Is it possible to come up with a consistent set of rules
> which allows all these primary use cases to continue to function cleanly
> going forward? Can we do so in a minimally-impacting manner that would
> allow most existing code to continue to function with (at most) only
> packaging changes? If not, which use cases can or should be sacrificed,
> and why?
If you can read class files and resources from a module's artifact then
existing components that publish information in that way can continue to
do so. Components that read such information will require some minor
changes, since the ClassLoader::getResource* methods might not work for a
module in the way that it does for the class path, or might work slowly,
but this change should be fairly simple, e.g., going from
object.getClass().getClassLoader().getResourceAsStream("foo")
to something like
object.getClass().getModule().getModuleArtifact().getStream("foo")
In return for mandating (or strongly suggesting) this minor change in
resource consumers we get resource encapsulation, and we can also avoid
having a complicated "exports resources" feature. That seems like a
worthwhile tradeoff.
> I could easily imagine adding a separate public resources concept which
> is wholly separate from the module internal content, where importers
> could import some or all of these resources into their own world, which
> would easily solve (4), but (2) and (3) are still left "high and dry".
> An "unexported resources" area of a module could address (3), leaving
> (2), which could be solved by co-locating those resources with the
> classes themselves. But by this point there is some additional
> complexity (maybe not *too* much, but definitely some).
Yes, this is getting rather hairy ...
> Module imports
> would specify the module they want to import (possibly to package
> granularity), as well as the resource directories they want to import
> (which could be re-exported just like module packages could). So from
> that perspective the additional complexity is manageable. But when it
> comes to build and packaging of a module itself, users would now have
> face possibly fairly complex decision regarding which category a
> resource belongs to (not to mention that packaging tooling would have to
> support this decision),
I agree that this seems like too much.
> whereas in today's world they just "throw it in
> there" and hope for the best.
Well, hopefully we can do better than that!
- Mark
More information about the jpms-spec-experts
mailing list