You are viewing the documentation for Blueriq 16. Documentation for other versions is available in our documentation directory.

The Aggregate Conversion API allows client code to provide custom behavior for importing the serialized profile of an aggregate into the current profile. This process is referred to as "conversion" and/or "import" in this document.

Terminology used in this document

  1. source version - the version of the application at the time an aggregate is saved
  2. target version - the version of the application at the time an aggregate is read, converted and imported into the profile
  3. source entity instance - in the context of a relation, the source entity instance is the instance which owns the forward relation (eg. in a Person -> Address relation, Person is the source)
  4. target entity instance - in the context of a relation, the target entity instance is the instance which owns the reverse relation (eg. in a Person -> Address relation, Address is the target)
  5. saved profile - part of a profile which was serialized and saved in the database at the time an aggregate was saved. Contains entity instances, attributes and relations.
  6. current profile - the current IProfile instance
  7. current entity instance - when importing an attribute or relation, this is set on an entity instance which is referred to as "the current entity instance"
  8. saved aggregate - used interchangeably with saved profile

The following diagram presents an overview of the Aggregate Conversion API. The package names are omitted throughout this document to minimize clutter.

On this page:

 

The main entrypoint is an implementation of IAggregateConverterFactory annotated with AquimaAggregateConverterFactory, provided by client code and available on the classpath. While there could be multiple classes implementing this interface, there must be a single class on the classpath annotated with AquimaAggregateConverterFactory (practically, there should be a single bean implementing IAggregateConverterFactory in the Spring context). If this requirement is not met, the following semantics are applied:

  • if there isn't any converter factory in the classpath, this is interpreted as "no custom conversion is desired", and implicit conversions will be done
  • if there are multiple converter factories in the classpath it is considered a configuration/programming error and an exception will be thrown

Annotation AquimaAggregateConverterFactory

This annotation extends the Spring @Component annotation and marks a class as a Spring bean. To allow the class to be picked up and an instance of it made available in the Spring context, the package containing the implementation annotated with AquimaAggregateConverterFactory should be included in a <component-scan> element in the Spring context configuration.

Interface IAggregateConverterFactory

This interface allows the AggregateDAO plugin to obtain a converter which is capable of converting a given aggregate from a given source version (the version in which the aggregate was saved) to a given target version (the current version). The only method of this interface is getAggregateConverter(aggregateName:String, source:ApplicationID, target:ApplicationID). This method should return an implementation of IAggregateConverter capable of converting the given aggregate from the given source version to the given target version, or null if implicit conversion is desired.

To prevent accidental implicit conversions, the factory may return a "catch-all" implementation which may:

  • throw an exception from all its methods , and in so doing prevent any conversions from taking place
  • silently ignore all entities, attributes and relations which should be imported and log messages or otherwise notify the concerned parties of the missing converter for the given parameters

Interface IAggregateConverter

This interfaces defines the API through which custom converters may hook into the conversion process. If a converter is available for a given aggregate/source/target combination, the default conversion process will first delegate to the custom converter. The converter may decide to do one of the following:

  • handle the conversion itself
  • let the default process do the conversion 

The interface provides five methods which are briefly described here and further detailed below:

  • addEntity - this method notifies the converter that an entity should be imported
  • setAttribute - this method notifies the converter that an attribute of an entity should be imported
  • setRelation - this method notifies the converter that a (forward) relation of an entity should be imported
  • preProcess - this method is called first, before all others and allows the converter to do any preprocessing or initialization
  • postProcess - this method is called last, after all others and allows the converter to do any final processing or cleanup

Method addEntity(ctx:IEntityConversionContext):boolean

This method notifies the converter that an entity is about to be imported. Information about the entity can be obtained from the ctx parameter.

The calling process can make the following guarantees related to this method:

  • this method will be invoked for each saved entity instance exactly once
  • for any given entity instance, this method will be invoked before any of the setAttribute and setRelation methods are invoked for the same instance

The calling process does not make any guarantees related to the following:

  • the order in which entity instances are imported
  • there is no guarantee that entity instances that have relations to the currently imported instance (either forward or backward relations) are already imported

The method may choose to create the corresponding instance in the profile itself at the moment this method is invoked or at a later time, in which case it should return true to indicate that it will handle the conversion of this entity instance itself. In most cases, where nothing is changed between the source and target version, the converter may return false to allow the default process to import the entity instance. 

If the entity instance is created at the moment the method is invoked, the converter may use ctx.setCurrentInstance(IEntityInstance) to notify the conversion process of the existence of the new instance. The given current instance will become the current instance for the setAttribute and setRelation methods, meaning the following attributes and relations will be set on this instance.

