org.ungoverned.moduleloader.search
Class ImportSearchPolicy

java.lang.Object
  extended by org.ungoverned.moduleloader.search.ImportSearchPolicy
All Implemented Interfaces:
java.util.EventListener, ModuleListener, SearchPolicy
Direct Known Subclasses:
OSGiImportSearchPolicy

public class ImportSearchPolicy
extends java.lang.Object
implements SearchPolicy, ModuleListener

This class implements a ModuleLoader search policy to support modules that import and export classes and resources from/to one another. Modules import from other modules by specifying a set of import identifiers and associated version numbers. Modules export their classes and resources by specifying a set of export identifiers and associated versions. Exports for a given module are also treated as imports for that module, meaning that it is possible for a module that exports classes to not use the classes it exports, but to actually use classes that are exported from another module. This search policy requires the following meta-data attributes be attached to each module:

The value of the ImportSearchPolicy.EXPORTS_ATTR attribute is an array of Object arrays, i.e., Object[][]. Each element in the array signifies a particular export that is offered by this associated module. Each element is an array triple of Object, where the index into this triple is:

The value of the ImportSearchPolicy.IMPORTS_ATTR attribute is essentially the same as the ImportSearchPolicy.EXPORTS_ATTR defined above; the only difference is that the array of versioned identifiers denote import targets rather than exports.

The value of the ImportSearchPolicy.PROPAGATES_ATTR attribute is an array of Objects, i.e., Object[]. Each element in the array is an identifier of a propagated import target from the ImportSearchPolicy.IMPORTS_ATTR attribute. Only identifiers for import targets are candidates for inclusion and the version number is unnecessary since it is assumed from the corresponding import target.

The value of the ImportSearchPolicy.VALID_ATTR attribute is a Boolean. The value is initially set to Boolean.FALSE and indicates that the module has not yet been validated. After the module is validated, the value is set to Boolean.TRUE. The search policy automatically adds this attribute to all modules and maintains its value.

These meta-data attributes help the search policy enforce consistency using a process called validation; validation ensures that classes and resources are only loaded from a module whose imports are satisfied. Therefore, a valid module is a module whose imports are satisfied and an invalid module is a module whose imports are not yet satisfied. An invalid module may be invalid for two reasons:

  1. Its imports are not available or
  2. It has not yet been validated.

These two possibilities arise due to the fact that module validation is not performed until it is necessary (i.e., lazy evaluation). A module is automatically validated when an attempt is made to get classes or resources from it, although it is possible to manually validate a module. For a given module, called M, the validation process attempts to find an exporting module for every import target of M. If an exporter is not found for a specific import target, then the validation of module M fails. If an exporting module is found, then this module is also validated, if it is not already. As a result, the validation of module M depends on the validation of the transitive closure of all modules on which M depends. It is also possible for modules to exhibit dependency cycles; circular dependencies are allowed. Initially, a module's VALID_ATTR is set to Boolean.FALSE, but after the module is successfully validated, this attribute is set to Boolean.TRUE.

Besides ensuring that every import target is resolved to an appropriate exporting module, the validation process also attempts to maintain consistency along "propagation" chains. Propagation occurs when a module imports classes that are also visible from its own exports; for example, an HTTP server implementation may import classes from javax.servlet and export classes that have methods that use the type javax.servlet.Servlet in their signatures. Monitoring these types of occurences is important to uncover import source and version conflicts when multiple sources or versions of an import target are available within one virtual machine. When a module M is validated, the propagation information of each module that resolves the imports of M is checked to ensure that they do not propagate conflicting sources of M's imports; specifically, it is verified that all propagators of a particular import target have the same source module for that import target.

To facilitate applicability in as many scenarios as possible, this search policy delegates some decisions via additional policy interfaces. The following two policy interfaces must be specified by the code that instantiates the ImportSearchPolicy object:

Once an instance is created with definitions of the above policy interfaces, this search policy will operate largely self-contained. There are a few utility methods for manually validating modules, adding validation listeners, and access meta-data attributes, but for the most part these are not necessary except for implementing more sophisticated infrastructure.

