Callbacks and hooks provided by CDM
For many functionalities in the CDM library, the CDM library will specify default behavior, which can be overwritten for specific applications, might the need arise. In this section we will describe all hooks and callbacks that you can provide to override the default CDM behavior.
Remote commit notification
Upon every commit to a category in CDM, all connected clients will get a notification about the particular revision begin committed. You can specify how CDM should react to such notifications through the optional commitNotificationProcedure
argument of the procedures cdm::CreateCategory
and cdm::ConnectToCategory
.
Default implementation
By default, the CDM library will call the procedure cdm::DefaultCommitInfoNotification
for every commit notification. It will automatically pull the changes for the category, if the branch being committed to is current branch for the specified category, and cdm::AutoPullCategory
has been set for the category. Through the parameter cdm::SequentialPullCategory
you can indicate whether you want commits for that category to be pulled strictly sequentially. If there are more commits ready to be pulled the first commit notification would normally cause all changes up to the head to the current branch to be pulled in a single call to cdm::PullChanges
. By indicating that you want a category to be pulled sequentially, each commit notification will cause only the changes for that particular commit to be pulled. This may be necessary, for instance, when your model has cross-category rootset - subset dependencies, where non-sequential pulling might cause a subset to be filled with elements that the rootset does not yet contain.
Providing commit info
When committing changes, you can provide a callback which will set the commit author and provide the commit comment through the optional argument commitInfoProvider
of the cdm::CommitChanges
procedure.
Default implementation
The default callback for this argument is the procedure cdm::CommitInfoProvider
which will get
the author from the parameter
cdm::CommitAuthor
, which is set during the initialization of the session based on the run contextthe commit comment from the parameter
cdm::CommitComment
, which you should set to an appropriate context-specific value programmatically, or which can be set by the end-user when committing from theBranch and Revision Overview
page.
Local data change notification
Upon data change in your model, the CDM library will get a notification from the AIMMS engine. If the CDM library detects data changes in any of your categories, it will call the procedure specified through the optional dataChangeProcedure
argument of the procedures cdm::CreateCategory
and cdm::ConnectToCategory
.
Default implementation
By default, the CDM library will call the procedure cdm::DataChangeProcedure
for every data change notification, if it applies to the category at hand. The default implementation will automatically commit the changes for the category, if the parameter cdm::AutoPullCategory
has been set for the category.
Changes in connected state
Whenever a change in connected state the CDM service takes place, the CDM DLL will call the pre-defined procedure cdm::SetCDMConnectedState
. The callback will be called initially when the CDM library initially connects to the CDM service, and it will subsequently be called whenever you disconnect explicitly, or when the heartbeat mechanism included in the CDM library reports a failing connection to the CDM service.
By default, the only action taken by cdm::SetCDMConnectedState
is to set the parameter cdm::ConnectedToCDMService
to the appropriate value. By setting cdm::AutoReconnectToCDMService
to 1, the callback will try to re-connect to the CDM service automatically, whenever the connection has fallen away.
You can modify the behavior of cdm::SetCDMConnectedState
by assigning the a procedure to the global hook cdm::ConnectedStateProcedureHook
, which will be called at the end of cdm::SetCDMConnectedState
. In such a hook, you can, for instance, take any other measure to notify your end-users of the fact the connection has been dropped or has come up again. You can detect that a re-connect has taken place by observing that the installed hook has been called in the connected state multiple times in sequence.
Getting notified of errors
By default, all low-level API and high-level API CDM functions provide their status through return values, returning 1 for success, and 0 in case of failure.
All error messages, codes, dates and stack locations reported through the low-level API are collected in the identifiers in the Error Handling
section of the CDM library, whether you call the low-level API functions directly, or indirectly by calling high-level API functions.
All low-level API methods also call the procedure pointed to by the cdm::OnErrorProcedureHook
parameter. You can use this hook to set a function, that you can use, for instance, to notify the end-user of any error occurring while calling either the low- or high-level CDM API. You can also use the on-error hook to raise error that you can catch in on-error blocks elsewhere in your code, or in the global AIMMS error handler.
The CDM library provides two default on-error hooks:
cdm::EmptyOnErrorHook
(default), which just return 0. With the on-error hook you need to check the error codes of all low- and high-level API methodscdm::ErrorRaisingOnErrorHook
, which will raise an error that you can catch in an on-error block, reporting back the last reported CDM error.
Custom handling of conflict resolution
Either when pulling in changes, or when merging branches, merge conflicts can occur as discussed here. Through the element parameter cdm::SelectedConflictResolutionMethod
, a conflict resolution method can be selected.
When you specify the Custom
conflict resolution method, the CDM library will call the procedure pointed to by the element parameter cdm::ResolveConflictsHook
. Using this mechanism you can implement a custom, app-specific, conflict resolution method.
In your conflict resolution method, you should select for all identifiers with conflicts whether, for each index tuple with conflicting values, you want to assign
the remote value (either from the pulled-in changes, or from the branch to merge in the current branch), or
the locally changed value (from a change by the local user when pulling in commits, or, when merging in another branch, from the changes on the current branch since the revision where the branch to merge in, was branched off the current branch).
Selecting remote or local value
You can select for either value by either setting the value of
the associated
cdmrt::dori
shadow identifier to 0 if you want to select the remote value (stored in thecdmrt::dii
identifier), orthe associated
cdmrt::diri
shadow identifier to 0 if you want to select the locally changed value (stored in thecdmrt::doi
identifier).
If your custom conflict resolution method returns 1, the CDM library will consider all conflicts resolved, and will assign all values of the cdmrt::dii
identifiers to their corresponding actual identifiers for all tuples for which cdmrt::diri
still hold non-zero values. This will override all actual values, whether or not they have been locally changed.
Notice that the procedure to resolve conflicts will not commit the resulting local changes after resolving all conflicts to the CDM database. You can commit these local changes by explicitly committing the changes for the given category.