source: branches/new-datamodel/src/json/json_tmcl_validation.lisp

Last change on this file was 307, checked in by lgiessmann, 14 years ago

new-datamodel: adapted some functions of the rest-interface to the new datamodel, so it is possible to read fragments

File size: 22.9 KB
Line 
1;;+-----------------------------------------------------------------------------
2;;+  Isidorus
3;;+  (c) 2008-2009 Marc Kuester, Christoph Ludwig, Lukas Giessmann
4;;+
5;;+  Isidorus is freely distributable under the LGPL license.
6;;+  You can find a detailed description in trunk/docs/LGPL-LICENSE.txt.
7;;+-----------------------------------------------------------------------------
8
9
10(defpackage :json-tmcl
11  (:use :cl :datamodel :constants :json-tmcl-constants)
12  (:export :get-constraints-of-fragment
13           :topictype-p
14           :abstract-p
15           :valid-instance-p
16           :list-subtypes))
17
18
19(in-package :json-tmcl)
20
21
22(defun abstract-p (topic-instance &key (revision *TM-REVISION*))
23  "Returns t if this topic type is an abstract topic type."
24  (declare (type (or integer null) revision)
25           (TopicC topic-instance))
26  (let ((constraint-role (get-item-by-psi *constraint-role-psi* :revision revision))
27        (topictype-role (get-item-by-psi *topictype-role-psi* :revision revision))
28        (applies-to (get-item-by-psi *applies-to-psi* :revision revision))
29        (abstract-topictype-constraint
30         (get-item-by-psi *abstract-topictype-constraint-psi* :revision revision)))
31    (loop for role in (player-in-roles topic-instance :revision revision)
32       when (and (eq topictype-role (instance-of role :revision revision))
33                 (eq applies-to (instance-of (parent role :revision revision)
34                                             :revision revision)))
35       return (loop for other-role in (roles (parent role :revision revision)
36                                             :revision revision)
37                 when (and (eq constraint-role (instance-of other-role
38                                                            :revision revision))
39                           (topictype-of-p (player other-role :revision revision)
40                                           abstract-topictype-constraint nil nil
41                                           nil revision))
42                 return t))))
43
44
45(defun topictype-of-p (topic-instance type-instance &optional
46                       (topictype (get-item-by-psi *topictype-psi* :revision 0))
47                       (topictype-constraint (is-type-constrained :revision 0))
48                       checked-topics (revision *TM-REVISION*))
49  "Returns a list of all types and supertypes of this topic if this topic is a
50   valid instance-topic of the type-topic called type-instance. TMCL 4.4.2.
51   When the type-instance is set to nil there will be checked only if the
52   topic-instance is a valid instance."
53  (declare (type (or integer null) revision)
54           (TopicC topic-instance)
55           (type (or TopicC null) topictype-constraint)
56           (list checked-topics))
57  (let ((current-checked-topics (append checked-topics (list topic-instance)))
58        (isas-of-this (get-direct-types-of-topic topic-instance :revision revision))
59        (akos-of-this (get-direct-supertypes-of-topic topic-instance
60                                                      :revision revision)))
61    (when (eq topic-instance topictype)
62      t)
63    (when (and (not isas-of-this)
64               (not akos-of-this))
65      (return-from topictype-of-p nil))
66    (loop for isa-of-this in isas-of-this
67       do (let ((found-topics
68                 (topictype-p isa-of-this topictype topictype-constraint nil revision)))
69            (when (not found-topics)
70              (return-from topictype-of-p nil))
71            (dolist (item found-topics)
72              (pushnew item current-checked-topics))))
73    (loop for ako-of-this in akos-of-this
74       when (not (find ako-of-this current-checked-topics :test #'eq))
75       do (let ((found-topics
76                 (topictype-of-p ako-of-this type-instance topictype
77                                 topictype-constraint current-checked-topics
78                                 revision)))
79            (when (not found-topics)
80              (return-from topictype-of-p nil))
81            (dolist (item found-topics)
82              (pushnew item current-checked-topics))))
83    (if type-instance
84        (when (find type-instance current-checked-topics)
85          current-checked-topics)
86        current-checked-topics)))
87
88
89(defun topictype-p (topic-instance &optional
90                    (topictype (get-item-by-psi *topictype-psi* :revision 0))
91                    (topictype-constraint (is-type-constrained :revision 0))
92                    (checked-topics nil) (revision *TM-REVISION*))
93  "Returns a list of all instanceOf-topics and all Supertypes of this topic
94   if this topic is a valid topic (-type). I.e. the passed topic is the
95   topictype or it is an instanceOf of the topictype or it is a subtype of
96   the topictype. TMDM 7.2 + TMDM 7.3"
97  (declare (type (or integer null) revision)
98           (type (or TopicC null) topictype topic-instance)
99           (list checked-topics))
100  (let ((current-checked-topics (append checked-topics (list topic-instance)))
101        (akos-of-this (get-direct-supertypes-of-topic topic-instance
102                                                      :revision revision))
103        (isas-of-this (get-direct-types-of-topic topic-instance :revision revision)))
104    (when (eq topictype topic-instance)
105      (return-from topictype-p current-checked-topics))
106    (when (not (union akos-of-this isas-of-this :test #'eq))
107      (when topictype-constraint
108        (error "~a is not a valid type for ~a"
109               (uri (first (psis topic-instance :revision revision)))
110               (uri (first (psis topictype :revision revision)))))
111      (return-from topictype-p current-checked-topics))
112    (let ((akos-are-topictype nil))
113      (loop for ako-of-this in akos-of-this
114         when (not (find ako-of-this current-checked-topics))
115         do (let ((further-topics
116                   (topictype-p ako-of-this topictype topictype-constraint
117                                nil revision)))
118              (if further-topics
119                  (progn
120                    (dolist (item further-topics)
121                      (pushnew item current-checked-topics))
122                    (pushnew ako-of-this akos-are-topictype))
123                  (when topictype-constraint
124                    (error "~a is not a valid type for ~a"
125                           (uri (first (psis topic-instance :revision revision)))
126                           (uri (first (psis topictype :revision revision))))))))
127      (when isas-of-this
128        (let ((topictype-topics-of-isas nil))
129          (loop for isa-of-this in isas-of-this
130             do (let ((topic-akos (subtype-p isa-of-this topictype nil revision)))
131                  (when topic-akos
132                    (pushnew isa-of-this topictype-topics-of-isas)
133                    (pushnew isa-of-this current-checked-topics)
134                    (dolist (item topic-akos)
135                      (pushnew item current-checked-topics)))))
136          (when (and (not topictype-topics-of-isas)
137                     (not akos-are-topictype)
138                     topictype-constraint)
139            (error "~a is not a valid type for ~a"
140                   (uri (first (psis topic-instance :revision revision)))
141                   (uri (first (psis topictype :revision revision)))))
142          (loop for isa-of-this in isas-of-this
143             when (and (not (find isa-of-this current-checked-topics :test #'eq))
144                       (not (find isa-of-this topictype-topics-of-isas :test #'eq)))
145             do (let ((further-topic-types
146                       (topictype-p isa-of-this topictype topictype-constraint
147                                    current-checked-topics revision)))
148                  (if further-topic-types
149                      (dolist (item further-topic-types)
150                        (pushnew item current-checked-topics))
151                      (when topictype-constraint
152                        (error "~a is not a valid type for ~a"
153                               (uri (first (psis topic-instance :revision revision)))
154                               (uri (first (psis topictype :revision revision)))))))))))
155    current-checked-topics))
156
157
158(defun subtype-p (topic-instance &optional
159                  (topictype (get-item-by-psi *topictype-psi* :revision 0))
160                  (checked-topics nil) (revision *TM-REVISION*))
161  "Returns a list of all supertypes of the passed topic if the passed topic
162   is not an instanceOf any other topic but a subtype of some supertypes
163   of a topictype or it is the topictype-topic itself.
164   This function isn't useable as a standalone function - it's only necessary
165   for a special case in the function topictype-p."
166  (declare (type (or integer null) revision)
167           (TopicC topic-instance)
168           (type (or TopicC null) topictype)
169           (list checked-topics))
170  (let ((current-checked-topics
171         (remove-duplicates (append checked-topics (list topic-instance)))))
172    (when (eq topictype topic-instance)
173      (return-from subtype-p current-checked-topics))
174    (when (get-direct-types-of-topic topic-instance :revision revision)
175      (return-from subtype-p nil))
176    (let ((supertypes-of-this
177           (get-direct-supertypes-of-topic topic-instance :revision revision)))
178      (when (not supertypes-of-this)
179        (return-from subtype-p nil))
180      (when supertypes-of-this
181        (loop for supertype-of-this in supertypes-of-this
182           when (not (find supertype-of-this current-checked-topics :test #'eq))
183           do (let ((further-supertypes
184                     (subtype-p topictype supertype-of-this current-checked-topics
185                                revision)))
186                (when (not further-supertypes)
187                  (return-from subtype-p nil))
188                (dolist (item further-supertypes)
189                  (pushnew item current-checked-topics))))))
190    current-checked-topics))
191
192
193(defun get-direct-types-of-topic(topic-instance &key (revision *TM-REVISION*))
194  "Returns the direct types of the topic as a list passed to this function.
195   This function only returns the types of the type-instance-relationship -> TMDM 7.2
196   This function was defined for the use in topictype-p and not for a standalone
197   usage."
198  (declare (type (or integer null) revision)
199           (TopicC topic-instance))
200  (let ((type-instance (get-item-by-psi *type-instance-psi* :revision revision))
201        (instance (get-item-by-psi *instance-psi* :revision revision))
202        (type (get-item-by-psi *type-psi* :revision revision)))
203    (let ((topic-types
204           (loop for role in (player-in-roles topic-instance :revision revision)
205              when (eq instance (instance-of role :revision revision))
206              collect (loop for other-role in
207                           (roles (parent role :revision revision) :revision revision)
208                         when (and (not (eq role other-role))
209                                   (eq type-instance (instance-of
210                                                      (parent role :revision revision)
211                                                      :revision revision))
212                                   (eq type (instance-of other-role
213                                                         :revision revision)))
214                         return (player other-role :revision revision)))))
215      (when topic-types
216        (remove-if #'null topic-types)))))
217
218
219(defun get-direct-instances-of-topic(topic-instance &key (revision *TM-REVISION*))
220  "Returns the direct instances of the topic as a list.
221   This function only returns the types of the type-instance-relationship -> TMDM 7.2
222   This function was defined for the use in topictype-p and not for a standalone
223   usage."
224  (declare (type (or integer null) revision)
225           (TopicC topic-instance))
226  (let ((type-instance (get-item-by-psi *type-instance-psi* :revision revision))
227        (instance (get-item-by-psi *instance-psi* :revision revision))
228        (type (get-item-by-psi *type-psi* :revision revision)))
229    (let ((topic-instances
230           (loop for role in (player-in-roles topic-instance :revision revision)
231              when (eq type (instance-of role :revision revision))
232              collect (loop for other-role in (roles (parent role :revision revision)
233                                                     :revision revision)
234                         when (and (not (eq role other-role))
235                                   (eq type-instance
236                                       (instance-of (parent role :revision revision)
237                                                    :revision revision))
238                                   (eq instance (instance-of other-role
239                                                             :revision revision)))
240                         return (player other-role :revision revision)))))
241      (when topic-instances
242        (remove-if #'null topic-instances)))))
243
244
245(defun get-direct-supertypes-of-topic(topic-instance &key (revision *TM-REVISION*))
246  "Returns the direct supertypes of the topic as a list passed to this function.
247   This function only returns the types of the supertype-subtype-relationship -> TMDM 7.3.
248   This function was defined for the use in topictype-p and not for a standalone
249   usage."
250  (declare (type (or integer null) revision)
251           (TopicC topic-instance))
252  (let ((supertype-subtype (get-item-by-psi *supertype-subtype-psi* :revision revision))
253        (supertype (get-item-by-psi *supertype-psi* :revision revision))
254        (subtype (get-item-by-psi *subtype-psi* :revision revision)))
255    (let ((supertypes
256           (loop for role in (player-in-roles topic-instance :revision revision)
257              when (eq subtype (instance-of role :revision revision))
258              append (loop for other-role in (roles (parent role :revision revision)
259                                                    :revision revision)
260                         when (and (not (eq role other-role))
261                                   (eq supertype-subtype
262                                       (instance-of (parent role :revision revision)
263                                                    :revision revision))
264                                   (eq supertype
265                                       (instance-of other-role :revision revision)))
266                         collect (player other-role)))))
267      (when supertypes
268        (remove-if #'null supertypes)))))
269
270
271(defun get-direct-subtypes-of-topic(topic-instance &key (revision *TM-REVISION*))
272  "Returns the direct subtypes of the topic as a list.
273   This function only returns the types of the supertype-subtype-relationship
274   -> TMDM 7.3.
275   This function was defined for the use in topictype-p and not for a standalone
276   usage."
277  (declare (type (or integer null) revision)
278           (TopicC topic-instance))
279  (let ((supertype-subtype (get-item-by-psi *supertype-subtype-psi* :revision revision))
280        (supertype (get-item-by-psi *supertype-psi* :revision revision))
281        (subtype (get-item-by-psi *subtype-psi* :revision revision)))
282    (let ((subtypes
283           (loop for role in (player-in-roles topic-instance :revision revision)
284              when (eq supertype (instance-of role :revision revision))
285              append (loop for other-role in (roles (parent role :revision revision)
286                                                    :revision revision)
287                         when (and (not (eq role other-role))
288                                   (eq supertype-subtype
289                                       (instance-of (parent role :revision revision)
290                                                    :revision revision))
291                                   (eq subtype (instance-of other-role
292                                                            :revision revision)))
293                         collect (player other-role :revision revision)))))
294      (when subtypes
295        (remove-if #'null subtypes)))))
296
297
298(defun list-subtypes (topic-instance &optional
299                      (topictype (get-item-by-psi *topictype-psi* :revision 0))
300                      (topictype-constraint (is-type-constrained :revision 0))
301                      (checked-topics nil) (valid-subtypes nil)
302                      (revision *TM-REVISION*))
303  "Returns all valid subtypes of a topic, e.g.:
304   nametype-constraint ako constraint .
305   first-name isa nametype .
306   first-name-1 ako first-name .
307   // ...
308   The return value is a named list of the form (:subtypes (<topic> <...>)
309   :checked-topics (<topic> <...>)"
310  (let ((current-checked-topics (append checked-topics (list topic-instance))))
311    (handler-case (topictype-p topic-instance topictype topictype-constraint
312                               nil revision)
313      (condition () (return-from list-subtypes
314                      (list :subtypes nil :checked-topics current-checked-topics))))
315    (let ((subtype (get-item-by-psi *subtype-psi* :revision revision))
316          (supertype (get-item-by-psi *supertype-psi* :revision revision))
317          (supertype-subtype (get-item-by-psi *supertype-subtype-psi*
318                                              :revision revision))
319          (current-valid-subtypes (append valid-subtypes (list topic-instance))))
320      (loop for role in (player-in-roles topic-instance :revision revision)
321         when (and (eq supertype (instance-of role :revision revision))
322                   (eq supertype-subtype
323                       (instance-of (parent role :revision revision)
324                                    :revision revision)))
325         do (loop for other-role in (roles (parent role :revision revision)
326                                           :revision revision)
327               do (when (and (eq subtype (instance-of other-role :revision revision))
328                             (not (find (player other-role :revision revision)
329                                        current-checked-topics)))
330                    (let ((new-values
331                           (list-subtypes (player other-role :revision revision)
332                                          topictype topictype-constraint
333                                          current-checked-topics
334                                          current-valid-subtypes revision)))
335                      (dolist (item (getf new-values :subtypes))
336                        (pushnew item current-valid-subtypes))
337                      (dolist (item (getf new-values :checked-topics))
338                        (pushnew item current-checked-topics))))))
339      (list :subtypes current-valid-subtypes :checked-topics current-checked-topics))))
340
341
342(defun list-instances (topic-instance &optional
343                       (topictype (get-item-by-psi *topictype-psi* :revision 0))
344                       (topictype-constraint (is-type-constrained :revision 0))
345                       (revision *TM-REVISION*))
346  "Returns the topic-instance, all subtypes found by the function list-subtypes
347   and all direct instances for the found subtypes."
348  (let ((all-subtypes-of-this
349         (getf (list-subtypes topic-instance topictype topictype-constraint
350                              nil nil revision)
351               :subtypes))
352        (type (get-item-by-psi *type-psi* :revision revision))
353        (instance (get-item-by-psi *instance-psi* :revision revision))
354        (type-instance (get-item-by-psi *type-instance-psi* :revision revision)))
355    (let ((all-instances-of-this
356           (remove-duplicates
357            (loop for subtype-of-this in all-subtypes-of-this
358               append (loop for role in (player-in-roles subtype-of-this
359                                                         :revision revision)
360                         when (and (eq type (instance-of role :revision revision))
361                                   (eq type-instance
362                                       (instance-of (parent role :revision revision)
363                                                    :revision revision)))
364                         append (loop for other-role in
365                                     (roles (parent role :revision revision)
366                                            :revision revision)
367                                   when (eq instance (instance-of other-role
368                                                                  :revision revision))
369                                   collect (player other-role :revision revision)))))))
370      (let ((all-subtypes-of-all-instances
371             (remove-if #'null
372                        (remove-duplicates
373                         (loop for subtype in all-instances-of-this
374                            append (getf
375                                    (list-subtypes subtype topictype
376                                                   nil nil nil revision)
377                                    :subtypes))))))
378        (union all-instances-of-this 
379               (remove-if #'null
380                          (map 'list #'(lambda(x)
381                                         (handler-case (progn
382                                                         (topictype-of-p x nil nil nil
383                                                                         nil revision)
384                                                         x)
385                                           (condition () nil)))
386                               all-subtypes-of-all-instances)))))))
387
388
389(defun valid-instance-p (topic-instance &optional
390                         (akos-checked nil) (all-checked-topics nil)
391                         (revision *TM-REVISION*))
392  "Returns a list of all checked topics or throws an exception if the given
393   topic is not a valid instance of any topictype in elephant."
394  (declare (type (or integer null) revision)
395           (TopicC topic-instance)
396           (list akos-checked all-checked-topics))
397  (let ((isas-of-this
398         (get-direct-types-of-topic topic-instance :revision revision))
399        (akos-of-this
400         (get-direct-supertypes-of-topic topic-instance :revision revision))
401        (psi-of-this (uri (first (psis topic-instance :revision revision))))
402        (topictype (get-item-by-psi *topictype-psi* :revision revision))
403        (topictype-constraint (is-type-constrained :revision revision))
404        (local-all-checked-topics all-checked-topics)
405        (local-akos-checked))
406    (when (not topictype-constraint)
407      (return-from valid-instance-p (list topic-instance)))
408    (when (and topictype-constraint
409               (not topictype))
410      (error "From valid-instance-p(): The topic \"~a\" does not exist - please create it or remove the topic \"~a\""
411             *topictype-psi*
412             (uri (first (psis topictype-constraint :revision revision)))))
413    (when (eql topic-instance topictype)
414      (return-from valid-instance-p
415        (remove-duplicates (append all-checked-topics (list topic-instance)))))
416    (unless (or isas-of-this akos-of-this)
417      (error "The topic \"~a\" is not a valid topic-instance for any topic-type"
418              psi-of-this))
419    (when (find topic-instance akos-checked)
420      (return-from valid-instance-p all-checked-topics))
421    (pushnew topic-instance local-all-checked-topics)
422    (pushnew topic-instance local-akos-checked)
423    (dolist (isa isas-of-this)
424      (handler-case (let ((topics
425                           (topictype-p isa topictype topictype-constraint
426                                        nil revision)))
427                      (dolist (top topics)
428                        (pushnew top local-all-checked-topics)))
429        (condition (err) (error "The topic \"~a\" is not a valid topic-instance for any topic-type~%~%~a"
430                                psi-of-this err))))
431
432    (dolist (ako akos-of-this)
433      (when (not (handler-case
434                     (let ((topics
435                            (topictype-p ako topictype topictype-constraint
436                                         all-checked-topics revision)))
437                                 (dolist (top topics)
438                                   (pushnew top local-all-checked-topics))
439                                 (pushnew ako local-akos-checked)
440                                 topics)
441                   (condition () nil)))
442        (handler-case 
443            (let ((topics
444                   (valid-instance-p ako akos-checked (append all-checked-topics
445                                                              (list ako)) revision)))
446                        (dolist (top topics)
447                          (pushnew top local-all-checked-topics)
448                          (pushnew top local-akos-checked))
449                        topics)
450          (condition (err) (error "The topic \"~a\" is not a valid topic-instance for any topic-type~%~%~a"
451                                  psi-of-this err)))))
452    local-all-checked-topics))
453
454
455(defun return-all-tmcl-types (&key (revision *TM-REVISION*))
456  "Returns all topics that are valid tmcl-types"
457  (declare (type (or integer null) revision))
458  (let ((all-topics (get-all-topics revision))
459        (topictype (get-item-by-psi json-tmcl-constants::*topictype-psi*
460                                    :revision revision))
461        (topictype-constraint (is-type-constrained :revision revision)))
462    (let ((all-types
463           (remove-if
464            #'null
465            (map 'list #'(lambda(x)
466                           (handler-case
467                               (progn
468                                 (topictype-p x topictype topictype-constraint
469                                              nil revision)
470                                 x)
471                             (condition () nil))) all-topics))))
472      (let ((not-abstract-types
473             (remove-if #'null
474                        (map 'list #'(lambda(x)
475                                       (unless (abstract-p x :revision revision)
476                                         x))
477                             all-types))))
478        not-abstract-types))))
479
480
481(defun return-all-tmcl-instances (&key (revision *TM-REVISION*))
482  "Returns all topics that are valid instances of any topic type.
483   The validity is only oriented on the typing of topics, e.g.
484   type-instance or supertype-subtype."
485  (declare (type (or integer null) revision))
486  (let ((all-topics (get-all-topics revision)))
487    (let ((valid-instances
488           (remove-if
489            #'null
490            (map 'list #'(lambda(x)
491                           (handler-case (progn
492                                           (valid-instance-p x nil nil revision)
493                                           x)
494                             (condition () nil))) all-topics))))
495      valid-instances)))
496
497
498(defun is-type-constrained (&key (what *topictype-constraint-psi*)
499                            (revision *TM-REVISION*))
500  "Returns nil if there is no type-constraint otherwise the instance of
501   the type-constraint."
502  (declare (string what)
503           (type (or integer null) revision))
504  (let ((topictype-constraint (get-item-by-psi what :revision revision)))
505    (when topictype-constraint
506      (let ((ttc
507             (remove-duplicates
508              (remove-if
509               #'null
510               (remove-if #'(lambda(x) (when (eql topictype-constraint x)
511                                         t))
512                          (get-direct-instances-of-topic topictype-constraint
513                                                         :revision revision))))))
514        ttc))))
515
516
517(defun list-all-supertypes (topic-instance &optional (checked-topics nil)
518                            (revision *TM-REVISION*))
519  "Returns all supertypes of the given topic recursively."
520  (declare (type (or integer null) revision)
521           (TopicC topic-instance)
522           (list checked-topics))
523  (let ((current-checked-topics (append checked-topics (list topic-instance)))
524        (akos-of-this (get-direct-supertypes-of-topic topic-instance
525                                                      :revision revision)))
526    (dolist (ako-of-this akos-of-this)
527      (when (not (find ako-of-this current-checked-topics))
528        (let ((new-checked-topics
529               (list-all-supertypes ako-of-this current-checked-topics revision)))
530          (dolist (new-topic new-checked-topics)
531            (pushnew new-topic current-checked-topics)))))
532    current-checked-topics))
533
534
535(defun get-all-upper-constrainted-topics (topic &key (revision *TM-REVISION*))
536  "Returns all topics that are supertypes or direct types
537   of the given topic-type. So all direct constraints of the found
538   topics are valid constraints for the given one."
539  (declare (TopicC topic)
540           (type (or integer null) revision))
541  ;; find all direct types
542  (let ((direct-isas-of-this
543         (get-direct-types-of-topic topic :revision revision)))
544  ;; find all supertypes (recursive -> transitive relationship
545    (let ((all-akos-of-this
546           (list-all-supertypes topic nil revision)))
547      (remove-duplicates (union direct-isas-of-this all-akos-of-this)))))
Note: See TracBrowser for help on using the repository browser.