OT/Equinox supports the notion of forced exports by which roles can be bound to base classes from another bundle even if these base classes are not exported from their bundle. This specific form of decapsulation consists of two parts:
- A request to force-export a particular package is specified in the aspect bundle's Aspect Binding
- This request is granted either by an entry in the config.ini or by Aspect Binding Negotiation.
The only legal access to a force-exported class is via a playedBy binding (OTJLD §2.1).
This page describes how Eclipse's
config.ini is used for granting forced exports for a given Eclipse installation.
(camel cased words are non-terminals, | denotes a choice, everything else on the RHS is literal)
ForcedExportDecls ::= otequinox.forced.exports=ForcedExports ForcedExports ::= ForcedExport | ForcedExport,ForcedExports ForcedExport ::= BaseBundleID[PackageExports] PackageExports ::= PackageExport | PackageExport,PackageExports PackageExport ::= PackageName;x-friends:=AspectBundleIDs AspectBundleIDs ::= AspectBundleID | "QuotedAspectBundleIDs" QuotedAspectBundleIDs ::= AspectBundleID | AspectBundleID,QuotedAspectBundleIDs
The declaration is used to tell the framework that a given package within a given base bundle (e.g.,
some.base.pack1 within bundle
some.base.bundle) should be exported to one or more specific aspects (e.g.,
some.aspect1), although the base bundle does not declare to export the given package.
The PackageExports part actually utilizes the syntax from a
Export-Package: directive within a bundle's
MANIFEST.MF, but note, that the
x-friends part is actually mandatory here.
In order for this declaration to be effective, also the aspect's
plugin.xml must contain an Aspect Binding with a matching
forcedExports element (only a package/list of packages, without the base bundle ID nor the
x-friends part). With matching declarations in both locations in place, the given aspect bundle may indeed access classes from the otherwise inaccessible base package. Such usage is in fact restricted to base imports (OTJLD §2.1.2.d) and any uses that are allowed for base imported classes.
The complex example above shows that declarations can soon become lengthy, yet the declaration must be given on a single line within
config.ini. Since version 1.2.6 it is possible to extract the forced exports declaration into a separate file and just leave a reference to this file within
config.ini (see ticket #198). As mentioned, other levels for granting forced exports exist by way of Aspect Binding Negotiation.
Compilation vs. Runtime:
The above explains how forced exports are enabled in the OT/Equinox runtime. As of ticket #18 the compiler also interprets the declarations from
plugin.xml and checks them against usage within the code.
Whether or not the compiler should report forced exports can be configured by the "decapsulation" warning token, or by the option "Decapsulation (overriding access restrictions)" when using the compiler preferences dialog -- choose one of error/warning/ignore. The compiler will never tolerate access to a non-exported base class for which no forced export is declared.