Method setAttribute(ctx:IAttributeConversionContext):boolean

This method notifies the converter that an attribute is about to be imported. Information about the entity, entity instance and attribute is available in the ctx parameter.

The calling process can make the following guarantees related to this method:

  • the addEntity method for the corresponding entity instance has been invoked before this method
  • for each saved single-valued attribute, this method will be invoked exactly once
  • for each saved value of a multivalue attribute, this method will be invoked exactly once

The ctx.getCurrentInstance() may be used to obtain the current entity instance on which this attribute should be set. Please note that the getCurrentInstance() method may return null if the preceding addEntity method returned true and it did not set a current instance. 

The method may return true to indicate it will handle the attribute itself, or return false to allow the default conversion to import the attribute. 

Method setRelation(ctx:IRelationConversionContext):boolean

This method notifies the converter that a relation is about to be imported. Information about the entity, entity instance and relation is available in the ctx parameter.

The calling process can make the following guarantees related to this method:

  • the addEntity method for the corresponding source entity instance has been invoked before this method
  • for each saved single-valued relation, this method will be invoked exactly once
  • for each saved value of a multivalued relation, this method will be invoked exactly once
  • for each target entity instance, the addEntity method will eventually be invoked

The calling process does not make any guarantees related to the following:

  • that the target entity instance has already been imported
  • the time at which the addEntity method for the target instance will be invoked (only guarantee is that it will be after preProcess and before postProcess)

 

The ctx.getCurrentInstance() method may be used to obtain the current entity instance, with the same remarks about null as for attributes.

The ctx.getRelationValue() method will return the instance ID in the saved profile of the target entity instance. This instance may or may not have already been imported.

The ctx.hasInstance(GUID) may be used to check whether the calling process knows that the target instance has already been imported. Please consult the documentation for IAggregateConversionContext.hasInstance(GUID) for details.

The ctx.getInstance(GUID) may be used to obtain the IEntityInstance from the current profile associated with the given GUID. Please consult the documentation for IAggregateConversionContext.getInstance(GUID) for details.

Method preProcess(ctx:IAggregateConversionContext):void

This method will be called before the conversion of a saved aggregate effectively starts. Implementations may use this opportunity to initialize, obtain and cache information from the current profile and metamodel for use in the subsequent addEntitysetAttribute and setRelation method calls. 

Method postProcess(ctx:IAggregateConversionContext):void

This method will be called last, after all entity instances, attributes and relations have been imported (or at least, their corresponding addEntity, setAttribute and setRelation methods have been called). Implementations may use this opportunity to create additional entity instances in the current profile based on the information accumulated in the preceding addEntitysetAttribute and setRelation method calls, as well as set attributes and relations on those instances. This method is most useful when there are complex changes (usually involving relations) between the source and target version. In those cases, information about the saved aggregate is progressively accumulated and then the complex conversions are made at the end in the postProcess method.

Class AggregateConverterAdapter

This class is provided for convenience that simple implementations may extend. The pre- and post-process methods have an empty implementation, and all other methods return false. This class may be used as a base class when simple converters only need to implement one or two methods of the IAggregateConverter interface.

Interface IAggregateConversionContext

An object implementing this interface is provided as parameter to preProcess and postProcess methods of an IAggregateConverter and can be used to obtain information about the source and target versions and the aggregate. It also provides access to the current profile and metamodel.

The IAggregateConversionContext is the base interface of all conversion contexts in the conversion API and are accessible from any point of a converter.

Method getSourceVersion():ApplicationID

This method returns the application id at the time this aggregate was last saved. This can be used to determine the project name and version at the time the aggregate was last saved. The value returned by this method will be identical to the source parameter provided to the IAggregateConverterFactory.getAggregateConverter method.

Method getTargetVersion():ApplicationID

This method returns the current application id (at the time the aggregate is converted). This can be used to determine the project name and version at the present time. This value returned by this method will be identical to the target parameter provided to the IAggregateConverterFactory.getAggregateConverter method.

Method getAggregateName():String

This method returns the name of the aggregate being converted. This, together with the source version can be used to determine what entity instances to expect in the addEntity method. The value returned by this method will be identical to the aggregateName parameter provided to the IAggregateConverterFactory.getAggregateConverter method.

Method getProfile():IProfile

This method returns the current profile. It can be used by the converter to obtain references to existing entity instances or to create new entity instances in the profile.

Method getMetaModel():IMetaModel

This method returns the current metamodel. It can be used by the converter to obtain information about aggregate, entity, attribute and relation definitions.

Method hasInstance(instanceId:GUID):boolean

