Vertec objects and their connection to the UI model
Product line
Standard
|Expert
Operating mode
CLOUD ABO
|ON-PREMISES
Modules
Services & CRM
Budget & Phases
Purchases
Resource Planning
Business Intelligence
In Vertec, data such as projects, invoices, services, but also folders, list settings, etc. are objects in memory that are saved persistently in a database. Whether or not they are loaded in memory plays no role here; for the object system only objects exist in the memory of the corresponding Vertec session.
These objects are classic software objects in the OO (Object-Oriented) sense, so they also carry logic (e.g. the VAT of an invoice is calculated by itself), and the other properties of OO systems are also used, such as inheritance, polymorphism over inheritance (example Adresseintrag
) and abstraction (example Usereintrag
). We call the objects that are present in a single Vertec session the Object Space.
So the objects carry the data on themselves and regulate their own relations, which is practical for the user of these objects. But the objects only live in a single session, i.e. an Object Space, what if data changes, objects are deleted, etc. in another session? This is where the Notif server comes into play.
Since the objects only live in an Object Space, they have to find out if something has changed and therefore the data in an Object Space is out of date
. This is done via the Notif server.
Each Vertec session periodically (by default every 30 seconds) saves the objects that have been changed in the local Object Space, which are dirty
, to the database. At the same time, it sends a list of the objects it has updated in the DB to the Notif server and receives from it a list of objects that have been changed since the last access by other sessions. This list matches the session with the objects loaded in its own Object Space, and sets them, if any, to out of date
. This means that these objects reload themselves from the database the next time they are accessed and thus have the up-to-date database.
The key is that every session (each client or object space) calls the Notif server every 30 seconds, even if it does not have any dirty
objects to store. This way, changes from other sessions will pass through even if the user or the session is inactive.
Well, the objects are now up-to-date in the Object Space, but how do they get on the user interface (UI)?
When connecting the Object Space to the UI, we follow a pattern that is based on the Model View Controller (MVC) pattern, see e.g. https://de.wikipedia.org/wiki/Model_View_Controller and the following graphic:
We see here that the data in the model (in our case, the objects in the Object Space) are changed by a controller, while the user sees a “View” that updates itself from the model. This “Update” arrow contains the logic that is necessary for the user to notice if something has been changed in the model that was not done directly by him (a side effect of a change made by him, by another user, etc.).
How exactly is this “update” implemented in Vertec?
If you look at the “Update” arrow in the graphic above, it seems simple at first glance. However, values such as a project code can be shown in different locations on the interface. Perhaps there are other values that depend on this value (e.g. the save path of the project, or the contents of the project selection field on a service). So it quickly becomes clear that a “push” mechanism – i.e. if the model were to “push” the data changes forward – quickly reaches its limits. The arrow is therefore to be understood more as an arrow of the data flow direction and not as the direction of the program logic.
We address this problem by using another pattern, namely the “Publish/Subscribe” pattern, here called Subscription. There are many good review articles, see for example https://www.ably.io/concepts/pub-sub.
What does a subscription do? As an example, let’s take something in Vertec that is based on a value of an object, e.g. the field with the code on the project page, the calculation of the save path of the project, or just a project selection field on a service. This element now has the possibility (and in the Vertec context the obligation) to “subscribe” to changes in the underlying value via a complex mechanism – in the example to the code of a project. If this actually changes, then all these subscriptions will “fire,” i.e. the corresponding items will be set to out of date
.
Setting out of date
has no immediate effect, except that the element knows that it is not up-to-date. Now, if someone (the UI directly, a Python script, via COM, XML, etc.) accesses the element, they know that it needs to recalculate and do so before returning its new value and deducting the necessary subscriptions during the recalculation.
This is the basic system. Now a few cases in detail:
Each list contains many OCL expressions, from simple (e.g. code
) to complex (e.g. rechnungen->select(total>0)->size
). The OCL expression automatically drops the necessary subscriptions, so that the whole cell out of date
can be set if something changes to the underlying data. In the first case, the code member on the corresponding project is subscribed. In the second case, the following subscriptions are required: 1. to the invoice list of the project (a new invoice could be added or an existing one could be deleted), 2. to the total of each individual invoice – this is an exciting case, which is described below, because it is a derived attribute, i.e. a calculated attribute (whose calculation also leads to a lot of subscriptions). So you can see that even in simple cases you quickly have a lot of subscriptions.
These are calculated attributes on objects that are not saved in the database, but calculate their values at run time. This is a nice way to encapsulate the business logic (e.g. VAT amount of an invoice). The total in the example above is such an attribute. Since these attributes are calculated only once on the first access, they must subscribe to everything on which the calculation is based. If anything changes in these values, the total out of date
is set, which in turn triggers the subscription in the example above.
If a Derived Attribute does not remove all required subscriptions, and is then no longer up-to-date at some point during the run time, we talk about a Subscription Error. In such a case, you can no longer get the attribute to be recalculated, unless you restart the session. Subscription errors can of course also occur elsewhere, the developer has to pay attention during the implementation to remove all necessary subscriptions.
Operators such as ->getWorktime(from, to) cannot usually drop subscriptions. In many cases this is impossible, e.g. if the date interval is called via a date literal value – no subscription can be dropped on it. With the OCL Call operators it is even more obvious, because the person writing the Python script called by the OCL Call Operator would have to drop all subscriptions, and this is not possible because there is no subscriber in the Python methods.
This means that the results of such features do not “automatically” update. If you want to be sure that you have up-to-date data, you have to call the features again when you use them.