The follow snippet of code illustrates a typical usage scenario for this search policy:

     ...
     ImportSearchPolicy searchPolicy =
         new ImportSearchPolicy(
             new MyCompatibilityPolicy(), new MySelectionPolicy());
     ModuleManager mgr = new ModuleManager(searchPolicy);
     ...
     Object[][] exports = new Object[][] {
         { "org.apache.jasper", "2.1.0", null }
     };
     Object[][] imports = new Object[][] {
         { "javax.servlet", "2.3.1", null }
     };
     Object[][] attributes = new Object[][] {
         new Object[] { ImportSearchPolicy.EXPORTS_ATTR, exports },
         new Object[] { ImportSearchPolicy.IMPORTS_ATTR, imports },
         new Object[] { ImportSearchPolicy.PROPAGATES_ATTR, new Object[] { "javax.servlet" } }
      };
     ResourceSource[] resSources = new ResourceSource[] {
         new JarResourceSource(file1)
         new JarResourceSource(file2)
     };
     Module module = mgr.addModule(id, attributes, resSources, null);
     ClassLoader loader = module.getClassLoader();
     // Assuming that all imports are satisfied...
     Class clazz = loader.loadClass("org.foo.MyClass");
     ...
 

The above code snippet illustrates creating a module with one export and one import, where the import is also propagated via the module's export. The module has multiple resource sources, but no library sources.

See Also:
SearchPolicy, Module, ModuleClassLoader, ModuleManager

Field Summary
static java.lang.String EXPORTS_ATTR
          This is the name of the "exports" meta-data attribute that should be attached to each module.
static int IDENTIFIER_IDX
          This is the index used to retrieve the import or export identifier from a given element of the EXPORTS_ATTR or the IMPORTS_ATTR attribute.
static java.lang.String IMPORTS_ATTR
          This is the name of the "imports" meta-data attribute that should be attached to each module.
static java.lang.String PROPAGATES_ATTR
          This is the name of the "propagates" meta-data attribute that should be attached to each module.
static int RESOLVING_MODULE_IDX
          This is the index used to retrieve the resolving module for an import or export target from a given element of the EXPORTS_ATTR or the IMPORTS_ATTR attribute.
static java.lang.String VALID_ATTR
          This is the name of the "valid" meta-data attribute that is automatically attached to each module.
static int VERSION_IDX
          This is the index used to retrieve the import or export version number from a given element of the EXPORTS_ATTR or the IMPORTS_ATTR attribute.
 
Constructor Summary
ImportSearchPolicy(CompatibilityPolicy compatPolicy, SelectionPolicy selectPolicy)
          Constructs an import search policy instance with the supplied compatibility and selection policies.
 
Method Summary
 void addValidationListener(ValidationListener l)
          Adds a validation listener to this import search policy.
static java.util.List createImporterList(ModuleManager mgr, Module module)
          Utility method to create a list of modules that import from the specified module.
static boolean doesImport(Module module, java.lang.Object identifier)
          Utility method to determine if the specified module imports a given import identifier, regardless of version.
 java.lang.Class findClass(Module module, java.lang.String name)
          This method is part of the SearchPolicy interface; it should not be called directly.
 java.net.URL findResource(Module module, java.lang.String name)
          This method is part of the SearchPolicy interface; it should not be called directly.
protected  void fireModuleInvalidated(Module module)
          Fires an invalidation event for the specified module.
protected  void fireModuleValidated(Module module)
          Fires a validation event for the specified module.
 CompatibilityPolicy getCompatibilityPolicy()
          Returns the compatibility policy used by this import search policy instance.
protected  Module[] getCompatibleModules(java.lang.Object identifier, java.lang.Object version)
          This method returns a list of modules that have an export that is compatible with the given import identifier and version.
static Module getExportResolvingModule(Module module, java.lang.Object identifier)
          Utility method to get the resolving module of a specific export identifier for the specified module.
static java.lang.Object[][] getExportsAttribute(Module module)
          Utility method that returns the EXPORTS_ATTR attribute for the specified module.
static java.lang.Object getExportVersion(Module module, java.lang.Object identifier)
          Utility method to get the export version number associated with a specific export identifier of the specified module.
static Module getImportResolvingModule(Module module, java.lang.Object identifier)
          Utility method to get the resolving module of a specific import identifier for the specified module.
static java.lang.Object[][] getImportsAttribute(Module module)
          Utility method that returns the IMPORTS_ATTR attribute for the specified module.
static java.lang.Object[][] getImportsOrExports(Module module, java.lang.String name)
          Utility method that returns the IMPORTS_ATTR or the EXPORTS_ATTR attribute for the specified module.
static java.lang.Object getImportVersion(Module module, java.lang.Object identifier)
          Utility method to get the import version number associated with a specific import identifier of the specified module.
