« Back to Secure Tropos Project

Event "BeforeDeleteInstance"

Combination View Flat View Tree View
Threads [ Previous | Next ]
toggle
Event "BeforeDeleteInstance"
community documentation adoscript trigger
Answer
10/28/15 7:28 AM
NEW APPROACH DESCRIBED IN FOLLOWING POST - Use of EVENT UpdateAction is discouraged!

Currently, the "BeforeDeleteInstance" deletes related connectors, even if the event is cancelled, meaning the EXIT value is set to -1. This is due to the fact, that the deletion of events is happened beforehand. To overcome this limitation, the following implementation can be used. This is actually a restore mechanism of relation instances after the delete.

- Implement a stack of deletedRelations as a map with the deleted relations and the related timestamp as a key, that is only updated in case the event triggering the delete is from the BeforeDeleteInstance event
- Implement the UpdateAction event inclduing a trigger flag (otherwise the event is triggered continously.
- Implement a timestamp capture mechanism to realize the events that should be restored.


Limitations:
- attribute values are currently not captured, this would to be implemented on a custom/method level

 1ON_EVENT "AppInitialized" {
 2  # init the holder for deleted relations as a map and the event time when these where triggered
 3  SETG mDeletedRelations: (map())
 4  SETG sEventTime:""
 5  ...
 6}
 7
 8ON_EVENT "BeforeDeleteInstance" {
 9  CC "Application" GET_DATE_TIME date-format:"dd/mm/yyyy" time-format:"hh:mm:ss"
10  #... [other code to determine whether the EXIT is set to -1
11  # set the flag only if the delete of the instance comes from a cancelled delete of objects
12  IF (execResult = -1) {
13    SETG bUpdate: (1)
14    SETG sEventTime: (time)
15  }
16  ELSE {
17    SETG bUpdate: (0)
18  }
19  EXIT (execResult)   
20}
21
22ON_EVENT "DeleteRelationInstance" {
23  CC "Application" GET_DATE_TIME date-format:"dd/mm/yyyy" time-format:"hh:mm:ss"
24  # store all parameters so that they are available in other action, for restore
25  IF (type (mDeletedRelations[time]) = "undefined") {
26    SET sTimeStampedDeletedActions: (STR relationclassid + "|" + STR toinstanceid + "|" + STR frominstanceid)
27  }
28  ELSE {
29    SET sTimeStampedDeletedActions: (tokunion (mDeletedRelations[time], STR relationclassid + "|" + STR toinstanceid + "|" + STR frominstanceid))
30  }
31  SETG mDeletedRelations[time]: (sTimeStampedDeletedActions)
32  # TODO: add attribute value collecting functionality
33}
34
35ON_EVENT "UpdateActions" {
36  # only if flag is there
37  IF (bUpdate) {
38    # reset flag
39    SETG bUpdate: (0)
40    IF (type (mDeletedRelations[sEventTime]) <> "undefined") {
41      FOR sDeletedRelation in: (mDeletedRelations[sEventTime]) {
42          # only do if the timestamp contains a value
43          CC "Core" CREATE_CONNECTOR modelid: (modelid) fromobjid: (VAL token (sDeletedRelation, 2, "|")) toobjid: (VAL token (sDeletedRelation, 1, "|")) classid: (VAL token (sDeletedRelation, 0, "|"))
44      }
45      # reset the list of deletedRelations
46      SETG mDeletedRelations: (map())
47      # TODO: add functionality to restore attribute values.
48    }
49  }
50}

RE: Event "BeforeDeleteInstance"
Answer
9/25/14 12:24 PM as a reply to Wilfrid Utz.
Does the same limitation hold for the object deletion or is there a way to prevent ADOxx from deleting modeling class instances?

Thank you.
- Domenik

RE: Event "BeforeDeleteInstance"
Answer
9/30/14 11:39 AM as a reply to Dominik Bork.
Hi Domenik,

to prevent the deletion of instances (NOT relation instances), you can just EXIT the event with -1 and you are good. See a small example below.

1ON_EVENT "BeforeDeleteInstance" {
2  # your custom logic, if not done, no deletion is possible at all
3  EXIT -1
4}

RE: Event "BeforeDeleteInstance"
Answer
10/27/15 11:59 AM as a reply to Wilfrid Utz.
As an update to the previous implementation proposal, please consider the following update. It is discouraged to use the "UpdateAction" event as this could result in unpredicted behaviour. The approach for preventing relation instances to be deleted, we can combine the "DeleteRelationInstance" with "DiscardRelationInstance". The approach is based on the sequence of events, as during the DeleteRelationInstance we can capture the deleted relation and all available attributes, serialize this information and run a re-create in the DiscardRelationInstance, as this event is triggered when the relation instance is discarded from the modelling core.

The proposal below builds upon this assumption, serialization between the events is realized using a map object, e.g. serializing in memory.

1ON_EVENT "AppInitialized"
2{
3  # ...
4  SETG mDeletedRelations: (map())
5  # ....
6}
During AppInitialized, the map for serializing is initialized.

 1ON_EVENT "DeleteRelationInstance" {
 2  IF (( #select the appropriate instance type#)) {
 3  # get the position of the relation
 4  CC "Core" GET_ATTR_VAL objid: (relationinstanceid) attrname:"Positions"
 5  SETL sPositionsVal: (val)
 6  # get all attributes of the relation
 7  CC "Core" GET_ALL_ATTRS classid: (relationclassid)
 8  SETL lAttributeIDs: (attrids)
 9  SETL lAttributeMap: ("")
10  FOR sAttributeID in: (lAttributeIDs) {
11    CC "Core" GET_ATTR_VAL objid: (relationinstanceid) attrid: (VAL sAttributeID) as-string
12    SETL sAttributeValue: (val)
13    SETL sIDValuePair: (sAttributeID + "#" + sAttributeValue)
14     SETL lAttributeMap: (tokunion (lAttributeMap, sIDValuePair, "|"))
15  }
16  IF (type (mDeletedRelations[id_componentid]) = "undefined") {
17      SET sTimeStampedDeletedActions: (STR relationclassid + "|" + STR toinstanceid + "|" + STR frominstanceid + "|" + base64encode(sPositionsVal) + "|" + base64encode(lAttributeMap)+ "|" + STR relationinstanceid)
18  }
19  ELSE {
20    SET sTimeStampedDeletedActions: (tokunion (mDeletedRelations[id_componentid], STR relationclassid + "|" + STR toinstanceid + "|" + STR frominstanceid + "|" + base64encode(sPositionsVal)+ "|" + base64encode(lAttributeMap) + "|" + STR relationinstanceid))
21  }
22  SETG mDeletedRelations[id_componentid]: (sTimeStampedDeletedActions)
23}
The "DeleteRelationInstance" retrieves the values from the deleted relation and stores them into the map element

 1ON_EVENT "DiscardRelationInstance" {
 2  CC "Modeling" GET_ACT_MODEL
 3  SETL nCreatedModelID: (modelid)
 4  IF (nCreatedModelID != -1 AND LEN (mDeletedRelations) > 0) {
 5    FOR sDeletedRelation in: (mDeletedRelations) {
 6      IF (LEN (sDeletedRelation) > 0) {
 7        EVENT_LOG msgType:"EVENT_LOG" message: (sDeletedRelation)
 8        CC "Core" CREATE_CONNECTOR modelid: (modelid) fromobjid: (VAL token (sDeletedRelation, 2, "|")) toobjid: (VAL token (sDeletedRelation, 1, "|")) classid: (VAL token (sDeletedRelation, 0, "|"))
 9        SETL nNewRelationID: (objid)
10        CC "Core" SET_ATTR_VAL objid: (nNewRelationID) attrname:"Positions" val: (base64decode(token (sDeletedRelation, 3, "|")))
11        SETL lAttributeValueMap: (base64decode(token (sDeletedRelation, 4, "|")))
12        FOR sAttributeKeyValue in: (lAttributeValueMap) sep:"|" {
13          SET sAttributeID: (token (sAttributeKeyValue, 0, "#"))
14          SET sAttributeValue: (token (sAttributeKeyValue, 1, "#"))
15          CC "Core" GET_ATTR_TYPE attrid: (VAL sAttributeID)
16          IF (attrtype = "INTEGER" OR attrtype = "DOUBLE" OR attrtype = "TIME") {
17            CC "Core" SET_ATTR_VAL objid: (nNewRelationID) attrid: (VAL sAttributeID) val: (VAL sAttributeValue)
18          } ELSE {
19            CC "Core" SET_ATTR_VAL objid: (nNewRelationID) attrid: (VAL sAttributeID) val: (sAttributeValue)
20          }
21        }
22      }
23    }
24    # reset map
25    SETG mDeletedRelations: (map())
26  }
27}
The event "DiscardRelationInstance" is used to re-create the missing connector.