Contribution Modularity

Contribution Imports and Exports

Embedding artifacts and libraries in the META-INF/lib directory of a contribution is simple but lacks the flexibility required by many applications. For example, several applications may need to share the same WSDL document or library. Fabric3 supports three forms of sharing:

  • Java package sharing
  • XML resource sharing
  • Java contribution sharing

In all cases, a resource (or set of resources) are exported by one contribution and *imported*by another. Imports and exports are specified in the contribution manifest file.

Java Package Sharing

Java resources (i.e. classes) are shared by exporting and importing their packages. Java package sharing in Fabric3 is based on OSGi, so if you are familiar with that technology, you already understand Fabric3's approach and capabilities. Classes contained in Java packages are made available to other contributions using the <export.java> element in the contribution manifest:

<contribution xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912">
   <export.java package="com.foo.bar" version="1.0"/>
</contribution>

Exported packages may then be imported using the <import.java> element in the manifest of another contribution:

<contribution xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912">
   <import.java package="com.foo.bar" version="1.0"/>
</contribution>

The previous examples make classes in the com.foo.bar package available to the importing contribution.

Fabric3 and OSGi Classloading

Fabric3 loads contributions in separate classloaders using OSGi. This provides contribution isolation (Java classes and artifacts are not visibile to other contributions unless they are exported, thereby reducing the potential for conflicts) and allows versioning. Further, each contribution is associated a classloader space. When a package is imported, a "wire" is created between the importing and exporting contribution. This wire is used by the importing contribution's classloader to load classes belonging to the package using the exporting conribution's classloader. A classloader space therefore consists of the contribution classloader and the classloaders it is wired to via a set of import/export pairs.

Since package imports and exports can specify versions, it is possible to control contribution isolation is a very precise manner. For example, by specifying a version, is is possible for two contributions to use different versions of the same package. For example, versions 1.0 and 2.0 of package com.bar.foo can be provided by using the @version attribute of the <export.java> element:

<contribution xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912">
   <export.java uri="com.foo.bar"/>
</contribution>

An importing contribution can control which version it receives by specifying the @version attribute of the <import.java> element:

<contribution xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912">
   <export.java uri="com.foo.bar"/>
</contribution>

Often, it is useful to specify a version range instead of an exact version. This can be done using the @min, @minInclusive, @max, and @maxInclusive attributes of the <import.java> element:

<import.java package="org.foo.bar" min=1.0.0" minInclusive="false" max="2.0.0" maxInclusive="true"/>

By default, @minInclusive and @maxInclusive are true.
It is also possible to specify a '*' wildcard when exporting and importing packages. For example, the following will export packages com.foo.bar and com.foo.baz:

<export.java package="org.foo.*"/>

Imports can also be made optional by setting the @required attribute to false. In this case, if a matching export is not found, the contribution will still be loaded :

<import.java package="org.foo.bar" version="1.0.0" required="false"/>

XML Resource Sharing

XML resources are shared by exporting and importing their qualified name (qname). For example, assume a set of portTypes in a WSDL document need to be shared among several contributions. The contribution manifest file contining the WSDL document will export the document's qname using the <export> element:

<contribution xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912">
   <export name={"urn:somenamespace:1.0"/>
</contribution>

Contributions that require access to the portTypes defined in the urn:somenamespace:1.0 namespace may import it using the <import> element in their manifest:

<contribution xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912">
   <import name="urn:somenamespace:1.0"/>
</contribution>

When the qname is imported, Fabric3 will ensure the portTypes may be referenced by artifacts such as composite files contained in the importing contribution.

Contribution Imports and Exports

Fabric3 supports the ability to export and import all Java packages from a contribution using <export.contribution> and <import.contribution>. Matching is done using a symbolic name provided by the @uri attribute:

<export.contribution uri="MyContribution"/>
<import.contribution uri="MyContribution"/>

It is recommended to use <export.java>/<import.java> instead of contribution importing to avoid unnecessary coupling between contributions. However, contribution importing is useful when an application is composed of multiple Maven modules where one module performs integration tests and requires access to non-public classes provided by the other.