static java.lang.Object[] getPropagatesAttribute(Module module)
          Utility method that returns the PROPAGATES_ATTR attribute for the specified module.
 SelectionPolicy getSelectionPolicy()
          Returns the selection policy used by this import search policy instance.
static java.lang.Boolean getValidAttribute(Module module)
          Utility method that returns the VALID_ATTR attribute for the specified module.
 void invalidate(Module module, java.lang.Object[][] attributes, ResourceSource[] resSources, LibrarySource[] libSources)
          Invalidates a module by flushing its class loader and re-initializing its meta-data values.
 void moduleAdded(ModuleEvent event)
          Callback method for ModuleListener; this should not be called directly.
 void moduleRemoved(ModuleEvent event)
          Callback method for ModuleListener; this should not be called directly.
 void moduleReset(ModuleEvent event)
          Callback method for ModuleListener; this should not be called directly.
 void removeValidationListener(ValidationListener l)
          Removes a validation listener to this import search policy.
 Module resolveImportTarget(java.lang.Object identifier, java.lang.Object version)
          This utility method returns the module that exports the specified import identifier and version.
 void setModuleManager(ModuleManager mgr)
           This method is called once by the ModuleManager to give the search policy instance a reference to its associated module manager.
 void validate(Module module)
          This method validates the specified target module.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

EXPORTS_ATTR

public static final java.lang.String EXPORTS_ATTR
This is the name of the "exports" meta-data attribute that should be attached to each module. The value of this attribute is of type Object[][] and is described in the overview documentation for this class.

See Also:
Constant Field Values

IMPORTS_ATTR

public static final java.lang.String IMPORTS_ATTR
This is the name of the "imports" meta-data attribute that should be attached to each module. The value of this attribute is of type Object[][] and is described in the overview documentation for this class.

See Also:
Constant Field Values

PROPAGATES_ATTR

public static final java.lang.String PROPAGATES_ATTR
This is the name of the "propagates" meta-data attribute that should be attached to each module. The value of this attribute is of type Object[] and is described in the overview documentation for this class.

See Also:
Constant Field Values

VALID_ATTR

public static final java.lang.String VALID_ATTR
This is the name of the "valid" meta-data attribute that is automatically attached to each module. The value of this attribute is of type Boolean and is described in the overview documentation for this class.

See Also:
Constant Field Values

IDENTIFIER_IDX

public static final int IDENTIFIER_IDX
This is the index used to retrieve the import or export identifier from a given element of the EXPORTS_ATTR or the IMPORTS_ATTR attribute.

See Also:
Constant Field Values

VERSION_IDX

public static final int VERSION_IDX
This is the index used to retrieve the import or export version number from a given element of the EXPORTS_ATTR or the IMPORTS_ATTR attribute.

See Also:
Constant Field Values

RESOLVING_MODULE_IDX

public static final int RESOLVING_MODULE_IDX
This is the index used to retrieve the resolving module for an import or export target from a given element of the EXPORTS_ATTR or the IMPORTS_ATTR attribute.

See Also:
Constant Field Values
Constructor Detail

ImportSearchPolicy

public ImportSearchPolicy(CompatibilityPolicy compatPolicy,
                          SelectionPolicy selectPolicy)
Constructs an import search policy instance with the supplied compatibility and selection policies.

Parameters:
compatPolicy - the compatibility policy implementation to be used by the search policy.
selectPolicy - the selection policy implementation to be used by the search policy.
Method Detail

getCompatibilityPolicy

public CompatibilityPolicy getCompatibilityPolicy()
Returns the compatibility policy used by this import search policy instance.

Returns:
the compatibility policy of this import search policy instance.

getSelectionPolicy

public SelectionPolicy getSelectionPolicy()
Returns the selection policy used by this import search policy instance.

Returns:
the selection policy of this import search policy instance.

setModuleManager

public void setModuleManager(ModuleManager mgr)
                      throws java.lang.IllegalStateException
Description copied from interface: SearchPolicy

This method is called once by the ModuleManager to give the search policy instance a reference to its associated module manager. This method should be implemented such that it cannot be called twice; calling this method a second time should produce an illegal state exception.

Specified by:
setModuleManager in interface SearchPolicy
Parameters:
mgr - the module manager associated with this search policy.
Throws:
java.lang.IllegalStateException - if the method is called more than once.

findClass

public java.lang.Class findClass(Module module,
                                 java.lang.String name)
                          throws java.lang.ClassNotFoundException
