Introduction

In the client target, a RepositoryAdmin is available that provides a model of the objects and associations that the provisioning server works with.

Object graph

Objects

The objects that are used in the model are Artifact, Group, License and Gateway. All of the objects are managed using a repository of that type, including the association objects.

(note: the BundleObject in this image has been replaced with a more generic ArtifactObject; see below)

All objects are based on attributes and tags, with the attributes being the identifying elements of the object, and tags as extra information which does not have any influence on the identity. Each of the object's interfaces contains a number of convenience methods for getting and setting these.

Validation

Every object has some mandatory attributes. There is a standard mechanism to help descendents of RepositoryObjectImpl in enforcing this. In short: in createNewInhabitant, there is the opportunity to check complicated rules on attributes (such as, if a exists, so must b). In each descendent's constructor, the attributes can be passed into checkAttributes, along with a list of attribute keys which should exist.

Associations

We do not have a distinction between static and dynamic associations: all associations are dynamic, with static associations being a special case of that. The associations are based on LDAP filter strings, which should match some object's attributes. When there can be multiple matches for a given filter, a Comparator is used to pick the most suited one. When a match is found, the association registers itself with the object.

Each object knows how to create its own endpoints.

Based on an optional set of properties, each object can create a filter string and cardinality by overriding getAssociationFilter and getCardinality. Optionally, a comparator can be provided by getComparator; only one comparator per <...>ObjectImpl is allowed.

For the properties of associations, it is wise to include a key for this in the object's interface.

Artifacts

Helpers

An overview of the currently used helpers and recognizers can be found here.

The 'elements to be provisioned' are known as artifacts. For each type of artifact, there should be a specific AttributeHelper service, which is registered with the same mimetype as the corresponding types of artifacts in the service properties (there are no subtypes of ArtifactObject in the Java sense of subtype; an artifact without a corresponding helper service is considered to be illegal). The ArtifactHelper interface shows the functions the service should provide.

The helper has influence over the checking of the attributes, and over the creation of associations, as shown below.

  • Attribute checking Complex rules can be enforced in the helper's checkAttributes; validation, such as normalization, can be done here too. For attributes that must be present in an artifact's metadata, without making claims about the exact content, getMandatoryAttributes should return an array of their keys.
  • Association creation Since ArtifactObject is intended to be extended with ArtifactHelper services for the different types of artifact, both the creation of filters and the determination of cardinalities will be directly delegated to the helper.

Depending on the complexity of the artifact, the AttributeHelper could provide its own interface with additional convenience functions, such as creating basic versions of the artifact, easier access to secondary information, and the creation of common types of 'smart' associations.

Recognizers

To recognize artifacts that are imported into the system, available ArtifactRecognizer s are asked to whether they recognize it. Furthermore, the role of an artifact recognizer is to extract metadata from the artifact.

Resource processors

Chapter 114 of the OSGi compendium specification (Deployment Admin) mentions ResourceProcessor services that handle the deployment of resources, other than bundles. A resource processor is a service, which is published by a specially marked bundle in the deployment package. For each special resource, the deployment package contains the PID of the service that should be used to handle it.

In the provisioning server, we need to know which bundle will handle which processor PID, so they can be packed in a deployment package whenever they are needed. To detect that a bundle will publish a resource processor, it's manifest needs an extra header,
Deployment-ProvidesResourceProcessor: <processor-pid>

XML representation

The basic objects have all of their state defined in their attributes and tags, so that's all that needs to be stored for them. Associations have the filters which they use to find their endpoints stored in the attributes too. Therefore, we do not need to store any object references, but we can reconstruct them based on the filters, and can get away with storing only the attributes and tags for all objects in the same way. This leads to a rather clean and almost-human-readable XML representation, in this example for the store, with three bundles, two group, and some associations between them.

Some notes about the representation:

  • <repository> is always the outer tag.
  • Below <repository>, the various repositories show up, such as <bundles> and <groups2licenses>. The order is of no interest.
  • Within the repositories, the objects are stored, such as <bundle> and <group2license>. A <bundle> should of course only show up in a <bundles> repository, but the exact order of the object is of no interest.
  • The objects contain <attributes> and <tags>. Each one of these consists of <the-name>the-value</the-name>. The reserved values, such as for an association's endpoints, are available in that object's interface definition. <attributes> must come before <tags>.

Event mechanism

To allow the UI to react on changes in the repository, events will be fired upon these changes using the EventAdmin. For all types of objects, specific topics are available, each starting with the name of the object's interface. So, anything having to do with LicenseObject fires events of net/luminis/liq/client/repository/object/LicenseObject, with specific subtypes for /ADDED, /REMOVED and /CHANGED. Since there are no 'real' subtypes of Artifact, all artifacts will use the same set of event topics. These values are available as constants in the object's interface. Note that events will be suppressed when serializing or deserializing the repository.

RepositoryAdmin

The RepositoryAdmin is responsible for serialization and deserialization, and the handling of logins, commits and checkouts.

Local caching

The admin supports checking out and committing data from and to a server. To allow reverting to a previously checked out version, and to store changes between several sessions of the UI, local copies of the data are kept: one current, which is the most recently edited version, and one backup, which is identical to the version that was most recently checked out or committed.

  • No labels