Dynamic component reference bindings

The JAIN SLEE specification states that every deployable component has an identity specified by a name, vendor, and version tuple. This identity must be unique within the scope of a given component type. A component may reference other components of various types by specifying their type and identity in the component deployment descriptor.

These references are static, that is: they are defined prior to installation in the SLEE; and once the component is installed the references cannot be changed. Static references in general function adequately; however they can make the application upgrade process more complicated that it need be.

For example, if a library component used by an application has a bug fixed and a new version of the library is produced, then all dependent components such as SBBs and profile specifications need to have their references updated and new versions released; and all components dependent on those, such as other SBBs and service components, also need updating and releasing; and so on through the chain of dependencies.

A more dynamic approach to dependency specification and binding would help make the upgrade process easier. Rhino provides such an approach, which is supported by the following concepts:

Each of these concepts is described in detail below.

Install levels

The JAIN SLEE specification defines that a deployable unit and the components it contains is either installed or not installed in the SLEE. When a deployable unit is installed, its components are verified for correctness, and if verification is successful the components are made ready for use; for example, service components are initialised ready for activation.

To facilitate the management of dynamic component bindings, Rhino provides finer-grained control over the degree to which a deployable unit and its components are installed. Installed components each have one of the following install levels:

  • INSTALLED — The component is installed in the SLEE. The deployment descriptor has been validated for syntax and and has been parsed; however any component and class references, configuration parameters, and other relevant information contained in the deployment descriptor has not been verified for correctness.

  • VERIFIED — The component is installed and has successfully passed all verification checks.

  • DEPLOYED — The component is installed, it has passed verification, any necessary implementation code has been generated, and it has been deployed to each cluster node ready for immediate use (such as service activation).

Here are some ways you can manage install levels:

Specify the level

The initial install level for a deployable unit and the components it contains can be specified when the deployable unit is installed. For example, using rhino-console:

