Import constraints
Bryan Atsatt
bryan.atsatt at oracle.com
Mon Jun 4 11:38:18 PDT 2007
Currently the spec provides a somewhat odd mix of functionality here...
1. Module name. We have declaration syntax (superpackage name) and
runtime support for using a module name as a constraint
(ImportDependency class and Query.name()).
2. Versions. We have declaration syntax (VersionConstraint annotation)
and runtime support for using a collection of version/version-ranges as
a constraint (VersionConstraint/ImportDependency classes, and
Query.version()).
3. Attributes. We have declaration syntax for *assigning* attributes to
a definition (ModuleAttributes annotation), but no declaration syntax
for using them as constraints (a custom ImportPolicy is required). We
have runtime support for using them as constraints (Query.attribute()).
4. Extensible constraints. We have no declaration syntax, but we *do*
have runtime support for expressing any type of constraint and combining
them with boolean operators (Query).
I'd like to emphasize that Query should be seen *as the runtime
representation of a constraint*, and that:
Any import declaration must be expressible as a Query.
This includes the module name (and potentially a package name, TBD).
This last is an important point: other than optimizing searches, a
module name is not special! It's just another Query element (ditto for a
package name Query), evaluated along with any others in a compound Query
(i.e. Query elements combined with boolean operators). A definition can
even be looked up *without* a module name, using nothing but attribute
matching.
When I initially designed Query (and Repository.find()), I wanted
something very flexible and extensible, with the expectation that it
could be used to represent the entire constraint model. But I don't
think we're using it as effectively as we can...
Ok, so?
Well, first, I think we ought to generalize the runtime dependency type
to fully leverage Query. So change ImportDependency to:
public class ImportDependency extends Query {
private Query constraint;
private boolean optional;
private boolean reExport;
public ImportDependency (Query constraint,
boolean optional,
boolean reExport) {
this.constraint = constraint;
this.optional = optional;
this.reExport = reExport;
}
public boolean match(ModuleDefinition target) {
return constraint.match(target);
}
public boolean isOptional() {
return optional;
}
public boolean isReExported() {
return reExport;
}
public String toString() {
...
}
}
This way, we rely on the flexibility of Query to express *all*
constraints, and have a single concrete type to represent dependencies.
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?
And, more importantly, ModuleDefinition.getImportDependency()
implementations are free to return any kind of constraints they want,
simply by varying the Query.
Module name, if present, is just a Query element. Again, I think the
only place this (and/or package name) is explicitly needed is to enable
search *optimization*: if we want to avoid linear searches in
Repository.findModuleDefinition(Query) implementations, there needs to
be a way to narrow the search efficiently. But it's just an
optimization, and a topic for a different thread.
Second, I think we should eliminate VersionConstraint as a separate
class. It's functionality is easy to replace with Query elements that
match Version or VersionRange, strung together with appropriate boolean
operators.
Third, we should add a getExportedPackages() method to ModuleDefinition.
This way a Query can easily be created to search by package name.
Whether or not we choose to surface import-by-package declaratively, it
should at least be possible for a ModuleSystem to use such a Query.
Fourth, we should add support for simple attribute constraint
declarations. Enabling simple equality constraints ought to be easy
enough: an AttributeConstraint annotation that takes key/value lists
(key1==value1;key2==value2;...). We already have support for expressing
these as Query instances.
This simple type of attribute constraint is supported by OSGi. I don't
have a good sense of how common its usage is (Glyn/Richard?), but some
will likely view the absence of this support in 277 as an
interoperability issue.
More complex attribute comparisons could still be left up to custom
import policies. Or...
<dreaming-out-loud>
We could instead create a generic *query* declaration syntax, with
support for expressing module-name, package-name, version,
version-range, attribute matching, as well as boolean operators and
precedence.
This would eliminate the need for VersionConstraint/AttributeConstraint
annotations. The current VersionConstraint syntax using ";" separators
would no longer be required, as the boolean operators could be used instead.
And the expressiveness might reduce or eliminate the need for many
custom import policies.
</dreaming-out-loud>
Finally, Query ought to have a toString() implementation so that we can
log them, examine in a debugger, put them in error messages, etc.
Regardless of the approach, it would certainly be nice to provide some
symmetry between our declarative syntax and our runtime capabilities.
Thoughts?
// Bryan
More information about the jsr277-eg-observer
mailing list