This method checks whether for the given instanceId from the saved profile, an IEntityInstance is known to have been imported into the current profile (where it has a different instance id). This method used in combination with getInstance(GUID) is a convenient way for converter implementors to obtain an entity instance from the current profile which corresponds to an entity instance from the saved profile, freeing them of the need to maintain the mapping between saved and current profile themselves. 

Note: a return value of true from this method does not guarantee that getInstance(GUID) will not throw an exception, it only indicates whether a mapping is known. For example it is possible for implementors to delete the imported entity instance from the current profile after the mapping becomes known. However, if no entity instances are deleted by the converter implementor it is generally safe to assume that if hasInstance(GUID) returns true for a given GUID, then getInstance(GUID) for the same GUID will return an IEntityInstance without throwing exceptions.

This method may be used in any of the methods of IAggregateConverter.

Method getInstance(instanceId:GUID):boolean

This method returns the entity instance from the current profile, which is mapped to the given instance id from the saved profile. This method may return null if no mapping is known for the given instance id or may throw exceptions if a mapping is known but the entity instance cannot be found in the current profile (possibly because it was deleted by the implementor). 

This method may be used in any of the methods of IAggregateConverter, although in preProcess no mappings will be known since the import hasn't started yet at that point.

Interface IEntityConversionContextBase

This interface serves as a base interface for entity, attribute and relation conversion contexts and provides methods for obtaining information about the entity instance currently being imported.

Method getEntityName():String

This method returns the entity name of the entity instance currently being imported. 

Note: using IEntityConversionContext.setCurrentInstance() in addEntity has no effect on the return value of this method in setAttribute and setRelation; it will always return the entity name in the saved profile

Method getInstanceId():GUID

This method returns the instance id in the saved profile of the entity instance currently being imported. 

Note: using IEntityConversionContext.setCurrentInstance() in addEntity has no effect on the return value of this method in setAttribute and setRelation; it will always return the instance id from the saved profile

Method getInstanceName():String

This method returns the instance name in the saved profile of the entity instance currently being imported, or null if the saved entity instance doesn't have a name.

Method isRootInstance():boolean

This method checks whether the entity instance currently being imported is a root instance in the aggregate. An entity instance is a root instance if it is explicitly included in the aggregate. If the entity instance is not explicitly included, but was included anyway because of a relation, then it is not a root instance. This information may be used when entities are removed from an aggregate definition, but there might still be other instances that should remain due to relations to other instances. 

Interface IAttributeConversionContext

This interface extends IEntityConversionContextBase and provides methods specific to attributes which allow obtaining information about the attribute currently being imported, as well as about the current entity instance on which attributes are set.

Method getAttributeName():String

This method returns the name of the attribute currently being imported. 

Method getAttributeValue():String

This method returns the saved value of the attribute currently being imported. If the attribute is multivalued, then this method returns the value currently being imported. 

Method isMultiValued():boolean

This method indicates whether the attribute currently being imported is multivalued. If an attribute or relation is multivalued, the setAttribute method will be called multiple times for that attribute, once for each saved value. 

Method getCurrentInstance():IEntityInstance

This method returns the current entity instance being imported into the profile or null:

  • it will return an IEntityInstance if the preceding addEntity method returned false, or if it called setCurrentInstance with a non-null instance
  • it will return null if the preceding addEntity method returned true and did not set a current instance using setCurrentInstance

Interface IRelationConversionContext

This interface extends IEntityConversionContextBase and provides methods specific to relations which allow obtaining information about the relation currently being imported, as well as about the current entity instance on which the relations are set.

Method getRelationName():String

This method returns the name of the relation currently being imported.

Method getRelationValue():GUID

This method returns the instance id in the saved profile of the related (target) entity instance. The value returned by this method can be used in hasInstance and getInstance to obtain the actual entity instance from the current profile, if has previously been imported.

Method getCurrentInstance():IEntityInstance

This method returns the current entity instance being imported into the profile or null:

  • it will return an IEntityInstance if the preceding addEntity method returned false, or if it called setCurrentInstance with a non-null instance
  • it will return null if the preceding addEntity method returned true and did not set a current instance using setCurrentInstance

Interface IEntityConversionContext

This interface extends IEntityConversionContextBase and adds the possibility of setting the current entity instance on which setAttribute and setRelation will set attributes and relations.

Method setCurrentInstance(IEntityInstance):void

This method allows the converter implementor to specify a current entity instance from addEntity, on which setAttribute and setRelation should set attributes or relations. If addEntity returns false, the default import process will set the current instance. If addEntity decides that it will handle the conversion of an entity instance itself, it may use setCurrentInstance to allow the default conversion of attributes and relations to take places on this instance.