[Rhino@localhost:2199 (#0)] installlocaldu /path/to/deployable-unit.jar -installlevel INSTALLED
Installed: DeployableUnitID[url=file:/path/to/deployable-unit.jar]
Note The -installlevel parameter is optional. If an install level is not specified when a deployable unit is installed, an install level of DEPLOYED is assumed.

Verify an installed component

An installed component can subsequently be verified using the verify management operation. For example, using rhino-console:

[Rhino@localhost:2199 (#0)] verify sbb name=MySBB,vendor=OpenCloud,version=1.0
SbbID[name=MySBB,vendor=OpenCloud,version=1.0] verified
The following components were also verified:
  ProfileSpecificationID[name=MyProfileSpec,vendor=OpenCloud,version=1.0]
  LibraryID[name=MyLibrary,vendor=OpenCloud,version=1.0]

If the component being verified depends on other components that are installed but yet to be verified, then Rhino will automatically verify those dependent components first. (See the note about install levels below.)

Verify an installed DU

An installed deployable unit may also be "verified". Deployable unit verification is a convenience mechanism to verify all the components contained in the deployable unit with a single command. For example, using rhino-console:

[Rhino@localhost:2199 (#0)] verify du file:/path/to/deployable-unit.jar
Deployable unit file:/path/to/deployable-unit.jar verified
The following components were verified:
  SbbID[name=MySBB,vendor=OpenCloud,version=1.0]
  ProfileSpecificationID[name=MyProfileSpec,vendor=OpenCloud,version=1.0]
  LibraryID[name=MyLibrary,vendor=OpenCloud,version=1.0]

Only the deployable unit components that have yet to be verified are affected by this command. As such, verifying a deployable unit that only contains already verified components has no further effect.

Deploy a component

A component can be deployed using the deploy management operation. For example, using rhino-console:

[Rhino@localhost:2199 (#0)] deploy sbb name=MySBB,vendor=OpenCloud,version=1.0
SbbID[name=MySBB,vendor=OpenCloud,version=1.0] deployed
No other components were affected by this operation

If the component being deployed depends on other components that are not yet deployed, then Rhino will automatically deploy those dependent components first, and so on recursively. (See the note about install levels below.)

If any component being deployed has not yet been verified, then Rhino will automatically verify the component before deploying it. The deploy operation will fail if any verification errors are found in this case.

Deploy an installed DU

An installed deployable unit may also be "deployed". Deployable unit deployment is, again, a convenience mechanism to deploy all the components contained in the deployable unit with a single command. A deployable unit can be deployed in rhino-console, for example, as follows:

[Rhino@localhost:2199 (#0)] deploy du file:/path/to/deployable-unit.jar
Deployable unit file:/path/to/deployable-unit.jar deployed
The following components were deployed:
  SbbID[name=MySBB,vendor=OpenCloud,version=1.0] deployed

Only the deployable unit components that have yet to be deployed are affected by this command. As such, deploying a deployable unit that only contains already deployed components has no further effect.

Undeploy a deployed component

A deployed component can subsequently be undeployed. When a component is undeployed it reverts to the VERIFIED install level. Dynamic changes to a component’s bindings cannot be made while a component is DEPLOYED; therefore it is necessary to undeploy a component if it is currently deployed and its bindings need to be changed.

A deployed component is undeployed using the undeploy management operation. For example, using rhino-console:

[Rhino@localhost:2199 (#0)] undeploy service name=MyService,vendor=OpenCloud,version=1.0
ServiceID[name=MyService,vendor=OpenCloud,version=1.0] undeployed
No other components were affected by this operation

If there are any components that depend on the component being undeployed that themselves have an install level of DEPLOYED, then those components too will also be undeployed by this operation, and so on recursively. (See the note about install levels below.)

An undeploy operation will fail if any component that would be affected by the operation does not satisfy the below requirements:

  • A service component can only be undeployed if it is in the INACTIVE state.

  • A profile specification component can only be undeployed if there are no profile tables created from it currently in existence.

  • A resource adaptor component can only be undeployed if there are no resource adaptor entities created from it currently in existence.

Unverify a component

A verified or deployed component can subsequently be unverified. When a component is unverified it reverts to the INSTALLED install level. If the component was deployed then it is undeployed first. Dynamic changes to a component’s bindings cannot be made while a component install level is not INSTALLED. Rhino will automatically unverify (but not undeploy) a verified component affected by a binding operation; however the unverify management operation exists to allow this transition to be manually controlled. Manually unverifying a component is also necessary if, for example, dependent linked or shadowed components need to be updated.

A component is unverified using the unverify management operation. For example, using rhino-console:

[Rhino@localhost:2199 (#0)] unverify service name=MyService,vendor=OpenCloud,version=1.0
ServiceID[name=MyService,vendor=OpenCloud,version=1.0] unverified
No other components were affected by this operation

If there are any components that depend on the component being unverified that themselves have an install level of VERIFIED or DEPLOYED, then those components too will also be unverified by this operation, and so on recursively. (See the note about install levels below.)

Note
About install levels

The general rule for install levels is that any given component cannot have an install level greater than any of the components that it depends on.

If a component desires to transition to a higher install level then all its dependent components must successfully transition to the new install level first.

If a component desires to transition to a lower install level then all components that depend on it must successfully transition to the new install level first.

Component copy

In order to maintain compatibility with the JAIN SLEE specification, Rhino does not permit the component references of components installed using a standard SLEE deployable unit — hereinafter termed "original" components — to be dynamically modified. Rather, a virtual copy of each component to be modified must be made, and the references of the copied components modified instead. A copied component is still a SLEE component in its own right, and must have a unique identity within the scope of the component type as for any other component. The only difference between an original SLEE component and a copied component is from where the component originates in the SLEE. A copied component uses the same set of interfaces and classes, and inherits the configuration properties such as environment entries, from the component it is copied from.

Here are some commands for managing copies:

Copy

A component can be copied using the copyComponent management operation. For example, using rhino-console:

[Rhino@localhost:2199 (#0)] help copycomponent
copycomponent <type> <source-id> <target-name> <target-vendor> <target-version> [-installlevel <level>]
   Make a copy of the source component with the target identity. The -installlevel
   option controls to what degree the copied component is installed after it is
   created

[Rhino@localhost:2199 (#1)] copycomponent sbb name=MySBB,vendor=OpenCloud,version=1.0 MySBB OpenCloud 1.0.1
Component SbbID[name=MySBB=OpenCloud,version=1.0] copied to SbbID[name=MySBB,vendor=OpenCloud,version=1.0.1]

The install level of the copied component can optionally be specified when the copy is made. If not specified, a default install level of DEPLOYED is used. Specifying an install level of INSTALLED is typically most efficient when making a copy of a component for use in a later binding operation, and is necessary when copying a component that itself will not pass verification checks.

Show copy history

A copied component may be subsequently copied again, leading to the treelike structure of copies branching out from the original. The ComponentDescriptorExtensions class in rhino-management included in a component’s metadata descriptor provides information about the source of a component and what copies have been made of it. The getdescriptor command in rhino-console reports this information, as shown in the example below:

[Rhino@localhost:2199 (#0)] getdescriptor sbb name=MySBB,vendor=OpenCloud,version=1.0
For component SbbID[name=MySBB,vendor=OpenCloud,version=1.0]:
 Deployable unit: DeployableUnitID[url=file:/path/to/deployable-unit.jar]
 Component source: my-sbb.jar
 Defined using SLEE version: 1.1
 ...
 Copies made from this component:
  SbbID[name=MySBB,vendor=OpenCloud,version=1.0.1]
 ...

[Rhino@localhost:2199 (#1)] getdescriptor sbb name=MySBB,vendor=OpenCloud,version=1.0.1
For component SbbID[name=MySBB,vendor=OpenCloud,version=1.0.1]:
 Copied from: SbbID[name=MySBB,vendor=OpenCloud,version=1.0]
 ...
 Original component: SbbID[name=MySBB,vendor=OpenCloud,version=1.0]
 Copies made from this component: none
 ...

Remove copied components

A copied component has an implicit dependency on its original. This means that a deployable unit that has copied components cannot be uninstalled from the SLEE until all its copied components have been removed. Copied components are removed using the removeCopiedComponents management operation. For example, in rhino-console:

[Rhino@localhost:2199 (#0)] help removecopiedcomponents
removecopiedcomponents [<type> <url|component-id>]*
   Remove components that have been copied from another component. Either
   individual components or a single deployable unit identifier can be specified.
   In the latter case, all copied components of the DU will be removed

[Rhino@localhost:2199 (#1)] removecopiedcomponents sbb name=MySBB,vendor=OpenCloud,version=1.0.1
1 component removed

(or)

[Rhino@localhost:2199 (#2)] removecopiedcomponents du file:/path/to/deployable-unit.jar
The following copied components were removed:
 SbbID[name=MySBB,vendor=OpenCloud,version=1.0.1]

Find orphaned copied components

After some copied components have been removed, other copied components may remain that are no longer referenced by any other component. The findOrphanedCopiedComponents command in rhino-console can be helpful in finding these components, as shown in the example below:

[Rhino@localhost:2199 (#0)] help findorphanedcopiedcomponents
findorphanedcopiedcomponents
   Find copied components that are no longer referenced by any other component.
   Components such as services and resource adaptors that sit at the top of the
   dependency hierarchy are not included

[Rhino@localhost (#1)] findorphanedcopiedcomponents
Copied components not used by any other component:
  SbbID[name=MySBB,vendor=OpenCloud,version=1.0.2]
  ...

Dynamic dependency specification

Dynamic component dependencies are specified using a binding descriptor. A binding descriptor is a JSON document that describes the changes that should be made to the deployment descriptors of one or more components. For example, a binding descriptor may change the root SBB of a service, or may add a new library reference to an SBB. A binding descriptor can only add to or change existing information contained in a deployment descriptor; it cannot remove any existing information.

A binding descriptor is a new component type in Rhino. As a component type, a binding descriptor has an identity described by the name, vendor, and version tuple — like all other SLEE component types. A binding descriptor document may be installed in Rhino as a new type of deployable entity.

Binding descriptor format

A binding descriptor is a JSON document that must conform to the schema defined by Rhino. The binding descriptor schema can be found in the doc/dtd directory of a Rhino install. Loosely speaking, a binding descriptor document must contain the declaration of a single JSON object with:

  • an optional description property containing an arbitrary string description

  • mandatory name, vendor, and version properties

  • an optional service property containing a service descriptor

  • an optional sbbs property containing an array of zero or more SBB descriptors

  • an optional sbbParts property containing an array of zero or more SBB part descriptors

  • an optional profileSpecs property containing an array of zero or more profile specification descriptors

  • an optional libraries property containing an array of zero or more library descriptors.

Each component descriptor that can be contained by a binding descriptor has a structure based on the corresponding SLEE-defined DTD for that component type. Only component properties that can be modified by bindings are defined by the schema and can be included in a binding descriptor.

Below is an example of a binding descriptor that can be used to change the root SBB of a service:

{
    "description": "Change service's root SBB",

    "name": "Example binding descriptor",
    "vendor": "OpenCloud",
    "version": "1.0",

    "service": {
        "rootSbb": {
            "name": "MyOtherSBB",
            "vendor": "OpenCloud",
            "version": "1.0"
        }
    }
}

Managing binding descriptors

A binding descriptor is installed into Rhino much like a SLEE deployable unit. The deployable type option must be used to indicate that the type of object being installed is a binding descriptor.

Here’s how to install and uninstall them:

Install a binding descriptor

The example below shows how a binding descriptor can be installed using rhino-console:

[Rhino@localhost:2199 (#0)] install file:/path/to/my-binding-descriptor.json -type bindings
Installed: DeployableUnitID[url=file:/path/to/my-binding-descriptor.json]

Install levels are not relevant for binding descriptors. Any install level specified when a binding descriptor is installed is ignored.

Note An installed binding descriptor document is a deployable unit that contains one binding descriptor component with an identity as specified by the name, vendor, and version properties in the JSON document. Binding descriptor components do not support Component copy operations, as such an operation has little meaning.

Uninstall a binding descriptor

An installed binding descriptor can be uninstalled in the same way as any other SLEE deployable unit. For example, using rhino-console:

[Rhino@localhost:2199 (#1)] uninstall file:/path/to/my-binding-descriptor.json
uninstalled: DeployableUnitID[url=file:/path/to/my-binding-descriptor.json]

Binding descriptor application

Binding descriptors are applied to components within the scope of a service. That is, a binding descriptor can be associated with a service, and its effects are propagated to the affected components used by the service. Binding descriptors can be associated with, and subsequently disassociated from, any service with an install level of INSTALLED or VERIFIED. A service with an install level of DEPLOYED must be undeployed before its binding descriptor associations can be changed.

Binding descriptors can only be associated with a component copy service component. If a command is given to associate a binding descriptor with an original service component, a new copy of the service component will automatically be made by Rhino and the binding descriptor associated with the copied component instead.

A binding descriptor associated with a service that affects dependent components of the service, such as SBBs or libraries, requires that those components be copied and the effects of the binding descriptor applied to the copied components. Rhino will automatically copy components where necessary to fulfil this requirement, according to the following rules:

  • If an original component needs its bindings modified, a copy is first made and the copy modified.

  • If a copied component needs its bindings modified, and the copied component is not used in any other service, then the copied component is reused for the new modifications.

  • If a copied component needs its bindings modified, but the copied component is in use by some other service, then a new copy is made and the new copy modified.

  • The ripple effect may cause other copies to be generated. For example, if SBB A references SBB B and SBB B is copied and its bindings modified, then SBB A also needs to be modified with an update to reference the copied SBB B. To do this SBB A may also need to be copied first as described above.

The component identifiers of copied components may be specified as part of the binding operation, if specific identifiers are desired. If a component needs to be copied but a component identifier has not been specified for the copy, then Rhino will automatically generate a new unique component identifier based on the original component’s identifier.

Service binding capabilities

A binding descriptor applied to a service may cause any of the following actions:

  • change the root SBB of the service

  • modify one or more dependent SBBs by:

  • modify one or more dependent SBB parts by:

  • modify one or more dependent profile specifications by:

    • adding new library and/or profile specification references

    • adding new environment entries, or changing the values of existing environment entries

    • changing the definition or options of static queries

  • modify one or more dependent libraries by:

    • adding new library references.

Warning Due to classloader limitations, a profile specification can only have its bindings modified if there are no profile tables, resource adaptor entities, or services with an install level of DEPLOYED, that depend on any profile specification in the same profile specification component jar present in the SLEE. Attempting to change the bindings of a profile specification that does not meet this criteria will result in the failure of the binding operation.

Binding conflicts

It is possible that a conflict may arise with a binding descriptor that is associated with a service:

  • A binding descriptor may declare a usage parameters interface of type X, as extending a different usage parameters interface type than a previous definition of X (either in the original deployment descriptor or in another associated binding descriptor).

    Note No conflict arises if X has previously been declared with no extends type, but an associated binding descriptor specifies an extends type for X. In this case, the SLEE assumes that X should now extend the specified type rather than extend nothing.
  • A binding may declare an environment entry with name X with a different Java type than a previous definition of X.

If either of these types of conflicts occur, the binding descriptor association fails. The conflict must be resolved before the binding descriptor can be successfully associated.

Duplicate definitions such as component references do not cause a conflict. For example if the deployment descriptor and one or more binding descriptors all declare the same library reference, they are simply merged together into a single reference.

Associating a binding with a service

Here’s how to associate a binding descriptor with a service, map target component identifiers of copied component, and disassociate a binding descriptor from a service:

Associate

A binding descriptor is associated with a service using the addBindings operation defined on the ServiceManagementMBean. This operation may be invoked in rhino-console, for example, as shown below:

[Rhino@localhost:2199 (#0)] help addservicebinding
addservicebinding <service-id> [-binding <binding-descriptor-id>]* [-mapping <map-name>] [-dryrun]
   Add one or more bindings to a service. The -mapping option specifies a component
   mapping created with the createbindingcomponentmap command. The -dryrun option
   will display the affects the binding operation will make but will not actually
   commit the changes

The example below associates a binding descriptor with a service:

[Rhino@localhost:2199 (#0)] addservicebinding name=MyService,vendor=OpenCloud,version=1.0 -binding name=MyBinding,vendor=OpenCloud,version=1.0
Bindings added to service ServiceID[name=MyService,vendor=OpenCloud,version=1.0]
The following new components were created:
  SbbID[name=MySbb,vendor=OpenCloud,version=1.0-copy#1]
  ServiceID[name=MyService,vendor=OpenCloud,version=1.0-copy#1]
No components were removed

Create mappings

The -mapping argument can be used to specify the target component identifiers of copied components, rather than have Rhino autogenerate them. In rhino-console such a map is managed using the following additional commands:

createbindingcomponentmap <map-name>
   Create a component mapping that can be used with the addservicebinding command.
   Mappings can be added using the addbindingcomponentmapping command. Created
   mappings exist only in the client, and will be lost when the client terminates

removebindingcomponentmap <map-name>
   Remove an existing bindings component mapping

listbindingcomponentmaps
   List the current bindings component maps

addbindingcomponentmapping <map-name> <source-id> <target-name> <target-vendor> <target-version>
   Add a bindings mapping from the source component to the target identity

removebindingcomponentmapping <map-name> <source-id>
   Remove a bindings component mapping

dumpbindingcomponentmap <map-name>
   Dump the current mappings in the specified bindings component maps

The following example creates a mapping and uses it to control the component identifier of the SBB copied by the binding operation:

[Rhino@localhost:2199 (#1)] createbindingcomponentmap mymap
Bindings component mapping mymap created

[Rhino@localhost:2199 (#2)] addbindingcomponentmapping mymap sbb name=MySbb,vendor=OpenCloud,version=1.0 MySbb OpenCloud 1.0.1
Mapping SbbID[name=MySbb,vendor=OpenCloud,version=1.0] -> SbbID[name=MySbb,vendor=OpenCloud,version=1.0.1] added to mapping mymap

[Rhino@localhost:2199 (#3)] dumpbindingcomponentmap mymap
Component mappings for mymap:
  SbbID[name=MySbb,vendor=OpenCloud,version=1.0] -> SbbID[name=MySbb,vendor=OpenCloud,version=1.0.1]

[Rhino@localhost:2199 (#4)] addservicebinding name=MyService,vendor=OpenCloud,version=1.0 -binding name=MyBinding,vendor=OpenCloud,version=1.0 -mapping mymap
Bindings added to service ServiceID[name=MyService,vendor=OpenCloud,version=1.0]
The following new components were created:
  SbbID[name=MySbb,vendor=OpenCloud,version=1.0.1]
  ServiceID[name=MyService,vendor=OpenCloud,version=1.0-copy#2]
No components were removed
Note As part of a binding operation, the service and all its dependent components transition to the VERIFIED install level. This means that the addition (or removal) of a binding to (or from) a service must leave the service in a state that will pass all SLEE verification checks. If any of these checks fail, then the binding operation will also fail.

Disassociate

A binding descriptor can be disassociated from a service using the removeBindings operation defined on the ServiceManagementMBean. This operation may be invoked in rhino-console, for example, as shown below:

[Rhino@localhost:2199 (#0)] help removeservicebinding
removeservicebinding <service-id> [-binding <binding-descriptor-id>]* [-dryrun]
  Remove one or more bindings from a service. The -dryrun option will display the
  affects the binding operation will make but will not actually commit the changes

An example of a binding descriptor being disassociated from a service is shown below:

[Rhino@localhost:2199 (#0)] removeservicebinding name=MyService,vendor=OpenCloud,version=1.0-copy#1 -binding name=MyBinding,vendor=OpenCloud,version=1.0
Bindings removed from service ServiceID[name=MyService,vendor=OpenCloud,version=1.0-copy#1]
No new components were created
The following components were no longer required and were removed:
  SbbID[name=MySbb,vendor=OpenCloud,version=1.0-copy#1]
  Service ServiceID[name=MyService,vendor=OpenCloud,version=1.0-copy#1] now has no bindings and may be removed if no longer required
Previous page Next page