This method is part of the SearchPolicy interface; it should not be called directly. This method finds a class based on the import/export meta-data attached to the module. It first attempts to validate the target module, if it cannot be validated, then a ClassNotFoundException is thrown. Once the module is validated, the module's imports are searched for the target class, then the module's exports are searched. If the class is found in either place, then it is returned; otherwise, null is returned.

Specified by:
findClass in interface SearchPolicy
Parameters:
module - the target module that is loading the class.
name - the name of the class being loaded.
Returns:
the class if found, null otherwise.
Throws:
java.lang.ClassNotFoundException - if the target module could not be validated.

findResource

public java.net.URL findResource(Module module,
                                 java.lang.String name)
                          throws ResourceNotFoundException
This method is part of the SearchPolicy interface; it should not be called directly. This method finds a resource based on the import/export meta-data attached to the module. It first attempts to validate the target module, if it cannot be validated, then it returns null. Once the module is validated, the module's imports are searched for the target resource, then the module's exports are searched. If the resource is found in either place, then a URL to is is returned; otherwise, null is returned.

Specified by:
findResource in interface SearchPolicy
Parameters:
module - the target module that is loading the resource.
name - the name of the resource being loaded.
Returns:
a URL to the resource if found, null otherwise.
Throws:
ResourceNotFoundException - if the resource could not be found and the entire search operation should fail.

validate

public void validate(Module module)
              throws ValidationException
This method validates the specified target module. If the module is already validated, then this method returns immediately. This method synchronizes on the associated module manager to ensure that modules are not added or removed while the validation is occuring. Each import and export for the target module are resolved by first using the compatibility policy to create a list of candidate export modules, then using the selection policy to choose among the candidates. Each selected candidate is also recursively validated; this process validates a transitive closure of all dependent modules. After the selected candidate is validated, its propagated imports are checked to make sure that they do not conflict with any existing propagated imports. If no validation errors occur, then all dependent modules are marked as validated, if they are not already validated. If an error occurs, the valid state of all modules remains unchanged.

Parameters:
module - the module to validate.
Throws:
ValidationException - if the module or any dependent modules could not be validated.

getCompatibleModules

protected Module[] getCompatibleModules(java.lang.Object identifier,
                                        java.lang.Object version)
This method returns a list of modules that have an export that is compatible with the given import identifier and version.

Parameters:
identifier - the import identifier.
version - the version of the import identifier.
Returns:
an array of modules that have compatible exports or null if none are found.

invalidate

public void invalidate(Module module,
                       java.lang.Object[][] attributes,
                       ResourceSource[] resSources,
                       LibrarySource[] libSources)
Invalidates a module by flushing its class loader and re-initializing its meta-data values.

Parameters:
module - the module to be invalidated.
attributes - the attributes associated with the module, since they might have changed.
resSources - the resource sources associated wih the module, since they might have changed.
libSources - the library sources associated wih the module, since they might have changed.

addValidationListener

public void addValidationListener(ValidationListener l)
Adds a validation listener to this import search policy. Validation listeners are notified when a module is validated and/or invalidated by the search policy.

Parameters:
l - the validation listener to add.

removeValidationListener

public void removeValidationListener(ValidationListener l)
Removes a validation listener to this import search policy.

Parameters:
l - the validation listener to remove.

fireModuleValidated

protected void fireModuleValidated(Module module)
Fires a validation event for the specified module.

Parameters:
module - the module that was validated.

fireModuleInvalidated

protected void fireModuleInvalidated(Module module)
Fires an invalidation event for the specified module.

Parameters:
module - the module that was invalidated.

moduleAdded

public void moduleAdded(ModuleEvent event)
Callback method for ModuleListener; this should not be called directly. This callback is used to initialize module meta-data attributes; it adds the VALID_ATTR attribute and initializes the resolving module entries in EXPORTS_ATTR and IMPORTS_ATTR to null.

Specified by:
moduleAdded in interface ModuleListener
Parameters:
event - the event object containing the event details.

moduleReset

public void moduleReset(ModuleEvent event)
Callback method for ModuleListener; this should not be called directly. This callback is used to re-initialize module meta-data attributes; it adds the VALID_ATTR attribute and initializes the resolving module entries in EXPORTS_ATTR and IMPORTS_ATTR to null. It then invalidates all modules that import from the reset module.

Specified by:
moduleReset in interface ModuleListener
Parameters:
event - the event object containing the event details.

