Re: Exported resources

2007-06-12 Thread Bryan Atsatt

Whoops, .jsp files are not candidates for private resources, since the
*container* must have access to them. But I stand by the gif/html/xml
comment :^).

Another candidate is property files (thanks to Stephen McConnell for
reminding me), when used as default configuration.

Bryan Atsatt wrote:

Stanley M. Ho wrote:

Hi Bryan,

Bryan Atsatt wrote:

Yes, I think we're getting close now :^)

(By privileged reflection, you mean having permission to call
AccessibleObject.setAccessible(true), right? If so, then we're back to
the grant issue!)


Yes. In this case, it's the ResourceBundle API calling it to retrieve
ListResourceBundle, so it'll have the sufficient permissions to do that.
Anyway, I think we should leave this issue aside for now.


I still think we can provide private, (i.e. non-exported) resources
which *are* available to the module classes, but to no class outside
of it.

Without using permissions.

Remember this?

  private static class StackAccessor extends SecurityManager {
  public Class[] getStack() {
  return getClassContext();
  }
  }

  private static final STACK_ACCESSOR = new StackAccessor();

If a resource is found, and is not-exported, a module class loader can
use this (or similar) to get the immediate caller's class (at a fixed
index).

If the caller class' Module does not match that for the loader, we don't
return the resource.


I think we should step back to rethink the use cases a bit.

Typically, a module calls some APIs (e.g. ResourceBundle, AWTToolkit,
etc.) and these APIs might then retrieve resources through the module's
ClassLoader.getResource*(). If we are saying that a module is required
to make these resources exported in order for these use cases to work,
then what are the actual use cases we want to support by hiding
resources from getResource*()?

I think there remains a common use case where hiding resources would be
a good thing if developers want to hide all the resources that are not
used by anyone through ClassLoader.getResource*() (e.g. all the .class
files). On the other hand, I think the use case where the code in the
module calls its own ClassLoader.getResource*() to retrieve private
resources directly is not very common; If this is a rare use case, I
don't think it makes sense to introduce this notion of private
resources. If we are forcing developers to export resources for the
common use cases (like ResourceBundle and ServiceLoader) anyway, then
why not require them to export resources in other cases as well?

It would help if there are some real use cases to support why it is
important to have this notion of private resources.


One very common use case comes from the EE world: web modules containing
html/gif/xml/jsp files, all of which are implementation details.

I would assume that most any app with a UI would have similar resources.



- Stanley





Re: Import specifications (was Re: Import constraints)

2007-06-12 Thread Bryan Atsatt

Bryan Atsatt wrote:

Stanley M. Ho wrote:

Hi Bryan,

Bryan Atsatt wrote:

...
By having Dependency extend Query, instances can be directly passed to
Repository.find(); no conversion required. We could obviously just make
a getter for the Query if we want, but why not make this convenient to
use?


An import dependency describes the relationship between two modules.


Agreed. And I think we would be far better off thinking of and modeling
this relationship as a general *requirement specification*, rather than
using the very narrow definition:

   name + version(s)

Clearly these are important elements of an import specification. But the
design should allow for and even support others.

One concrete example is attributes. What is the point of declaring them
on a module if they cannot be used in an import specification?


Sorry, I meant to change this before sending. I do know that you meant
for attributes to be used by higher level mechanisms (e.g.
ServiceLoader). And that is certainly a valid use case (though it isn't
entirely clear to me how this works other than by polling).

But enabling them as import specifiers seems like an even more natural
use case.


And I think these could be very valuable.

The term constraint makes sense when you think of name as the primary
specification, and everything else as modifiers of it.

But this puts all the emphasis on the wrong syLLable, IMO. What will we
do when a contract model is introduced, where attributes and
version(s) are all that is required to specify the desired contract?

Module name won't be required at all in such a specification.


So far, we have three distinct actors in the resolution process:

1. Developer: creates import specifications, using whatever selection
criteria makes sense.

2. Admin: creates import specification *filter* (ImportOverridePolicy),
mapping developer specification to fit the local environment. (Can also
use a VisibilityPolicy, but it isn't clear to me why that same
functionality can't be achieved in the override policy.)

3. Module System: locates definitions that match specifications.

All of these actors collaborate to produce a single list of candidate
definitions at runtime. If that list contains duplicate packages, the
module system must select the best fit, or fail.

Clearly the Query mechanism provides an extensible solution to the
problem in #3. And annotations give us an extensible solution to the
problem in #1.

But, just as clearly, we have a big gap in the middle: the filter model
is not a general, extensible mechanism. And I think we need to fix this.

It seems to me that the best solution is to use the *same* model to
filter as we use for lookup: Query.

(Please see the Query optimization thread for my proposal to change
Query from an opaque to a transparent type.)

So, rather than pass VersionConstraint instances through the narrow()
method, we can pass Query instances. Yes, this does make it a bit more
work to implement such a filter, but it is then a completely extensible,
symmetric model.

And this is also why I proposed that we change ImportDependency to
simply take a Query as a ctor argument:

  public ImportDependency (Query spec,
   boolean optional,
   boolean reExport) {...}

(I should have sent my optimization proposal before I suggested the
above change, so it would've made more sense. Really this would be so
much easier if you could just read my mind :^)


Further, I don't understand the need to limit the filter to only
narrowing operations. For example, why shouldn't an admin be able to
map a module *name* as well? This could be really handy (and might even
allow for elimination of the refactoring/name problem).

In fact, why not allow the admin to be able to filter *any* part of the
import specification? I would prefer to see a more generic model than
the current ImportOverridePolicy, for example:

public class ImportOverridePolicy {
   public ListImportDependency getImports(ModuleDefinition def) {
   return def.getImportDependencies();
   }

   public static ImportOverridePolicy getPolicy() {...}
   static void setPolicy(ImportOverridePolicy policy) {...}
}

The default implementation does nothing, but subtypes can perform any
transformation they want. The ModuleSystem just calls this method
instead of calling the definition directly.


It is true that we may want to query a module described in the import
dependency, but an import dependency itself is not a query. In fact,
someone may even want to query a module which contains the specific
import dependency, although I think this use case is very rare. Anyway,
it sounded like the main benefit to have import dependency extend query
is to make it easier to pass into Repository.find(). Unfortunately, once
a class is extended from another, all the public/protected
methods/fields from the parent class would automatically become part of
the signature of the child class.


No kidding? :^)


I don't