A PDS data entry is defined by a 2-level key and its value. The first level key, called module key, usually describes the environment for which the PDS data is defined. A module key must correspond to an internal application name. The available applications are stored in an internal table. The initial contents of this table is written to 'README.txt' in the user customization directory. The internal application name corresponds to the fourth column. Since a new application can be defined using the Integration Kit an interface is provided to add new entries to the internal application table. The second level key, called property key, identifies the entry within the underlying environment defined by the module key. A property key must be unique within its environment. Both, module and property key, are of type string and are by definition not case sensitive. Typical values for data entries are boolean, strings, numbers, and any kind of lists.
For each module key a separate file is created when Creo Elements/Direct Modeling terminates. PDS file names obey to the common customization file naming conventions. That is, a module key must correspond to an internal application name. The associated PDS file will be written to the corresponding subdirectory in the user customization directory. Its name is composed of the application prefix and the base name "data". Since we write PDS files in LISP format we use the ".lsp" suffix. Assume module key is set to "ANNOTATION" then the PDS file created on system exit will be written to
'<user_cust_dir>/ANNOTATION/am_data.lsp'
When writing a PDS file the former version - if existing - is overwritten.
For programmers functions are available to set, get, and remove data entries from the PDS System.
(sd-set-persistent-data module_key property_key data :subkey subkey :store-flag store-flag)
(sd-set-persistent-data "ALL" ;; module key "UNITS" ;; property key '(:mass (:g 1) ;; data entry :angle (:deg 1) :length (:mm 1)) :store-flag t) ;; store flag (sd-set-persistent-data "ALL" ;; module key "UNITS" ;; property key '(:inch 1) ;; data entry :subkey :length ;; modifies just the subkey :length value :store-flag t) ;; store flag
(sd-get-persistent-data module_key property_key :default default-value :subkey subkey)
(multiple-value-bind (value found) (sd-get-persistent-data "ALL" ;; module key "UNITS" ;; property key :default '(:mass (:g 1) ;; return value when entry not found :angle (:deg 1) :length (:mm 1))) (if found ;; then .... ;; else ....) ) ;; multiple-value-bindor just using the return value no matter if the inquiry was successful or not:
(setf value (sd-get-persistent-data "ALL" ;; module key "UNITS" ;; property key :default '(:mass (:g 1) ;; return value when entry not found :angle (:deg 1) :length (:mm 1)))) (setf value (sd-get-persistent-data "ALL" ;; module key "UNITS" ;; property key :default '(:mm 1) ;; return value when entry not found :subkey :length)) ;; access single entry of PDS value property list
(sd-remove-persistent-data module_key property_key :subkey subkey)
(sd-remove-persistent-data "ALL" ;; module key "UNITS") ;; property key
(sd-subscribe-init-persistent-data function)
(defun init-fun (&rest args) (declare (ignore args)) (multiple-value-bind (pos found) (sd-get-persistent-data "MY-MODULE" "POSITION" :default '(:x 0 :y 0)) ;; do initialization ...) ) ;; defun (sd-subscribe-init-persistent-data #'init-fun)
(sd-unsubscribe-init-persistent-data function)
(sd-unsubscribe-init-persistent-data #'init-fun)
An application needn't to meet special requirements to use the PDS System. Simply set, get, or remove data. What you need to take care on when using PDS is described here.
If your application is not listed in the internal application table you need to add your application data to the table before using the PDS interface. The next example shows how to add the necessary information.
(sd-add-application-data "Annotation" ;; internal application name "ANNOTATION" ;; application subdirectory "am" ;; application prefix "Annotation") ;; product name
There are two ways to check whether your application is element of the internal application table. Either you open the file "README.TXT" which you can find in your user customization directory or for a more programmatic way use the Integration Kit function sd-inq-application-data-p which returns t when your application has been already added.
(sd-inq-application-data "Annotation") ;; internal application name => t
A programmer hasn't to care about loading the PDS System. The PDS interface functions ensure that the addressed PDS file is loaded on first access. That is, for example, the first call to a PDS function with the module key "ANNOTATION" causes the PDS System to load "<user_cust_dir>/ANNOTATION/am_data.lsp".
Usually during module activation global variables are initialized. This might be setting a flag or assigning a property list to the variable. Making such data persistent forces the programmer to slightly change the initialization.
At the best, the variable can be removed from the code. Its value is kept in the PDS System. If the program needs to inquire or set the value it just calls PDS functions. Initialization is done by the PDS System. Typical applications are variables that evaluate to a simple data type (e.g. a number).
Original Code | Replaced by PDS based Code |
---|---|
(defvar *my-variable* ....) |
;; not needed - data kept in PDS |
(setq .... *my-variable*) |
(sd-get-persistent-data "MY-MODULE" "PROPERTY" :default ...) |
(setq *my-variable* ...) |
(sd-set-persistent-data "MY-MODULE" "PROPERTY" ...) |
Maybe there are reasons to preserve the existence of the global variable.
In this case a programmer should provide an initialization function which
can be added to the subscription list of the PDS initialization (see
here for an
example).
There is a scenario when the contents of the PDS System changes. If a user
loads a session file the PDS System is re-initialized. All initialization
functions subscribed to the PDS System are called. This ensures that the
global variable is updated as well. Removing the initialization function
from the subscription list prevents the PDS System from updating a global
variable. A programmer needs to decide which approach to prefer.
There are two cases we need to regard when setting a data entry. In the first case we add to or - if the entry already exists - we replace data in the PDS System.
(sd-set-persistent-data "MY-MODULE" "MY-KEY" 4711)
There is no need to care about the old entry. Thus let's move directly to the second case. Assume we need to modify an existing entry which identifies a property list. We only want to change parts of these properties. In this case we need to inquire the data entry first. Second, apply the changes and, third, bring the entry back to the repository which replaces the old entry.
(multiple-value-bind (entry found) ;; inquire existing entry - this call fills 'entry' and 'found' (sd-get-persistent-data "MY-MODULE" "MY-KEY") (if found ;; then - replace value (setf (getf entry :x) x_value) ;; else - new entry (setf entry `(:x ,x_value :y 100)) ) ;; if (sd-set-persistent-data "MY-MODULE" "MY-KEY" entry))
A good programming style is to provide a set (and of course a get) function to access a global variable. Prepared with such an infrastructure, making data persistent is just one step forward.
(defvar *my-property-list* ...) (defun set-value (keywd value) (setf (getf keywd *my-property-list*) value) (sd-set-persistent-data "MY-MODULE" "MY-KEY" *my-property-list*))
As mentioned in the previous paragraph, providing a get function is a good style. It makes it easy to exchange the source of data without touching other code statements.
;;(defvar *my-variable* '(:x 10 :y 10)) (defun get-my-variable (&optional (keywd nil keywd-p)) (let ((data (sd-get-persistent-data "MY-MODULE" "MY-KEY" :default '(:x 10 :y 10)))) (if keywd-p ;; then (getf data keywd) ;; else data)))
Removing a data entry is not that difficult. It's just a call like the following one.
(sd-remove-persistent-data "MY-MODULE" "MY-KEY")
But removing a data entry when setting is expected makes this topic more interesting. Assume a persistent data is changed. This implicates that the new value is set in the PDS System. But is it set in any case? No. Usually for each data a default value is defined. If changing the data back to its default value the corresponding setting function may simply remove the entry from the PDS System.
(defun get-value () (sd-get-persistent-data "MY-MODULE" "MY-KEY" :default 4711)) (defun set-value (value) (if (= value 4711) ;; then (sd-remove-persistent-data "MY-MODULE" "MY-KEY") ;; else (sd-set-persistent-data "MY-MODULE" "MY-KEY" value)))
If the data is a property list, of course, this function gets more complex. But it is always a good style to remove an entry from the PDS System when the entry contains the default value.
Saving the PDS System to the file system - to the user customization directory - is accomplished automatically on system exit. A programmer has not to care about saving PDS.
© 2023 Parametric
Technology GmbH (a subsidiary of PTC Inc.), All Rights Reserved |