1/* Part of SWI-Prolog 2 3 Author: Jan Wielemaker 4 E-mail: J.Wielemaker@vu.nl 5 WWW: http://www.swi-prolog.org 6 Copyright (c) 2003-2013, University of Amsterdam 7 VU University Amsterdam 8 All rights reserved. 9 10 Redistribution and use in source and binary forms, with or without 11 modification, are permitted provided that the following conditions 12 are met: 13 14 1. Redistributions of source code must retain the above copyright 15 notice, this list of conditions and the following disclaimer. 16 17 2. Redistributions in binary form must reproduce the above copyright 18 notice, this list of conditions and the following disclaimer in 19 the documentation and/or other materials provided with the 20 distribution. 21 22 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 25 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 26 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 30 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 32 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 POSSIBILITY OF SUCH DAMAGE. 34*/ 35 36:- module(rdf_edit, 37 [ rdfe_assert/3, % Sub, Pred, Obj 38 rdfe_assert/4, % Sub, Pred, Obj, PayLoad 39 rdfe_retractall/3, % Sub, Pred, Obj 40 rdfe_retractall/4, % Sub, Pred, Obj, PayLoad 41 rdfe_update/4, % Sub, Pred, Obj, +Action 42 rdfe_update/5, % Sub, Pred, Obj, +PayLoad, +Action 43 rdfe_load/1, % +File 44 rdfe_load/2, % +File, +Options 45 rdfe_delete/1, % +Resource 46 47 rdfe_register_ns/2, % +Id, +URI 48 rdfe_unregister_ns/2, % +Id, +URI 49 50 rdfe_reset/0, % clear everything 51 52 rdfe_transaction/1, % :Goal 53 rdfe_transaction/2, % :Goal, +Name 54 rdfe_transaction_member/2, % +Transactions, -Action 55 rdfe_transaction_name/2, % +Transactions, -Name 56 rdfe_set_transaction_name/1,% +Name 57 58 rdfe_set_watermark/1, % +Name 59 60 rdfe_undo/0, % 61 rdfe_redo/0, 62 rdfe_can_undo/1, % -TID 63 rdfe_can_redo/1, % -TID 64 65 rdfe_set_file_property/2, % +File, +Property 66 rdfe_get_file_property/2, % ?File, ?Property 67 68 rdfe_is_modified/1, % ?File 69 rdfe_clear_modified/1, % +File 70 71 rdfe_open_journal/2, % +File, +Mode 72 rdfe_close_journal/0, 73 rdfe_replay_journal/1, % +File 74 rdfe_current_journal/1, % -Path 75 76 rdfe_snapshot_file/1 % -File 77 ]). 78:- use_module(library(semweb/rdf_prefixes), 79 [ (rdf_meta)/1, 80 op(_,_,rdf_meta) 81 ]). 82 83:- autoload(rdf_db, 84 [ rdf_assert/4, rdf/4, rdf_retractall/4, rdf_update/4, 85 rdf_update/5, rdf_load/2, rdf_statistics/1, rdf_md5/2, 86 rdf_unload/1, rdf_save_db/2, rdf_load_db/1, rdf_register_ns/2, 87 rdf_source/2, rdf_graph_property/2, rdf_graph/1, rdf_set_graph/2, 88 rdf_reset_db/0, rdf_load/1 89 ]). 90:- autoload(library(broadcast),[broadcast/1]). 91:- use_module(library(debug),[debug/3,debugging/1]). 92:- autoload(library(gui_tracer),[gtrace/0]). 93:- autoload(library(lists),[append/3]). 94:- autoload(library(uri),[uri_file_name/2,uri_components/2,uri_data/3]). 95 96:- meta_predicate 97 rdfe_transaction( ), 98 rdfe_transaction( , ). 99 100:- predicate_options(rdfe_load/2, 2, 101 [pass_to(rdf_db:rdf_load/2, 2)]). 102 103:- dynamic 104 undo_log/5, % TID, Action, Subj, Pred, Obj 105 current_transaction/1, % TID 106 transaction_name/2, % TID, Name 107 undo_marker/2, % Mode, TID 108 journal/3, % Path, Mode, Stream 109 snapshot_file/1. % File
125:- rdf_meta 126 rdfe_assert(r,r,o), 127 rdfe_assert(r,r,o,+), 128 rdfe_retractall(r,r,o), 129 rdfe_update(r,r,o,t), 130 rdfe_delete(r), 131 rdfe_transaction(:), 132 rdfe_transaction(:, +). 133 134 135 /******************************* 136 * BASIC EDIT OPERATIONS * 137 *******************************/ 138 139rdfe_assert(Subject, Predicate, Object) :- 140 rdfe_assert(Subject, Predicate, Object, user). 141 142rdfe_assert(Subject, Predicate, Object, PayLoad) :- 143 rdf_assert(Subject, Predicate, Object, PayLoad), 144 rdfe_current_transaction(TID), 145 assert_action(TID, assert(PayLoad), Subject, Predicate, Object), 146 journal(assert(TID, Subject, Predicate, Object, PayLoad)). 147 148rdfe_retractall(Subject, Predicate, Object) :- 149 rdfe_retractall(Subject, Predicate, Object, _). 150 151rdfe_retractall(Subject, Predicate, Object, PayLoad) :- 152 rdfe_current_transaction(TID), 153 ( rdf(Subject, Predicate, Object, PayLoad), 154 assert_action(TID, retract(PayLoad), Subject, Predicate, Object), 155 journal(retract(TID, Subject, Predicate, Object, PayLoad)), 156 fail 157 ; true 158 ), 159 rdf_retractall(Subject, Predicate, Object, PayLoad).
! subject(+Subject)
! predicate(+Predicate)
! object(+Object)
! source(+Source)
170rdfe_update(Subject, Predicate, Object, Action) :- 171 rdfe_current_transaction(TID), 172 rdf_update(Subject, Predicate, Object, Action), 173 ( Action = object(New) 174 -> assert_action(TID, object(Object), Subject, Predicate, New) 175 ; Action = predicate(New) 176 -> assert_action(TID, predicate(Predicate), Subject, New, Object) 177 ; Action = subject(New) 178 -> assert_action(TID, subject(Subject), New, Predicate, Object) 179 ; Action = source(New) 180 -> forall(rdf(Subject, Predicate, Object, PayLoad), 181 assert_action(TID, source(PayLoad, New), 182 Subject, Predicate, Object)) 183 ), 184 journal(update(TID, Subject, Predicate, Object, Action)). 185 186rdfe_update(Subject, Predicate, Object, PayLoad, Action) :- 187 rdfe_current_transaction(TID), 188 rdf_update(Subject, Predicate, Object, PayLoad, Action), 189 ( Action = source(New) 190 -> assert_action(TID, source(PayLoad, New), 191 Subject, Predicate, Object) 192 ; throw(tbd) % source is used internally 193 ), 194 journal(update(TID, Subject, Predicate, Object, PayLoad, Action)).
202rdfe_delete(Subject) :- 203 rdfe_transaction(delete(Subject)). 204 205delete(Subject) :- 206 rdfe_retractall(Subject, _, _), 207 rdfe_retractall(_, Subject, _), 208 rdfe_retractall(_, _, Subject). 209 210 211 /******************************* 212 * FILE HANDLING * 213 *******************************/
221rdfe_load(File) :- 222 rdfe_load(File, []). 223 224 225rdfe_load(File, Options) :- 226 rdfe_current_transaction(TID), 227 absolute_file_name(File, 228 [ access(read), 229 extensions([rdf,rdfs,owl,ttl,nt,'']) 230 ], Path), 231 rdf_load(Path, 232 [ graph(Graph), 233 modified(Modified) 234 | Options 235 ]), 236 ( Modified == not_modified 237 -> true 238 ; absolute_file_name('.', PWD), 239 size_file(Path, Size), 240 ( Modified = last_modified(Stamp) 241 -> true 242 ; time_file(Path, Stamp) 243 ), 244 SecTime is round(Stamp), 245 rdf_statistics(triples_by_graph(Graph, Triples)), 246 rdf_md5(Graph, MD5), 247 assert_action(TID, load_file(Path), -, -, -), 248 journal(rdf_load(TID, 249 Path, 250 [ pwd(PWD), 251 size(Size), 252 modified(SecTime), 253 triples(Triples), 254 md5(MD5), 255 from(File) 256 ])), 257 ensure_snapshot(Path) 258 ). 259 260 261rdfe_unload(Path) :- 262 rdfe_current_transaction(TID), 263 rdf_unload(Path), 264 assert_action(TID, unload_file(Path), -, -, -), 265 journal(rdf_unload(TID, Path)).
274ensure_snapshot(Path) :- 275 rdfe_current_journal(_), 276 rdf_md5(Path, MD5), 277 ( snapshot_file(Path, MD5, 278 [ access(read), 279 file_errors(fail) 280 ], 281 File) 282 -> debug(snapshot, 'Existing snapshot for ~w on ~w', [Path, File]) 283 ; snapshot_file(Path, MD5, 284 [ access(write) 285 ], 286 File), 287 debug(snapshot, 'Saving snapshot for ~w to ~w', [Path, File]), 288 rdf_save_db(File, Path) 289 ), 290 assert(snapshot_file(File)). 291ensure_snapshot(_).
301load_snapshot(Source, Path) :-
302 statistics(cputime, T0),
303 rdf_load_db(Path),
304 statistics(cputime, T1),
305 Time is T1 - T0,
306 rdf_statistics(triples_by_graph(Source, Triples)),
307 rdf_md5(Source, MD5),
308 % 1e10: modified far in the future
309 assert(rdf_db:rdf_source(Source, 1e12, Triples, MD5)),
310 print_message(informational,
311 rdf(loaded(Source, Triples, snapshot(Time)))),
312 assert(snapshot_file(Path)).
319snapshot_file(Path, MD5, Options, SnapShot) :-
320 file_base_name(Path, Base),
321 atomic_list_concat([Base, @, MD5], File),
322 absolute_file_name(snapshot(File),
323 [ extensions([trp])
324 | Options
325 ],
326 SnapShot).
336rdfe_snapshot_file(File) :- 337 snapshot_file(File). 338 339 340 /******************************* 341 * NAMESPACE HANDLING * 342 *******************************/ 343 344:- dynamic 345 system_ns/2. 346:- volatile 347 system_ns/2.
rdf_register_ns(Id, URI)
353rdfe_register_ns(Id, URI) :- 354 rdf_db:ns(Id, URI), 355 !. 356rdfe_register_ns(Id, URI) :- 357 save_system_ns, 358 rdfe_current_transaction(TID), 359 rdf_register_ns(Id, URI), 360 broadcast(rdf_ns(register(Id, URI))), 361 assert_action(TID, ns(register(Id, URI)), -, -, -), 362 journal(ns(TID, register(Id, URI))). 363 364rdfe_unregister_ns(Id, URI) :- 365 save_system_ns, 366 rdfe_current_transaction(TID), 367 retractall(rdf_db:ns(Id, URI)), 368 broadcast(rdf_ns(unregister(Id, URI))), 369 assert_action(TID, ns(unregister(Id, URI)), -, -, -), 370 journal(ns(TID, unregister(Id, URI))). 371 372% rdfe_register_ns/0 373% 374% Reset namespaces to the state they were before usage of the 375% rdf_edit layer. 376 377rdfe_reset_ns :- 378 ( system_ns(_, _) 379 -> retractall(rdf_db:ns(Id, URI)), 380 forall(system_ns(Id, URI), assert(rdf_db:ns(Id, URI))) 381 ; true 382 ). 383 384save_system_ns :- 385 system_ns(_, _), 386 !. % already done 387save_system_ns :- 388 forall(rdf_db:ns(Id, URI), assert(system_ns(Id, URI))). 389 390 391 /******************************* 392 * TRANSACTIONS * 393 *******************************/
401rdfe_transaction(Goal) :- 402 rdfe_transaction(Goal, []). 403rdfe_transaction(Goal, Name) :- 404 rdfe_begin_transaction(Name), 405 ( catch(Goal, E, true) 406 -> ( var(E) 407 -> check_file_protection(Error), 408 ( var(Error) 409 -> rdfe_commit 410 ; rdfe_rollback, 411 throw(Error) 412 ) 413 ; rdfe_rollback, 414 throw(E) 415 ) 416 ; rdfe_rollback, 417 fail 418 ).
425rdfe_begin_transaction(Name) :- 426 current_transaction(TID), % nested transaction 427 !, 428 append(TID, [1], TID2), 429 asserta(current_transaction(TID2)), 430 assert(transaction_name(TID2, Name)). 431rdfe_begin_transaction(Name) :- % toplevel transaction 432 flag(rdf_edit_tid, TID, TID+1), 433 asserta(current_transaction([TID])), 434 assert(transaction_name(TID, Name)). 435 436rdfe_current_transaction(TID) :- 437 current_transaction(TID), 438 !. 439rdfe_current_transaction(_) :- 440 throw(error(existence_error(rdf_transaction, _), _)). 441 442rdfe_commit :- 443 retract(current_transaction(TID)), 444 !, 445 retractall(undo_marker(_, _)), 446 ( rdfe_transaction_member(TID, _) 447 -> get_time(Time), % transaction is not empty 448 journal(commit(TID, Time)), 449 ( TID = [Id] 450 -> broadcast(rdf_transaction(Id)) 451 ; true 452 ) 453 ; true 454 ). 455 456rdfe_rollback :- 457 retract(current_transaction(TID)), 458 !, 459 journal(rollback(TID)), 460 rollback(TID).
469rollback(TID) :- 470 append(TID, _, Id), 471 ( retract(undo_log(Id, Action, Subject, Predicate, Object)), 472 ( rollback(Action, Subject, Predicate, Object) 473 -> fail 474 ; print_message(error, 475 rdf_undo_failed(undo(Action, Subject, 476 Predicate, Object))), 477 fail 478 ) 479 ; true 480 ). 481 482rollback(assert(PayLoad), Subject, Predicate, Object) :- 483 !, 484 rdf_retractall(Subject, Predicate, Object, PayLoad). 485rollback(retract(PayLoad), Subject, Predicate, Object) :- 486 !, 487 rdf_assert(Subject, Predicate, Object, PayLoad). 488rollback(Action, Subject, Predicate, Object) :- 489 action(Action), 490 !, 491 rdf_update(Subject, Predicate, Object, Action). 492 493 494assert_action(TID, Action, Subject, Predicate, Object) :- 495 asserta(undo_log(TID, Action, Subject, Predicate, Object)).
502undo(TID) :- 503 append(TID, _, Id), 504 ( retract(undo_log(Id, Action, Subject, Predicate, Object)), 505 ( undo(Action, Subject, Predicate, Object) 506 -> fail 507 ; print_message(warning, 508 rdf_undo_failed(undo(Action, Subject, 509 Predicate, Object))), 510 fail 511 ) 512 ; true 513 ). 514 515undo(assert(PayLoad), Subject, Predicate, Object) :- 516 !, 517 rdfe_retractall(Subject, Predicate, Object, PayLoad). 518undo(retract(PayLoad), Subject, Predicate, Object) :- 519 !, 520 rdfe_assert(Subject, Predicate, Object, PayLoad). 521undo(source(Old, New), Subject, Predicate, Object) :- 522 !, 523 rdfe_update(Subject, Predicate, Object, Old, source(New)). 524undo(ns(Action), -, -, -) :- 525 !, 526 ( Action = register(Id, URI) 527 -> rdfe_unregister_ns(Id, URI) 528 ; Action = unregister(Id, URI) 529 -> rdfe_register_ns(Id, URI) 530 ). 531undo(load_file(Path), -, -, -) :- 532 !, 533 rdfe_unload(Path). 534undo(unload_file(Path), -, -, -) :- 535 !, 536 rdfe_load(Path). 537undo(Action, Subject, Predicate, Object) :- 538 action(Action), 539 !, 540 rdfe_update(Subject, Predicate, Object, Action). 541 542action(subject(_)). 543action(predicate(_)). 544action(object(_)).
552rdfe_undo :- 553 undo_marker(undo, TID), 554 !, 555 ( undo_previous(TID, UnDone) 556 -> retractall(undo_marker(_, _)), 557 assert(undo_marker(undo, UnDone)), 558 broadcast(rdf_undo(undo, UnDone)) 559 ; fail % start of undo log 560 ). 561rdfe_undo :- 562 retract(undo_marker(redo, _)), 563 !, 564 last_transaction(TID), 565 undo_previous(TID, UnDone), 566 assert(undo_marker(undo, UnDone)), 567 broadcast(rdf_undo(undo, UnDone)). 568rdfe_undo :- 569 last_transaction(TID), 570 undo_previous(TID, UnDone), 571 assert(undo_marker(undo, UnDone)), 572 broadcast(rdf_undo(undo, UnDone)). 573 574find_previous_undo(-1, _) :- 575 !, 576 fail. 577find_previous_undo(TID, TID) :- 578 undo_log([TID|_], _, _, _, _), 579 !. 580find_previous_undo(TID0, TID) :- 581 TID1 is TID0 - 1, 582 find_previous_undo(TID1, TID). 583 584undo_previous(TID, Undone) :- 585 find_previous_undo(TID, Undone), 586 rdfe_transaction(undo([Undone])). 587 588last_transaction(TID) :- 589 undo_log([TID|_], _, _, _, _), 590 !.
596rdfe_redo :-
597 ( retract(undo_marker(undo, _))
598 -> last_transaction(TID),
599 undo_previous(TID, UnDone),
600 assert(undo_marker(redo, UnDone)),
601 broadcast(rdf_undo(redo, UnDone))
602 ; retract(undo_marker(redo, TID))
603 -> undo_previous(TID, UnDone),
604 assert(undo_marker(redo, UnDone)),
605 broadcast(rdf_undo(redo, UnDone))
606 ; true
607 ).
617rdfe_can_redo(Redo) :- 618 undo_marker(undo, _), 619 !, 620 last_transaction(TID), 621 find_previous_undo(TID, Redo). 622rdfe_can_redo(Redo) :- 623 undo_marker(redo, TID), 624 find_previous_undo(TID, Redo). 625 626rdfe_can_undo(Undo) :- % continue undo 627 undo_marker(undo, TID), 628 !, 629 find_previous_undo(TID, Undo). 630rdfe_can_undo(Undo) :- % start undo 631 last_transaction(TID), 632 find_previous_undo(TID, Undo).
638rdfe_transaction_name(TID, Name) :-
639 transaction_name(TID, Name),
640 Name \== [].
646rdfe_set_transaction_name(Name) :-
647 current_transaction(TID),
648 !,
649 assert(transaction_name(TID, Name)).
656rdfe_transaction_member(TID, Member) :- 657 ( integer(TID) 658 -> Id = [TID|_] 659 ; append(TID, _, Id) 660 ), 661 undo_log(Id, Action, Subject, Predicate, Object), 662 user_transaction_member(Action, Subject, Predicate, Object, Member). 663 664user_transaction_member(assert(_), Subject, Predicate, Object, 665 assert(Subject, Predicate, Object)) :- !. 666user_transaction_member(retract(_), Subject, Predicate, Object, 667 retract(Subject, Predicate, Object)) :- !. 668user_transaction_member(load_file(Path), -, -, -, 669 file(load(Path))) :- !. 670user_transaction_member(unload_file(Path), -, -, -, 671 file(unload(Path))) :- !. 672user_transaction_member(Update, Subject, Predicate, Object, 673 update(Subject, Predicate, Object, Update)). 674 675 676 /******************************* 677 * PROTECTION * 678 *******************************/ 679 680:- dynamic 681 rdf_source_permission/2, % file, ro/rw 682 rdf_current_default_file/2. % file, all/fallback
access(ro/rw)
default(all/fallback)
691rdfe_set_file_property(File, access(Access)) :- 692 !, 693 to_uri(File, URL), 694 retractall(rdf_source_permission(URL, _)), 695 assert(rdf_source_permission(URL, Access)), 696 broadcast(rdf_file_property(URL, access(Access))). 697rdfe_set_file_property(File, default(Type)) :- 698 to_uri(File, URL), 699 rdfe_set_file_property(URL, access(rw)), % must be writeable 700 retractall(rdf_current_default_file(_,_)), 701 assert(rdf_current_default_file(URL, Type)), 702 broadcast(rdf_file_property(URL, default(Type))).
710rdfe_get_file_property(FileOrURL, access(Access)) :- 711 ( ground(FileOrURL) 712 -> to_uri(FileOrURL, URL) 713 ; rdf_source(_DB, URL), 714 FileOrURL = URL 715 ), 716 ( rdf_source_permission(URL, Access0) 717 -> Access0 = Access 718 ; uri_file_name(URL, File), 719 access_file(File, write) 720 -> assert(rdf_source_permission(URL, rw)), 721 Access = rw 722 ; assert(rdf_source_permission(URL, ro)), 723 Access = ro 724 ). 725rdfe_get_file_property(FileOrURL, default(Default)) :- 726 ground(FileOrURL), 727 to_uri(FileOrURL, URL), 728 ( rdf_current_default_file(URL, Default) 729 -> true 730 ; FileOrURL = user, 731 Default = fallback 732 ). 733rdfe_get_file_property(URL, default(Default)) :- 734 ( rdf_current_default_file(URL, Default) 735 -> true 736 ; URL = user, 737 Default = fallback 738 ).
745check_file_protection(Error) :-
746 ( rdfe_get_file_property(File, access(ro)),
747 rdfe_is_modified(File)
748 -> Error = error(permission_error(modify, source, File), triple20)
749 ; true
750 ).
757to_uri(URL, URL) :- 758 uri_components(URL, Components), 759 uri_data(scheme, Components, Scheme), 760 nonvar(Scheme), 761 uri_scheme(Scheme), 762 !. 763to_uri(File, URL) :- 764 uri_file_name(URL, File). 765 766 767uri_scheme(file). 768uri_scheme(http). 769uri_scheme(https). 770uri_scheme(ftp). 771uri_scheme(ftps). 772 773 774 /******************************* 775 * MODIFIED * 776 *******************************/
783rdfe_is_modified(Source) :- 784 rdf_source(Graph, Source), 785 rdf_graph_property(Graph, modified(true)). 786 787 788rdfe_clear_modified :- 789 forall(rdf_graph(File), 790 rdfe_clear_modified(File)).
796rdfe_clear_modified(Graph) :- 797 rdf_set_graph(Graph, modified(false)). 798 799 800 /******************************* 801 * WATERMARKS * 802 *******************************/
809rdfe_set_watermark(Name) :- 810 rdfe_current_transaction(TID), 811 assert_action(TID, watermark(Name), -, -, -), 812 journal(watermark(TID, Name)). 813 814 815 /******************************* 816 * RESET * 817 *******************************/
823rdfe_reset :-
824 rdfe_reset_journal,
825 rdfe_reset_ns,
826 rdfe_reset_undo,
827 rdf_reset_db,
828 broadcast(rdf_reset).
834rdfe_reset_journal :- 835 ( rdfe_current_journal(_) 836 -> rdfe_close_journal 837 ; true 838 ). 839 840rdfe_reset_undo :- 841 retractall(undo_log(_,_,_,_,_)), 842 retractall(current_transaction(_)), 843 retractall(transaction_name(_,_)), 844 retractall(undo_marker(_,_)), 845 retractall(snapshot_file(_)). 846 847% close possible open journal at exit. Using a Prolog hook 848% guarantees closure, even for most crashes. 849 850:- at_halt(rdfe_reset_journal). 851 852 853 /******************************* 854 * JOURNALLING * 855 *******************************/ 856 857journal_version(1).
873rdfe_open_journal(_, _) :- % already open 874 journal(_, _, _), 875 !. 876rdfe_open_journal(File, read) :- 877 !, 878 absolute_file_name(File, 879 [ extensions([rdfj, '']), 880 access(read) 881 ], 882 Path), 883 rdfe_replay_journal(Path), 884 rdfe_clear_modified. 885rdfe_open_journal(File, write) :- 886 !, 887 absolute_file_name(File, 888 [ extensions([rdfj, '']), 889 access(write) 890 ], 891 Path), 892 open(Path, write, Stream, [close_on_abort(false)]), 893 assert(journal(Path, write, Stream)), 894 get_time(T), 895 journal_open(start, T). 896rdfe_open_journal(File, append) :- 897 working_directory(CWD, CWD), 898 absolute_file_name(File, 899 [ extensions([rdfj, '']), 900 relative_to(CWD), 901 access(write) 902 ], 903 Path), 904 ( exists_file(Path) 905 -> rdfe_replay_journal(Path), 906 rdfe_clear_modified, 907 get_time(T), 908 assert(journal(Path, append(T), [])) 909 ; rdfe_open_journal(Path, write) 910 ). 911 912 913journal_open(Type, Time) :- 914 journal_comment(Type, Time), 915 SecTime is round(Time), 916 journal_version(Version), 917 Start =.. [ Type, [ time(SecTime), 918 version(Version) 919 ] 920 ], 921 journal(Start), 922 broadcast(rdf_journal(Start)). 923 924journal_comment(start, Time) :- 925 journal(_, _, Stream), 926 format_time(string(String), '%+', Time), 927 format(Stream, 928 '/* Triple20 Journal File\n\n \c 929 Created: ~w\n \c 930 Triple20 by Jan Wielemaker <wielemak@science.uva.nl>\n\n \c 931 EDIT WITH CARE!\n\c 932 */~n~n', [String]). 933journal_comment(resume, Time) :- 934 journal(_, _, Stream), 935 format_time(string(String), '%+', Time), 936 format(Stream, 937 '\n\c 938 /* Resumed: ~w\n\c 939 */~n~n', [String]).
946rdfe_close_journal :-
947 get_time(T),
948 SecTime is round(T),
949 journal(end([ time(SecTime)
950 ])),
951 retract(journal(_, Mode, Stream)),
952 ( Mode = append(_)
953 -> true
954 ; close(Stream)
955 ).
961rdfe_current_journal(Path) :- 962 journal(Path, _Mode, _Stream). 963 964journal(Term) :- 965 journal(Path, append(T), _), 966 !, 967 ( Term = end(_) 968 -> true 969 ; open(Path, append, Stream, [close_on_abort(false)]), 970 retractall(journal(Path, _, _)), 971 assert(journal(Path, append, Stream)), 972 journal_open(resume, T), 973 journal(Term) 974 ). 975journal(Term) :- 976 ( journal(_, _, Stream) 977 -> write_journal(Term, Stream), 978 flush_output(Stream) 979 ; broadcast(rdf_no_journal(Term)) 980 ). 981 982write_journal(commit(TID, Time), Stream) :- 983 !, 984 format(Stream, 'commit(~q, ~2f).~n~n', [TID, Time]). 985write_journal(Term, Stream) :- 986 format(Stream, '~q.~n', [Term]).
995rdfe_replay_journal(File) :- 996 absolute_file_name(File, 997 [ extensions([rdfj, '']), 998 access(read) 999 ], 1000 Path), 1001 open(Path, read, Stream), 1002 replay(Stream), 1003 close(Stream). 1004 1005replay(Stream) :- 1006 read(Stream, Term), 1007 replay(Term, Stream). 1008 1009replay(end_of_file, _) :- !. 1010replay(start(_Attributes), Stream) :- 1011 !, 1012 read(Stream, Term), 1013 replay(Term, Stream). 1014replay(resume(_Attributes), Stream) :- 1015 !, 1016 read(Stream, Term), 1017 replay(Term, Stream). 1018replay(end(_Attributes), Stream) :- 1019 !, 1020 read(Stream, Term), 1021 replay(Term, Stream). 1022replay(Term0, Stream) :- 1023 replay_transaction(Term0, Stream), 1024 read(Stream, Term), 1025 replay(Term, Stream). 1026 1027replay_transaction(Term0, Stream) :- 1028 collect_transaction(Term0, Stream, Transaction, Last), 1029 ( committed_transaction(Last) 1030 -> replay_actions(Transaction) 1031 ; true 1032 ). 1033 1034collect_transaction(End, _, [], End) :- 1035 ends_transaction(End), 1036 !. 1037collect_transaction(A, Stream, [A|T], End) :- 1038 read(Stream, Term), 1039 collect_transaction(Term, Stream, T, End). 1040 1041committed_transaction(commit(_)). 1042committed_transaction(commit(_, _)). 1043 1044ends_transaction(end_of_file). 1045ends_transaction(commit(_)). 1046ends_transaction(commit(_, _)). 1047ends_transaction(rollback(_)). 1048ends_transaction(end(_)). 1049ends_transaction(start(_)). 1050 1051replay_actions([]). 1052replay_actions([H|T]) :- 1053 ( replay_action(H) 1054 -> replay_actions(T) 1055 ; print_message(warning, 1056 rdf_replay_failed(H)), 1057 ( debugging(journal) 1058 -> gtrace, 1059 replay_actions([H|T]) 1060 ; replay_actions(T) 1061 ) 1062 ).
1077replay_action(retract(_, Subject, Predicate, Object, PayLoad)) :- 1078 rdf_retractall(Subject, Predicate, Object, PayLoad). 1079replay_action(assert(_, Subject, Predicate, Object, PayLoad)) :- 1080 rdf_assert(Subject, Predicate, Object, PayLoad). 1081replay_action(update(_, Subject, Predicate, Object, Action)) :- 1082 rdf_update(Subject, Predicate, Object, Action). 1083replay_action(update(_, Subject, Predicate, Object, Payload, Action)) :- 1084 rdf_update(Subject, Predicate, Object, Payload, Action). 1085replay_action(rdf_load(_, File, Options)) :- 1086 memberchk(md5(MD5), Options), 1087 snapshot_file(File, MD5, 1088 [ access(read), 1089 file_errors(fail) 1090 ], 1091 Path), 1092 !, 1093 debug(snapshot, 'Reloading snapshot ~w~n', [Path]), 1094 load_snapshot(File, Path). 1095replay_action(rdf_load(_, File, Options)) :- 1096 find_file(File, Options, Path), 1097 ( memberchk(triples(0), Options), 1098 memberchk(modified(Modified), Options) 1099 -> rdf_retractall(_,_,_,Path:_), 1100 retractall(rdf_db:rdf_source(Path, _, _, _)), % TBD: move 1101 rdf_md5(Path, MD5), 1102 assert(rdf_db:rdf_source(Path, Modified, 0, MD5)) 1103 ; rdf_load(Path) 1104 ). 1105replay_action(rdf_unload(_, Source)) :- 1106 rdf_unload(Source). 1107replay_action(ns(_, register(ID, URI))) :- 1108 !, 1109 rdf_register_ns(ID, URI). 1110replay_action(ns(_, unregister(ID, URI))) :- 1111 retractall(rdf_db:ns(ID, URI)). 1112replay_action(watermark(_, _Name)) :- 1113 true. 1114 1115find_file(File, _, File) :- 1116 exists_file(File), 1117 !. 1118find_file(File, Options, Path) :- 1119 memberchk(pwd(PWD), Options), 1120 make_path(File, PWD, Path), 1121 exists_file(Path), 1122 !.
1128make_path(File, PWD, Path) :- 1129 atom_concat(PWD, /, PWD2), 1130 atom_concat(PWD2, Path, File). 1131 1132 1133 /******************************* 1134 * MESSAGES * 1135 *******************************/ 1136 1137:- multifile 1138 prolog:message/3, 1139 user:message_hook/3. 1140 1141% Catch messages. 1142 1143prologmessage(rdf_replay_failed(Term)) --> 1144 [ 'RDFDB: Replay of ~p failed'-[Term] ]. 1145prologmessage(rdf_undo_failed(Term)) --> 1146 [ 'RDFDB: Undo of ~p failed'-[Term] ]
RDF edit layer
This library provides a number of functions on top of the rdf_db module:
rdf_persistency.pl
provides reliable persistency, but without changes boardcasting and undo/redo. */