Each module contains a module.properties which sits in the resources folder, and is also available on the module's class path. In practice, this means placing module.properties in the module's resources folder. This file is important because it is used to describe the module's dependencies as well as other configuration for the module.
However, as we see later on this page, it is also possible to externalize part or all of a module's configuration, which is useful if the module configuration needs to be overridden at deployment time. The easiest way to set up a module is through the file module.properties.
An example of module.properties is shown below:
parent=petclinic
type=servlet
context-locations=petclinic-web-context.xml
This example is taken from the web module definition of the Impala Petclinic application.
parent: The name of the parent module. This property is required for all modules apart from the root module. Remember that each module typically is backed both by its own class loader, and it's own Spring application context. The relationship between the child and the parent typically applies both for the class loader and the application context. This means that classes defined in the parent module are visible to child modules, but not vice versa. Similarly, beans accessible through the parent's ApplictionContext
are accessible to beans in the child's ApplicationContext
, and not vice versa.
type: The type of the module. The type of the module governs both the mechanism for loading module definitions, and the mechanism for loading the module, that is the resources for the module as well as its ApplicationContext
.
The following types are available out of the box:
root:
Associated with the root module. This may be backed by the system class or application class loader, or by an Impala custom class loader, depending on the configuration. It will also be backed by a Spring GenericApplicationContext
.
application:
The module type used for most other non-web modules. Typically backed by an Impala custom class loader and a Spring GenericApplicationContext
.
servlet:
This is Impala's main form of web module. It is backed by a GenericWebApplicationContext
instance, and by an Impala custom class loader. Web modules can be arranged in a hierarchy. However, there can only be one 'root' web module. This module will also contain web application files, such as the WEB-INF/web.xml as well CSS styles, images, etc.
web_root:
Similar to the servlet module. There are two main differences. Firstly, servlet modules follow the convention of having Spring configuration files located as class path resources, while web_root modules are found as servlet context resources, that is, relative to the ServletContext
root directory. The first is consistent with Impala's typical usage, while the latter is closer to the convention of vanilla Spring applications, which use the servlet-name plus servlet suffix convention to locate Spring config files.
web_placeholder:
This is a special type of module which can be used in some configurations to 'turn off' the functionality that would otherwise be provided by a servlet module. The usage of this type of module is explained in WebConfiguration.
context-locations: A comma-separated list of Spring configuration files which make up the bean definitions for the module. Not required - if not specified the name %MODULE_NAME%-context.xml is assumed.
depends-on: A comma-separated list of modules on which the current module depends. By default, the parent will be included as the first item on this list. However, this can be overridden by explicitly including the parent module in the list. Note that depends-on only applies when the graph-based class loader is used. In this case, module classes will have visibility of public classes visible to dependencies. See Impala configuration for more information.
optional-depends-on: A comma-separated list of modules on which the current module will depend if they are present. In other words, if the optional dependency is present, it can be used as the source for classes, resources and beans used by the current module. However, if not, the application will still start without error.
If using this property, care should be taken to ensure that there are not any hard references to the optional dependency.
runtime: Specifies the runtime which backs the module type. By default, the runtime type is spring
.
capabilities: A simple mechanism to tag modules as implementing a particular set of capabilities. For example, if a module adds cacheing support, an entry such as the following may be present:
capabilities=cacheing
The capabilities for a particular module configuration can be retrieved using ModuleDefinition.getCapabilities()
. Also org.impalaframework.module.metadata.ModuleMetadataHelper
has a method getCapabilities()
which can retrieve the capabilities of a full set of modules.
attributes: Any property not included in the above listing is will be picked up from module.properties and is accessible using ModuleDefinition.getAttributes()
. This allows custom module types to pick up custom configuration in arbitrary ways.
The properties listed above are the most commonly used properties. It should be noted that more esoteric module types may use other properties. Any of these additional module properties which doesn't have specific meaning for the built in module loading mechanism is still available via the ModuleDefinition.getAttributes()
method.
The type of module configuration described in this section is also know as an internal module configuration, because all of the information required to describe the module's position in the module hierarchy is contained within the module. This is also the simplest and most easily reusable configuration.
With this self-describing style of module configuration, all that remains to set up the application as a whole is to list the names of the modules to be used.
An example is the module configuration for the web frameworks sample:
<parent>
<names>
#The root module
webframeworks
webframeworks-service
#Web modules
webframeworks-web
webframeworks-struts
webframeworks-wicket
webframeworks-tapestry5
</names>
</parent>
Note that from 1.0.3 the #This is a comment
syntax can be used for comments as shown in the example above.
The snippet above shows an example of the contents of the moduledefintions.xml file, which used for setting up the module hierarchy in a web application.
reloadable (from 1.0.3): By default a module is reloadable, provide a mechanism is provide through the runtime environment to support this (normally via auto-reloading or via JMX).
For some environments, its useful to be able to turn off reloading for specific modules. For example, for a large application, we probably don't want to support reloading of the entire module tree on a live server. However, it might be useful to support reloading specific modules.
To turn off reloading for a module, use the following entry in module.properties.
reloadable=false
Note that if a module is not-reloadable, then any ancestors or dependency modules are not reloadable. This rule, enforced implicitly and automatically, is in place because any module which reloads needs to be able to reload its descendents.
There is one configuration setting that needs to apply to turn on selective reloading of modules: the Impala configuration property enforce.reloadability
needs to be set to true. This occurs by default, but can be turned off.
Typical for development enviroments, selective reloadability of modules would not need to apply - it is a feature that would typically be more useful in a production environment. For this reason, a typical configuration might have enforce.reloadability
set to true only for production.
Note that if any module is not reloadable, then it auto-reloading for that module will automatically be disabled. Also, attempting to reload the module explicitly via JMX will result in an error being reported to the user.
While the internal configuration is generally pretty convenient, there are times when you don't wish to reuse the default internal module configuration in its entirety.
Suppose, for example, one of your modules consist of a set of JMX Spring beans which you may wish to use in some environments but not others. One approach to this problem would be to split these beans into a separate module. However, in some cases this may seem like overkill, and if followed through, could lead to an explosion in the number of modules.
In plain Spring applications, functionality is often turned on or off by the inclusion or otherwise of Spring application context files. This same approach can be applied within a module, by externally overriding the context-locations property.
In the example below, we are using the moduledefinitions.xml to add an additional context location to the example-web module. Of course, the extra-location.xml file needs to be present for this example to work.
<root>
<names>
example-hibernate
example-dao
example-service
example-web
example-servlet1
example-servlet2
example-servlet3
example-servlet4
</names>
<modules>
<module>
<name>example-web</name>
<context-locations>
<context-location>example-web.xml</context-location>
<context-location>extra-location.xml</context-location>
</context-locations>
</module>
</modules>
</root>
For each module type, any of the properties can be overridden this way. This is because each module type-specific definition reader can read module properties both from simple properties (as in a Java properties file), or from an XML definition document.
ModuleDefinitionSource
There are essentially two parts to applying an overall module configuration:
The question you may be asking is how does this all fit together, and when are the different mechanisms used?
The key to all of this is the interface ModuleDefinitionSource
. This interface defines a strategy for loading module definitions. The module definition hierarchy can be loaded by any implementation of ModuleDefinitionSource
. Remember, module definitions are metadata. When you load a module definition, you are not loading the module, just an abstract representation of what the module is supposed to contain.
There are a number of implementations of ModuleDefintionSource
. Which implementation is best to use depends on the circumstances.
The moduledefinitions.xml is used with XmlModuleDefinitionSource
as convenient for web applications, because it can be implemented through simply placing an XML file on the web application class loader's class path (for example, in WEB-INF\classes).
For integration tests, it's easier to implement ModuleDefinitionSource
in code the test directly. Here's an example:
public class EntryDAOTest implements ModuleDefinitionSource {
public static void main(String[] args) {
InteractiveTestRunner.run(EntryDAOTest.class);
}
protected void setUp() throws Exception {
//update the module hierarchy as required
Impala.init(this);
}
public void testDAO() {
EntryDAO dao = Impala.getBean("entryDAO", EntryDAO.class);
... do a bunch of tests on the DAO
}
public RootModuleDefinition getModuleDefinition() {
return new TestDefinitionSource(new String[]{"example-dao", "example-hibernate"}).getModuleDefinition();
}
}
The our example integration test is using an instance of TestDefinitionSource
, where the names of modules required for the test are passed in an array.
It's pretty straightforward to introduce new module types. Here you may need to override the typeReaders
bean in the Impala Spring configuration, as well as the moduleLoaders
property of the moduleLoaderRegistry
Impala Spring bean.
For more information on how to do this, see ImpalaConfiguration.
Wiki: Configuration
Wiki: GettingStartedPart4
Wiki: HowToDynamicallyAddModulesUsingJMX
Wiki: SamplesWebframework
Wiki: WebConfiguration
Wiki: WikiHome