moduleRemoved

public void moduleRemoved(ModuleEvent event)
Callback method for ModuleListener; this should not be called directly. Used to listen for module removal events in order to invalidate all the modules that import form the removed moduled.

Specified by:
moduleRemoved in interface ModuleListener
Parameters:
event - the event object containing the event details.

resolveImportTarget

public Module resolveImportTarget(java.lang.Object identifier,
                                  java.lang.Object version)
This utility method returns the module that exports the specified import identifier and version. This method uses the validate() method to find the exporting module and, as a result, relies on the compatibility and selection policies associated with this ImportSearchPolicy instance. If successful, the returned module is guaranteed to be validated. This method only needs to be used for more advanced purposes (i.e., check import availability dynamically, etc.) and need not be used under normal circumstances.

Parameters:
identifier - the identifier of the import to resolve.
version - the version of the import to resolve.
Returns:
the exporting module selected to resolve the specified import target.

getValidAttribute

public static java.lang.Boolean getValidAttribute(Module module)
Utility method that returns the VALID_ATTR attribute for the specified module.

Parameters:
module - the module whose VALID_ATTR attribute is to be retrieved.
Returns:
an instance of Boolean.

getImportsAttribute

public static java.lang.Object[][] getImportsAttribute(Module module)
Utility method that returns the IMPORTS_ATTR attribute for the specified module.

Parameters:
module - the module whose IMPORTS_ATTR attribute is to be retrieved.
Returns:
an Object[][] value or null.

getExportsAttribute

public static java.lang.Object[][] getExportsAttribute(Module module)
Utility method that returns the EXPORTS_ATTR attribute for the specified module.

Parameters:
module - the module whose EXPORTS_ATTR attribute is to be retrieved.
Returns:
an Object[][] value or null.

getImportsOrExports

public static java.lang.Object[][] getImportsOrExports(Module module,
                                                       java.lang.String name)
Utility method that returns the IMPORTS_ATTR or the EXPORTS_ATTR attribute for the specified module.

Parameters:
module - the module whose IMPORTS_ATTR or EXPORTS_ATTR attribute is to be retrieved.
name - either IMPORTS_ATTR or EXPORTS_ATTR depending on which attribute should be retrieved.
Returns:
an Object[][] value or null.

getPropagatesAttribute

public static java.lang.Object[] getPropagatesAttribute(Module module)
Utility method that returns the PROPAGATES_ATTR attribute for the specified module.

Parameters:
module - the module whose PROPAGATES_ATTR attribute is to be retrieved.
Returns:
an Object[] value or null.

doesImport

public static boolean doesImport(Module module,
                                 java.lang.Object identifier)
Utility method to determine if the specified module imports a given import identifier, regardless of version. This method checks both imports and exports, since a module is assumed to import what it exports.

Parameters:
module - the module to check.
identifier - the import identifier to check.
Returns:
true if the module imports the specified import identifier or false if it does not.

createImporterList

public static java.util.List createImporterList(ModuleManager mgr,
                                                Module module)
Utility method to create a list of modules that import from the specified module.

Parameters:
mgr - the module manager that contains the module.
module - the module for which to create an importer list.
Returns:
a list of modules that import from the specified module or null.

getImportVersion

public static java.lang.Object getImportVersion(Module module,
                                                java.lang.Object identifier)
Utility method to get the import version number associated with a specific import identifier of the specified module.

Parameters:
module - the module to investigate.
identifier - the import identifier for which the version should be retrieved.
Returns:
the version number object or null.

getExportVersion

public static java.lang.Object getExportVersion(Module module,
                                                java.lang.Object identifier)
Utility method to get the export version number associated with a specific export identifier of the specified module.

Parameters:
module - the module to investigate.
identifier - the export identifier for which the version should be retrieved.
Returns:
the version number object or null.

getImportResolvingModule

public static Module getImportResolvingModule(Module module,
                                              java.lang.Object identifier)
Utility method to get the resolving module of a specific import identifier for the specified module.

Parameters:
module - the module to investigate.
identifier - the import identifier for which the resolving module should be retrieved.
Returns:
the resolving module or null.

getExportResolvingModule

public static Module getExportResolvingModule(Module module,
                                              java.lang.Object identifier)
Utility method to get the resolving module of a specific export identifier for the specified module.

Parameters:
module - the module to investigate.
identifier - the export identifier for which the resolving module should be retrieved.
Returns:
the resolving module or null.